1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-09-24 03:32:51 +02:00
bitwarden-browser/libs/common/src/misc/serviceUtils.ts
Andreas Coroiu ea6666780a
[EC-775] [Technical Dependency] Refactor Vault Filters to be routable (#4733)
* [EC-775] feat: add compatibility layer from #4154

* [EC-775] fix: ciphers not reloading on filter change

* [EC-775] feat: add support for cipher types

* [EC-775] feat: implement organization switching

* [EC-775] feat: remove invalid folder and collection checks

Had to remove these becuase they were causing double navigations on each click.

* [EC-775] fix: fix reverse data flow race condition

vault-filter.component was pushing up old filter models which would sometimes overwrite new filter models that came from the routed filter service.

* [EC-775] fix: No folder use-case not working

* [EC-775] feat: make navigation behave like master

* [EC-775] feat: add support for trash

* [EC-775] chore: simplify findNode

* [EC-775] feat: add support for org vault

* [EC-775] feat: add support for orgId in path

* [EC-775] feat: use proper treenode constructor

* [EC-775] chore: remove unnecessary variable

* [EC-775] docs: add docs to relevant classes

* [EC-775] chore: use existing function for searching tree

* [EC-775] fix: hide "new" button in trash view

* [EC-775] feat: add explicit handling for `AllItems`

* [EC-775] fix: prune folderId when changing organization

* [EC-775] fix: properly use `undefined` instead of `null`

* [EC-775] chore: simplify setters using ternary operator

* [EC-775] feat: add static typing to `type` filter

* [EC-775] feat: use new `All` variable for collections

* [EC-775] feat: return `RouterLink` compatible link from `createRoute`

* [EC-775] feat: add ordId path support to `createRoute`

* [EC-775] fix: interpret params differently in org vault

This is needed due to how defaults used to work when using `state-in-code`. We really want to get rid of this type of logic going forward.

* [EC-775] doc: clarify `createRoute`

* [EC-775] fix: better `type` typing

* [EC-775] feat: remove support for path navigation

It's better that we circle back to this type of navigationt when we're working on the VVR and have more knowledge about how this is supposed to work.

* [EC-775] fix: refactor bridge service to improve readability

Refactor follows feedback from PR review
2023-03-06 08:34:13 +01:00

118 lines
3.8 KiB
TypeScript

import { ITreeNodeObject, TreeNode } from "../models/domain/tree-node";
export class ServiceUtils {
/**
* Recursively adds a node to nodeTree
* @param {TreeNode<ITreeNodeObject>[]} nodeTree - An array of TreeNodes that the node will be added to
* @param {number} partIndex - Index of the `parts` array that is being processed
* @param {string[]} parts - Array of strings that represent the path to the `obj` node
* @param {ITreeNodeObject} obj - The node to be added to the tree
* @param {ITreeNodeObject} parent - The parent node of the `obj` node
* @param {string} delimiter - The delimiter used to split the path string, will be used to combine the path for missing nodes
*/
static nestedTraverse(
nodeTree: TreeNode<ITreeNodeObject>[],
partIndex: number,
parts: string[],
obj: ITreeNodeObject,
parent: TreeNode<ITreeNodeObject> | undefined,
delimiter: string
) {
if (parts.length <= partIndex) {
return;
}
const end: boolean = partIndex === parts.length - 1;
const partName: string = parts[partIndex];
for (let i = 0; i < nodeTree.length; i++) {
if (nodeTree[i].node.name !== partName) {
continue;
}
if (end && nodeTree[i].node.id !== obj.id) {
// Another node exists with the same name as the node being added
nodeTree.push(new TreeNode(obj, parent, partName));
return;
}
// Move down the tree to the next level
ServiceUtils.nestedTraverse(
nodeTree[i].children,
partIndex + 1,
parts,
obj,
nodeTree[i],
delimiter
);
return;
}
// If there's no node here with the same name...
if (nodeTree.filter((n) => n.node.name === partName).length === 0) {
// And we're at the end of the path given, add the node
if (end) {
nodeTree.push(new TreeNode(obj, parent, partName));
return;
}
// And we're not at the end of the path, combine the current name with the next name
// 1, *1.2, 1.2.1 becomes
// 1, *1.2/1.2.1
const newPartName = partName + delimiter + parts[partIndex + 1];
ServiceUtils.nestedTraverse(
nodeTree,
0,
[newPartName, ...parts.slice(partIndex + 2)],
obj,
parent,
delimiter
);
}
}
/**
* Searches a tree for a node with a matching `id`
* @param {TreeNode<T>} nodeTree - A single TreeNode branch that will be searched
* @param {string} id - The id of the node to be found
* @returns {TreeNode<T>} The node with a matching `id`
*/
static getTreeNodeObject<T extends ITreeNodeObject>(
nodeTree: TreeNode<T>,
id: string
): TreeNode<T> {
if (nodeTree.node.id === id) {
return nodeTree;
}
for (let i = 0; i < nodeTree.children.length; i++) {
if (nodeTree.children[i].children != null) {
const node = ServiceUtils.getTreeNodeObject(nodeTree.children[i], id);
if (node !== null) {
return node;
}
}
}
return null;
}
/**
* Searches an array of tree nodes for a node with a matching `id`
* @param {TreeNode<ITreeNodeObject>} nodeTree - An array of TreeNode branches that will be searched
* @param {string} id - The id of the node to be found
* @returns {TreeNode<ITreeNodeObject>} The node with a matching `id`
*/
static getTreeNodeObjectFromList(
nodeTree: TreeNode<ITreeNodeObject>[],
id: string
): TreeNode<ITreeNodeObject> {
for (let i = 0; i < nodeTree.length; i++) {
if (nodeTree[i].node.id === id) {
return nodeTree[i];
} else if (nodeTree[i].children != null) {
const node = ServiceUtils.getTreeNodeObjectFromList(nodeTree[i].children, id);
if (node !== null) {
return node;
}
}
}
return null;
}
}