working on usability

Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
This commit is contained in:
2026-04-03 01:22:26 +02:00
parent a933ced8d8
commit 3d840b9f8a
6 changed files with 57 additions and 23 deletions

View File

@@ -13,10 +13,12 @@ import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
import de.srsoftware.umbrella.core.model.*; import de.srsoftware.umbrella.core.model.*;
import org.json.JSONObject; import org.json.JSONObject;
import static de.srsoftware.umbrella.core.constants.Path.SOURCES;
import static de.srsoftware.umbrella.core.constants.Path.DESTINATIONS;
import java.io.IOException; import java.io.IOException;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
@@ -72,6 +74,8 @@ public class AccountingModule extends BaseHandler implements AccountingService {
var head = path.pop(); var head = path.pop();
return switch (head) { return switch (head) {
case null -> postEntry(user.get(),ex); case null -> postEntry(user.get(),ex);
case SOURCES -> postSearchSources(user.get(),ex);
case DESTINATIONS -> postSearchDestinations(user.get(),ex);
default -> super.doPost(path,ex); default -> super.doPost(path,ex);
}; };
} catch (UmbrellaException e){ } catch (UmbrellaException e){
@@ -170,4 +174,18 @@ public class AccountingModule extends BaseHandler implements AccountingService {
return sendContent(ex,newAccount != null ? newAccount : transaction); return sendContent(ex,newAccount != null ? newAccount : transaction);
} }
public boolean postSearchDestinations(UmbrellaUser user, HttpExchange ex) throws IOException {
var key = body(ex);
var users = userService().search(key);
// TODO: search known transactions for possible destinations
return sendContent(ex,mapValues(users));
}
public boolean postSearchSources(UmbrellaUser user, HttpExchange ex) throws IOException {
var key = body(ex);
var users = userService().search(key);
// TODO: search known transactions for possible sources
return sendContent(ex,mapValues(users));
}
} }

View File

@@ -22,4 +22,5 @@ public interface UserService {
Optional<UmbrellaUser> loadUser(Optional<Token> sessionToken) throws UmbrellaException; Optional<UmbrellaUser> loadUser(Optional<Token> sessionToken) throws UmbrellaException;
Optional<UmbrellaUser> loadUser(HttpExchange ex) throws UmbrellaException; Optional<UmbrellaUser> loadUser(HttpExchange ex) throws UmbrellaException;
Optional<UmbrellaUser> refreshSession(HttpExchange ex); Optional<UmbrellaUser> refreshSession(HttpExchange ex);
Map<Long, ? extends UmbrellaUser> search(String key);
} }

View File

@@ -13,6 +13,8 @@ public class Path {
public static final String COMPANY = "company"; public static final String COMPANY = "company";
public static final String CONNECTED = "connected"; public static final String CONNECTED = "connected";
public static final String DESTINATIONS = "destinations";
public static final String EVALUATE = "evaluate"; public static final String EVALUATE = "evaluate";
public static final String ITEM = "item"; public static final String ITEM = "item";
@@ -44,6 +46,7 @@ public class Path {
public static final String SEARCH = "search"; public static final String SEARCH = "search";
public static final String SELECT = "select"; public static final String SELECT = "select";
public static final String SETTINGS = "settings"; public static final String SETTINGS = "settings";
public static final String SOURCES = "sources";
public static final String STATES = "states"; public static final String STATES = "states";
public static final String STARTED = "started"; public static final String STARTED = "started";
public static final String STATE = "state"; public static final String STATE = "state";

View File

@@ -27,8 +27,7 @@
}); });
let router = useTinyRouter(); let router = useTinyRouter();
async function getUsers(text){ async function getTerminal(text,url){
var url = api('user/search');
var res = await post(url,text); var res = await post(url,text);
if (res.ok){ if (res.ok){
yikes(); yikes();
@@ -40,6 +39,16 @@
} }
} }
async function getDestinations(text){
var url = api('accounting/destinations');
return await getTerminal(text,url);
}
async function getSources(text){
var url = api('accounting/sources');
return await getTerminal(text,url);
}
async function save(){ async function save(){
let data = { let data = {
...entry, ...entry,
@@ -68,24 +77,32 @@
<fieldset class="grid2"> <fieldset class="grid2">
{#if new_account} {#if new_account}
<legend>{t('create_new_object',{object:t('account')})}</legend> <legend>{t('create_new_object',{object:t('account')})}</legend>
<span style="display:none"></span>
<span>{t('account name')}</span> <span>{t('account name')}</span>
<span>
<input type="text" bind:value={entry.account.name} /> <input type="text" bind:value={entry.account.name} />
</span>
<span>{t('currency')}</span> <span>{t('currency')}</span>
<span>
<input type="text" bind:value={entry.account.currency} /> <input type="text" bind:value={entry.account.currency} />
</span>
<hr/> <hr/>
<span style="grid-column-end: span 2">{t('first transaction')}</span>
{:else} {:else}
<legend>{t('add_object',{object:t('entry')})}</legend> <legend>{t('add_object',{object:t('transaction')})}</legend>
<span style="display:none"></span>
{/if} {/if}
<span>{t('date')}</span> <span>{t('date')}</span>
<span>
<input type="date" value={entry.date} /> <input type="date" value={entry.date} />
</span>
<span>{t('source')}</span> <span>{t('source')}</span>
<Autocomplete bind:candidate={entry.source} getCandidates={getUsers} /> <Autocomplete bind:candidate={entry.source} getCandidates={getSources} />
<span>{t('destination')}</span> <span>{t('destination')}</span>
<Autocomplete bind:candidate={entry.destination} getCandidates={getUsers} /> <Autocomplete bind:candidate={entry.destination} getCandidates={getDestinations} />
<span>{t('amount')}</span> <span>{t('amount')}</span>
<span> <span>
@@ -100,14 +117,3 @@
<button onclick={save}>{t('save')}</button> <button onclick={save}>{t('save')}</button>
</span> </span>
</fieldset> </fieldset>
<pre>
<code>
{JSON.stringify(entry,null,2)}
</code>
</pre>
<pre>
<code>
{JSON.stringify(user,null,2)}
</code>
</pre>

View File

@@ -33,7 +33,6 @@
</script> </script>
<fieldset> <fieldset>
<legend>{t('accounts')}</legend>
<span></span> <span></span>
<span> <span>
@@ -47,4 +46,6 @@
</li> </li>
{/each} {/each}
</ul> </ul>
<legend>{t('accounts')}</legend>
</fieldset> </fieldset>

View File

@@ -555,7 +555,7 @@ public class UserModule extends BaseHandler implements UserService {
var requestingUser = loadUser(ex); var requestingUser = loadUser(ex);
if (!(requestingUser.isPresent() && requestingUser.get() instanceof DbUser dbUser)) return unauthorized(ex); if (!(requestingUser.isPresent() && requestingUser.get() instanceof DbUser dbUser)) return unauthorized(ex);
var key = body(ex); var key = body(ex);
return sendContent(ex,mapValues(users.search(key))); return sendContent(ex,mapValues(search(key)));
} }
@Override @Override
@@ -576,6 +576,11 @@ public class UserModule extends BaseHandler implements UserService {
return score; return score;
} }
@Override
public Map<Long, ? extends UmbrellaUser> search(String key) {
return users.search(key);
}
private boolean update(HttpExchange ex, DbUser user, JSONObject json) throws UmbrellaException, IOException { private boolean update(HttpExchange ex, DbUser user, JSONObject json) throws UmbrellaException, IOException {
var id = user.id(); var id = user.id();
var name = json.has(NAME) && json.get(NAME) instanceof String s && !s.isBlank() ? s : user.name(); var name = json.has(NAME) && json.get(NAME) instanceof String s && !s.isBlank() ? s : user.name();