Nested folders
This commit is contained in:
parent
06f129e2c1
commit
6aba4550a4
|
@ -2,6 +2,7 @@ import { FolderData } from '../models/data/folderData';
|
|||
|
||||
import { Folder } from '../models/domain/folder';
|
||||
import { SymmetricCryptoKey } from '../models/domain/symmetricCryptoKey';
|
||||
import { TreeNode } from '../models/domain/treeNode';
|
||||
|
||||
import { FolderView } from '../models/view/folderView';
|
||||
|
||||
|
@ -13,6 +14,7 @@ export abstract class FolderService {
|
|||
get: (id: string) => Promise<Folder>;
|
||||
getAll: () => Promise<Folder[]>;
|
||||
getAllDecrypted: () => Promise<FolderView[]>;
|
||||
getAllNested: () => Promise<Array<TreeNode<FolderView>>>;
|
||||
saveWithServer: (folder: Folder) => Promise<any>;
|
||||
upsert: (folder: FolderData | FolderData[]) => Promise<any>;
|
||||
replace: (folders: { [id: string]: FolderData; }) => Promise<any>;
|
||||
|
|
|
@ -9,11 +9,14 @@ import { CipherType } from '../../enums/cipherType';
|
|||
import { CollectionView } from '../../models/view/collectionView';
|
||||
import { FolderView } from '../../models/view/folderView';
|
||||
|
||||
import { TreeNode } from '../../models/domain/treeNode';
|
||||
|
||||
import { CollectionService } from '../../abstractions/collection.service';
|
||||
import { FolderService } from '../../abstractions/folder.service';
|
||||
|
||||
export class GroupingsComponent {
|
||||
@Input() showFolders = true;
|
||||
@Input() loadNestedFolder = false;
|
||||
@Input() showCollections = true;
|
||||
@Input() showFavorites = true;
|
||||
|
||||
|
@ -26,6 +29,7 @@ export class GroupingsComponent {
|
|||
@Output() onCollectionClicked = new EventEmitter<CollectionView>();
|
||||
|
||||
folders: FolderView[];
|
||||
nestedFolders: Array<TreeNode<FolderView>>;
|
||||
collections: CollectionView[];
|
||||
loaded: boolean = false;
|
||||
cipherType = CipherType;
|
||||
|
@ -64,6 +68,9 @@ export class GroupingsComponent {
|
|||
return;
|
||||
}
|
||||
this.folders = await this.folderService.getAllDecrypted();
|
||||
if (this.loadNestedFolder) {
|
||||
this.nestedFolders = await this.folderService.getAllNested();
|
||||
}
|
||||
}
|
||||
|
||||
selectAll() {
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
export class TreeNode<T> {
|
||||
node: T;
|
||||
children: Array<TreeNode<T>> = [];
|
||||
|
||||
constructor(node: T) {
|
||||
this.node = node;
|
||||
}
|
||||
}
|
|
@ -19,11 +19,13 @@ import { UserService } from '../abstractions/user.service';
|
|||
import { CipherData } from '../models/data/cipherData';
|
||||
|
||||
import { Utils } from '../misc/utils';
|
||||
import { TreeNode } from '../models/domain/treeNode';
|
||||
|
||||
const Keys = {
|
||||
foldersPrefix: 'folders_',
|
||||
ciphersPrefix: 'ciphers_',
|
||||
};
|
||||
const NestingDelimiter = '/';
|
||||
|
||||
export class FolderService implements FolderServiceAbstraction {
|
||||
decryptedFolderCache: FolderView[];
|
||||
|
@ -95,6 +97,18 @@ export class FolderService implements FolderServiceAbstraction {
|
|||
return this.decryptedFolderCache;
|
||||
}
|
||||
|
||||
async getAllNested(): Promise<Array<TreeNode<FolderView>>> {
|
||||
const folders = await this.getAllDecrypted();
|
||||
const nodes: Array<TreeNode<FolderView>> = [];
|
||||
folders.forEach((f) => {
|
||||
const folderCopy = new FolderView();
|
||||
folderCopy.id = f.id;
|
||||
folderCopy.revisionDate = f.revisionDate;
|
||||
this.nestedTraverse(nodes, 0, f.name.split(NestingDelimiter), folderCopy);
|
||||
});
|
||||
return nodes;
|
||||
}
|
||||
|
||||
async saveWithServer(folder: Folder): Promise<any> {
|
||||
const request = new FolderRequest(folder);
|
||||
|
||||
|
@ -185,4 +199,37 @@ export class FolderService implements FolderServiceAbstraction {
|
|||
await this.apiService.deleteFolder(id);
|
||||
await this.delete(id);
|
||||
}
|
||||
|
||||
private nestedTraverse(nodeTree: Array<TreeNode<FolderView>>, partIndex: number,
|
||||
parts: string[], folder: FolderView) {
|
||||
if (parts.length <= partIndex) {
|
||||
return;
|
||||
}
|
||||
|
||||
const end = partIndex === parts.length - 1;
|
||||
const partName = parts[partIndex];
|
||||
|
||||
for (let i = 0; i < nodeTree.length; i++) {
|
||||
if (nodeTree[i].node.name === parts[partIndex]) {
|
||||
if (end && nodeTree[i].node.id !== folder.id) {
|
||||
// Another node with the same name.
|
||||
folder.name = partName;
|
||||
nodeTree.push(new TreeNode(folder));
|
||||
return;
|
||||
}
|
||||
this.nestedTraverse(nodeTree[i].children, partIndex + 1, parts, folder);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (nodeTree.filter((n) => n.node.name === partName).length === 0) {
|
||||
if (end) {
|
||||
folder.name = partName;
|
||||
nodeTree.push(new TreeNode(folder));
|
||||
return;
|
||||
}
|
||||
const newPartName = parts[partIndex] + NestingDelimiter + parts[partIndex + 1];
|
||||
this.nestedTraverse(nodeTree, 0, [newPartName, ...parts.slice(partIndex + 2)], folder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue