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 6 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
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
cfisher-scottlogic marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { LayoutJSON } from "@finos/vuu-layout";
import { Layout, LayoutMetadata } from "@finos/vuu-shell";

export interface LayoutPersistenceManager {
/**
* Saves a new layout
*
* @param metadata - Metadata about the layout to be saved (excluding ID)
* @param layout - Full JSON representation of the layout to be saved
*
* @returns ID assigned to the saved layout
*/
saveLayout: (layouts: Layout[]) => string;
vferraro-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 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

/**
* Deletes an existing layout
cfisher-scottlogic marked this conversation as resolved.
Show resolved Hide resolved
*
* @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 deleted
*
* @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[];

cfisher-scottlogic marked this conversation as resolved.
Show resolved Hide resolved
/**
* 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[];
cfisher-scottlogic marked this conversation as resolved.
Show resolved Hide resolved

// 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
@@ -0,0 +1,82 @@
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";

export class LocalLayoutPersistenceManager implements LayoutPersistenceManager {
saveLayout(inputLayouts: Layout[]): string {
vferraro-scottlogic marked this conversation as resolved.
Show resolved Hide resolved
const layouts = Array.from(inputLayouts);
vferraro-scottlogic marked this conversation as resolved.
Show resolved Hide resolved

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

const layout = this.deepCopy(layouts[layouts.length - 1]);
cfisher-scottlogic marked this conversation as resolved.
Show resolved Hide resolved
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 {
cfisher-scottlogic marked this conversation as resolved.
Show resolved Hide resolved
cfisher-scottlogic marked this conversation as resolved.
Show resolved Hide resolved
return JSON.parse(JSON.stringify(object));
};

updateLayout(id: string, newMetadata: Omit<LayoutMetadata, "id">, newLayoutJson: LayoutJSON): void {
const layouts = this.getExistingLayouts();
const layoutJson = getLocalEntity<LayoutJSON>("api/vui");
vferraro-scottlogic marked this conversation as resolved.
Show resolved Hide resolved

if (layoutJson) {
layouts.filter(layout => layout.metadata.id !== id)
const newLayout = {json: newLayoutJson, metadata: newMetadata} as Layout;
vferraro-scottlogic marked this conversation as resolved.
Show resolved Hide resolved
layouts.push(newLayout);
}

saveLocalEntity<Layout[]>("layouts", layouts);
};

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

loadLayout(id: string): LayoutJSON {
const layout = this.getExistingLayouts().filter(layout => layout.metadata.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 this.getExistingLayouts().map(layout => layout.metadata);
};

loadMetadataByUser(user: string): LayoutMetadata[] {
return this.getExistingLayouts()
.filter(layout => layout.metadata.user === user)
.map(layout => layout.metadata);
};

private getExistingLayouts() {
return getLocalEntity<Layout[]>("layouts") || [];
cfisher-scottlogic marked this conversation as resolved.
Show resolved Hide resolved
}

// TODO: remove
loadLayouts(): Layout[] {
return this.getExistingLayouts();
}
}
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
@@ -1,42 +1,41 @@
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 { getLocalEntity } from "@finos/vuu-filters";
import { LayoutJSON, LayoutPersistenceManager } from "@finos/vuu-layout";
import { LayoutMetadata, Layout } from "./layoutTypes";

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

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

const [layouts, setLayouts] = useState<Layout[]>([])
export const LayoutManagementProvider = (props: {
persistenceManager: LayoutPersistenceManager,
cfisher-scottlogic marked this conversation as resolved.
Show resolved Hide resolved
children: JSX.Element | JSX.Element[]
}) => {
const [layouts, setLayouts] = useState<Layout[]>([]);
const [tempLayouts, setTempLayouts] = useState<Layout[]>([]);
vferraro-scottlogic marked this conversation as resolved.
Show resolved Hide resolved

useEffect(() => {
const layouts = getLocalEntity<Layout[]>("layouts")
setLayouts(layouts || [])
const loadedLayouts = props.persistenceManager.loadLayouts();
setLayouts(loadedLayouts || [])
}, [])

useEffect(() => {
vferraro-scottlogic marked this conversation as resolved.
Show resolved Hide resolved
saveLocalEntity<Layout[]>("layouts", layouts)
}, [layouts])
if (tempLayouts.length !== 0) {
// Persist layouts
const generatedId = props.persistenceManager.saveLayout([...layouts, ...tempLayouts]);

// Update state
const newLayout = tempLayouts[0];
newLayout.metadata.id = generatedId;
setLayouts(prev => [...prev, newLayout]);
}
}, [tempLayouts])
cfisher-scottlogic marked this conversation as resolved.
Show resolved Hide resolved

const saveLayout = useCallback((metadata: Omit<LayoutMetadata, "id">) => {
const json = getLocalEntity<LayoutJSON>("api/vui")
const json = getLocalEntity<LayoutJSON>("api/vui");
cfisher-scottlogic marked this conversation as resolved.
Show resolved Hide resolved
if (json) {
setLayouts(prev =>
[
...prev,
{
metadata: {
...metadata,
id: getUniqueId()
},
json
}
]
)
setTempLayouts([...layouts, { metadata: { ...metadata, id: "" }, json }])
}
}, [])

Expand Down
2 changes: 1 addition & 1 deletion vuu-ui/packages/vuu-shell/src/left-nav/LeftNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ export const LeftNav = ({
Layout Templates
</div>
<div className="vuuLeftNav-drawer">
<LayoutsList layouts={[]} />
<LayoutsList/>
</div>
</Stack>
</div>
Expand Down
10 changes: 6 additions & 4 deletions vuu-ui/showcase/src/examples/Apps/NewTheme.examples.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ import {
LayoutManagementProvider,
useLayoutManager
} from "@finos/vuu-shell";
import { registerComponent } from "@finos/vuu-layout";
import {
LocalLayoutPersistenceManager,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we dont need to import LocalLayoutPersistenceManager here anymore

registerComponent
} from "@finos/vuu-layout";
import { TableSettingsPanel } from "@finos/vuu-table-extras";
import {
ContextMenuProvider,
Expand Down Expand Up @@ -46,7 +49,6 @@ const ShellWithNewTheme = () => {
const { saveLayout } = useLayoutManager();

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 @@ -176,7 +178,6 @@ const ShellWithNewTheme = () => {
style={{ maxHeight: 500, borderColor: "#6d188b" }}
title={"Save Layout"}
hideCloseButton
headerProps={{ className: "dialogHeader" }}
>
{dialogContent}
</Dialog>
Expand All @@ -186,8 +187,9 @@ const ShellWithNewTheme = () => {
};

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