Merge branch 'main' into dev
This commit is contained in:
@@ -29,6 +29,7 @@
|
||||
import Search from "./routes/search/Search.svelte";
|
||||
import SendDoc from "./routes/document/Send.svelte";
|
||||
import Stock from './routes/stock/Index.svelte';
|
||||
import TagList from "./routes/tags/Index.svelte";
|
||||
import TagUses from "./routes/tags/TagUses.svelte";
|
||||
import TaskList from "./routes/task/Index.svelte";
|
||||
import Times from "./routes/time/Index.svelte";
|
||||
@@ -98,6 +99,7 @@
|
||||
<Route path="/project/:id/view" component={ViewPrj} />
|
||||
<Route path="/search" component={Search} />
|
||||
<Route path="/stock" component={Stock} />
|
||||
<Route path="/tags" component={TagList} />
|
||||
<Route path="/tags/use/:tag" component={TagUses} />
|
||||
<Route path="/task" component={TaskList} />
|
||||
<Route path="/task/:parent_task_id/add_subtask" component={AddTask} />
|
||||
|
||||
@@ -56,6 +56,7 @@ onMount(fetchModules);
|
||||
<a href="/company" {onclick}>{t('companies')}</a>
|
||||
<a href="/project" {onclick}>{t('projects')}</a>
|
||||
<a href="/task" {onclick}>{t('tasks')}</a>
|
||||
<a href="/tags" {onclick}>{t('tags')}</a>
|
||||
<a href="/document" {onclick}>{t('documents')}</a>
|
||||
<a href="/bookmark" {onclick}>{t('bookmarks')}</a>
|
||||
<a href="/notes" {onclick}>{t('notes')}</a>
|
||||
|
||||
40
frontend/src/routes/tags/Index.svelte
Normal file
40
frontend/src/routes/tags/Index.svelte
Normal file
@@ -0,0 +1,40 @@
|
||||
<script>
|
||||
import { useTinyRouter } from 'svelte-tiny-router';
|
||||
import { onMount } from 'svelte';
|
||||
import { api } from '../../urls.svelte';
|
||||
import { error, yikes } from '../../warn.svelte';
|
||||
import { t } from '../../translations.svelte';
|
||||
|
||||
let router = useTinyRouter();
|
||||
let tags = $state(null);
|
||||
|
||||
function onclick(e){
|
||||
e.preventDefault();
|
||||
var target = e.target;
|
||||
while (target && !target.href) target=target.parentNode;
|
||||
let href = target.getAttribute('href');
|
||||
if (href) router.navigate(href);
|
||||
return false;
|
||||
}
|
||||
|
||||
async function loadTags(){
|
||||
const url = api('tags');
|
||||
const res = await fetch(url,{credentials:'include'});
|
||||
if (res.ok){
|
||||
yikes();
|
||||
tags = await res.json();
|
||||
} else error(res);
|
||||
}
|
||||
|
||||
onMount(loadTags)
|
||||
</script>
|
||||
|
||||
<h1>{t('tags')}</h1>
|
||||
|
||||
<div class="cloud">
|
||||
{#if tags}
|
||||
{#each tags as entry}
|
||||
<a href="/tags/use/{encodeURIComponent(entry.tag)}" class="tag" style="font-size: {40 - 28/entry.count}px" title={t('count_of_occurrences',entry)} {onclick} >{entry.tag}</a>
|
||||
{/each}
|
||||
{/if}
|
||||
</div>
|
||||
@@ -6,15 +6,12 @@ import static de.srsoftware.umbrella.core.ModuleRegistry.userService;
|
||||
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import de.srsoftware.tools.Path;
|
||||
import de.srsoftware.tools.SessionToken;
|
||||
import de.srsoftware.umbrella.core.BaseHandler;
|
||||
import de.srsoftware.umbrella.core.ModuleRegistry;
|
||||
import de.srsoftware.umbrella.core.Util;
|
||||
import de.srsoftware.umbrella.core.api.MarkdownService;
|
||||
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
|
||||
import de.srsoftware.umbrella.core.model.Token;
|
||||
import java.io.IOException;
|
||||
import java.util.Optional;
|
||||
|
||||
public class MarkdownApi extends BaseHandler implements MarkdownService {
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ public class Constants {
|
||||
|
||||
public static final String COMMENT_HASH = "comment_hash";
|
||||
public static final String CONFIG_DATABASE = "umbrella.modules.tags.database";
|
||||
public static final String COUNT = "count";
|
||||
public static final String TABLE_COMMENTS = "comments";
|
||||
public static final String TABLE_TAGS = "tags";
|
||||
public static final String TABLE_TAGS_NEW = "tags_new";
|
||||
|
||||
@@ -17,6 +17,7 @@ import static java.lang.System.Logger.Level.*;
|
||||
import static java.text.MessageFormat.format;
|
||||
import static java.time.ZoneOffset.UTC;
|
||||
|
||||
import de.srsoftware.tools.Tuple;
|
||||
import de.srsoftware.tools.jdbc.Query;
|
||||
import de.srsoftware.umbrella.bookmarks.BookmarkDb;
|
||||
import de.srsoftware.umbrella.core.BaseDb;
|
||||
@@ -269,6 +270,24 @@ CREATE TABLE IF NOT EXISTS {0} (
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Tuple<String,Long>> list(long userId) {
|
||||
try {
|
||||
var rs = select("tag, COUNT(tag) as count").from(TABLE_TAGS).where(USER_ID,equal(userId)).groupBy(TAG).sort(TAG).exec(db);
|
||||
var list = new ArrayList<Tuple<String,Long>>();
|
||||
while (rs.next()) {
|
||||
var tag = rs.getString(TAG);
|
||||
if (tag.isBlank()) continue;;
|
||||
var count = rs.getLong("count");
|
||||
list.add(Tuple.of(tag,count));
|
||||
}
|
||||
rs.close();
|
||||
return list;
|
||||
} catch (SQLException e) {
|
||||
throw databaseException("Failed to load tags for user {0}",userId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Long, ? extends Collection<String>> list(long userId, String module, Collection<Long> entityIds) {
|
||||
try {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
package de.srsoftware.umbrella.tags;
|
||||
|
||||
|
||||
import de.srsoftware.tools.Tuple;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -14,6 +15,8 @@ public interface TagDB {
|
||||
|
||||
Map<String, List<Long>> getUses(String tag, long id);
|
||||
|
||||
Collection<Tuple<String, Long>> list(long userId);
|
||||
|
||||
Set<String> list(long userId, String module, long entityId);
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,8 +7,7 @@ import static de.srsoftware.umbrella.core.ModuleRegistry.userService;
|
||||
import static de.srsoftware.umbrella.core.ResponseCode.HTTP_UNPROCESSABLE;
|
||||
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.missingFieldException;
|
||||
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.unprocessable;
|
||||
import static de.srsoftware.umbrella.tags.Constants.CONFIG_DATABASE;
|
||||
import static de.srsoftware.umbrella.tags.Constants.TAG;
|
||||
import static de.srsoftware.umbrella.tags.Constants.*;
|
||||
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import de.srsoftware.configuration.Configuration;
|
||||
@@ -67,7 +66,7 @@ public class TagModule extends BaseHandler implements TagService {
|
||||
var user = userService().refreshSession(ex);
|
||||
if (user.isEmpty()) return unauthorized(ex);
|
||||
var module = path.pop();
|
||||
if (module == null) throw unprocessable("Module missing in path.");
|
||||
if (module == null) return getUserTags(ex, user.get());
|
||||
var head = path.pop();
|
||||
if (USES.equals(module)) return getTagUses(ex,head,user.get());
|
||||
long entityId = Long.parseLong(head);
|
||||
@@ -79,10 +78,6 @@ public class TagModule extends BaseHandler implements TagService {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean getTagUses(HttpExchange ex, String tag, UmbrellaUser user) throws IOException {
|
||||
return sendContent(ex,tagDb.getUses(tag,user.id()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doPost(Path path, HttpExchange ex) throws IOException {
|
||||
addCors(ex);
|
||||
@@ -117,6 +112,10 @@ public class TagModule extends BaseHandler implements TagService {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean getTagUses(HttpExchange ex, String tag, UmbrellaUser user) throws IOException {
|
||||
return sendContent(ex,tagDb.getUses(tag,user.id()));
|
||||
}
|
||||
|
||||
public Collection<String> getTags(String module, long entityId, UmbrellaUser user) throws UmbrellaException{
|
||||
return tagDb.list(user.id(),module,entityId);
|
||||
}
|
||||
@@ -126,6 +125,11 @@ public class TagModule extends BaseHandler implements TagService {
|
||||
return tagDb.list(user.id(),module,entityIds);
|
||||
}
|
||||
|
||||
private boolean getUserTags(HttpExchange ex, UmbrellaUser user) throws IOException {
|
||||
var tuples = tagDb.list(user.id()).stream().filter(t -> t.a != null && t.b != null);
|
||||
return sendContent(ex,tuples.map(t -> Map.of(TAG,t.a,COUNT,t.b)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(String module, long entityId, Collection<Long> userIds, Collection<String> tags) {
|
||||
tagDb.save(userIds,module,entityId,tags);
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
"contained_tax": "enthaltene Steuer",
|
||||
"content": "Inhalt",
|
||||
"context": "Kontext",
|
||||
"count_of_occurrences": "{count} Verwendungen",
|
||||
"country": "Land",
|
||||
"COURT": "Amtsgericht",
|
||||
"CUSTOMER-NUMBER": "Kundennummer",
|
||||
|
||||
@@ -423,4 +423,13 @@ fieldset.vcard{
|
||||
|
||||
.vcard td button.symbol{
|
||||
float: right;
|
||||
}
|
||||
|
||||
.cloud .tag{
|
||||
border: 1px solid;
|
||||
border-radius: 4px;
|
||||
padding: 2px;
|
||||
margin: 0 6px;
|
||||
white-space: nowrap;
|
||||
display: inline flow-root;
|
||||
}
|
||||
Reference in New Issue
Block a user