feat: collections are stored as objects in workspaces

This commit is contained in:
Anoop M D 2022-10-15 13:50:58 +05:30
parent d546709b26
commit 91981a48e4
8 changed files with 68 additions and 21 deletions

View File

@ -16,11 +16,13 @@ const SelectCollection = ({onClose, onSelect, title}) => {
handleCancel={onClose} handleCancel={onClose}
> >
<ul className="mb-2" > <ul className="mb-2" >
{collections && collections.length && collections.map((c) => ( {(collections && collections.length) ? collections.map((c) => (
<div className="collection" key={c.uid} onClick={() => onSelect(c.uid)}> <div className="collection" key={c.uid} onClick={() => onSelect(c.uid)}>
<IconFiles size={18} strokeWidth={1.5}/> <span className="ml-2">{c.name}</span> <IconFiles size={18} strokeWidth={1.5}/> <span className="ml-2">{c.name}</span>
</div> </div>
))} )) : (
<div>No collections found</div>
)}
</ul> </ul>
</Modal> </Modal>
</StyledWrapper> </StyledWrapper>

View File

@ -4,6 +4,7 @@ import find from 'lodash/find';
import filter from 'lodash/filter'; import filter from 'lodash/filter';
import Collection from './Collection'; import Collection from './Collection';
import CreateOrAddCollection from './CreateOrAddCollection'; import CreateOrAddCollection from './CreateOrAddCollection';
import { findCollectionInWorkspace } from 'utils/workspaces';
const Collections = ({searchText}) => { const Collections = ({searchText}) => {
const { collections } = useSelector((state) => state.collections); const { collections } = useSelector((state) => state.collections);
@ -14,8 +15,7 @@ const Collections = ({searchText}) => {
return null; return null;
} }
const { collectionUids } = activeWorkspace; const collectionToDisplay = filter(collections, (c) => findCollectionInWorkspace(activeWorkspace, c.uid));
const collectionToDisplay = filter(collections, (c) => collectionUids.includes(c.uid));
if(!collectionToDisplay || !collectionToDisplay.length) { if(!collectionToDisplay || !collectionToDisplay.length) {
return <CreateOrAddCollection />; return <CreateOrAddCollection />;

View File

@ -1,4 +1,5 @@
import axios from 'axios'; import axios from 'axios';
import each from 'lodash/each';
import toast from 'react-hot-toast'; import toast from 'react-hot-toast';
import { uuid } from 'utils/common'; import { uuid } from 'utils/common';
import cloneDeep from 'lodash/cloneDeep'; import cloneDeep from 'lodash/cloneDeep';

View File

@ -3,6 +3,7 @@ import filter from 'lodash/filter';
import { uuid } from 'utils/common'; import { uuid } from 'utils/common';
import cloneDeep from 'lodash/cloneDeep'; import cloneDeep from 'lodash/cloneDeep';
import { workspaceSchema } from '@usebruno/schema'; import { workspaceSchema } from '@usebruno/schema';
import { findCollectionInWorkspace } from 'utils/workspaces';
import { getWorkspacesFromIdb, saveWorkspaceToIdb, deleteWorkspaceInIdb } from 'utils/idb/workspaces'; import { getWorkspacesFromIdb, saveWorkspaceToIdb, deleteWorkspaceInIdb } from 'utils/idb/workspaces';
import { import {
loadWorkspaces, loadWorkspaces,
@ -18,7 +19,7 @@ const seedWorkpace = () => {
const workspace = { const workspace = {
uid: uid, uid: uid,
name: 'My workspace', name: 'My workspace',
collectionUids: [] collections: []
}; };
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@ -52,7 +53,7 @@ export const addWorkspace = (workspaceName) => (dispatch) => {
const newWorkspace = { const newWorkspace = {
uid: uuid(), uid: uuid(),
name: workspaceName, name: workspaceName,
collectionUids: [] collections: []
}; };
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@ -131,12 +132,16 @@ export const addCollectionToWorkspace = (workspaceUid, collectionUid) => (dispat
} }
const workspaceCopy = cloneDeep(workspace); const workspaceCopy = cloneDeep(workspace);
if(workspaceCopy.collectionUids && workspace.collectionUids.length) { if(workspaceCopy.collections && workspace.collections.length) {
if(!workspaceCopy.collectionUids.includes(collectionUid)) { if(!findCollectionInWorkspace(workspace, collectionUid)) {
workspaceCopy.collectionUids.push(collectionUid); workspaceCopy.collections.push([{
uid: collectionUid
}]);
} }
} else { } else {
workspaceCopy.collectionUids = [collectionUid]; workspaceCopy.collections = [{
uid: collectionUid
}];
} }
workspaceSchema workspaceSchema
@ -167,8 +172,8 @@ export const removeCollectionFromWorkspace = (workspaceUid, collectionUid) => (d
} }
const workspaceCopy = cloneDeep(workspace); const workspaceCopy = cloneDeep(workspace);
if(workspaceCopy.collectionUids && workspace.collectionUids.length) { if(workspaceCopy.collections && workspace.collections.length) {
workspaceCopy.collectionUids = filter(workspaceCopy.collectionUids, (uid) => uid !== collectionUid); workspaceCopy.collections = filter(workspaceCopy.collections, (c) => c.uid !== collectionUid);
} }
saveWorkspaceToIdb(window.__idb, workspaceCopy) saveWorkspaceToIdb(window.__idb, workspaceCopy)
@ -184,5 +189,5 @@ export const removeCollectionFromWorkspace = (workspaceUid, collectionUid) => (d
// TODO // TODO
// Workspaces can have collection uids that no longer exist // Workspaces can have collection uids that no longer exist
// or the user may have the collections access revoked (in teams) // or the user may have the collections access revoked (in teams)
// This action will have to be called at the beginning to purge any zombi collectionUids in the workspaces // This action will have to be called at the beginning to purge any zombi collection references in the workspaces
export const removeZombieCollectionFromAllWorkspaces = (collectionUid) => (dispatch, getState) => {}; export const removeZombieCollectionFromAllWorkspaces = (workspaceUid) => (dispatch, getState) => {};

View File

@ -1,6 +1,7 @@
import { createSlice } from '@reduxjs/toolkit'; import { createSlice } from '@reduxjs/toolkit';
import find from 'lodash/find'; import find from 'lodash/find';
import filter from 'lodash/filter'; import filter from 'lodash/filter';
import { findCollectionInWorkspace } from 'utils/workspaces';
const initialState = { const initialState = {
workspaces: [], workspaces: [],
@ -43,12 +44,16 @@ export const workspacesSlice = createSlice({
const workspace = find(state.workspaces, (w) => w.uid === workspaceUid); const workspace = find(state.workspaces, (w) => w.uid === workspaceUid);
if(workspace) { if(workspace) {
if(workspace.collectionUids && workspace.collectionUids.length) { if(workspace.collections && workspace.collections.length) {
if(!workspace.collectionUids.includes(collectionUid)) { if(!findCollectionInWorkspace(workspace, collectionUid)) {
workspace.collectionUids.push(collectionUid); workspace.collections.push([{
uid: collectionUid
}]);
} }
} else { } else {
workspace.collectionUids = [collectionUid]; workspace.collections = [{
uid: collectionUid
}];
} }
} }
}, },
@ -56,8 +61,8 @@ export const workspacesSlice = createSlice({
const { workspaceUid, collectionUid } = action.payload; const { workspaceUid, collectionUid } = action.payload;
const workspace = find(state.workspaces, (w) => w.uid === workspaceUid); const workspace = find(state.workspaces, (w) => w.uid === workspaceUid);
if(workspace && workspace.collectionUids && workspace.collectionUids.length) { if(workspace && workspace.collections && workspace.collections.length) {
workspace.collectionUids = filter(workspace.collectionUids, (uid) => uid !== collectionUid); workspace.collections = filter(workspace.collections, (c) => c.uid !== collectionUid);
} }
} }
} }

View File

@ -0,0 +1,5 @@
import find from 'lodash/find';
export const findCollectionInWorkspace = (workspace, collectionUid) => {
return find(workspace.collections, (c) => c.uid === collectionUid);
};

View File

@ -1,13 +1,17 @@
const Yup = require('yup'); const Yup = require('yup');
const { uidSchema } = require("../common"); const { uidSchema } = require("../common");
const collectionsSchema = Yup.object({
uid: uidSchema,
}).noUnknown(true).strict();
const workspaceSchema = Yup.object({ const workspaceSchema = Yup.object({
uid: uidSchema, uid: uidSchema,
name: Yup.string() name: Yup.string()
.min(1, 'name must be atleast 1 characters') .min(1, 'name must be atleast 1 characters')
.max(50, 'name must be 50 characters or less') .max(50, 'name must be 50 characters or less')
.required('name is required'), .required('name is required'),
collectionUids: Yup.array().of(uidSchema) collections: Yup.array().of(collectionsSchema)
}).noUnknown(true).strict(); }).noUnknown(true).strict();
module.exports = { module.exports = {

View File

@ -83,4 +83,29 @@ describe('Workspace Schema Validation', () => {
) )
]); ]);
}); });
it('workspace schema must validate successfully with collections', async () => {
const workspace = {
uid: uuid(),
name: 'My workspace' ,
collections: [{uid: uuid()}]
};
const isValid = await workspaceSchema.validate(workspace);
expect(isValid).toBeTruthy();
});
it('workspace schema throw an error when collections has an unknown property', async () => {
const workspace = {
uid: uuid(),
name: 'My workspace' ,
collections: [{uid: uuid(), foo: 'bar'}]
};
return Promise.all([
expect(workspaceSchema.validate(workspace)).rejects.toEqual(
validationErrorWithMessages('collections[0] field has unspecified keys: foo')
)
]);
});
}); });