Skip to content

Commit

Permalink
VUU-20: Manage layout persistence via interface
Browse files Browse the repository at this point in the history
  • Loading branch information
pling-scottlogic committed Sep 21, 2023
1 parent dbe29bd commit 9e52a75
Show file tree
Hide file tree
Showing 8 changed files with 159 additions and 38 deletions.
1 change: 1 addition & 0 deletions vuu-ui/packages/vuu-layout/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export * from "./DraggableLayout";
export * from "./flexbox";
export { Action } from "./layout-action";
export * from "./layout-header";
export * from "./layout-persistence";
export * from "./layout-provider";
export * from "./layout-reducer";
export * from "./layout-view";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { LayoutJSON } from "@finos/vuu-layout";
import { LayoutMetadata } from "@finos/vuu-shell";

export interface LayoutPersistenceManager {
/**
* Saves a new layout
*
* @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
*/
createLayout: (metadata: Omit<LayoutMetadata, "id">, layout: LayoutJSON) => string;

/**
* Overwrites an existing layout with a new one
*
* @param id - Unique identifier of the existing layout to be updated
* @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;

/**
* Deletes an existing layout
*
* @param id - Unique identifier of the existing layout to be deleted
*/
deleteLayout: (id: string) => void;

/**
* Retrieves an existing layout
*
* @param id - Unique identifier of the existing layout to be retrieved
*
* @returns the layout corresponding to provided metadata
*/
loadLayout: (id: string) => LayoutJSON;

/**
* Retrieves metadata for all existing layouts
*
* @returns an array of all persisted layout metadata
*/
loadMetadata: () => LayoutMetadata[];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { Layout, LayoutMetadata } from "@finos/vuu-shell";
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 {
createLayout(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();

const id = getUniqueId();

this.appendAndPersist(id, metadata, layout, existingLayouts, existingMetadata);

return id;
}

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);

this.appendAndPersist(id, metadata, newLayoutJson, existingLayouts, existingMetadata);
}

deleteLayout(id: string): void {
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.loadLayouts().filter(layout => layout.id === id);

switch (layout.length) {
case 1: {
return layout[0].json;
}
case 0: {
console.log(`WARNING: no layout exists for ID "${id}"; returning empty layout`);
return {} as LayoutJSON;
}
default: {
console.log(`WARNING: multiple layouts exist for ID "${id}"; returning first instance`)
return layout[0].json;
}
}
}

loadMetadata(): LayoutMetadata[] {
return getLocalEntity<LayoutMetadata[]>(metadataSaveLocation) || [];
}

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

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});

this.saveLayoutsWithMetadata(existingLayouts, existingMetadata);
}

private saveLayoutsWithMetadata(layouts: Layout[], metadata: LayoutMetadata[]): void {
saveLocalEntity<Layout[]>(layoutsSaveLocation, layouts);
saveLocalEntity<LayoutMetadata[]>(metadataSaveLocation, metadata);
}
}
2 changes: 2 additions & 0 deletions vuu-ui/packages/vuu-layout/src/layout-persistence/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './LayoutPersistenceManager';
export * from './LocalLayoutPersistenceManager';
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
Expand Up @@ -10,6 +10,6 @@ export type LayoutMetadata = {
};

export type Layout = {
id: string,
json: LayoutJSON;
metadata: LayoutMetadata;
};
Original file line number Diff line number Diff line change
@@ -1,47 +1,46 @@
import React, { useState, useCallback, useContext, useEffect } from "react";
import { getLocalEntity, saveLocalEntity } from "@finos/vuu-filters";
import { LayoutJSON } from "@finos/vuu-layout";
import { getUniqueId } from "@finos/vuu-utils";
import { LayoutMetadata, Layout } from "./layoutTypes";
import { getLocalEntity } from "@finos/vuu-filters";
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: () => { } })

export const LayoutManagementProvider = (props: { children: JSX.Element | JSX.Element[] }) => {
}>({ layoutMetadata: [], saveLayout: () => { } })

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

useEffect(() => {
const layouts = getLocalEntity<Layout[]>("layouts")
setLayouts(layouts || [])
const loadedMetadata = persistenceManager.loadMetadata();
setLayoutMetadata(loadedMetadata || [])
}, [])

useEffect(() => {
saveLocalEntity<Layout[]>("layouts", layouts)
}, [layouts])

const saveLayout = useCallback((metadata: Omit<LayoutMetadata, "id">) => {
const json = getLocalEntity<LayoutJSON>("api/vui")
const json = getLocalEntity<LayoutJSON>("api/vui");

if (json) {
setLayouts(prev =>
[
...prev,
{
metadata: {
...metadata,
id: getUniqueId()
},
json
}
]
)
// Persist layouts
const generatedId = persistenceManager.createLayout(metadata, json);

// Update state
const newMetadata: LayoutMetadata = {
...metadata,
id: generatedId
};

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
4 changes: 0 additions & 4 deletions vuu-ui/showcase/src/examples/Apps/NewTheme.examples.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,6 @@ const ShellWithNewTheme = () => {

const handleSave = useCallback(
(layoutMetadata: Omit<LayoutMetadata, "id">) => {
console.log(
`Save layout as ${layoutMetadata.name} to group ${layoutMetadata.group}`
);
saveLayout(layoutMetadata);
setDialogContent(undefined);
},
Expand Down Expand Up @@ -229,7 +226,6 @@ const ShellWithNewTheme = () => {
style={{ maxHeight: 500, borderColor: "#6d188b" }}
title={"Save Layout"}
hideCloseButton
headerProps={{ className: "dialogHeader" }}
>
{dialogContent}
</Dialog>
Expand Down

0 comments on commit 9e52a75

Please sign in to comment.