Skip to content

[EC-775] [Technical Dependency] Refactor Vault Filters to be routable#4733

Merged
coroiu merged 34 commits intomasterfrom
EC-775-technical-dependency-refactor-vault-filters-to-be-routable
Mar 6, 2023
Merged

[EC-775] [Technical Dependency] Refactor Vault Filters to be routable#4733
coroiu merged 34 commits intomasterfrom
EC-775-technical-dependency-refactor-vault-filters-to-be-routable

Conversation

@coroiu
Copy link
Contributor

@coroiu coroiu commented Feb 13, 2023

Type of change

- [ ] Bug fix
- [ ] New feature development
- [x] Tech debt (refactoring, code cleanup, dependency upgrades, etc)
- [ ] Build/deploy pipeline (DevOps)
- [ ] Other

Objective

This PR introduces an temporary bridge between URL filtering and the old state-in-code method. It enables us to move forward with refactoring the table and the navigation, and allow us to work on them separately. This is great for smaller PRs and more efficient coding.

Code changes

  • apps/web/src/vault/individual-vault/vault-filter/components/vault-filter.component.ts: Remove the reverse data flow. I.e. let the data flow one-way into the component. Also remove the removeInvalidCollectionSelection functionality because it's not needed anymore.

  • apps/web/src/vault/org-vault/vault-filter/vault-filter.component.ts: Same as individual vault component.

  • apps/web/src/vault/individual-vault/vault-filter/services/abstractions/vault-filter.service.ts: Add ability to get a cipherTypeTree which is needed to be able to populate the bridge filter model with tree nodes.

  • apps/web/src/vault/individual-vault/vault-filter/services/vault-filter.service.ts: Implementation of the above.

  • apps/web/src/vault/individual-vault/vault-filter/services/routed-vault-filter.service.ts: The new filter service that builds and emits the new filter model based on URL params. Also contains a method for generating routes.

  • apps/web/src/vault/individual-vault/vault-filter/shared/models/routed-vault-filter.model.ts: The new model used to represent filters. Very basic, only primitives.

  • apps/web/src/vault/[org and individual]/vault.component.ts: Fetch active filters from the new services. Also remove applyVaultFilter which used direct component references to reload the vault-items.component

  • apps/web/src/vault/individual-vault/vault-items.component.ts: Reload ciphers when a new activeFilter is set by the parent component, instead of relying of direct function calls.

Temporary compatibility layer

This layer is used to temporary bridge between URL filtering and the old state-in-code method. This should be removed after we have refactored the vault-items.component and introduced vertical navigation (which will refactor the vault-filter.component).

  • apps/web/src/vault/individual-vault/vault-filter/services/routed-vault-filter-bridge.service.ts: Listens to both the new RoutedVaultFilterService and the old VaultFilterService. When a new filter is emitted the service uses the ids to find the corresponding tree nodes needed for the old VaultFilter model. It then emits a bridge model that contains this information.
  • apps/web/src/vault/individual-vault/vault-filter/shared/models/routed-vault-filter-bridge.model.ts: This model supplies legacy code with the old state-in-code models saved as tree nodes. It can also receive requests to select a new tree node by using setters. However instead of just replacing the tree node models, it requests a URL navigation, thereby bridging between legacy and URL filtering.

Screenshots

Nothing has really changed graphically. Works just like usual.

Before you submit

  • Please add unit tests where it makes sense to do so (encouraged but not required)
  • If this change requires a documentation update - notify the documentation team
  • If this change has particular deployment requirements - notify the DevOps team

@coroiu coroiu marked this pull request as ready for review February 15, 2023 14:27
@coroiu coroiu requested a review from a team as a code owner February 15, 2023 14:27
@eliykat eliykat self-requested a review February 16, 2023 05:36
Copy link
Member

@jlf0dev jlf0dev left a comment

Choose a reason for hiding this comment

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

Everything looks good to me, I just had some minor suggestions for the code. I'll also hold off approving until @eliykat takes a look as well.


if (filter.type !== undefined && filter.type === "trash") {
legacyFilter.selectedCipherTypeNode = {
node: { id: "trash", name: "", icon: "", type: "trash" },
Copy link
Member

Choose a reason for hiding this comment

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

minor suggestion: you could use the TreeNode constructor here:

legacyFilter.selectedCipherTypeNode = new TreeNode<CipherTypeFilter>({ id: "trash", name: "", type: "trash", icon: ""}, null);

we really should refactor this constructor to be more useful, I don't even think this will save you that many characters 😄

Copy link
Member

Choose a reason for hiding this comment

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

My question was going to be whether we could find the existing Trash node, or export & import the Trash node object, rather than recreating it. It looks like it's currently declared in the VaultFilterComponent though, which I guess we don't really want to pull in to a service.

In any case I agree you should use a real TreeNode object, not really to save any characters, just to be properly typesafe.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@jlf0dev Good point, will update!

@eliykat Yeah that was exactly the issue, I contemplated moving it from VaultFilterComponent to VaultFilterService but I really wanted to keep the modifications to a minimum, so this is what I ended up with it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed!

Copy link
Member

Choose a reason for hiding this comment

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

lgtm but I'll let @jlf0dev resolve the thread when he's happy


const bridgeModel = new RoutedVaultFilterBridge(filter, legacyFilter, this);

return bridgeModel;
Copy link
Member

Choose a reason for hiding this comment

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

suggestion: unnecessary variable here, just return the model

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Huh, I wonder why I did this. Must've been a console.log here at some point 😅

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed!

import { RoutedVaultFilterService } from "./routed-vault-filter.service";

@Injectable()
export class RoutedVaultFilterBridgeService {
Copy link
Member

Choose a reason for hiding this comment

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

suggestion: you could add a jsdoc comment here explaining the purpose of the bridge service

Copy link
Member

@eliykat eliykat Feb 17, 2023

Choose a reason for hiding this comment

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

Something I'm wondering about 😁 is it transitional? If so, do we need a tech debt ticket to remove the old services? I assume that when we build the new filter list in the left-hand nav, they'll be routing directly to the query URL rather than going via a service, and then it'll be much simpler to clean up the old code. This feels like something EC pod should do as part of VVR, before handing off to Vault team.

Note that we also have DeprecatedVaultFilterService floating around 🤯

EDIT: ok, after reviewing the rest of the code, (I think) I understand that this is basically a wrapper around existing logic to implement routing with a minimum of code changes. The downside is that it adds complexity in the short term, but I'm OK with this if we're deprecating it quickly after VVR (because the new components won't use it).

Copy link
Contributor Author

@coroiu coroiu Feb 17, 2023

Choose a reason for hiding this comment

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

@jlf0dev Sure I can add the file descriptions I've used in the PR description field into the code!

@eliykat Yes exactly, this is a transitional class. I'm glad that it becomes apparent when reading the code, means it's not too complex/confusing. As I mention in the Objective part of the PR description:

This PR introduces an temporary bridge between URL filtering and the old state-in-code method. It enables us to move forward with refactoring the table and the navigation, and allow us to work on them separately.

You have a good point, maybe we should add a TD ticket, but really all of this should be removed as part of VVR

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Instead of a TD ticket I added a task to the VVR story instead EC-208 [Admin Console] Add Filters under Left Nav

Copy link
Member

@eliykat eliykat Feb 20, 2023

Choose a reason for hiding this comment

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

Looks good, and serves me right for not reading your PR description properly 🙈
I'll let @jlf0dev mark this thread resolved once he's had a chance to look at it

node: TreeNode<T>,
id: string
): TreeNode<T> | undefined {
if (node.node.id === id) {
Copy link
Member

@jlf0dev jlf0dev Feb 16, 2023

Choose a reason for hiding this comment

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

comment: we need to rename the node to object or something at some point 😄

Copy link
Member

Choose a reason for hiding this comment

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

There's probably some background discussion here that I'm not familiar with, but - object seems worse! Everything's an object! 😅 and Object is a keyword.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Haha yeah, hopefully we'll get rid of the TreeNode completely and not have to worry about it :D

import { RoutedVaultFilterModel } from "../shared/models/routed-vault-filter.model";

@Injectable()
export class RoutedVaultFilterService implements OnDestroy {
Copy link
Member

Choose a reason for hiding this comment

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

suggestion: a comment here might be helpful as well. The name RoutedVaultFilterService makes sense, but only if you understand why we need it

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed!

Copy link
Member

@eliykat eliykat left a comment

Choose a reason for hiding this comment

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

Great PR, 10/10 would review again.

This will also need to be implemented for other clients (particularly desktop) after we've "perfected" it in the web vault. (and by "we" I mean the vault team ;) Can you please create a linked tech debt ticket for that?


if (filter.type !== undefined && filter.type === "trash") {
legacyFilter.selectedCipherTypeNode = {
node: { id: "trash", name: "", icon: "", type: "trash" },
Copy link
Member

Choose a reason for hiding this comment

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

My question was going to be whether we could find the existing Trash node, or export & import the Trash node object, rather than recreating it. It looks like it's currently declared in the VaultFilterComponent though, which I guess we don't really want to pull in to a service.

In any case I agree you should use a real TreeNode object, not really to save any characters, just to be properly typesafe.

import { RoutedVaultFilterService } from "./routed-vault-filter.service";

@Injectable()
export class RoutedVaultFilterBridgeService {
Copy link
Member

@eliykat eliykat Feb 17, 2023

Choose a reason for hiding this comment

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

Something I'm wondering about 😁 is it transitional? If so, do we need a tech debt ticket to remove the old services? I assume that when we build the new filter list in the left-hand nav, they'll be routing directly to the query URL rather than going via a service, and then it'll be much simpler to clean up the old code. This feels like something EC pod should do as part of VVR, before handing off to Vault team.

Note that we also have DeprecatedVaultFilterService floating around 🤯

EDIT: ok, after reviewing the rest of the code, (I think) I understand that this is basically a wrapper around existing logic to implement routing with a minimum of code changes. The downside is that it adds complexity in the short term, but I'm OK with this if we're deprecating it quickly after VVR (because the new components won't use it).

node: TreeNode<T>,
id: string
): TreeNode<T> | undefined {
if (node.node.id === id) {
Copy link
Member

Choose a reason for hiding this comment

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

There's probably some background discussion here that I'm not familiar with, but - object seems worse! Everything's an object! 😅 and Object is a keyword.

@coroiu
Copy link
Contributor Author

coroiu commented Feb 17, 2023

@eliykat Ticket already seems to exist EC-517 [Tech Debt] Refactor Vault Filter in Browser and Desktop


if (filter.type !== undefined && filter.type === "trash") {
legacyFilter.selectedCipherTypeNode = {
node: { id: "trash", name: "", icon: "", type: "trash" },
Copy link
Member

Choose a reason for hiding this comment

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

lgtm but I'll let @jlf0dev resolve the thread when he's happy

Copy link
Member

@eliykat eliykat left a comment

Choose a reason for hiding this comment

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

I think I've responded to everything above :)

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.
Refactor follows feedback from PR review
eliykat
eliykat previously approved these changes Feb 21, 2023
Copy link
Member

@eliykat eliykat left a comment

Choose a reason for hiding this comment

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

Great work! Let's get it to QA :shipit:

@eliykat eliykat added the needs-qa Marks a PR as requiring QA approval label Feb 21, 2023
@coroiu coroiu removed the needs-qa Marks a PR as requiring QA approval label Mar 6, 2023
@coroiu coroiu merged commit ea66667 into master Mar 6, 2023
@coroiu coroiu deleted the EC-775-technical-dependency-refactor-vault-filters-to-be-routable branch March 6, 2023 07:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants