diff --git a/client/src/components/appbar/AddTabMenu.tsx b/client/src/components/appbar/AddTabMenu.tsx
index f3eb48f..a9e0755 100644
--- a/client/src/components/appbar/AddTabMenu.tsx
+++ b/client/src/components/appbar/AddTabMenu.tsx
@@ -35,6 +35,6 @@ export default function AddTabMenu(props: IProps) {
windowType: WindowType.ManageTags,
})
}}
- >{WindowType.ManageTags}
+ >Manage Tags
}
\ No newline at end of file
diff --git a/client/src/components/windows/manage_tags/ManageTagMenu.tsx b/client/src/components/windows/manage_tags/ManageTagMenu.tsx
index 758b689..d71cbf6 100644
--- a/client/src/components/windows/manage_tags/ManageTagMenu.tsx
+++ b/client/src/components/windows/manage_tags/ManageTagMenu.tsx
@@ -25,13 +25,39 @@ export function MenuEditText(props: {
/>
}
+export function PickTag(props: {
+ tags: any[]
+ open: boolean
+ root: boolean
+ onPick: (v: number | null) => void
+}) {
+
+ return <>
+ {props.root && }
+ {props.tags.map((tag: any) => {
+ if ('children' in tag && tag.children.length > 0) {
+ return props.onPick(tag.tagId)}
+ >
+
+
+ }
+ return
+ })
+ }>
+}
+
export interface IProps {
position: null | number[],
open: boolean,
onClose: () => void,
onRename: (s: string) => void,
onDelete: () => void,
+ onMove: (to: number | null) => void,
tag: any,
+ changedTags: any[], // Tags organized hierarchically with "children" fields
}
export default function ManageTagMenu(props: IProps) {
@@ -64,6 +90,15 @@ export default function ManageTagMenu(props: IProps) {
}}
/>
-
+
+ {
+ console.log("onPick:", v)
+ props.onClose();
+ props.onMove(v);
+ }} />
+
}
\ No newline at end of file
diff --git a/client/src/components/windows/manage_tags/ManageTagsWindow.tsx b/client/src/components/windows/manage_tags/ManageTagsWindow.tsx
index 816bf1f..d77468a 100644
--- a/client/src/components/windows/manage_tags/ManageTagsWindow.tsx
+++ b/client/src/components/windows/manage_tags/ManageTagsWindow.tsx
@@ -19,7 +19,8 @@ export enum TagChangeType {
export interface TagChange {
type: TagChangeType,
id: number, // MuDBase ID. If not in database yet, negative IDs will be used until submitted.
- parent?: number, // MuDBase ID. If not in database yet, negative IDs will be used until submitted.
+ parent?: number | null, // MuDBase ID. If not in database yet, negative IDs will be used until submitted.
+ // null refers to the tags root.
name?: string,
}
@@ -51,10 +52,12 @@ export function ManageTagsWindowReducer(state: ManageTagsWindowState, action: an
}
export function organiseTags(allTags: Record, fromId: number | null): any[] {
- const base = Object.values(allTags).filter((tag: any) =>
- (fromId === null && !tag.parentId) ||
- (tag.parentId && tag.parentId === fromId)
- );
+ const base = Object.values(allTags).filter((tag: any) => {
+ var par: any = ("proposedParent" in tag) ? tag.proposedParent : tag.parentId;
+
+ return (fromId === null && !par) ||
+ (par && par === fromId)
+ });
return base.map((tag: any) => {
return {
@@ -102,6 +105,7 @@ export function SingleTag(props: {
prependElems: any[],
dispatch: (action: any) => void,
state: ManageTagsWindowState,
+ changedTags: any[],
}) {
const tag = props.tag;
const hasChildren = 'children' in tag && tag.children.length > 0;
@@ -153,6 +157,7 @@ export function SingleTag(props: {
/]}
dispatch={props.dispatch}
state={props.state}
+ changedTags={props.changedTags}
/>)}
{
+ props.dispatch({
+ type: ManageTagsWindowActions.SetPendingChanges,
+ value: [
+ ...props.state.pendingChanges,
+ {
+ type: TagChangeType.MoveTo,
+ id: tag.tagId,
+ parent: to,
+ }
+ ]
+ })
+ }}
tag={tag}
+ changedTags={props.changedTags}
/>
>
}
-function addTagChanges(tags: Record, changes: TagChange[]) {
- var retval = tags;
+function annotateTagsWithChanges(tags: Record, changes: TagChange[]) {
+ var retval = _.cloneDeep(tags);
const applyDelete = (id: number) => {
retval[id].proposeDelete = true;
@@ -205,6 +224,37 @@ function addTagChanges(tags: Record, changes: TagChange[]) {
case TagChangeType.Delete:
applyDelete(change.id);
break;
+ case TagChangeType.MoveTo:
+ retval[change.id].proposedParent = change.parent;
+ break;
+ default:
+ throw new Error("Unimplemented tag change")
+ }
+ })
+ return retval;
+}
+
+function applyTagsChanges(tags: Record, changes: TagChange[]) {
+ var retval = _.cloneDeep(tags);
+
+ const applyDelete = (id: number) => {
+ Object.values(tags).filter((t: any) => t.parentId === id)
+ .forEach((child: any) => applyDelete(child.tagId));
+ delete retval[id].proposeDelete;
+ }
+
+ changes.forEach((change: TagChange) => {
+ switch (change.type) {
+ case TagChangeType.Rename:
+ retval[change.id].name = change.name;
+ break;
+ case TagChangeType.Delete:
+ applyDelete(change.id);
+ break;
+ case TagChangeType.MoveTo:
+ retval[change.id].parentId = change.parent;
+ if (change.parent === null) { delete retval[change.id].parentId; }
+ break;
default:
throw new Error("Unimplemented tag change")
}
@@ -234,7 +284,10 @@ export default function ManageTagsWindow(props: IProps) {
})();
}, [props.state.fetchedTags]);
- const tagsWithChanges = addTagChanges(props.state.fetchedTags || {}, props.state.pendingChanges)
+ const tagsWithChanges = annotateTagsWithChanges(props.state.fetchedTags || {}, props.state.pendingChanges)
+ const changedTags = organiseTags(
+ applyTagsChanges(props.state.fetchedTags || {}, props.state.pendingChanges),
+ null);
const tags = organiseTags(tagsWithChanges, null);
return
@@ -263,6 +316,7 @@ export default function ManageTagsWindow(props: IProps) {
prependElems={[]}
dispatch={props.dispatch}
state={props.state}
+ changedTags={changedTags}
/>;
})}