Browse Source

working on project settings update:

adding/updating members not implemented
kanban
Stephan Richter 4 months ago
parent
commit
6016f81c27
  1. 1
      core/src/main/java/de/srsoftware/umbrella/core/Constants.java
  2. 2
      core/src/main/java/de/srsoftware/umbrella/core/model/Member.java
  3. 12
      core/src/main/java/de/srsoftware/umbrella/core/model/Permission.java
  4. 40
      core/src/main/java/de/srsoftware/umbrella/core/model/Project.java
  5. 3
      frontend/src/Components/ListTask.svelte
  6. 42
      frontend/src/Components/MemberEditor.svelte
  7. 26
      frontend/src/Components/PermissionSelector.svelte
  8. 25
      frontend/src/routes/project/View.svelte
  9. 1
      items/src/main/java/de/srsoftware/umbrella/items/Constants.java
  10. 1
      items/src/main/java/de/srsoftware/umbrella/items/Item.java
  11. 14
      project/src/main/java/de/srsoftware/umbrella/project/ProjectModule.java
  12. 9
      project/src/main/java/de/srsoftware/umbrella/project/SqliteDb.java
  13. 8
      task/src/main/java/de/srsoftware/umbrella/task/TaskModule.java
  14. 6
      translations/src/main/resources/de.json
  15. 1
      user/src/main/java/de/srsoftware/umbrella/user/Constants.java
  16. 1
      user/src/main/java/de/srsoftware/umbrella/user/UserModule.java
  17. 11
      web/src/main/resources/web/css/default.css

1
core/src/main/java/de/srsoftware/umbrella/core/Constants.java

@ -12,6 +12,7 @@ public class Constants {
public static final String ATTACHMENTS = "attachments"; public static final String ATTACHMENTS = "attachments";
public static final String AUTHORIZATION = "Authorization"; public static final String AUTHORIZATION = "Authorization";
public static final String BODY = "body"; public static final String BODY = "body";
public static final String CODE = "code";
public static final String COMPANY = "company"; public static final String COMPANY = "company";
public static final String COMPANY_ID = "company_id"; public static final String COMPANY_ID = "company_id";
public static final String CONTENT_TYPE = "Content-Type"; public static final String CONTENT_TYPE = "Content-Type";

2
core/src/main/java/de/srsoftware/umbrella/core/model/Member.java

@ -10,6 +10,6 @@ import java.util.Map;
public record Member(long userId, Permission permission) implements Mappable { public record Member(long userId, Permission permission) implements Mappable {
@Override @Override
public Map<String, Object> toMap() { public Map<String, Object> toMap() {
return Map.of(USER_ID,userId,PERMISSION,permission.name()); return Map.of(USER_ID,userId,PERMISSION,permission.toMap());
} }
} }

12
core/src/main/java/de/srsoftware/umbrella/core/model/Permission.java

@ -1,11 +1,16 @@
/* © SRSoftware 2025 */ /* © SRSoftware 2025 */
package de.srsoftware.umbrella.core.model; package de.srsoftware.umbrella.core.model;
import de.srsoftware.tools.Mappable;
import static de.srsoftware.umbrella.core.Constants.CODE;
import static de.srsoftware.umbrella.core.Constants.NAME;
import static java.text.MessageFormat.format; import static java.text.MessageFormat.format;
import java.security.InvalidParameterException; import java.security.InvalidParameterException;
import java.util.Map;
public enum Permission { public enum Permission implements Mappable {
OWNER(1), OWNER(1),
EDIT(2), EDIT(2),
ASSIGNEE(3), ASSIGNEE(3),
@ -27,4 +32,9 @@ public enum Permission {
} }
throw new InvalidParameterException(format("{0} is not a valid permission code")); throw new InvalidParameterException(format("{0} is not a valid permission code"));
} }
@Override
public Map<String, Object> toMap() {
return Map.of(NAME,name(),CODE,code);
}
} }

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

@ -1,18 +1,23 @@
/* © SRSoftware 2025 */ /* © SRSoftware 2025 */
package de.srsoftware.umbrella.core.model; package de.srsoftware.umbrella.core.model;
import static de.srsoftware.tools.Optionals.isSet;
import static de.srsoftware.tools.Optionals.nullable; import static de.srsoftware.tools.Optionals.nullable;
import static de.srsoftware.umbrella.core.Constants.*; import static de.srsoftware.umbrella.core.Constants.*;
import static de.srsoftware.umbrella.core.Util.markdown; import static de.srsoftware.umbrella.core.Util.markdown;
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.invalidFieldException;
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.missingFieldException;
import de.srsoftware.tools.Mappable; import de.srsoftware.tools.Mappable;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.*; import java.util.*;
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
import org.json.JSONObject; import org.json.JSONObject;
public class Project implements Mappable { public class Project implements Mappable {
private final Collection<Member> members; private final Map<Long,Member> members;
private final boolean showClosed; private final boolean showClosed;
private final Long companyId; private final Long companyId;
private Status status; private Status status;
@ -21,7 +26,7 @@ public class Project implements Mappable {
private String description; private String description;
private final Set<String> dirtyFields = new HashSet<>(); private final Set<String> dirtyFields = new HashSet<>();
public Project(long id, String name, String description, Status status, Long companyId, boolean showClosed, Collection<Member> members) { public Project(long id, String name, String description, Status status, Long companyId, boolean showClosed, Map<Long,Member> members) {
this.id = id; this.id = id;
this.name = name; this.name = name;
this.description = description; this.description = description;
@ -44,17 +49,15 @@ public class Project implements Mappable {
} }
public boolean hasMember(UmbrellaUser user) { public boolean hasMember(UmbrellaUser user) {
for (var member : members){ var member = members.get(user.id());
if (member.userId() == user.id()) return true; return isSet(member) && member.userId() == user.id();
}
return false;
} }
public long id(){ public long id(){
return id; return id;
} }
public Collection<Member> members(){ public Map<Long,Member> members(){
return members; return members;
} }
@ -64,13 +67,14 @@ public class Project implements Mappable {
public static Project of(ResultSet rs) throws SQLException { public static Project of(ResultSet rs) throws SQLException {
var companyId = rs.getLong(COMPANY_ID); var companyId = rs.getLong(COMPANY_ID);
return new Project(rs.getLong(ID),rs.getString(NAME),rs.getString(DESCRIPTION),Status.of(rs.getInt(STATUS)),companyId == 0 ? null : companyId,rs.getBoolean(SHOW_CLOSED),new ArrayList<>()); return new Project(rs.getLong(ID),rs.getString(NAME),rs.getString(DESCRIPTION),Status.of(rs.getInt(STATUS)),companyId == 0 ? null : companyId,rs.getBoolean(SHOW_CLOSED),new HashMap<>());
} }
public Project patch(JSONObject json) { public Project patch(JSONObject json) {
for (var key : json.keySet()){ for (var key : json.keySet()){
switch (key){ switch (key){
case DESCRIPTION: description = json.getString(key); break; case DESCRIPTION: description = json.getString(key); break;
case MEMBERS: patchMembers(json.getJSONObject(MEMBERS)); break;
case NAME: name = json.getString(key); break; case NAME: name = json.getString(key); break;
case STATUS: status = json.get(key) instanceof Number number ? Status.of(number.intValue()) : Status.valueOf(json.getString(key)); break; case STATUS: status = json.get(key) instanceof Number number ? Status.of(number.intValue()) : Status.valueOf(json.getString(key)); break;
default: key = null; default: key = null;
@ -80,6 +84,20 @@ public class Project implements Mappable {
return this; return this;
} }
private void patchMembers(JSONObject json) throws UmbrellaException {
for (var key : json.keySet()){
long userId;
try {
userId = Long.parseLong(key);
} catch (NumberFormatException e) {
throw invalidFieldException(USER_ID,"long");
}
if (!(json.get(key) instanceof Number number)) throw invalidFieldException(PERMISSION,"int");
var permission = Permission.of(number.intValue());
members.put(userId,new Member(userId,permission));
}
}
public boolean showClosed(){ public boolean showClosed(){
return showClosed; return showClosed;
} }
@ -91,13 +109,17 @@ public class Project implements Mappable {
@Override @Override
public Map<String, Object> toMap() { public Map<String, Object> toMap() {
var map = new HashMap<String, Object>(); var map = new HashMap<String, Object>();
var memberMap = new HashMap<Long,Map<String,Object>>();
if (members != null) for (var entry : members.entrySet()){
memberMap.put(entry.getKey(),entry.getValue().toMap());
}
map.put(ID,id); map.put(ID,id);
map.put(NAME,name); map.put(NAME,name);
map.put(DESCRIPTION,Map.of(SOURCE,description,RENDERED,markdown(description))); map.put(DESCRIPTION,Map.of(SOURCE,description,RENDERED,markdown(description)));
map.put(STATUS,Map.of(STATUS_CODE,status.code(), NAME,status.name())); map.put(STATUS,Map.of(STATUS_CODE,status.code(), NAME,status.name()));
map.put(COMPANY_ID,companyId); map.put(COMPANY_ID,companyId);
map.put(SHOW_CLOSED,showClosed); map.put(SHOW_CLOSED,showClosed);
map.put(MEMBERS,members == null ? List.of() : members.stream().map(Member::toMap).toList()); map.put(MEMBERS,memberMap);
return map; return map;
} }

3
frontend/src/Components/ListTask.svelte

@ -29,7 +29,8 @@
function openTask(evt){ function openTask(evt){
evt.preventDefault(); evt.preventDefault();
router.navigate(`/task/${task.id}/view`); //router.navigate(`/task/${task.id}/view`);
location.href = `https://umbrella.srsoftware.de/task/${task.id}/view`;
} }
if (task.estimated_time){ if (task.estimated_time){

42
frontend/src/Components/MemberEditor.svelte

@ -0,0 +1,42 @@
<script>
import { onMount } from 'svelte';
import { t } from '../translations.svelte.js';
import PermissionSelector from './PermissionSelector.svelte';
let { members, updatePermission = (uid,perm) => console.log({user:uid,perm:perm}) } = $props();
let error = $state(null);
let sortedMembers = $derived.by(() => Object.values(members).sort((a, b) => a.user.name.localeCompare(b.user.name)));
let permissions = $state(null);
async function loadPermissions(){
const url = `${location.protocol}//${location.host.replace('5173','8080')}/api/task/permissions`;
var resp = await fetch(url,{credentials: 'include'});
if (resp.ok){
permissions = await resp.json();
} else {
message = await resp.text();
}
}
onMount(loadPermissions);
</script>
{#if error}
<span class="error">{error}</span>
{/if}
<table>
<tbody>
{#each sortedMembers as member,i}
<tr>
{#if !i}
<th rowspan={sortedMembers.length}>{t('members')}</th>
{/if}
<td>{member.user.name}</td>
<td>
<PermissionSelector {permissions} selected={member.permission.code} onchange={(perm) => updatePermission(member.user.id,perm)} />
</td>
</tr>
{/each}
</tbody>
</table>

26
frontend/src/Components/PermissionSelector.svelte

@ -0,0 +1,26 @@
<script>
import {onMount} from 'svelte';
import {t} from '../translations.svelte.js';
let {
caption = t('select_permission'),
selected = $bindable(0),
onchange = (val) => console.log('changed to',val),
permissions = null
} = $props();
function onSelect(newVal){
onchange({name:permissions[newVal],code:newVal});
}
let message = $state(t('loading'));
</script>
{#if permissions}
<select bind:value={selected} onchange={() => onSelect(selected)}>
{#each Object.entries(permissions) as [k,perm]}
<option value={+k}>{t('permission_'+perm.toLowerCase())}</option>
{/each}
</select>
{:else}
<span>{message}</span>
{/if}

25
frontend/src/routes/project/View.svelte

@ -5,12 +5,14 @@
import MarkdownEditor from '../../Components/MarkdownEditor.svelte'; import MarkdownEditor from '../../Components/MarkdownEditor.svelte';
import LineEditor from '../../Components/LineEditor.svelte'; import LineEditor from '../../Components/LineEditor.svelte';
import StateSelector from '../../Components/StateSelector.svelte'; import StateSelector from '../../Components/StateSelector.svelte';
import MemberEditor from '../../Components/MemberEditor.svelte';
let { id } = $props(); let { id } = $props();
let project = $state(null); let project = $state(null);
let error = $state(null); let error = $state(null);
let tasks = $state(null); let tasks = $state(null);
let estimated_time = $state({sum:0}); let estimated_time = $state({sum:0});
let showSettings = $state(false);
async function loadProject(){ async function loadProject(){
const url = `${location.protocol}//${location.host.replace('5173','8080')}/api/project/${id}`; const url = `${location.protocol}//${location.host.replace('5173','8080')}/api/project/${id}`;
@ -54,6 +56,12 @@
} }
} }
function updatePermission(user_id,permission){
let members = {};
members[user_id] = permission.code;
update({members:members});
}
onMount(loadProject); onMount(loadProject);
</script> </script>
@ -68,6 +76,7 @@
<th>{t('project')}</th> <th>{t('project')}</th>
<td class="name"> <td class="name">
<LineEditor bind:value={project.name} editable={true} onSet={val => update({name:val})} /> <LineEditor bind:value={project.name} editable={true} onSet={val => update({name:val})} />
<button class="symbol" onclick={() => showSettings = true}></button>
</td> </td>
</tr> </tr>
<tr> <tr>
@ -110,16 +119,12 @@
{/if} {/if}
</td> </td>
</tr> </tr>
<tr>
<th>{t('members')}</th>
<td>
<ul>
{#each Object.entries(project.members) as [uid,member]}
<li>{member.user.name}: {t('permission.'+member.permission)}</li>
{/each}
</ul>
</td>
</tr>
</tbody> </tbody>
</table> </table>
{/if}
{#if showSettings}
<fieldset class="project settings">
<legend>{t('settings')}</legend>
<MemberEditor members={project.members} {updatePermission} />
</fieldset>
{/if} {/if}

1
items/src/main/java/de/srsoftware/umbrella/items/Constants.java

@ -3,7 +3,6 @@ package de.srsoftware.umbrella.items;
public class Constants { public class Constants {
private Constants(){} private Constants(){}
public static final String CODE = "code";
public static final String CONFIG_DATABASE = "umbrella.modules.items.database"; public static final String CONFIG_DATABASE = "umbrella.modules.items.database";
public static final String TABLE_ITEMS = "items"; public static final String TABLE_ITEMS = "items";
public static final String TAX = "tax"; public static final String TAX = "tax";

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

@ -2,6 +2,7 @@
package de.srsoftware.umbrella.items; package de.srsoftware.umbrella.items;
import static de.srsoftware.umbrella.core.Constants.*; import static de.srsoftware.umbrella.core.Constants.*;
import static de.srsoftware.umbrella.core.Constants.CODE;
import static de.srsoftware.umbrella.core.Util.markdown; import static de.srsoftware.umbrella.core.Util.markdown;
import static de.srsoftware.umbrella.items.Constants.*; import static de.srsoftware.umbrella.items.Constants.*;

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

@ -118,9 +118,9 @@ public class ProjectModule extends BaseHandler implements ProjectService {
private boolean addMembers(Project project, HttpExchange ex) throws IOException { private boolean addMembers(Project project, HttpExchange ex) throws IOException {
var map = project.toMap(); var map = project.toMap();
var members = new HashMap<Long,Map<String,Object>>(); var members = new HashMap<Long,Map<String,Object>>();
for (var member : project.members()){ for (var entry : project.members().entrySet()){
var perm = member.permission().name(); var userId = entry.getKey();
var userId = member.userId(); var perm = entry.getValue().permission().toMap();
members.put(userId,Map.of(USER,users.loadUser(userId).toMap(),PERMISSION,perm)); members.put(userId,Map.of(USER,users.loadUser(userId).toMap(),PERMISSION,perm));
} }
if (!members.isEmpty()) map.put(MEMBERS,members); if (!members.isEmpty()) map.put(MEMBERS,members);
@ -170,9 +170,9 @@ public class ProjectModule extends BaseHandler implements ProjectService {
var map = project.toMap(); var map = project.toMap();
var members = new HashMap<Long,Map<String,Object>>(); var members = new HashMap<Long,Map<String,Object>>();
var userMap = new HashMap<Long,UmbrellaUser>(); var userMap = new HashMap<Long,UmbrellaUser>();
for (var member : project.members()){ for (var memberEntry : project.members().entrySet()){
var perm = member.permission().name(); var perm = memberEntry.getValue().permission().name();
var userId = member.userId(); var userId = memberEntry.getKey();
var u = userMap.get(userId); var u = userMap.get(userId);
if (u == null) userMap.put(userId,u = users.loadUser(userId)); if (u == null) userMap.put(userId,u = users.loadUser(userId));
members.put(userId,Map.of(USER,u.toMap(),PERMISSION,perm)); members.put(userId,Map.of(USER,u.toMap(),PERMISSION,perm));
@ -205,7 +205,7 @@ public class ProjectModule extends BaseHandler implements ProjectService {
if (json.has(SETTINGS) && json.get(SETTINGS) instanceof JSONObject settingsJson){ if (json.has(SETTINGS) && json.get(SETTINGS) instanceof JSONObject settingsJson){
showClosed = settingsJson.has(SHOW_CLOSED) && settingsJson.get(SHOW_CLOSED) == TRUE; showClosed = settingsJson.has(SHOW_CLOSED) && settingsJson.get(SHOW_CLOSED) == TRUE;
} }
var prj = new Project(0,name,description, OPEN,companyId,showClosed, List.of(new Member(user.id(), OWNER))); var prj = new Project(0,name,description, OPEN,companyId,showClosed, Map.of(user.id(),new Member(user.id(), OWNER)));
prj = projects.save(prj); prj = projects.save(prj);
return sendContent(ex,prj); return sendContent(ex,prj);
} }

9
project/src/main/java/de/srsoftware/umbrella/project/SqliteDb.java

@ -43,7 +43,7 @@ public class SqliteDb implements ProjectDb {
var userId = rs.getLong(USER_ID); var userId = rs.getLong(USER_ID);
var projectId = rs.getLong(PROJECT_ID); var projectId = rs.getLong(PROJECT_ID);
var permission = Permission.of(rs.getInt(PERMISSIONS)); var permission = Permission.of(rs.getInt(PERMISSIONS));
projects.get(projectId).members().add(new Member(userId,permission)); projects.get(projectId).members().put(userId, new Member(userId,permission));
} }
rs.close(); rs.close();
return projects; return projects;
@ -198,7 +198,7 @@ CREATE TABLE IF NOT EXISTS {0} ( {1} VARCHAR(255) PRIMARY KEY, {2} VARCHAR(255)
if (id != null){ if (id != null){
if (!prj.members().isEmpty()) { if (!prj.members().isEmpty()) {
var query = insertInto(TABLE_PROJECT_USERS, PROJECT_ID, USER_ID, PERMISSIONS); var query = insertInto(TABLE_PROJECT_USERS, PROJECT_ID, USER_ID, PERMISSIONS);
for (var member : prj.members()) query.values(id, member.userId(), member.permission().code()); for (var entry : prj.members().entrySet()) query.values(id, entry.getKey(), entry.getValue().permission().code());
query.execute(db).close(); query.execute(db).close();
} }
return new Project(id, prj.name(), prj.description(),prj.status(),prj.companyId().orElse(null),prj.showClosed(),prj.members()); return new Project(id, prj.name(), prj.description(),prj.status(),prj.companyId().orElse(null),prj.showClosed(),prj.members());
@ -208,6 +208,11 @@ CREATE TABLE IF NOT EXISTS {0} ( {1} VARCHAR(255) PRIMARY KEY, {2} VARCHAR(255)
} }
} else { // Update } else { // Update
try { try {
if (prj.dirtyFields().contains(MEMBERS)){
// TODO:
LOG.log(ERROR,"Updating/Adding project members not implemented!");
prj.dirtyFields().remove(MEMBERS);
}
if (prj.isDirty()){ if (prj.isDirty()){
update(TABLE_PROJECTS).set(NAME,DESCRIPTION,STATUS,COMPANY_ID,SHOW_CLOSED).where(ID,equal(prj.id())).prepare(db) update(TABLE_PROJECTS).set(NAME,DESCRIPTION,STATUS,COMPANY_ID,SHOW_CLOSED).where(ID,equal(prj.id())).prepare(db)
.apply(prj.name(),prj.description(),prj.status().code(),prj.companyId(),prj.showClosed()) .apply(prj.name(),prj.description(),prj.status().code(),prj.companyId(),prj.showClosed())

8
task/src/main/java/de/srsoftware/umbrella/task/TaskModule.java

@ -11,6 +11,7 @@ import static de.srsoftware.umbrella.core.ResponseCode.HTTP_NOT_IMPLEMENTED;
import static de.srsoftware.umbrella.core.Util.mapValues; import static de.srsoftware.umbrella.core.Util.mapValues;
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.forbidden; import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.forbidden;
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.missingFieldException; import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.missingFieldException;
import static de.srsoftware.umbrella.project.Constants.PERMISSIONS;
import static de.srsoftware.umbrella.task.Constants.*; import static de.srsoftware.umbrella.task.Constants.*;
import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpExchange;
@ -56,6 +57,7 @@ public class TaskModule extends BaseHandler implements TaskService {
if (user.isEmpty()) return unauthorized(ex); if (user.isEmpty()) return unauthorized(ex);
var head = path.pop(); var head = path.pop();
return switch (head) { return switch (head) {
case PERMISSIONS -> getPermissionList(ex);
case STATES -> getStateList(ex); case STATES -> getStateList(ex);
default -> super.doGet(path,ex); default -> super.doGet(path,ex);
}; };
@ -104,6 +106,12 @@ public class TaskModule extends BaseHandler implements TaskService {
return sendContent(ex,result); return sendContent(ex,result);
} }
private boolean getPermissionList(HttpExchange ex) throws IOException {
var map = new HashMap<Integer,String>();
for (var permission : Permission.values()) map.put(permission.code(),permission.name());
return sendContent(ex,map);
}
private boolean getStateList(HttpExchange ex) throws IOException { private boolean getStateList(HttpExchange ex) throws IOException {
var map = new HashMap<Integer,String>(); var map = new HashMap<Integer,String>();
for (var status : Status.values()) map.put(status.code(),status.name()); for (var status : Status.values()) map.put(status.code(),status.name());

6
translations/src/main/resources/de.json

@ -140,6 +140,10 @@
"OWNER": "Besitzer" "OWNER": "Besitzer"
}, },
"permissions": "Berechtigungen", "permissions": "Berechtigungen",
"permission_assignee": "Verantwortlichter",
"permission_edit": "bearbeiten",
"permission_owner": "Besitzer",
"permission_read_only": "lesen",
"pos": "Pos", "pos": "Pos",
"position": "Position", "position": "Position",
"positions": "Positionen", "positions": "Positionen",
@ -165,7 +169,7 @@
"sender_tax_id": "Steuernummer", "sender_tax_id": "Steuernummer",
"sent_email": "Email gesendet", "sent_email": "Email gesendet",
"service": "Service", "service": "Service",
"settings" : "Eisntellungen", "settings" : "Einstellungen",
"state": "Status", "state": "Status",
"state_cancelled": "abgebrochen", "state_cancelled": "abgebrochen",
"state_complete": "abgeschlossen", "state_complete": "abgeschlossen",

1
user/src/main/java/de/srsoftware/umbrella/user/Constants.java

@ -11,7 +11,6 @@ public class Constants {
public static final String CLIENT_ID = "client_id"; public static final String CLIENT_ID = "client_id";
public static final String CLIENT_SECRET = "client_secret"; public static final String CLIENT_SECRET = "client_secret";
public static final String CODE = "code";
public static final String CONFIG_DATABASE = "umbrella.modules.user.database"; public static final String CONFIG_DATABASE = "umbrella.modules.user.database";

1
user/src/main/java/de/srsoftware/umbrella/user/UserModule.java

@ -6,6 +6,7 @@ import static de.srsoftware.tools.Optionals.*;
import static de.srsoftware.tools.Strings.uuid; import static de.srsoftware.tools.Strings.uuid;
import static de.srsoftware.umbrella.core.ConnectionProvider.connect; import static de.srsoftware.umbrella.core.ConnectionProvider.connect;
import static de.srsoftware.umbrella.core.Constants.*; import static de.srsoftware.umbrella.core.Constants.*;
import static de.srsoftware.umbrella.core.Constants.CODE;
import static de.srsoftware.umbrella.core.Paths.LIST; import static de.srsoftware.umbrella.core.Paths.LIST;
import static de.srsoftware.umbrella.core.Paths.LOGOUT; import static de.srsoftware.umbrella.core.Paths.LOGOUT;
import static de.srsoftware.umbrella.core.ResponseCode.*; import static de.srsoftware.umbrella.core.ResponseCode.*;

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

@ -99,4 +99,15 @@ td, tr{
font-family: awesome; font-family: awesome;
font-size: 20px; font-size: 20px;
font-weight: normal; font-weight: normal;
}
.settings {
position: fixed;
background: black;
top: 60px;
left: 10px;
right: 10px;
padding: 10px;
border: 1px solid orange;
border-radius: 5px;
} }
Loading…
Cancel
Save