Browse Source

improved handling of null values when mapping entities to json

kanban
Stephan Richter 3 months ago
parent
commit
3d81ddd3c5
  1. 8
      core/src/main/java/de/srsoftware/umbrella/core/Util.java
  2. 3
      core/src/main/java/de/srsoftware/umbrella/core/model/Project.java
  3. 5
      core/src/main/java/de/srsoftware/umbrella/core/model/Task.java
  4. 5
      core/src/main/java/de/srsoftware/umbrella/core/model/Time.java
  5. 5
      documents/src/main/java/de/srsoftware/umbrella/documents/model/Document.java
  6. 4
      documents/src/main/java/de/srsoftware/umbrella/documents/model/Position.java
  7. 56
      frontend/src/routes/project/Create.svelte
  8. 4
      frontend/src/routes/task/Add.svelte
  9. 6
      frontend/src/routes/task/View.svelte
  10. 27
      frontend/src/unused/ClickInput.svelte
  11. 34
      frontend/src/unused/ClickSelect.svelte
  12. 31
      frontend/src/unused/EditableField.svelte
  13. 3
      items/src/main/java/de/srsoftware/umbrella/items/Item.java
  14. 7
      project/src/main/java/de/srsoftware/umbrella/project/ProjectModule.java
  15. 7
      web/src/main/resources/web/css/default.css

8
core/src/main/java/de/srsoftware/umbrella/core/Util.java

@ -48,7 +48,15 @@ public class Util { @@ -48,7 +48,15 @@ public class Util {
return result;
}
public static HashMap<String, Object> mapMarkdown(String source){
var map = new HashMap<String,Object>();
map.put(SOURCE,source);
map.put(RENDERED,markdown(source));
return map;
}
public static String markdown(String source){
if (source == null) return source;
try {
if (plantumlJar.exists()) {
var matcher = UML_PATTERN.matcher(source);

3
core/src/main/java/de/srsoftware/umbrella/core/model/Project.java

@ -3,6 +3,7 @@ package de.srsoftware.umbrella.core.model; @@ -3,6 +3,7 @@ package de.srsoftware.umbrella.core.model;
import static de.srsoftware.tools.Optionals.nullable;
import static de.srsoftware.umbrella.core.Constants.*;
import static de.srsoftware.umbrella.core.Util.mapMarkdown;
import static de.srsoftware.umbrella.core.Util.markdown;
import de.srsoftware.tools.Mappable;
@ -95,7 +96,7 @@ public class Project implements Mappable { @@ -95,7 +96,7 @@ public class Project implements Mappable {
}
map.put(ID,id);
map.put(NAME,name);
map.put(DESCRIPTION,Map.of(SOURCE,description,RENDERED,markdown(description)));
map.put(DESCRIPTION,mapMarkdown(description));
map.put(STATUS,Map.of(STATUS_CODE,status.code(), NAME,status.name()));
map.put(COMPANY_ID,companyId);
map.put(SHOW_CLOSED,showClosed);

5
core/src/main/java/de/srsoftware/umbrella/core/model/Task.java

@ -3,8 +3,7 @@ package de.srsoftware.umbrella.core.model; @@ -3,8 +3,7 @@ package de.srsoftware.umbrella.core.model;
import static de.srsoftware.tools.Optionals.nullIfEmpty;
import static de.srsoftware.umbrella.core.Constants.*;
import static de.srsoftware.umbrella.core.Util.LOG;
import static de.srsoftware.umbrella.core.Util.markdown;
import static de.srsoftware.umbrella.core.Util.*;
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.invalidFieldException;
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.missingFieldException;
import static java.lang.System.Logger.Level.WARNING;
@ -182,7 +181,7 @@ public class Task implements Mappable { @@ -182,7 +181,7 @@ public class Task implements Mappable {
map.put(PROJECT_ID, projectId);
map.put(PARENT_TASK_ID, parentTaskId);
map.put(NAME, name);
map.put(DESCRIPTION, Map.of(SOURCE,description,RENDERED,markdown(description)));
map.put(DESCRIPTION, mapMarkdown(description));
map.put(STATUS, Map.of(NAME,status.name(),STATUS_CODE,status.code()));
map.put(ESTIMATED_TIME, estimatedTime);
map.put(START_DATE,start);

5
core/src/main/java/de/srsoftware/umbrella/core/model/Time.java

@ -2,8 +2,7 @@ @@ -2,8 +2,7 @@
package de.srsoftware.umbrella.core.model;
import static de.srsoftware.umbrella.core.Constants.*;
import static de.srsoftware.umbrella.core.Util.dateTimeOf;
import static de.srsoftware.umbrella.core.Util.markdown;
import static de.srsoftware.umbrella.core.Util.*;
import de.srsoftware.tools.Mappable;
import java.sql.ResultSet;
@ -103,7 +102,7 @@ public class Time implements Mappable{ @@ -103,7 +102,7 @@ public class Time implements Mappable{
map.put(ID,id);
map.put(USER_ID,userId);
map.put(SUBJECT,subject);
map.put(DESCRIPTION,Map.of(SOURCE,description,RENDERED,markdown(description)));
map.put(DESCRIPTION,mapMarkdown(description));
map.put(START_TIME,start.toString().replace("T"," "));
map.put(END_TIME,end.toString().replace("T"," "));
map.put(STATE,Map.of(STATUS_CODE,state.code,NAME,state.name()));

5
documents/src/main/java/de/srsoftware/umbrella/documents/model/Document.java

@ -3,6 +3,7 @@ package de.srsoftware.umbrella.documents.model; @@ -3,6 +3,7 @@ package de.srsoftware.umbrella.documents.model;
import static de.srsoftware.umbrella.core.Constants.*;
import static de.srsoftware.umbrella.core.ResponseCode.HTTP_UNPROCESSABLE;
import static de.srsoftware.umbrella.core.Util.mapMarkdown;
import static de.srsoftware.umbrella.core.Util.markdown;
import static de.srsoftware.umbrella.documents.Constants.*;
import static de.srsoftware.umbrella.documents.Constants.FIELD_CUSTOMER;
@ -218,8 +219,8 @@ public final class Document implements Mappable { @@ -218,8 +219,8 @@ public final class Document implements Mappable {
map.put(DATE, date);
map.put(STATE, state.code);
map.put(FIELD_DELIVERY, delivery == null ? "" : delivery);
map.put(FIELD_HEAD, Map.of(SOURCE,head,RENDERED,markdown(head)));
map.put(FIELD_FOOTER, Map.of(SOURCE,footer,RENDERED,markdown(footer)));
map.put(FIELD_HEAD, mapMarkdown(head));
map.put(FIELD_FOOTER, mapMarkdown(footer));
map.put(FIELD_CURRENCY, currency);
map.put(SENDER, sender.toMap());
map.put(FIELD_CUSTOMER, customer.toMap());

4
documents/src/main/java/de/srsoftware/umbrella/documents/model/Position.java

@ -3,6 +3,7 @@ package de.srsoftware.umbrella.documents.model; @@ -3,6 +3,7 @@ package de.srsoftware.umbrella.documents.model;
import static de.srsoftware.umbrella.core.Constants.*;
import static de.srsoftware.umbrella.core.Util.mapMarkdown;
import static de.srsoftware.umbrella.core.Util.markdown;
import static de.srsoftware.umbrella.documents.Constants.*;
@ -188,7 +189,6 @@ public final class Position implements Mappable { @@ -188,7 +189,6 @@ public final class Position implements Mappable {
}
public Map<String, Object> renderToMap() {
var descr = Map.of(SOURCE,description,RENDERED,markdown(description));
var map = new HashMap<String, Object>();
map.put(FIELD_DOCUMENT_ID, docId);
map.put(NUMBER, num);
@ -196,7 +196,7 @@ public final class Position implements Mappable { @@ -196,7 +196,7 @@ public final class Position implements Mappable {
map.put(FIELD_AMOUNT, amount);
map.put(FIELD_UNIT, unit);
map.put(TITLE, title);
map.put(DESCRIPTION, descr);
map.put(DESCRIPTION, mapMarkdown(description));
map.put(FIELD_UNIT_PRICE, unitPrice);
map.put(FIELD_TAX, tax);
map.put(FIELD_TIME_ID, timeId);

56
frontend/src/routes/project/Create.svelte

@ -3,6 +3,7 @@ @@ -3,6 +3,7 @@
import { t } from '../../translations.svelte.js';
import CompanySelector from '../../Components/CompanySelector.svelte';
import MarkdownEditor from '../../Components/MarkdownEditor.svelte';
import Settings from './Settings.svelte';
let showSettings = $state(false);
let ready = $derived(!!project.name.trim())
@ -11,7 +12,7 @@ @@ -11,7 +12,7 @@
let project = $state({
name:'',
description:'',
description : { source : '', rendered : '' },
settings:{
show_closed:false
}
@ -53,21 +54,44 @@ @@ -53,21 +54,44 @@
</legend>
<fieldset>
<legend>{t('basic_data')}</legend>
<label>
<CompanySelector caption={t('no_company')} {onselect} />
{t('company_optional')}
</label>
<label>
<input type="text" bind:value={project.name}/>
{t('Name')}
</label>
<label>
<textarea bind:value={project.description}></textarea>
{t('description')}
</label>
{#if !showSettings}
<button onclick={() => showSettings = true}>{t('extended_settings')}</button>
{/if}
<table>
<tbody>
<tr>
<th>
{t('company_optional')}
</th>
<td>
<CompanySelector caption={t('no_company')} {onselect} />
</td>
</tr>
<tr>
<th>
{t('Name')}
</th>
<td>
<input type="text" bind:value={project.name}/>
</td>
</tr>
<tr>
<th>
{t('description')}
</th>
<td>
<MarkdownEditor bind:value={project.description} simple={true} />
</td>
</tr>
{#if !showSettings}
<tr>
<th>
{t('settings')}
</th>
<td>
<button onclick={() => showSettings = true}>{t('extended_settings')}</button>
</td>
</tr>
{/if}
</tbody>
</table>
</fieldset>
{#if showSettings}
<Settings bind:settings={project.settings}/>

4
frontend/src/routes/task/Add.svelte

@ -84,7 +84,9 @@ @@ -84,7 +84,9 @@
});
if (resp.ok) {
task = await resp.json();
router.navigate(`/task/${task.id}/view`);
if (task.parent_task_id){
router.navigate(`/task/${task.parent_task_id}/view`);
} else router.navigate(`/task/${task.id}/view`);
error = null;
} else {
error = await resp.text();

6
frontend/src/routes/task/View.svelte

@ -175,9 +175,11 @@ @@ -175,9 +175,11 @@
</td>
</tr>
<tr>
<th>{t('subtasks')}</th>
<td class="children">
<th>
{t('subtasks')}
<button onclick={addChild} >{t('add_subtask')}</button>
</th>
<td class="children">
{#if children}
<TaskList tasks={children} {estimated_time} />
{/if}

27
frontend/src/unused/ClickInput.svelte

@ -1,27 +0,0 @@ @@ -1,27 +0,0 @@
<script>
import { t } from '../translations.svelte.js';
import { checkUser } from '../user.svelte.js';
let { key, onUpdate, value } = $props();
let input = $state(false);
function edit(){
input = true;
}
function check_key(evt){
if (evt.key === 'Enter'){
input = false;
let obj = {};
obj[key] = value;
onUpdate(obj);
}
}
</script>
{#if input}
<input type="text" bind:value onkeyup={check_key} />
{:else}
<span onclick={edit}>{value}</span>
{/if}

34
frontend/src/unused/ClickSelect.svelte

@ -1,34 +0,0 @@ @@ -1,34 +0,0 @@
<script>
import { t } from '../translations.svelte.js';
import { checkUser } from '../user.svelte.js';
let { fetchOptions, key, value, onUpdate } = $props();
let options = $state([]);
async function loadOptions(){
const resp = await fetchOptions();
const arr = await resp.json();
for (let entry of arr){
const value = entry.value;
const caption = entry.caption ? entry.caption : value;
options.push({caption:caption,value:value})
}
}
function propagate(){
let changeset = {}
changeset[key] = value;
onUpdate(changeset);
}
</script>
{#if options.length > 0}
<select bind:value onchange={propagate} >
{#each options as entry,i}
<option value={entry.value}>{entry.caption}</option>
{/each}
</select>
{:else}
<span onclick={loadOptions}>{value}</span>
{/if}

31
frontend/src/unused/EditableField.svelte

@ -1,31 +0,0 @@ @@ -1,31 +0,0 @@
<script>
import { t } from '../../translations.svelte.js';
import { checkUser } from '../../user.svelte.js';
let { key, onUpdate, value } = $props();
let input = $state(false);
function edit(){
input = true;
}
function check_key(evt){
if (evt.key === 'Enter'){
input = false;
let obj = {};
obj[key] = value;
onUpdate(obj);
}
}
</script>
<tr>
<th>{t(key)}</th>
{#if input}
<td >
<input type="text" bind:value onkeyup={check_key} />
</td>
{:else}
<td onclick={edit}>{value}</td>
{/if}
</tr>

3
items/src/main/java/de/srsoftware/umbrella/items/Item.java

@ -3,6 +3,7 @@ package de.srsoftware.umbrella.items; @@ -3,6 +3,7 @@ package de.srsoftware.umbrella.items;
import static de.srsoftware.umbrella.core.Constants.*;
import static de.srsoftware.umbrella.core.Constants.CODE;
import static de.srsoftware.umbrella.core.Util.mapMarkdown;
import static de.srsoftware.umbrella.core.Util.markdown;
import static de.srsoftware.umbrella.items.Constants.*;
@ -31,7 +32,7 @@ public record Item(long id, long companyId, String code, String name, String des @@ -31,7 +32,7 @@ public record Item(long id, long companyId, String code, String name, String des
ID,id,
COMPANY_ID,companyId,
CODE,code,NAME,name,
DESCRIPTION,Map.of(SOURCE,description,RENDERED,markdown(description)),
DESCRIPTION,mapMarkdown(description),
UNIT,unit,
UNIT_PRICE,unitPrice,
TAX,tax);

7
project/src/main/java/de/srsoftware/umbrella/project/ProjectModule.java

@ -216,7 +216,12 @@ public class ProjectModule extends BaseHandler implements ProjectService { @@ -216,7 +216,12 @@ public class ProjectModule extends BaseHandler implements ProjectService {
private boolean postProject(HttpExchange ex, UmbrellaUser user) throws IOException, UmbrellaException {
var json = json(ex);
if (!(json.has(NAME) && json.get(NAME) instanceof String name)) throw missingFieldException(NAME);
var description = json.has(DESCRIPTION) && json.get(DESCRIPTION) instanceof String d ? d : null;
String description = null;
if (json.has(DESCRIPTION)){
var desc = json.get(DESCRIPTION);
if (desc instanceof String d) description = d;
if (desc instanceof JSONObject nested && nested.has(SOURCE) && nested.get(SOURCE) instanceof String d) description = d;
}
Long companyId = null;
if (json.has(COMPANY_ID) && json.get(COMPANY_ID) instanceof Number number){
if (!companies.membership(number.longValue(), user.id())) throw forbidden("You are not a member of company {0}!",number);

7
web/src/main/resources/web/css/default.css

@ -7,6 +7,7 @@ a { @@ -7,6 +7,7 @@ a {
color: orange;
}
body {
font-family: sans;
background: black;
color: orange;
margin: 0;
@ -113,4 +114,10 @@ td, tr{ @@ -113,4 +114,10 @@ td, tr{
padding: 10px;
border: 1px solid orange;
border-radius: 5px;
}
.project .name,
.task .name{
font-size: 32px;
font-weight: bold;
}
Loading…
Cancel
Save