Files
Umbrella/frontend/src/routes/wiki/View.svelte
Stephan Richter 43ebb241e8
All checks were successful
Build Docker Image / Docker-Build (push) Successful in 4m48s
Build Docker Image / Clean-Registry (push) Successful in 21s
trying to achieve correct display update on page content update – I have a feeling that this still doesn`t work reliably
Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
2026-01-10 15:25:16 +01:00

184 lines
5.9 KiB
Svelte

<script>
import { onMount } from 'svelte';
import { useTinyRouter } from 'svelte-tiny-router';
import { api } from '../../urls.svelte';
import { error, yikes } from '../../warn.svelte';
import { t } from '../../translations.svelte';
import { user } from '../../user.svelte';
import MarkdownEditor from '../../Components/MarkdownEditor.svelte';
import LineEditor from '../../Components/LineEditor.svelte';
import Notes from '../notes/RelatedNotes.svelte';
import PermissionEditor from '../../Components/PermissionEditor.svelte';
import TagList from '../tags/TagList.svelte';
let detail = $state(false);
let { key, version } = $props();
let page = $state({});
let router = useTinyRouter();
let members = $state({});
let editable = $derived(page.members[user.id].permission.code<4);
async function addMember(entry){
let newMembers = JSON.parse(JSON.stringify(page.members));
for (var id of Object.keys(entry)){
if (!newMembers[id]) newMembers[id] = { permission : {name:'READ_ONLY'} };
}
return patch({members:newMembers});
}
async function dropMember(member){
var id = member.user.id;
let newMembers = JSON.parse(JSON.stringify(page.members));
newMembers[id].permission = null;
return patch({members:newMembers});
}
async function dropVersion(){
const msg = t('confirm_delete',{element:t('version_of',{version:page.version,element:page.title})});
if (!confirm(msg)) return;
let url = api(`wiki/page/${key}/version/${page.version}`);
let res = await fetch(url,{
credentials:'include',
method: 'DELETE'
});
if (res.ok){
let json = await res.json();
router.navigate(`/wiki/${page.id}/view`);
yikes();
} else {
error(res);
}
}
function nonMember(json){
return !page.members[json.id];
}
async function getCandidates(text){
const url = api('user/search');
const resp = await fetch(url,{
credentials : 'include',
method : 'POST',
body : text
});
if (resp.ok){
var json = await resp.json();
return Object.fromEntries(Object.values(json).filter(nonMember).map(user => [user.id,user.name]));
} else {
return [];
}
}
async function loadContent(res){
if (res.ok){
let json = await res.json();
json.versions.sort((a,b)=>b-a);
page = { ...json };
yikes();
return true;
} else {
error(res);
return false;
}
}
async function loadPage(){
let path = `wiki/page/${key}`;
if (version) path += `/version/${version}`;
const url = api(path);
const res = await fetch(url,{credentials:'include'});
loadContent(res);
}
function onclick(e){
e.preventDefault();
let href = e.target.getAttribute('href');
if (href) router.navigate(href);
return false;
}
async function patch(data){
const url = api(`wiki/page/${page.id}`);
const res = await fetch(url,{
credentials:'include',
method:'PATCH',
body:JSON.stringify(data)
});
return loadContent(res);
}
async function patchGuestPermissions(ev){
let data = {guest_allowed:page.guest_allowed};
console.log(data);
return patch(data);
}
async function patchTitle(t){
var result = await(patch({title:t}));
router.navigate(`/wiki/${page.id}/view`);
}
function toggleDetail(){
detail = !detail;
}
async function updatePermission(uid, newPerm){
let newMembers = JSON.parse(JSON.stringify(page.members));
newMembers[uid] = {permission:newPerm};
return patch({members:newMembers});
}
$effect(loadPage);
</script>
{#if page && page.versions}
<div class="wiki page">
<div class="versions">
<span class="version">{t('version')}</span>
{#each page.versions as v}
<span class="version">
<a href={`/wiki/${page.id}/version/${v}`} {onclick} class={page.version == v?'selected':''}>{v}</a> &nbsp;
</span>
{/each}
</div>
<LineEditor value={page.title} type="h2" {editable} onSet={t => patchTitle(t)} />
{#if page.version != page.versions[0]}
<span class="warn">{t('not_recent_version')}</span>
{/if}
<button onclick={toggleDetail} class="symbol" title={t('toggle_objects',{objects:t('users')})}></button>
<button onclick={dropVersion} class="symbol" title={t('delete_object',{object:t('version')})}> </button>
{#if detail}
{#if editable}
<PermissionEditor members={page.members} {addMember} {dropMember} {getCandidates} {updatePermission} />
<label>
<input type="checkbox" bind:checked={page.guest_allowed} onchange={patchGuestPermissions} />
{t('visible_to_guests')}
</label>
{:else}
<table>
<thead>
<tr>
<th>{t('user')}</th>
<th>{t('permissions')}</th>
</tr>
</thead>
<tbody>
{#each Object.values(page.members) as member,id}
<tr>
<td>{member.user.name}</td>
<td>{t('permission_'+member.permission.name.toLowerCase())}</td>
</tr>
{/each}
</tbody>
</table>
{/if}
{/if}
<MarkdownEditor {editable} value={page.content} onSet={s => patch({content:s})} />
<TagList module="wiki" id={page.id} user_list={Object.keys(page.members).map(id => +id)} />
<div class="notes">
<h3>{t('notes')}</h3>
<Notes module="wiki" entity_id={page.id} />
</div>
</div>
{/if}