Browse Source

code cleanup

code-review
Stephan Richter 3 months ago
parent
commit
fccec9865a
  1. 40
      frontend/src/App.svelte
  2. 3
      frontend/src/Components/Menu.svelte
  3. 8
      frontend/src/routes/document/List.svelte
  4. 8
      frontend/src/routes/document/PositionList.svelte
  5. 2
      frontend/src/routes/document/TimeList.svelte
  6. 8
      frontend/src/routes/document/View.svelte
  7. 49
      frontend/src/routes/notes/List.svelte
  8. 35
      frontend/src/routes/project/Create.svelte
  9. 93
      frontend/src/routes/project/Kanban.svelte
  10. 34
      frontend/src/routes/project/List.svelte
  11. 76
      frontend/src/routes/project/View.svelte
  12. 17
      frontend/src/routes/search/Search.svelte
  13. 32
      frontend/src/routes/tags/TagList.svelte
  14. 66
      frontend/src/routes/task/Add.svelte
  15. 48
      frontend/src/routes/task/ListTask.svelte
  16. 2
      frontend/src/routes/task/TaskList.svelte
  17. 76
      frontend/src/routes/task/View.svelte
  18. 19
      frontend/src/routes/user/ConnectedServices.svelte
  19. 35
      frontend/src/routes/user/EditPassword.svelte
  20. 28
      frontend/src/routes/user/EditService.svelte
  21. 43
      frontend/src/routes/user/EditUser.svelte
  22. 24
      frontend/src/routes/user/List.svelte
  23. 41
      frontend/src/routes/user/LoginServices.svelte
  24. 26
      frontend/src/routes/user/OidcCallback.svelte
  25. 11
      frontend/src/routes/user/Profile.svelte
  26. 34
      frontend/src/routes/user/ResetPw.svelte
  27. 16
      frontend/src/routes/user/User.svelte

40
frontend/src/App.svelte

@ -1,28 +1,30 @@
<script> <script>
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { Router, Route } from 'svelte-tiny-router';
import { loadTranslation } from './translations.svelte.js'; import { loadTranslation } from './translations.svelte.js';
import { user } from './user.svelte.js'; import { user } from './user.svelte.js';
import { Router, Route } from 'svelte-tiny-router';
import AddDoc from "./routes/document/Add.svelte"; import AddDoc from "./routes/document/Add.svelte";
import AddTask from "./routes/task/Add.svelte"; import AddTask from "./routes/task/Add.svelte";
import Callback from "./routes/user/OidcCallback.svelte"; import Callback from "./routes/user/OidcCallback.svelte";
import DocList from "./routes/document/List.svelte"; import DocList from "./routes/document/List.svelte";
import EditService from "./routes/user/EditService.svelte"; import EditService from "./routes/user/EditService.svelte";
import EditUser from "./routes/user/EditUser.svelte"; import EditUser from "./routes/user/EditUser.svelte";
import Footer from "./Components/Footer.svelte"; import Footer from "./Components/Footer.svelte";
import Kanban from "./routes/project/Kanban.svelte"; import Kanban from "./routes/project/Kanban.svelte";
import Login from "./Components/Login.svelte"; import Login from "./Components/Login.svelte";
import Messages from "./routes/message/Messages.svelte"; import Messages from "./routes/message/Messages.svelte";
import Menu from "./Components/Menu.svelte"; import Menu from "./Components/Menu.svelte";
import ProjectList from "./routes/project/List.svelte"; import ProjectList from "./routes/project/List.svelte";
import ProjectAdd from "./routes/project/Create.svelte"; import ProjectAdd from "./routes/project/Create.svelte";
import ResetPw from "./routes/user/ResetPw.svelte"; import ResetPw from "./routes/user/ResetPw.svelte";
import Search from "./routes/search/Search.svelte"; import Search from "./routes/search/Search.svelte";
import SendDoc from "./routes/document/Send.svelte"; import SendDoc from "./routes/document/Send.svelte";
import User from "./routes/user/User.svelte"; import User from "./routes/user/User.svelte";
import ViewDoc from "./routes/document/View.svelte"; import ViewDoc from "./routes/document/View.svelte";
import ViewPrj from "./routes/project/View.svelte"; import ViewPrj from "./routes/project/View.svelte";
import ViewTask from "./routes/task/View.svelte"; import ViewTask from "./routes/task/View.svelte";
let translations_ready = $state(false); let translations_ready = $state(false);

3
frontend/src/Components/Menu.svelte

@ -2,7 +2,6 @@
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { useTinyRouter } from 'svelte-tiny-router'; import { useTinyRouter } from 'svelte-tiny-router';
import { api } from '../urls.svelte.js';
import { logout, user } from '../user.svelte.js'; import { logout, user } from '../user.svelte.js';
import { t } from '../translations.svelte.js'; import { t } from '../translations.svelte.js';
@ -10,7 +9,7 @@ const router = useTinyRouter();
const modules = $state([]); const modules = $state([]);
async function fetchModules(){ async function fetchModules(){
const url = api('/legacy/modules'); const url = `${location.protocol}//${location.host.replace('5173','8080')}/legacy/modules`;
const resp = await fetch(url,{credentials:'include'}); const resp = await fetch(url,{credentials:'include'});
if (resp.ok){ if (resp.ok){
const arr = await resp.json(); const arr = await resp.json();

8
frontend/src/routes/document/List.svelte

@ -11,14 +11,14 @@
let error = null; let error = null;
let companies = {}; let companies = {};
let router = useTinyRouter();
let company_id = +router.query.company_id; let company_id = +router.query.company_id;
let documents = null; let documents = null;
let router = useTinyRouter();
let docType = 0; let docType = 0;
let selected_company = null; let selected_company = null;
async function loadCompanies(){ async function loadCompanies(){
const url = api('company/list'); const url = api('company/list');
const resp = await fetch(url,{ credentials: 'include'}); const resp = await fetch(url,{ credentials: 'include'});
if (resp.ok){ if (resp.ok){
companies = await resp.json(); companies = await resp.json();
@ -40,7 +40,7 @@
async function load(company){ async function load(company){
router.navigate(`/document?company_id=${company.id}`); router.navigate(`/document?company_id=${company.id}`);
selected_company = company; selected_company = company;
const url = api('document/list'); const url = api('document/list');
const resp = await fetch(url,{ const resp = await fetch(url,{
credentials: 'include', credentials: 'include',
method: 'POST', method: 'POST',
@ -63,7 +63,7 @@
async function deleteDoc(ev,doc){ async function deleteDoc(ev,doc){
if (confirm(t('really_delete',doc.number))){ if (confirm(t('really_delete',doc.number))){
const url = api(`document/${doc.id}`; const url = api(`document/${doc.id}`);
const resp = await fetch(url,{ const resp = await fetch(url,{
credentials: 'include', credentials: 'include',
method: 'DELETE' method: 'DELETE'

8
frontend/src/routes/document/PositionList.svelte

@ -2,14 +2,14 @@
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { useTinyRouter } from 'svelte-tiny-router'; import { useTinyRouter } from 'svelte-tiny-router';
import { api } from '../../urls.svelte-js'; import { api } from '../../urls.svelte.js';
import { t } from '../../translations.svelte.js'; import { t } from '../../translations.svelte.js';
import Position from './Position.svelte'; import Position from './Position.svelte';
var { var {
document = $bindable(null), document = $bindable(null),
error = $bindable(null) error = $bindable(null),
submit = (key,newVal) => {}, submit = (key,newVal) => {},
} = $props(); } = $props();
@ -23,7 +23,7 @@
} }
async function movePos(number,step){ async function movePos(number,step){
const url = api(`document/${document.id}/position`; const url = api(`document/${document.id}/position`);
const resp = await fetch(url,{ const resp = await fetch(url,{
method : 'PATCH', method : 'PATCH',
credentials: 'include', credentials: 'include',
@ -39,7 +39,7 @@
async function drop(number){ async function drop(number){
let confirmed = confirm(t('confirm_deletion').replace('{pos}',document.positions[number].item)); let confirmed = confirm(t('confirm_deletion').replace('{pos}',document.positions[number].item));
if (!confirmed) return; if (!confirmed) return;
const url = api(`document/${document.id}/position`; const url = api(`document/${document.id}/position`);
const resp = await fetch(url,{ const resp = await fetch(url,{
method : 'DELETE', method : 'DELETE',
credentials: 'include', credentials: 'include',

2
frontend/src/routes/document/TimeList.svelte

@ -14,7 +14,7 @@
let times = $state(null); let times = $state(null);
async function loadProjects(){ async function loadProjects(){
const url = api'project/list'); const url = api('project/list');
let data = { company_id: company_id }; let data = { company_id: company_id };
const resp = await fetch(url,{ const resp = await fetch(url,{
credentials : 'include', credentials : 'include',

8
frontend/src/routes/document/View.svelte

@ -27,7 +27,7 @@
async function loadDoc(){ async function loadDoc(){
const url = api(`document/${id}`; const url = api(`document/${id}`);
const resp = await fetch(url,{credentials:'include'}); const resp = await fetch(url,{credentials:'include'});
if (resp.ok){ if (resp.ok){
doc = await resp.json(); doc = await resp.json();
@ -61,7 +61,7 @@
data[parts.pop()] = inner; data[parts.pop()] = inner;
} }
try { try {
const url = api(`document/${doc.id}`; const url = api(`document/${doc.id}`);
const resp = await fetch(url,{ const resp = await fetch(url,{
credentials : 'include', credentials : 'include',
method : 'PATCH', method : 'PATCH',
@ -74,7 +74,7 @@
} }
async function addPosition(selected){ async function addPosition(selected){
const url = api(`document/${doc.id}/position`; const url = api(`document/${doc.id}/position`);
const resp = await fetch(url,{ const resp = await fetch(url,{
method : 'POST', method : 'POST',
credentials : 'include', credentials : 'include',
@ -91,7 +91,7 @@
async function render(ev){ async function render(ev){
pdfDisabled = true; pdfDisabled = true;
const url = api(`document/${doc.id}/pdf`; const url = api(`document/${doc.id}/pdf`);
const resp = await fetch(url,{credentials:'include'}); const resp = await fetch(url,{credentials:'include'});
if (resp.ok){ if (resp.ok){
error = null; error = null;

49
frontend/src/routes/notes/List.svelte

@ -1,29 +1,34 @@
<script> <script>
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { api } from '../../urls.svelte.js';
import { t } from '../../translations.svelte.js'; import { api } from '../../urls.svelte.js';
import { user } from '../../user.svelte.js'; import { t } from '../../translations.svelte.js';
import { user } from '../../user.svelte.js';
import Editor from '../../Components/MarkdownEditor.svelte'; import Editor from '../../Components/MarkdownEditor.svelte';
let error = $state(null);
let { module = null, entity_id = null } = $props();
let note = $state({source:null,rendered:null});
let notes = $state(null);
let authors = $state(null); let authors = $state(null);
let error = $state(null);
let note = $state({source:null,rendered:null});
let notes = $state(null);
let {
module = null,
entity_id = null
} = $props();
async function saveNote(){ async function saveNote(){
const url = api(`notes/${module}/${entity_id}`); const url = api(`notes/${module}/${entity_id}`);
const resp = await fetch(url,{ const resp = await fetch(url,{
credentials:'include', credentials : 'include',
method:'POST', method : 'POST',
body:note.source body : note.source
}); });
if (resp.ok){ if (resp.ok){
let newNote = await resp.json(); let newNote = await resp.json();
authors[user.id] = user; authors[user.id] = user;
notes[newNote.id] = newNote; notes[newNote.id] = newNote;
note = {source:'',rendered:''}; note = {source:'',rendered:''};
error = null; error = null;
return true; return true;
} else { } else {
error = await resp.text(); error = await resp.text();
@ -32,12 +37,12 @@
} }
async function load(){ async function load(){
const url = api(`notes/${module}/${entity_id}`); const url = api(`notes/${module}/${entity_id}`);
const resp = await fetch(url,{credentials:'include'}); const resp = await fetch(url,{credentials:'include'});
if (resp.ok){ if (resp.ok){
const data = await resp.json(); const data = await resp.json();
notes = data.notes; notes = data.notes;
authors = data.authors; authors = data.authors;
} else { } else {
error = await resp.text(); error = await resp.text();
} }
@ -51,10 +56,10 @@
position: relative; position: relative;
} }
legend.time{ legend.time{
position: absolute; position : absolute;
top: -19px; top : -19px;
right: 20px; right : 20px;
background: black; background : black;
} }
</style> </style>

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

@ -1,34 +1,33 @@
<script> <script>
import { useTinyRouter } from 'svelte-tiny-router'; import { useTinyRouter } from 'svelte-tiny-router';
import { t } from '../../translations.svelte.js'; import { api } from '../../urls.svelte.js';
import { t } from '../../translations.svelte.js';
import CompanySelector from '../../Components/CompanySelector.svelte'; import CompanySelector from '../../Components/CompanySelector.svelte';
import MarkdownEditor from '../../Components/MarkdownEditor.svelte'; import MarkdownEditor from '../../Components/MarkdownEditor.svelte';
import Settings from './Settings.svelte'; import Settings from './Settings.svelte';
import Tags from '../tags/TagList.svelte'; import Tags from '../tags/TagList.svelte';
let error = $state(null); let error = $state(null);
let ready = $derived(!!project.name.trim()) let ready = $derived(!!project.name.trim())
const router = useTinyRouter(); const router = useTinyRouter();
let showSettings = $state(false); let showSettings = $state(false);
let project = $state({ let project = $state({
name:'', name : '',
description : { source : '', rendered : '' }, description : { source : '', rendered : '' },
settings:{ settings : { show_closed:false },
show_closed:false tags : []
},
tags: []
}); });
async function onsubmit(ev){ async function onsubmit(ev){
ev.preventDefault(); ev.preventDefault();
const url = `${location.protocol}//${location.host.replace('5173','8080')}/api/project`; const url = api('project');
var resp = await fetch(url,{ var resp = await fetch(url,{
credentials: 'include', credentials : 'include',
method: 'POST', method : 'POST',
body: JSON.stringify(project) body : JSON.stringify(project)
}); });
if (resp.ok){ if (resp.ok){
var newProject = await resp.json(); var newProject = await resp.json();

93
frontend/src/routes/project/Kanban.svelte

@ -1,48 +1,47 @@
<script> <script>
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { useTinyRouter } from 'svelte-tiny-router'; import { useTinyRouter } from 'svelte-tiny-router';
import { api } from '../../urls.svelte.js'; import { api } from '../../urls.svelte.js';
import { t } from '../../translations.svelte.js'; import { t } from '../../translations.svelte.js';
import { user } from '../../user.svelte.js'; import { user } from '../../user.svelte.js';
import Card from './KanbanCard.svelte'; import Card from './KanbanCard.svelte';
import LineEditor from '../../Components/LineEditor.svelte'; import LineEditor from '../../Components/LineEditor.svelte';
let { id } = $props(); let { id } = $props();
let dragged = null; let dragged = null;
let error = $state(null); let error = $state(null);
let highlight = $state({}); let highlight = $state({});
let project = $state(null);
let ready = $state(false);
let router = useTinyRouter();
let states = $state(null);
let tasks = $state({});
let filter_input = $state(''); let filter_input = $state('');
let filter = $derived(filter_input.toLowerCase()); let filter = $derived(filter_input.toLowerCase());
let users = {}; let project = $state(null);
let ready = $state(false);
let columns = $derived(states?Object.keys(states).length+1:1); let router = useTinyRouter();
let states = $state(null);
let tasks = $state({});
let users = {};
let columns = $derived(states?Object.keys(states).length+1:1);
async function create(name,user_id,state){ async function create(name,user_id,state){
var url = api('task/add'); var url = api('task/add');
let task = { let task = {
description: '', description : '',
members : {}, members : {},
name: name, name : name,
project_id: +id, project_id : +id,
status : { code : +state} status : { code : +state}
} }
task.members[user_id] = { permission: { name : 'ASSIGNEE' }}; task.members[user_id] = { permission: { name : 'ASSIGNEE' }};
task.members[user.id] = { permission: { name : 'OWNER' }}; task.members[user.id] = { permission: { name : 'OWNER' }};
const resp = await fetch(url,{ const resp = await fetch(url,{
credentials:'include', credentials : 'include',
method:'POST', method : 'POST',
body: JSON.stringify(task) body : JSON.stringify(task)
}); });
if (resp.ok) { if (resp.ok) {
task = await resp.json(); task = await resp.json();
task.assignee = user_id; task.assignee = user_id;
if (!tasks[user_id]) tasks[user_id] = {}; if (!tasks[user_id]) tasks[user_id] = {};
if (!tasks[user_id][state]) tasks[user_id][state] = {}; if (!tasks[user_id][state]) tasks[user_id][state] = {};
@ -54,18 +53,18 @@
} }
async function drop(user_id,state){ async function drop(user_id,state){
let task = dragged; let task = dragged;
dragged = null; dragged = null;
highlight = {}; highlight = {};
if (task.assignee == user_id && task.status.code == state) return; // no change if (task.assignee == user_id && task.status.code == state) return; // no change
let patch = {members:{},status:+state} let patch = {members:{},status:+state}
patch.members[user_id] = 'ASSIGNEE'; patch.members[user_id] = 'ASSIGNEE';
const url = api(`task/${task.id}`); const url = api(`task/${task.id}`);
const resp = await fetch(url,{ const resp = await fetch(url,{
credentials: 'include', credentials : 'include',
method: 'PATCH', method : 'PATCH',
body: JSON.stringify(patch) body : JSON.stringify(patch)
}); });
if (resp.ok){ if (resp.ok){
delete tasks[task.assignee][task.status.code][task.id] delete tasks[task.assignee][task.status.code][task.id]
@ -73,8 +72,8 @@
if (!tasks[user_id][state]) tasks[user_id][state] = {} if (!tasks[user_id][state]) tasks[user_id][state] = {}
tasks[user_id][state][task.id] = task; tasks[user_id][state][task.id] = task;
task.assignee = user_id; task.assignee = user_id;
task.status = {code:state,name:states[state]}; task.status = {code:state,name:states[state]};
error = null; error = null;
} else { } else {
error = await resp.text(); error = await resp.text();
} }
@ -89,7 +88,7 @@
} }
async function loadProject(){ async function loadProject(){
const url = api(`project/${id}`); const url = api(`project/${id}`);
const resp = await fetch(url,{credentials:'include'}); const resp = await fetch(url,{credentials:'include'});
if (resp.ok){ if (resp.ok){
project = await resp.json(); project = await resp.json();
@ -105,18 +104,18 @@
} }
async function loadStates(){ async function loadStates(){
const url = api(`project/${id}/states`); const url = api(`project/${id}/states`);
const resp = await fetch(url,{credentials:'include'}); const resp = await fetch(url,{credentials:'include'});
if (resp.ok){ if (resp.ok){
states = await resp.json(); states = await resp.json();
error = null; error = null;
} else { } else {
error = await resp.text(); error = await resp.text();
} }
} }
async function loadTag(task){ async function loadTag(task){
const url = api(`tags/task/${task.id}`); const url = api(`tags/task/${task.id}`);
const resp = await fetch(url,{credentials:'include'}); const resp = await fetch(url,{credentials:'include'});
if (resp.ok) { if (resp.ok) {
const tags = await resp.json(); const tags = await resp.json();
@ -136,24 +135,24 @@
} }
async function loadTasks(selector){ async function loadTasks(selector){
const url = api('task/list'); const url = api('task/list');
selector.show_closed = true; selector.show_closed = true;
selector.no_index = true; selector.no_index = true;
var resp = await fetch(url,{ var resp = await fetch(url,{
credentials: 'include', credentials : 'include',
method:'POST', method : 'POST',
body:JSON.stringify(selector) body : JSON.stringify(selector)
}); });
if (resp.ok){ if (resp.ok){
var json = await resp.json(); var json = await resp.json();
for (var task_id of Object.keys(json)) { for (var task_id of Object.keys(json)) {
let task = json[task_id]; let task = json[task_id];
let state = task.status.code; let state = task.status.code;
let owner = null; let owner = null;
let assignee = null; let assignee = null;
for (var user_id of Object.keys(task.members)){ for (var user_id of Object.keys(task.members)){
var member = task.members[user_id]; var member = task.members[user_id];
if (member.permission.name == 'OWNER') owner = user_id; if (member.permission.name == 'OWNER') owner = user_id;
if (member.permission.name == 'ASSIGNEE') assignee = user_id; if (member.permission.name == 'ASSIGNEE') assignee = user_id;
} }

34
frontend/src/routes/project/List.svelte

@ -1,28 +1,28 @@
<script> <script>
import { onMount } from 'svelte';
import { useTinyRouter } from 'svelte-tiny-router'; import { useTinyRouter } from 'svelte-tiny-router';
import { onMount } from 'svelte';
import { t } from '../../translations.svelte.js'; import { api } from '../../urls.svelte.js';
import { api } from '../../urls.svelte.js'; import { t } from '../../translations.svelte.js';
const router = useTinyRouter(); const router = useTinyRouter();
let error = $state(null); let error = $state(null);
let projects = $state(null); let projects = $state(null);
let companies = $state(null); let companies = $state(null);
let showClosed = $state(router.query.closed == "show"); let showClosed = $state(router.query.closed == "show");
let sortedProjects = $derived.by(() => Object.values(projects).sort((a, b) => a.name.localeCompare(b.name))); let sortedProjects = $derived.by(() => Object.values(projects).sort((a, b) => a.name.localeCompare(b.name)));
async function loadProjects(){ async function loadProjects(){
let url = api('company/list'); let url = api('company/list');
let resp = await fetch(url,{credentials:'include'}); let resp = await fetch(url,{credentials:'include'});
if (resp.ok){ if (resp.ok){
companies = await resp.json(); companies = await resp.json();
url = `${location.protocol}//${location.host.replace('5173','8080')}/api/project/list`; url = `${location.protocol}//${location.host.replace('5173','8080')}/api/project/list`;
resp = await fetch(url,{ resp = await fetch(url,{
credentials:'include', credentials : 'include',
method:'POST', method : 'POST',
body:JSON.stringify({show_closed:showClosed}) body : JSON.stringify({show_closed:showClosed})
}); });
if (resp.ok){ if (resp.ok){
projects = await resp.json(); projects = await resp.json();
@ -35,14 +35,14 @@
} }
async function setState(pid,state_name){ async function setState(pid,state_name){
const url = api(`project/${pid}`); const url = api(`project/${pid}`);
const resp = await fetch(url,{ const resp = await fetch(url,{
credentials:'include', credentials : 'include',
method:'PATCH', method : 'PATCH',
body:JSON.stringify({status:state_name}) body : JSON.stringify({status:state_name})
}); });
if (resp.ok){ if (resp.ok){
var prj = await resp.json(); var prj = await resp.json();
projects[prj.id].status = prj.status; projects[prj.id].status = prj.status;
} else { } else {
error = await resp.text(); error = await resp.text();

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

@ -1,25 +1,25 @@
<script> <script>
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { useTinyRouter } from 'svelte-tiny-router'; import { useTinyRouter } from 'svelte-tiny-router';
import { api } from '../../urls.svelte.js'; import { api } from '../../urls.svelte.js';
import { t } from '../../translations.svelte.js'; import { t } from '../../translations.svelte.js';
import LineEditor from '../../Components/LineEditor.svelte'; import LineEditor from '../../Components/LineEditor.svelte';
import MarkdownEditor from '../../Components/MarkdownEditor.svelte'; import MarkdownEditor from '../../Components/MarkdownEditor.svelte';
import MemberEditor from '../../Components/MemberEditor.svelte'; import MemberEditor from '../../Components/MemberEditor.svelte';
import Notes from '../notes/List.svelte'; import Notes from '../notes/List.svelte';
import StateSelector from '../../Components/StateSelector.svelte'; import StateSelector from '../../Components/StateSelector.svelte';
import Tags from '../tags/TagList.svelte'; import Tags from '../tags/TagList.svelte';
import TaskList from '../task/TaskList.svelte'; import TaskList from '../task/TaskList.svelte';
let router = useTinyRouter(); let { id } = $props();
let { id } = $props(); let error = $state(null);
let project = $state(null);
let error = $state(null);
let tasks = $state(null);
let estimated_time = $state({sum:0}); let estimated_time = $state({sum:0});
let showSettings = $state(false); let project = $state(null);
let router = useTinyRouter();
let showSettings = $state(false);
let tasks = $state(null);
async function addMember(entry){ async function addMember(entry){
const ids = Object.keys(entry); const ids = Object.keys(entry);
@ -40,11 +40,11 @@
} }
async function getCandidates(text){ async function getCandidates(text){
const url = api('user/search'); const url = api('user/search');
var resp = await fetch(url,{ const resp = await fetch(url,{
credentials: 'include', credentials : 'include',
method: 'POST', method : 'POST',
body: text body : text
}); });
if (resp.ok){ if (resp.ok){
var json = await resp.json(); var json = await resp.json();
@ -59,11 +59,11 @@
} }
async function loadProject(){ async function loadProject(){
const url = api(`project/${id}`); const url = api(`project/${id}`);
const resp = await fetch(url,{credentials:'include'}); const resp = await fetch(url,{credentials:'include'});
if (resp.ok){ if (resp.ok){
project = await resp.json(); project = await resp.json();
error = null; error = null;
loadTasks(); loadTasks();
} else { } else {
error = await resp.text(); error = await resp.text();
@ -71,35 +71,35 @@
} }
async function loadTasks(){ async function loadTasks(){
const url = api('task/list'); const url = api('task/list');
const data = { const data = {
project_id:+id, project_id:+id,
show_closed:project.show_closed show_closed:project.show_closed
} }
const resp = await fetch(url,{ const resp = await fetch(url,{
credentials:'include', credentials : 'include',
method:'POST', method : 'POST',
body:JSON.stringify(data) body : JSON.stringify(data)
}); });
if (resp.ok){ if (resp.ok){
tasks = {}; tasks = {};
estimated_time.sum = 0; estimated_time.sum = 0;
tasks = await resp.json(); tasks = await resp.json();
error = null; error = null;
} else { } else {
error = await resp.text(); error = await resp.text();
} }
} }
async function update(data){ async function update(data){
const url = api(`project/${id}`); const url = api(`project/${id}`);
const resp = await fetch(url,{ const resp = await fetch(url,{
credentials:'include', credentials : 'include',
method:'PATCH', method : 'PATCH',
body:JSON.stringify(data) body : JSON.stringify(data)
}); });
if (resp.ok){ if (resp.ok){
error = null; error = null;
project = await resp.json(); project = await resp.json();
return true; return true;
} else { } else {
@ -114,7 +114,7 @@
function updatePermission(user_id,permission){ function updatePermission(user_id,permission){
let members = {}; let members = {};
members[user_id] = permission.code; members[user_id] = permission.code;
update({members:members}); update({members:members});
} }

17
frontend/src/routes/search/Search.svelte

@ -1,18 +1,19 @@
<script> <script>
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import {t} from '../../translations.svelte.js';
let key = ""; import { t } from '../../translations.svelte.js';
let fulltext = false; let fulltext = false;
let html = ""; let html = "";
let key = "";
async function doSearch(ev){ async function doSearch(ev){
if (ev) ev.preventDefault(); if (ev) ev.preventDefault();
const url = `${location.protocol}//${location.host.replace('5173','8080')}/legacy/search`; const url = `${location.protocol}//${location.host.replace('5173','8080')}/legacy/search`;
const resp = await fetch(url,{ const resp = await fetch(url,{
credentials:'include', credentials : 'include',
method : 'POST', method : 'POST',
body: JSON.stringify({key:key,fulltext:fulltext?'on':'off'}) body : JSON.stringify({key:key,fulltext:fulltext?'on':'off'})
}); });
if (resp.ok){ if (resp.ok){
html = await resp.text(); html = await resp.text();
@ -22,7 +23,7 @@
onMount(() => { onMount(() => {
let params = new URLSearchParams(location.search); let params = new URLSearchParams(location.search);
key = params.get('key'); key = params.get('key');
if (key) doSearch(); if (key) doSearch();
}); });

32
frontend/src/routes/tags/TagList.svelte

@ -1,19 +1,19 @@
<script> <script>
import {onMount} from 'svelte'; import {onMount} from 'svelte';
import {api} from '../../urls.svelte.js'; import { api } from '../../urls.svelte.js';
import {t} from '../../translations.svelte.js'; import { t } from '../../translations.svelte.js';
import {user} from '../../user.svelte.js' import { user } from '../../user.svelte.js'
import Editor from '../../Components/LineEditor.svelte'; import Editor from '../../Components/LineEditor.svelte';
let { let {
id = null, id = null,
module, module,
tags = $bindable([]), tags = $bindable([]),
user_list = [], user_list = [],
} = $props(); } = $props();
let error = $state(null); let error = $state(null);
let newTag = $state(''); let newTag = $state('');
async function addTag(tag){ async function addTag(tag){
@ -25,14 +25,14 @@
} }
const url = api(`tags/${module}/${id}`); const url = api(`tags/${module}/${id}`);
const resp = await fetch(url,{ const resp = await fetch(url,{
credentials:'include', credentials : 'include',
method:'POST', method : 'POST',
body: JSON.stringify({tag:tag,user_list:user_list}) body : JSON.stringify({tag:tag,user_list:user_list})
}); });
if (resp.ok){ if (resp.ok){
tag = await resp.text(); tag = await resp.text();
tags.push(tag); tags.push(tag);
tags = tags.sort(); tags = tags.sort();
error = null; error = null;
} else { } else {
error = await resp.text(); error = await resp.text();
@ -47,12 +47,12 @@
} }
const url = api(`tags/${module}/${id}`); const url = api(`tags/${module}/${id}`);
const resp = await fetch(url,{ const resp = await fetch(url,{
credentials:'include', credentials : 'include',
method:'DELETE', method : 'DELETE',
body: tag body : tag
}); });
if (resp.ok){ if (resp.ok){
tag = await resp.text(); tag = await resp.text();
tags = tags.filter(item => item !== tag); tags = tags.filter(item => item !== tag);
} else { } else {
error = await resp.text(); error = await resp.text();
@ -62,7 +62,7 @@
async function loadTags(entityId){ async function loadTags(entityId){
if (!entityId) return; // when crating elements, they dont`t have an id, yet. if (!entityId) return; // when crating elements, they dont`t have an id, yet.
const url = api(`tags/${module}/${entityId}`); const url = api(`tags/${module}/${entityId}`);
const resp = await fetch(url,{credentials:'include'}); const resp = await fetch(url,{credentials:'include'});
if (resp.ok) { if (resp.ok) {
tags = await resp.json(); tags = await resp.json();

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

@ -1,30 +1,30 @@
<script> <script>
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { useTinyRouter } from 'svelte-tiny-router'; import { useTinyRouter } from 'svelte-tiny-router';
import { t } from '../../translations.svelte.js'; import { api } from '../../urls.svelte.js';
import { api } from '../../urls.svelte.js'; import { t } from '../../translations.svelte.js';
import { user } from '../../user.svelte.js'; import { user } from '../../user.svelte.js';
import MarkdownEditor from '../../Components/MarkdownEditor.svelte'; import MarkdownEditor from '../../Components/MarkdownEditor.svelte';
import MemberEditor from '../../Components/MemberEditor.svelte'; import MemberEditor from '../../Components/MemberEditor.svelte';
import Tags from '../tags/TagList.svelte'; import Tags from '../tags/TagList.svelte';
let { project_id = null, parent_task_id } = $props(); let { project_id = null, parent_task_id } = $props();
let error = $state(null); let error = $state(null);
let project = $state(null); let project = $state(null);
let extendedSettings = $state(false); let extendedSettings = $state(false);
let parent_task = $state(null); let parent_task = $state(null);
let task = $state({ let task = $state({
name : '', name : '',
description : { source : '', rendered : '' }, description : { source : '', rendered : '' },
due_date: null, due_date : null,
estimated_time: null, estimated_time : null,
no_index: false, no_index : false,
members : {}, members : {},
show_closed: false, show_closed : false,
start_date: null, start_date : null,
tags: [] tags : []
}); });
let router = useTinyRouter(); let router = useTinyRouter();
@ -44,28 +44,28 @@
} }
async function loadParent(){ async function loadParent(){
const url = api(`task/${parent_task_id}`); const url = api(`task/${parent_task_id}`);
const resp = await fetch(url,{credentials:'include'}); const resp = await fetch(url,{credentials:'include'});
if (resp.ok){ if (resp.ok){
parent_task = await resp.json(); parent_task = await resp.json();
task.parent_task_id = +parent_task_id; task.parent_task_id = +parent_task_id;
project_id = parent_task.project_id; project_id = parent_task.project_id;
error = null; error = null;
project = null; // TODO project = null; // TODO
} else { } else {
error = await resp.text(); error = await resp.text();
} }
} }
async function loadProject(){ async function loadProject(){
var url = api(`project/${project_id}`); const url = api(`project/${project_id}`);
const resp = await fetch(url,{credentials:'include'}); const resp = await fetch(url,{credentials:'include'});
if (resp.ok){ if (resp.ok){
project = await resp.json(); project = await resp.json();
task.project_id = +project_id; task.project_id = +project_id;
let member_source = parent_task?parent_task.members:project.members; let member_source = parent_task?parent_task.members:project.members;
task.members = JSON.parse(JSON.stringify(member_source)); // deep copy task.members = JSON.parse(JSON.stringify(member_source)); // deep copy
error = null; error = null;
} else { } else {
error = await resp.text(); error = await resp.text();
} }
@ -98,11 +98,11 @@
} }
async function saveTask(){ async function saveTask(){
var url = api('task/add'); const url = api('task/add');
const resp = await fetch(url,{ const resp = await fetch(url,{
credentials:'include', credentials : 'include',
method:'POST', method : 'POST',
body: JSON.stringify(task) body : JSON.stringify(task)
}); });
if (resp.ok) { if (resp.ok) {
task = await resp.json(); task = await resp.json();

48
frontend/src/routes/task/ListTask.svelte

@ -1,19 +1,19 @@
<script> <script>
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { useTinyRouter } from 'svelte-tiny-router'; import { useTinyRouter } from 'svelte-tiny-router';
import { t } from '../../translations.svelte.js'; import { api } from '../../urls.svelte.js';
import { api } from '../../urls.svelte.js'; import { t } from '../../translations.svelte.js';
import TaskList from './TaskList.svelte'; import TaskList from './TaskList.svelte';
import LineEditor from '../../Components/LineEditor.svelte'; import LineEditor from '../../Components/LineEditor.svelte';
const router = useTinyRouter();
let { estimated_time, show_closed, task } = $props(); let { estimated_time, show_closed, task } = $props();
let children = $state(null); let children = $state(null);
let error = $state(null); let deleted = $state(false);
let start = 0; let error = $state(null);
let deleted = $state(false); const router = useTinyRouter();
let start = 0;
function addSubtask(){ function addSubtask(){
router.navigate(`/task/${task.id}/add_subtask`); router.navigate(`/task/${task.id}/add_subtask`);
@ -21,10 +21,10 @@
async function deleteTask(){ async function deleteTask(){
if (confirm(t('confirm_delete',{element:task.name}))){ if (confirm(t('confirm_delete',{element:task.name}))){
const url = api(`task/${task.id}`); const url = api(`task/${task.id}`);
const resp = await fetch(url,{ const resp = await fetch(url,{
credentials:'include', credentials : 'include',
method:'DELETE' method : 'DELETE'
}); });
if (resp.ok){ if (resp.ok){
deleted = true; deleted = true;
@ -35,20 +35,20 @@
} }
async function loadChildren(){ async function loadChildren(){
const url = api('task/list'); const url = api('task/list');
var data = { const data = {
parent_task_id:+task.id, parent_task_id : +task.id,
show_closed: show_closed show_closed : show_closed
}; };
if (task.show_closed) data.show_closed = true; if (task.show_closed) data.show_closed = true;
const resp = await fetch(url,{ const resp = await fetch(url,{
credentials:'include', credentials : 'include',
method:'POST', method : 'POST',
body:JSON.stringify(data) body : JSON.stringify(data)
}); });
if (resp.ok){ if (resp.ok){
children = await resp.json(); children = await resp.json();
error = null; error = null;
} else { } else {
error = await resp.text(); error = await resp.text();
} }
@ -59,11 +59,11 @@
} }
async function patchTask(changeset){ async function patchTask(changeset){
const url = api(`task/${task.id}`); const url = api(`task/${task.id}`);
const resp = await fetch(url,{ const resp = await fetch(url,{
credentials:'include', credentials : 'include',
method: 'PATCH', method : 'PATCH',
body: JSON.stringify(changeset) body : JSON.stringify(changeset)
}); });
if (resp.ok){ if (resp.ok){
task = await resp.json(); task = await resp.json();

2
frontend/src/routes/task/TaskList.svelte

@ -1,5 +1,5 @@
<script> <script>
import { t } from '../../translations.svelte.js'; import { t } from '../../translations.svelte.js';
import ListTask from './ListTask.svelte'; import ListTask from './ListTask.svelte';
let { estimated_time, show_closed, tasks } = $props(); let { estimated_time, show_closed, tasks } = $props();

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

@ -1,27 +1,27 @@
<script> <script>
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { useTinyRouter } from 'svelte-tiny-router'; import { useTinyRouter } from 'svelte-tiny-router';
import { t } from '../../translations.svelte.js'; import { api } from '../../urls.svelte.js';
import { api } from '../../urls.svelte.js'; import { t } from '../../translations.svelte.js';
import LineEditor from '../../Components/LineEditor.svelte'; import LineEditor from '../../Components/LineEditor.svelte';
import MarkdownEditor from '../../Components/MarkdownEditor.svelte'; import MarkdownEditor from '../../Components/MarkdownEditor.svelte';
import MemberEditor from '../../Components/MemberEditor.svelte'; import MemberEditor from '../../Components/MemberEditor.svelte';
import Notes from '../notes/List.svelte'; import Notes from '../notes/List.svelte';
import StateSelector from '../../Components/StateSelector.svelte'; import StateSelector from '../../Components/StateSelector.svelte';
import TagList from '../tags/TagList.svelte'; import TagList from '../tags/TagList.svelte';
import TaskList from './TaskList.svelte'; import TaskList from './TaskList.svelte';
const router = useTinyRouter(); let { id } = $props();
let { id } = $props(); let children = $state(null);
let task = $state(null); let dummy = $derived(updateOn(id));
let project = $state(null); let error = $state(null);
let error = $state(null);
let children = $state(null);
let estimated_time = $state({sum:0}); let estimated_time = $state({sum:0});
let dummy = $derived(updateOn(id)); let project = $state(null);
let showSettings = $state(false); const router = useTinyRouter();
let showSettings = $state(false);
let task = $state(null);
$effect(() => updateOn(id)); $effect(() => updateOn(id));
@ -35,7 +35,7 @@
} }
async function getCandidates(text){ async function getCandidates(text){
const origin = task.parent ? task.parent.members : project.members; const origin = task.parent ? task.parent.members : project.members;
const candidates = Object.values(origin) const candidates = Object.values(origin)
.filter(member => member.user.name.toLowerCase().includes(text.toLowerCase())) .filter(member => member.user.name.toLowerCase().includes(text.toLowerCase()))
.map(member => [member.user.id,member.user.name]); .map(member => [member.user.id,member.user.name]);
@ -52,37 +52,37 @@
} }
async function loadChildren(){ async function loadChildren(){
const url = api('task/list'); const url = api('task/list');
var data = { const data = {
parent_task_id:+task.id, parent_task_id : +task.id,
show_closed: task.show_closed show_closed : task.show_closed
}; };
const resp = await fetch(url,{ const resp = await fetch(url,{
credentials:'include', credentials : 'include',
method:'POST', method : 'POST',
body:JSON.stringify(data) body:JSON.stringify(data)
}); });
if (resp.ok){ if (resp.ok){
children = await resp.json(); children = await resp.json();
error = null; error = null;
} else { } else {
error = await resp.text(); error = await resp.text();
} }
} }
async function loadProject(){ async function loadProject(){
const url = api(`project/${task.project_id}`); const url = api(`project/${task.project_id}`);
const resp = await fetch(url,{credentials:'include'}); const resp = await fetch(url,{credentials:'include'});
if (resp.ok){ if (resp.ok){
project = await resp.json(); project = await resp.json();
error = null; error = null;
} else { } else {
error = await resp.text(); error = await resp.text();
} }
} }
async function loadParent(){ async function loadParent(){
const url = api(`task/${task.parent_task_id}`); const url = api(`task/${task.parent_task_id}`);
const resp = await fetch(url,{credentials:'include'}); const resp = await fetch(url,{credentials:'include'});
if (resp.ok){ if (resp.ok){
task.parent = await resp.json(); task.parent = await resp.json();
@ -92,12 +92,12 @@
} }
async function loadTask(){ async function loadTask(){
const url = api(`task/${id}`); const url = api(`task/${id}`);
const resp = await fetch(url,{credentials:'include'}); const resp = await fetch(url,{credentials:'include'});
if (resp.ok){ if (resp.ok){
task = await resp.json(); task = await resp.json();
error = null; error = null;
project = null; project = null;
children = null; children = null;
loadChildren(); loadChildren();
if (task.project_id) loadProject(); if (task.project_id) loadProject();
@ -122,15 +122,15 @@
} }
async function update(data){ async function update(data){
const url = api(`task/${id}`); const url = api(`task/${id}`);
const resp = await fetch(url,{ const resp = await fetch(url,{
credentials:'include', credentials : 'include',
method:'PATCH', method : 'PATCH',
body:JSON.stringify(data) body : JSON.stringify(data)
}); });
if (resp.ok){ if (resp.ok){
error = null; error = null;
task = await resp.json(); task = await resp.json();
return true; return true;
} else { } else {
error = await resp.text(); error = await resp.text();
@ -147,7 +147,7 @@
} }
function updatePermission(user_id,permission){ function updatePermission(user_id,permission){
let members = {}; let members = {};
members[user_id] = permission.code; members[user_id] = permission.code;
update({members:members}); update({members:members});
} }

19
frontend/src/routes/user/ConnectedServices.svelte

@ -1,14 +1,15 @@
<script> <script>
import { t } from '../../translations.svelte.js';
import { user } from '../../user.svelte.js';
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { api } from '../../urls.svelte.js';
import { t } from '../../translations.svelte.js';
import { user } from '../../user.svelte.js';
let connections = $state([]); let connections = $state([]);
async function loadConnections(){ async function loadConnections(){
let url = `${location.protocol}//${location.host.replace('5173','8080')}/api/user/oidc/connected`; const url = api('/user/oidc/connected');
const resp = await fetch(url,{credentials:'include'});
let resp = await fetch(url,{credentials:'include'});
if (resp.ok){ if (resp.ok){
const arr = await resp.json(); const arr = await resp.json();
while (connections.length) connections.pop(); while (connections.length) connections.pop();
@ -19,11 +20,11 @@
onMount(loadConnections); onMount(loadConnections);
async function unlink(connection){ async function unlink(connection){
const url = `${location.protocol}//${location.host.replace('5173','8080')}/api/user/oidc/connected`; const url = api('user/oidc/connected');
const resp = await fetch(url,{ const resp = await fetch(url,{
method: 'DELETE', method : 'DELETE',
credentials: 'include', credentials : 'include',
body: JSON.stringify(connection) body : JSON.stringify(connection)
}); });
if (resp.ok){ if (resp.ok){
loadConnections(); loadConnections();

35
frontend/src/routes/user/EditPassword.svelte

@ -1,35 +1,34 @@
<script> <script>
import { t } from '../../translations.svelte.js'; import { api } from '../../urls.svelte.js';
import { t } from '../../translations.svelte.js';
let { editPassword = $bindable() } = $props(); let { editPassword = $bindable() } = $props();
let oldPass = $state(""); let caption = $state(t('update'));
let newPass = $state(""); let error = $state("");
let repeat = $state(""); let newPass = $state("");
let caption = $state(t('update'));
let oldEmpty = $derived(!/\S/.test(oldPass));
let newEmpty = $derived(!/\S/.test(newPass));
let mismatch = $derived(newPass != repeat); let mismatch = $derived(newPass != repeat);
let newEmpty = $derived(!/\S/.test(newPass));
let error = $state(""); let oldPass = $state("");
let sent = $state(false); let oldEmpty = $derived(!/\S/.test(oldPass));
let repeat = $state("");
let sent = $state(false);
function abort(){ function abort(){
editPassword = false; editPassword = false;
} }
async function submit(){ async function submit(){
caption = t('data_sent'); caption = t('data_sent');
const url = `${location.protocol}//${location.host.replace('5173','8080')}/api/user/password`; const url = `${location.protocol}//${location.host.replace('5173','8080')}/api/user/password`;
const data = { const data = {
old: oldPass, old : oldPass,
new: newPass new : newPass
}; };
const resp = await fetch(url,{ const resp = await fetch(url,{
method: 'PATCH', method : 'PATCH',
body: JSON.stringify(data), body : JSON.stringify(data),
credentials: 'include' credentials : 'include'
}); });
if (resp.ok){ if (resp.ok){

28
frontend/src/routes/user/EditService.svelte

@ -1,17 +1,19 @@
<script> <script>
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { t } from '../../translations.svelte.js';
import { useTinyRouter } from 'svelte-tiny-router'; import { useTinyRouter } from 'svelte-tiny-router';
import { api } from '../../urls.svelte.js'
import { t } from '../../translations.svelte.js';
let caption = $state(t('save_service'));
let disabled = $state(false);
let service = $state({})
let { serviceName } = $props(); let { serviceName } = $props();
let service = $state({}) let message = $state(t('loading_data'));
let caption = $state(t('save_service')); let router = useTinyRouter();
let message = $state(t('loading_data'));
let router = useTinyRouter();
let disabled = $state(false);
onMount(async () => { onMount(async () => {
const url = `${location.protocol}//${location.host.replace('5173','8080')}/api/user/oidc/${serviceName}`; const url = api(`user/oidc/${serviceName}`);
const resp = await fetch(url,{credentials:'include'}); const resp = await fetch(url,{credentials:'include'});
if (resp.ok){ if (resp.ok){
const json = await resp.json(); const json = await resp.json();
@ -23,12 +25,12 @@
}); });
async function update(){ async function update(){
caption = t('data_sent'); caption = t('data_sent');
const url = `${location.protocol}//${location.host.replace('5173','8080')}/api/user/oidc/${serviceName}`; const url = api(`user/oidc/${serviceName}`);
const resp = await fetch(url,{ const resp = await fetch(url,{
credentials: 'include', credentials : 'include',
method: 'PATCH', method : 'PATCH',
body: JSON.stringify(service) body : JSON.stringify(service)
}); });
if (resp.ok){ if (resp.ok){
caption = t('saved'); caption = t('saved');

43
frontend/src/routes/user/EditUser.svelte

@ -1,34 +1,33 @@
<script> <script>
import { t } from '../../translations.svelte.js';
import { useTinyRouter } from 'svelte-tiny-router'; import { useTinyRouter } from 'svelte-tiny-router';
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { checkUser } from '../../user.svelte.js';
const router = useTinyRouter(); import { api } from '../../urls.svelte.js'
import { checkUser } from '../../user.svelte.js';
import { t } from '../../translations.svelte.js';
let { user_id } = $props(); let { user_id } = $props();
let caption = $state(t('save_user'));
let editUser = $state(null); let editUser = $state(null);
let options = $state([]); let message = $state(t('loading_data'));
let sent = $state(false); let options = $state([]);
let caption = $state(t('save_user')); const router = useTinyRouter();
let message = $state(t('loading_data')); let sent = $state(false);
onMount(async () => { onMount(async () => {
let url = `${location.protocol}//${location.host.replace('5173','8080')}/themes.json`; let url = `${location.protocol}//${location.host.replace('5173','8080')}/themes.json`;
let resp = await fetch(url); let resp = await fetch(url);
if (resp.ok){ if (resp.ok){
const arr = await resp.json(); const arr = await resp.json();
for (let entry of arr){ for (let entry of arr){
const value = entry.value; const value = entry.value;
const caption = entry.caption ? entry.caption : value; const caption = entry.caption ? entry.caption : value;
options.push({caption:caption,value:value}) options.push({caption:caption,value:value})
} }
} }
if (user_id) { if (user_id) {
url = `${location.protocol}//${location.host.replace('5173','8080')}/api/user/${user_id}`; url = api(`user/${user_id}`);
resp = await fetch(url,{credentials:'include'}); resp = await fetch(url,{credentials:'include'});
if (resp.ok) { if (resp.ok) {
editUser = await resp.json(); editUser = await resp.json();
@ -43,20 +42,20 @@
async function save(ev){ async function save(ev){
ev.preventDefault(); ev.preventDefault();
sent = true; sent = true;
caption = t('data_sent'); caption = t('data_sent');
let method = 'PATCH'; let method = 'PATCH';
let url = null; let url = null;
if (user_id) { if (user_id) {
url = `${location.protocol}//${location.host.replace('5173','8080')}/api/user/${user_id}`; url = api(`user/${user_id}`);
} else { } else {
url = `${location.protocol}//${location.host.replace('5173','8080')}/api/user/create`; url = api('user/create');
method = 'POST'; method = 'POST';
} }
let resp = await fetch(url,{ let resp = await fetch(url,{
method: method, method : method,
credentials: 'include', credentials : 'include',
body: JSON.stringify(editUser) body : JSON.stringify(editUser)
}); });
if (resp.ok){ if (resp.ok){
caption = t('saved'); caption = t('saved');

24
frontend/src/routes/user/List.svelte

@ -1,27 +1,28 @@
<script> <script>
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { t } from '../../translations.svelte.js';
import { useTinyRouter } from 'svelte-tiny-router'; import { useTinyRouter } from 'svelte-tiny-router';
import { user } from '../../user.svelte.js';
const router = useTinyRouter(); import { api } from '../../urls.svelte.js';
import { t } from '../../translations.svelte.js';
import { user } from '../../user.svelte.js';
let users = $state([]); const router = useTinyRouter();
let users = $state([]);
onMount(async () => { async function listUsers(){
const url = `${location.protocol}//${location.host.replace('5173','8080')}/api/user/list`; const url = api('user/list');
const resp = await fetch(url,{credentials:'include'}); const resp = await fetch(url,{credentials:'include'});
if (resp.ok){ if (resp.ok){
const json = await resp.json(); const json = await resp.json();
for (let u of json) users.push(u); for (let u of json) users.push(u);
} }
}); }
async function impersonate(userId){ async function impersonate(userId){
const url = `${location.protocol}//${location.host.replace('5173','8080')}/api/user/${userId}/impersonate`; const url = api(`user/${userId}/impersonate`);
const resp = await fetch(url,{ const resp = await fetch(url,{
method: 'POST', method : 'POST',
credentials: 'include' credentials : 'include'
}); });
if (resp.ok){ if (resp.ok){
const json = await resp.json(); const json = await resp.json();
@ -29,6 +30,7 @@
} }
} }
onMount(listUsers);
</script> </script>
<fieldset tabindex="0"> <fieldset tabindex="0">

41
frontend/src/routes/user/LoginServices.svelte

@ -1,27 +1,16 @@
<script> <script>
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { t } from '../../translations.svelte.js';
import { useTinyRouter } from 'svelte-tiny-router'; import { useTinyRouter } from 'svelte-tiny-router';
import { user } from '../../user.svelte.js';
const router = useTinyRouter(); import { api } from '../../urls.svelte.js';
import { t } from '../../translations.svelte.js';
import { user } from '../../user.svelte.js';
const router = useTinyRouter();
let services = $state([]); let services = $state([]);
async function loadButtons(){
const url = `${location.protocol}//${location.host.replace('5173','8080')}/api/user/oidc/buttons`;
const resp = await fetch(url,{credentials:'include'});
if (resp.ok){
const json = await resp.json();
while (services.length) services.pop();
for (let service of json) services.push(service);
}
}
onMount(loadButtons);
async function connect(service){ async function connect(service){
const url = `${location.protocol}//${location.host.replace('5173','8080')}/api/user/oidc/redirect/${service}`; const url = api(`user/oidc/redirect/${service}`);
const resp = await fetch(url,{credentials:'include'}); const resp = await fetch(url,{credentials:'include'});
if (resp.ok){ if (resp.ok){
var json = await resp.json(); var json = await resp.json();
@ -33,14 +22,26 @@
} }
} }
async function loadButtons(){
const url = api(`user/oidc/buttons`);
const resp = await fetch(url,{credentials:'include'});
if (resp.ok){
const json = await resp.json();
while (services.length) services.pop();
for (let service of json) services.push(service);
}
}
async function drop(service){ async function drop(service){
const url = `${location.protocol}//${location.host.replace('5173','8080')}/api/user/oidc/${service}`; const url = api(`user/oidc/${service}`);
const resp = await fetch(url,{ const resp = await fetch(url,{
credentials: 'include', credentials : 'include',
method: 'DELETE' method : 'DELETE'
}); });
if (resp.ok) loadButtons(); if (resp.ok) loadButtons();
} }
onMount(loadButtons);
</script> </script>
<fieldset tabindex="0"> <fieldset tabindex="0">

26
frontend/src/routes/user/OidcCallback.svelte

@ -1,24 +1,26 @@
<script> <script>
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { t } from '../../translations.svelte.js';
import { useTinyRouter } from 'svelte-tiny-router'; import { useTinyRouter } from 'svelte-tiny-router';
import { checkUser } from '../../user.svelte.js';
import { api } from '../../urls.svelte.js';
import { t } from '../../translations.svelte.js';
import { checkUser } from '../../user.svelte.js';
const router = useTinyRouter(); const router = useTinyRouter();
let message = $state(t('processing_code'));
let message = $state(t('processing_code')); async function process(){
onMount(async () => {
let params = new URLSearchParams(location.search); let params = new URLSearchParams(location.search);
if (params.get('code')){ if (params.get('code')){
const url = `${location.protocol}//${location.host.replace('5173','8080')}/api/user/oidc/token`; const url = api('user/oidc/token');
const resp = await fetch(url,{ const resp = await fetch(url,{
method : 'POST', method : 'POST',
body: JSON.stringify(Object.fromEntries(params)), body : JSON.stringify(Object.fromEntries(params)),
credentials: 'include' credentials : 'include'
}); });
if (resp.ok){ if (resp.ok){
let json = await resp.json(); let json = await resp.json();
const redirect = json.redirect ? json.redirect : '/user'; const redirect = json.redirect ? json.redirect : '/user';
checkUser(); checkUser();
router.navigate(redirect); router.navigate(redirect);
@ -27,7 +29,9 @@
if (!message) message = t(resp); if (!message) message = t(resp);
} }
} }
}); }
onMount(process);
</script> </script>
{message} {message}

11
frontend/src/routes/user/Profile.svelte

@ -1,14 +1,15 @@
<script> <script>
import { t } from '../../translations.svelte.js';
import { user } from '../../user.svelte.js';
import { useTinyRouter } from 'svelte-tiny-router'; import { useTinyRouter } from 'svelte-tiny-router';
import EditPassword from './EditPassword.svelte'; import { t } from '../../translations.svelte.js';
const router = useTinyRouter(); import { user } from '../../user.svelte.js';
let editPassword = false; import EditPassword from './EditPassword.svelte';
const router = useTinyRouter();
let editPassword = false;
</script> </script>
<fieldset> <fieldset>
<legend> <legend>
{t('your_profile')} {t('your_profile')}

34
frontend/src/routes/user/ResetPw.svelte

@ -1,19 +1,21 @@
<script> <script>
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { t } from '../../translations.svelte.js';
import { useTinyRouter } from 'svelte-tiny-router'; import { useTinyRouter } from 'svelte-tiny-router';
let mail = ""; import { api } from '../../urls.svelte.js';
let caption = t('send_mail'); import { t } from '../../translations.svelte.js';
let error = null;
let caption = t('send_mail');
let error = null;
let mail = "";
const router = useTinyRouter(); const router = useTinyRouter();
async function submit(ev){ async function submit(ev){
ev.preventDefault(); ev.preventDefault();
const url = `${location.protocol}//${location.host.replace('5173','8080')}/api/user/reset_pw`; const url = api(`user/reset_pw`);
const resp = await fetch(url,{ const resp = await fetch(url,{
method : 'POST', method : 'POST',
body : mail body : mail
}); });
if (resp.ok) { if (resp.ok) {
caption = t('data_sent'); caption = t('data_sent');
@ -24,9 +26,9 @@
async function checkToken(){ async function checkToken(){
const urlParams = new URLSearchParams(window.location.search); const urlParams = new URLSearchParams(window.location.search);
const token = urlParams.get('token'); const token = urlParams.get('token');
if (token) { if (token) {
const url = `${location.protocol}//${location.host.replace('5173','8080')}/api/user/validate/${token}`; const url = api(`user/validate/${token}`);
const resp = await fetch(url,{ const resp = await fetch(url,{
credentials: 'include' credentials: 'include'
}); });
@ -46,13 +48,13 @@
<style> <style>
label{display:block} label{display:block}
fieldset{ fieldset{
display: block; display : block;
position: relative; position : relative;
left: 50%; left : 50%;
width: 200px; width : 200px;
margin-left: -100px; margin-left : -100px;
margin-bottom: 30px; margin-bottom : 30px;
text-align: center; text-align : center;
} }
</style> </style>

16
frontend/src/routes/user/User.svelte

@ -1,17 +1,15 @@
<script> <script>
import { t } from '../../translations.svelte.js'; import { user } from '../../user.svelte.js';
import { user } from '../../user.svelte.js'; import { t } from '../../translations.svelte.js';
import Services from './ConnectedServices.svelte'; import Services from './ConnectedServices.svelte';
import LoginServiceList from './LoginServices.svelte'; import LoginServiceList from './LoginServices.svelte';
import Profile from './Profile.svelte'; import Profile from './Profile.svelte';
import UserList from './List.svelte'; import UserList from './List.svelte';
let params = new URLSearchParams(location.search); let params = new URLSearchParams(location.search);
let redirect = params.get('returnTo'); let redirect = params.get('returnTo');
if (redirect && user.name){ if (redirect && user.name) location.href = redirect;
location.href = redirect;
}
</script> </script>
<h1>{t('user_module')}</h1> <h1>{t('user_module')}</h1>

Loading…
Cancel
Save