Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Manage layout persistence via interface #40

Closed
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
ef4d9fd
VUU-20: Define interface for layout persistence
pling-scottlogic Sep 7, 2023
59279f4
VUU-20: Adjust interface
pling-scottlogic Sep 8, 2023
1a74ae3
VUU-20: Implement local layout persistence via interface
pling-scottlogic Sep 8, 2023
72f676b
VUU-20: Access LayoutPersistenceManager via useLayoutManager
pling-scottlogic Sep 11, 2023
6debc78
VUU-20: Add LayoutPersistenceManager to hook props
pling-scottlogic Sep 11, 2023
dc107b7
VUU-20: Generate layout ID from persistence manager
pling-scottlogic Sep 12, 2023
904832e
VUU-20: Make tempLayouts a single layout
pling-scottlogic Sep 14, 2023
00a1850
VUU-20: Separate layout and metadata
pling-scottlogic Sep 14, 2023
13504b2
VUU-20: Refactor saveLayout
pling-scottlogic Sep 14, 2023
c896c71
VUU-20: Move ID out of metadata
pling-scottlogic Sep 14, 2023
566a0ab
VUU-20: Update documentation
pling-scottlogic Sep 15, 2023
065e007
VUU-20: Add PersistedLayoutMetadata type
pling-scottlogic Sep 15, 2023
597f9ce
VUU-20: Remove getLocalEntity from updateLayout
pling-scottlogic Sep 15, 2023
b859cfa
VUU-20: Remove loadMetadataByUser
pling-scottlogic Sep 15, 2023
ea956fc
VUU-20: Remove PersistedLayoutMetadata type
pling-scottlogic Sep 18, 2023
ec180bf
VUU-20: Remove metadata from Layout type
pling-scottlogic Sep 18, 2023
c6eb2db
VUU-20: Instantiate PersistenceManager in useLayoutManager
pling-scottlogic Sep 18, 2023
cee476f
VUU-20: Refactor LocalLayoutPersistenceManager
pling-scottlogic Sep 18, 2023
f7d0cfb
VUU-20: Remove unnecessary casting and import
pling-scottlogic Sep 19, 2023
38ce428
VUU-20: Remove layouts from state
pling-scottlogic Sep 19, 2023
4d9eeda
VUU-20: Remove loadLayouts from interface
pling-scottlogic Sep 19, 2023
ca04ca7
VUU-20: Remove unnecessary import
pling-scottlogic Sep 19, 2023
51abff6
VUU-20: Declare types in hook
pling-scottlogic Sep 19, 2023
c9bb4ee
VUU-20: Remove newLayout
pling-scottlogic Sep 19, 2023
ad3198c
VUU-20: Rename saveLayout to createLayout
pling-scottlogic Sep 21, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
cfisher-scottlogic marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
import { LayoutJSON } from "@finos/vuu-layout";
import { Layout, LayoutMetadata } from "@finos/vuu-shell";
import { LayoutMetadata } from "@finos/vuu-shell";

export interface LayoutPersistenceManager {
/**
* Saves a new layout
*
* @param metadata - Metadata about the layout to be saved (excluding ID)
* @param metadata - Metadata about the layout to be saved
* @param layout - Full JSON representation of the layout to be saved
*
* @returns ID assigned to the saved layout
*/
saveLayout: (layouts: Layout[]) => string;
saveLayout: (metadata: Omit<LayoutMetadata, "id">, layout: LayoutJSON) => string;
cfisher-scottlogic marked this conversation as resolved.
Show resolved Hide resolved

/**
* Overwrites an existing layout with a new one
cfisher-scottlogic marked this conversation as resolved.
Show resolved Hide resolved
*
* @param id - Unique identifier of the existing layout to be updated
* @param metadata - Metadata describing the new layout to overwrite with (excluding ID)
* @param metadata - Metadata describing the new layout to overwrite with
* @param layout - Full JSON representation of the new layout to overwrite with
*/
updateLayout: (id: string, metadata: Omit<LayoutMetadata, "id">, layout: LayoutJSON) => void;
vferraro-scottlogic marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -31,7 +31,7 @@ export interface LayoutPersistenceManager {
/**
* Retrieves an existing layout
*
* @param id - Unique identifier of the existing layout to be deleted
* @param id - Unique identifier of the existing layout to be retrieved
*
* @returns the layout corresponding to provided metadata
*/
Expand All @@ -43,16 +43,4 @@ export interface LayoutPersistenceManager {
* @returns an array of all persisted layout metadata
*/
loadMetadata: () => LayoutMetadata[];

/**
* Retrieves metadata for all existing layouts created by a given user
*
* @param user - Name of user
*
* @returns an array of metadata describing all persisted layouts created by {@link user}
*/
loadMetadataByUser: (user: string) => LayoutMetadata[];

// TODO: should be switched over to load metadata only; remove this
loadLayouts: () => Layout[];
cfisher-scottlogic marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,47 +4,39 @@ import { LayoutJSON, LayoutPersistenceManager } from "@finos/vuu-layout";
import { getLocalEntity, saveLocalEntity } from "@finos/vuu-filters";
import { getUniqueId } from "@finos/vuu-utils";

const metadataSaveLocation = "layouts/metadata";
const layoutsSaveLocation = "layouts/layouts";

export class LocalLayoutPersistenceManager implements LayoutPersistenceManager {
saveLayout(inputLayouts: Layout[]): string {
const layouts = Array.from(inputLayouts);
saveLayout(metadata: Omit<LayoutMetadata, "id">, layout: LayoutJSON): string {
console.log(`Saving layout as ${metadata.name} to group ${metadata.group}...`);

const existingLayouts = this.loadLayouts();
const existingMetadata = this.loadMetadata();

if (layouts.length === 0) {
return "";
}

const layout = this.deepCopy(layouts[layouts.length - 1]);
console.log(`Saving layout as ${layout.metadata.name} to group ${layout.metadata.group}...`);
const id = getUniqueId();
layout.metadata.id = id;
layouts[layouts.length - 1] = layout;
saveLocalEntity<Layout[]>("layouts", layouts);
return id;
}

private deepCopy<T>(object: T): T {
return JSON.parse(JSON.stringify(object));
};
this.appendAndPersist(id, metadata, layout, existingLayouts, existingMetadata);

updateLayout(id: string, newMetadata: Omit<LayoutMetadata, "id">, newLayoutJson: LayoutJSON): void {
const layouts = this.getExistingLayouts();
const layoutJson = getLocalEntity<LayoutJSON>("api/vui");
return id;
}

if (layoutJson) {
layouts.filter(layout => layout.metadata.id !== id)
const newLayout = {json: newLayoutJson, metadata: newMetadata} as Layout;
layouts.push(newLayout);
}
updateLayout(id: string, metadata: Omit<LayoutMetadata, "id">, newLayoutJson: LayoutJSON): void {
const existingLayouts = this.loadLayouts().filter(layout => layout.id !== id);
const existingMetadata = this.loadMetadata().filter(metadata => metadata.id !== id);
cfisher-scottlogic marked this conversation as resolved.
Show resolved Hide resolved

saveLocalEntity<Layout[]>("layouts", layouts);
};
this.appendAndPersist(id, metadata, newLayoutJson, existingLayouts, existingMetadata);
}

deleteLayout(id: string): void {
const layouts = this.getExistingLayouts().filter(layout => layout.metadata.id !== id);
saveLocalEntity<Layout[]>("layouts", layouts);
};
const layouts = this.loadLayouts().filter(layout => layout.id !== id);
const metadata = this.loadMetadata().filter(metadata => metadata.id !== id);

this.saveLayoutsWithMetadata(layouts, metadata);
}

loadLayout(id: string): LayoutJSON {
const layout = this.getExistingLayouts().filter(layout => layout.metadata.id === id);
const layout = this.loadLayouts().filter(layout => layout.id === id);

switch (layout.length) {
case 1: {
Expand All @@ -59,24 +51,29 @@ export class LocalLayoutPersistenceManager implements LayoutPersistenceManager {
return layout[0].json;
}
}
};
}

loadMetadata(): LayoutMetadata[] {
return this.getExistingLayouts().map(layout => layout.metadata);
};
return getLocalEntity<LayoutMetadata[]>(metadataSaveLocation) || [];
}

private loadLayouts(): Layout[] {
return getLocalEntity<Layout[]>(layoutsSaveLocation) || [];
}

loadMetadataByUser(user: string): LayoutMetadata[] {
return this.getExistingLayouts()
.filter(layout => layout.metadata.user === user)
.map(layout => layout.metadata);
};
private appendAndPersist(newId: string,
newMetadata: Omit<LayoutMetadata, "id">,
newLayout: LayoutJSON,
existingLayouts: Layout[],
existingMetadata: LayoutMetadata[]) {
existingLayouts.push({id: newId, json: newLayout});
existingMetadata.push({id: newId, ...newMetadata});

private getExistingLayouts() {
return getLocalEntity<Layout[]>("layouts") || [];
this.saveLayoutsWithMetadata(existingLayouts, existingMetadata);
}

// TODO: remove
loadLayouts(): Layout[] {
return this.getExistingLayouts();
private saveLayoutsWithMetadata(layouts: Layout[], metadata: LayoutMetadata[]): void {
saveLocalEntity<Layout[]>(layoutsSaveLocation, layouts);
saveLocalEntity<LayoutMetadata[]>(metadataSaveLocation, metadata);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,12 @@ type LayoutGroups = {
const classBase = "vuuLayoutList";

export const LayoutsList = (props: HTMLAttributes<HTMLDivElement>) => {
const { layouts } = useLayoutManager();

const layoutMetadata = layouts.map(layout => layout.metadata)
const { layoutMetadata } = useLayoutManager();

const handleLoadLayout = (layoutId?: string) => {
// TODO load layout
console.log("loading layout with id", layoutId)
console.log("json:", layouts.find(layout => layout.metadata.id === layoutId))
console.log("json:", layoutMetadata.find(metadata => metadata.id === layoutId))
}

const layoutsByGroup = layoutMetadata.reduce((acc: LayoutGroups, cur) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { LayoutJSON } from "@finos/vuu-layout";

export type LayoutMetadata = {
id: string;
name: string;
group: string;
screenshot: string;
user: string;
date: string;
id: string;
};

export type Layout = {
id: string,
json: LayoutJSON;
metadata: LayoutMetadata;
};
vferraro-scottlogic marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,46 +1,46 @@
import React, { useState, useCallback, useContext, useEffect } from "react";
import { getLocalEntity } from "@finos/vuu-filters";
import { LayoutJSON, LayoutPersistenceManager } from "@finos/vuu-layout";
import { LayoutMetadata, Layout } from "./layoutTypes";
import { LayoutJSON, LocalLayoutPersistenceManager } from "@finos/vuu-layout";
import { LayoutMetadata } from "./layoutTypes";

const persistenceManager = new LocalLayoutPersistenceManager();

export const LayoutManagementContext = React.createContext<{
layouts: Layout[],
layoutMetadata: LayoutMetadata[],
saveLayout: (n: Omit<LayoutMetadata, "id">) => void
}>({ layouts: [], saveLayout: () => { } })
}>({ layoutMetadata: [], saveLayout: () => { } })

export const LayoutManagementProvider = (props: {
persistenceManager: LayoutPersistenceManager,
children: JSX.Element | JSX.Element[]
}) => {
const [layouts, setLayouts] = useState<Layout[]>([]);
const [tempLayouts, setTempLayouts] = useState<Layout[]>([]);
const [layoutMetadata, setLayoutMetadata] = useState<LayoutMetadata[]>([]);

useEffect(() => {
const loadedLayouts = props.persistenceManager.loadLayouts();
setLayouts(loadedLayouts || [])
const loadedMetadata = persistenceManager.loadMetadata();
setLayoutMetadata(loadedMetadata || [])
}, [])

useEffect(() => {
if (tempLayouts.length !== 0) {
const saveLayout = useCallback((metadata: Omit<LayoutMetadata, "id">) => {
const json = getLocalEntity<LayoutJSON>("api/vui");

if (json) {
// Persist layouts
const generatedId = props.persistenceManager.saveLayout([...layouts, ...tempLayouts]);
const generatedId = persistenceManager.saveLayout(metadata, json);

// Update state
const newLayout = tempLayouts[0];
newLayout.metadata.id = generatedId;
setLayouts(prev => [...prev, newLayout]);
}
}, [tempLayouts])
const newMetadata: LayoutMetadata = {
...metadata,
id: generatedId
};

const saveLayout = useCallback((metadata: Omit<LayoutMetadata, "id">) => {
const json = getLocalEntity<LayoutJSON>("api/vui");
if (json) {
setTempLayouts([...layouts, { metadata: { ...metadata, id: "" }, json }])
setLayoutMetadata(prev => [...prev, newMetadata]);
}
}, [])

// TODO: add loadLayout function

return (
<LayoutManagementContext.Provider value={{ layouts, saveLayout }} >
<LayoutManagementContext.Provider value={{ layoutMetadata, saveLayout }} >
{props.children}
</LayoutManagementContext.Provider>
)
Expand Down
8 changes: 2 additions & 6 deletions vuu-ui/showcase/src/examples/Apps/NewTheme.examples.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,7 @@ import {
LayoutManagementProvider,
useLayoutManager
} from "@finos/vuu-shell";
import {
LocalLayoutPersistenceManager,
registerComponent
} from "@finos/vuu-layout";
import { registerComponent } from "@finos/vuu-layout";
import { TableSettingsPanel } from "@finos/vuu-table-extras";
import {
ContextMenuProvider,
Expand Down Expand Up @@ -187,9 +184,8 @@ const ShellWithNewTheme = () => {
};

export const ShellWithNewThemeAndLayoutManagement = () => {
const pm = new LocalLayoutPersistenceManager();
return (
<LayoutManagementProvider persistenceManager={pm}>
<LayoutManagementProvider>
<ShellWithNewTheme />
</LayoutManagementProvider>
)
Expand Down