implemented tags for items
Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
This commit is contained in:
@@ -36,6 +36,10 @@ public class DbLocation extends Location {
|
|||||||
return new DbLocation(rs.getLong(ID), OwnerRef.of(rs), rs.getLong(PARENT_LOCATION_ID), rs.getString(NAME),rs.getString(DESCRIPTION));
|
return new DbLocation(rs.getLong(ID), OwnerRef.of(rs), rs.getLong(PARENT_LOCATION_ID), rs.getString(NAME),rs.getString(DESCRIPTION));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Owner owner(){
|
||||||
|
return owner;
|
||||||
|
}
|
||||||
|
|
||||||
public Long parent(){
|
public Long parent(){
|
||||||
return parentLocationId;
|
return parentLocationId;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,8 +38,8 @@
|
|||||||
router.navigate(`/${n.module}/${n.entity_id}/view`);
|
router.navigate(`/${n.module}/${n.entity_id}/view`);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function load(){
|
async function load(id){
|
||||||
const url = api(`notes/${module}/${entity_id}`);
|
const url = api(`notes/${module}/${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();
|
||||||
@@ -87,7 +87,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(load);
|
$effect(() => load(entity_id));
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<List {authors} {module} {notes} />
|
<List {authors} {module} {notes} />
|
||||||
|
|||||||
@@ -8,15 +8,21 @@
|
|||||||
import ItemList from './ItemList.svelte';
|
import ItemList from './ItemList.svelte';
|
||||||
import ItemProps from './ItemProps.svelte';
|
import ItemProps from './ItemProps.svelte';
|
||||||
import Notes from '../notes/RelatedNotes.svelte';
|
import Notes from '../notes/RelatedNotes.svelte';
|
||||||
|
import Tags from '../tags/TagList.svelte';
|
||||||
|
|
||||||
|
|
||||||
let items = $derived.by(loadItems);
|
let loc_data = $derived.by(loadLocation);
|
||||||
let item = $state(null);
|
let item = $state(null);
|
||||||
let location = $state(null);
|
let location = $state(null);
|
||||||
|
|
||||||
|
$effect(() => {
|
||||||
|
// This effect runs whenever `location` changes
|
||||||
|
if (location !== null) item = null;
|
||||||
|
});
|
||||||
let properties = $state(null);
|
let properties = $state(null);
|
||||||
let top_level = $state(null);
|
let top_level = $state(null);
|
||||||
|
|
||||||
async function loadItems(){
|
async function loadLocation(){
|
||||||
if (!location) return null;
|
if (!location) return null;
|
||||||
const url = api(`stock/location/${location.id}`)
|
const url = api(`stock/location/${location.id}`)
|
||||||
const res = await fetch(url,{credentials:'include'});
|
const res = await fetch(url,{credentials:'include'});
|
||||||
@@ -59,6 +65,23 @@
|
|||||||
onMount(load);
|
onMount(load);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.grid3 {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: [left] 1fr [first] 1fr [second] 1fr [right]
|
||||||
|
}
|
||||||
|
|
||||||
|
.locations {
|
||||||
|
grid-row-end: span 3;
|
||||||
|
}
|
||||||
|
.notes, .tags{
|
||||||
|
grid-column-end: span 2;
|
||||||
|
}
|
||||||
|
.json {
|
||||||
|
grid-column-end: span 3;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
<h2>{t('Stock')}</h2>
|
<h2>{t('Stock')}</h2>
|
||||||
<div class="grid3">
|
<div class="grid3">
|
||||||
<div class="locations">
|
<div class="locations">
|
||||||
@@ -71,20 +94,31 @@
|
|||||||
{/each}
|
{/each}
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
{#await loc_data}
|
||||||
|
<span>loading…</span>
|
||||||
|
{:then data}
|
||||||
<div class="items">
|
<div class="items">
|
||||||
{#await items}
|
|
||||||
<span>loading…</span>
|
|
||||||
{:then data}
|
|
||||||
{#if location}
|
{#if location}
|
||||||
<h3>{location.name}</h3>
|
<h3>{location.name}</h3>
|
||||||
{/if}
|
{/if}
|
||||||
<ItemList items={data?.sort((a,b) => a.code.localeCompare(b.code))} bind:selected={item} />
|
<ItemList items={data?.items.sort((a,b) => a.code.localeCompare(b.code))} bind:selected={item} />
|
||||||
{/await}
|
|
||||||
</div>
|
</div>
|
||||||
<div class="properties">
|
<div class="properties">
|
||||||
<ItemProps {item} {properties} />
|
<ItemProps {item} {properties} />
|
||||||
</div>
|
</div>
|
||||||
{#if item}
|
{#if item}
|
||||||
<Notes module="stock" entity_id={item.id} />
|
<div class="tags">
|
||||||
|
<span>{t('tags')}</span>
|
||||||
|
<Tags module="stock" id={item.id} user_list={data.users} />
|
||||||
|
</div>
|
||||||
|
<div class="notes">
|
||||||
|
<span>{t('notes')}</span>
|
||||||
|
<Notes module="stock" entity_id={item.id} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<pre class="json">
|
||||||
|
{JSON.stringify(data.users,null,2)}
|
||||||
|
</pre>
|
||||||
{/if}
|
{/if}
|
||||||
|
{/await}
|
||||||
</div>
|
</div>
|
||||||
@@ -5,11 +5,10 @@ public class Constants {
|
|||||||
|
|
||||||
private Constants(){}
|
private Constants(){}
|
||||||
|
|
||||||
|
|
||||||
public static final String BELOW = "below";
|
public static final String BELOW = "below";
|
||||||
public static final String CONFIG_DATABASE = "umbrella.modules.stock.database";
|
public static final String CONFIG_DATABASE = "umbrella.modules.stock.database";
|
||||||
public static final String ITEM_ID = "item_id";
|
public static final String ITEM_ID = "item_id";
|
||||||
public static final String ITEMS_AT = "items_at";
|
public static final String ITEMS = "items";
|
||||||
public static final String LOCATIONS = "locations";
|
public static final String LOCATIONS = "locations";
|
||||||
public static final String OF_USER = "of_user";
|
public static final String OF_USER = "of_user";
|
||||||
public static final String PROPERTY_ID = "prop_id";
|
public static final String PROPERTY_ID = "prop_id";
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ public class StockModule extends BaseHandler implements StockService {
|
|||||||
case LOCATION -> {
|
case LOCATION -> {
|
||||||
try {
|
try {
|
||||||
var location = Location.of(Long.parseLong(path.pop()));
|
var location = Location.of(Long.parseLong(path.pop()));
|
||||||
yield getItemsAtLocation(user.get(), location, ex);
|
yield getLocationEntities(location, ex);
|
||||||
} catch (Exception e){
|
} catch (Exception e){
|
||||||
yield super.doGet(path,ex);
|
yield super.doGet(path,ex);
|
||||||
}
|
}
|
||||||
@@ -97,11 +97,18 @@ public class StockModule extends BaseHandler implements StockService {
|
|||||||
private boolean getChildLocations(UmbrellaUser user, long parentId, HttpExchange ex) throws IOException {
|
private boolean getChildLocations(UmbrellaUser user, long parentId, HttpExchange ex) throws IOException {
|
||||||
LOG.log(WARNING,"No security check implemented for {0}.getChildLocations(user, parentId, ex)!",getClass().getSimpleName()); // TODO check, that user is allowed to request that location
|
LOG.log(WARNING,"No security check implemented for {0}.getChildLocations(user, parentId, ex)!",getClass().getSimpleName()); // TODO check, that user is allowed to request that location
|
||||||
return sendContent(ex, stockDb.listChildLocations(parentId).stream().sorted(comparing(l -> l.name().toLowerCase())).map(DbLocation::toMap));
|
return sendContent(ex, stockDb.listChildLocations(parentId).stream().sorted(comparing(l -> l.name().toLowerCase())).map(DbLocation::toMap));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean getItemsAtLocation(UmbrellaUser user, Location location, HttpExchange ex) throws IOException {
|
private boolean getLocationEntities(Location location, HttpExchange ex) throws IOException {
|
||||||
return sendContent(ex, stockDb.listItemsAt(location).stream().map(Item::toMap).toList());
|
var items = stockDb.listItemsAt(location).stream().map(Item::toMap).toList();
|
||||||
|
var owner = location.resolve().owner();
|
||||||
|
List<Long> userIds = switch (owner.type()){
|
||||||
|
case COMPANY -> companyService().getMembers(owner.id()).stream().map(UmbrellaUser::id).toList();
|
||||||
|
case USER -> List.of(owner.id());
|
||||||
|
case null, default -> throw unprocessable("Unprocessable owner type: {0}",owner.type());
|
||||||
|
};
|
||||||
|
|
||||||
|
return sendContent(ex,Map.of(ITEMS,items,USERS,userIds));
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean getLocations(Path path, UmbrellaUser user, HttpExchange ex) throws IOException {
|
private boolean getLocations(Path path, UmbrellaUser user, HttpExchange ex) throws IOException {
|
||||||
|
|||||||
Reference in New Issue
Block a user