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

feat: add search functionality to views (part 1: Resources) #996

Merged
merged 43 commits into from
Feb 4, 2025

Conversation

shouples
Copy link
Contributor

@shouples shouples commented Jan 30, 2025

Summary of Changes

This PR adds a lot of basic functionality for view searching, which is initially available in the Resources view via ctrl+f/cmd+f when the view is focused.

resources-view-search.mov

Follow-on (smaller) PRs will implement this view-search functionality for the Topics and Schemas views.

Any additional details or context that should be provided?

Explanation of behavior

When the user enters a search string through this new <view>.search command, it sets an itemSearchString property on the view provider. This causes two main things to happen:

  • getChildren() will now filter any items based on two ideas:

    • the items will directly match or they will have children that match based on their searchableText property
    • if getChildren() was called due to expanding an element, if that element was previously returned as a filtered result, all of its children will also be returned so the user can expand them
  • getTreeItem() will now:

    • adjust the *TreeItem's collapsible state depending on whether or not it has children that matched the search string
    • update the resourceUri for any *TreeItem(s) that matched the search string, taking advantage of the (new) FileDecorationProvider and allowing the label(s), description(s) (if available), and a right-justified character to be (theme-)colored differently:
      image image image
  • Since ContainerTreeItem is now "searchable", its children must also now implement ISearchable -- otherwise we end up having a lot of funky Typescript workarounds to make T and ISearchable play nicely together.

Pull request checklist

Please check if your PR fulfills the following (if applicable):

Tests
  • Added new
  • Updated existing
  • Deleted existing
Other
  • All new disposables (event listeners, views, channels, etc.) collected as for eventual cleanup?
  • Does anything in this PR need to be mentioned in the user-facing CHANGELOG or README?
  • Have you validated this change locally by packaging and installing the extension .vsix file?
    gulp clicktest

@shouples shouples linked an issue Jan 31, 2025 that may be closed by this pull request
@shouples shouples requested a review from Copilot January 31, 2025 21:51

Choose a reason for hiding this comment

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

Copilot reviewed 5 out of 12 changed files in this pull request and generated no comments.

Files not reviewed (7)
  • package.json: Language not supported
  • src/commands/extra.ts: Evaluated as low risk
  • src/context/values.ts: Evaluated as low risk
  • src/viewProviders/resources.ts: Evaluated as low risk
  • src/models/schemaRegistry.ts: Evaluated as low risk
  • src/models/main.ts: Evaluated as low risk
  • src/models/environment.ts: Evaluated as low risk
Comments suppressed due to low confidence (1)

src/models/kafkaCluster.ts:21

  • Ensure that the searchableText method is covered by tests to validate its behavior.
searchableText(): string {
@airlock-confluentinc airlock-confluentinc bot force-pushed the djs/search-primary-views branch from 9421275 to 208569f Compare February 1, 2025 00:53
@@ -39,7 +39,6 @@
"kstreams",
"kafka streams",
"schema",
"schema registry",
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Unrelated to this PR; came up doing a search for "Schema Registry" label usage and can be removed since it's a lowercase version of what we already have

@@ -20,7 +24,7 @@ export const TEST_CCLOUD_KAFKA_CLUSTER: CCloudKafkaCluster = CCloudKafkaCluster.
region: TEST_CCLOUD_REGION,
bootstrapServers: `SASL_SSL://pkc-abc123.${TEST_CCLOUD_REGION}.${TEST_CCLOUD_PROVIDER}.confluent.cloud:443`,
uri: `https://pkc-abc123.${TEST_CCLOUD_REGION}.${TEST_CCLOUD_PROVIDER}.confluent.cloud:443`,
environmentId: TEST_CCLOUD_ENVIRONMENT.id,
environmentId: TEST_CCLOUD_ENVIRONMENT_ID,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Unrelated to this PR; TS hollering that the TEST_CCLOUD_ENVIRONMENT.id wasn't an EnvironmentID branded string type

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, am unsure why we're notified about these in a trickle.

@shouples shouples marked this pull request as ready for review February 3, 2025 20:36
@shouples shouples requested a review from a team as a code owner February 3, 2025 20:36
@shouples shouples requested a review from Copilot February 3, 2025 20:38

Choose a reason for hiding this comment

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

Copilot reviewed 5 out of 19 changed files in this pull request and generated no comments.

Files not reviewed (14)
  • package.json: Language not supported
  • src/models/schemaRegistry.ts: Evaluated as low risk
  • src/commands/extra.ts: Evaluated as low risk
  • src/viewProviders/resources.test.ts: Evaluated as low risk
  • tests/unit/testResources/kafkaCluster.ts: Evaluated as low risk
  • src/viewProviders/collapsing.test.ts: Evaluated as low risk
  • src/context/values.ts: Evaluated as low risk
  • CHANGELOG.md: Evaluated as low risk
  • src/emitters.ts: Evaluated as low risk
  • src/models/environment.ts: Evaluated as low risk
  • src/models/kafkaCluster.ts: Evaluated as low risk
  • src/models/schema.ts: Evaluated as low risk
  • src/models/main.ts: Evaluated as low risk
  • src/viewProviders/resources.ts: Evaluated as low risk
Comment on lines +70 to +72
if (uri.scheme === SEARCH_DECORATION_URI_SCHEME) {
return SEARCH_MATCH_DECORATION;
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

If we didn't provide a tooltip for our searchable items already, this is where we could parse the query of a (view) Uri to extract the search string (and any other info) to dynamically generate the decoration. Not necessary/applicable for now.

@airlock-confluentinc airlock-confluentinc bot force-pushed the djs/search-primary-views branch from db266f9 to b6161f4 Compare February 3, 2025 21:34
src/models/main.ts Show resolved Hide resolved
treeItem.collapsibleState = TreeItemCollapsibleState.None;
}

if (treeItem.collapsibleState !== origCollapsibleState) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this supposed to always ensure that the new id value changes?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep, it just needs to change from the "without search" id being used, due to the odd behavior we've seen in the past when dynamically adjusting collapsible states and not changing the id like with the "Confluent Cloud" container between sign-in/sign-out:

// XXX: adjust the ID to ensure the collapsible state is correctly updated in the UI
cloudContainerItem.id = `ccloud-connected-${EXTENSION_VERSION}`;

Copy link
Contributor

Choose a reason for hiding this comment

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

It would seem that the id would keep growing, if, say, someone does a search starting from the search button, then does one through the command palate, etc.

Probably inconsequential, however.

Copy link
Contributor

@jlrobins jlrobins left a comment

Choose a reason for hiding this comment

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

Works great! Love the UI and snappiness.

Only minor nits can be 1) ignored, 2) touched up in future, 3) done up front.

/** String to filter items returned by `getChildren`, if provided. */
itemSearchString: string | null = null;
/** Items directly matching the {@linkcode itemSearchString}, if provided. */
searchMatches: Set<ResourceViewProviderData> = new Set();
Copy link
Contributor

Choose a reason for hiding this comment

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

Probably overkill as a Set. Not like going to have any actual duplicates pushed into it, and is only ultimately used to determine size/count of matches. Could be a ResourceViewProviderData[] ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, I went back and forth on this a bit -- agreed we should never add duplicates if this were an array of the provider's data type. Is a slightly easier mental model to know the matches would never be duplicated and the count displayed as the view message would be accurate, but I don't think we'd see much (if any) performance benefit of a Set over an array.

import { ISearchable, isSearchable } from "../models/resource";

/** Check if an item matches the provided search string. */
export function itemMatchesSearch(item: ISearchable, searchStr: string): boolean {
Copy link
Contributor

Choose a reason for hiding this comment

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

If the view being searched made sure to lowercase searchStr before the looped calls into itemMatchesSearch() and / or traverseMatches(), then whole milliseconds would be saved in not repeatedly lowercasing searchStr.

The truly squirrelbrained would make a branded type for lowercased strings, but that's a hairy tail too far, innit? Or isn't 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.

True, but would then force all callers to make sure it was .toLowerCase() which could make this more fragile

@@ -20,7 +24,7 @@ export const TEST_CCLOUD_KAFKA_CLUSTER: CCloudKafkaCluster = CCloudKafkaCluster.
region: TEST_CCLOUD_REGION,
bootstrapServers: `SASL_SSL://pkc-abc123.${TEST_CCLOUD_REGION}.${TEST_CCLOUD_PROVIDER}.confluent.cloud:443`,
uri: `https://pkc-abc123.${TEST_CCLOUD_REGION}.${TEST_CCLOUD_PROVIDER}.confluent.cloud:443`,
environmentId: TEST_CCLOUD_ENVIRONMENT.id,
environmentId: TEST_CCLOUD_ENVIRONMENT_ID,
Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, am unsure why we're notified about these in a trickle.

@shouples shouples merged commit b6b2ed3 into main Feb 4, 2025
2 checks passed
@shouples shouples deleted the djs/search-primary-views branch February 4, 2025 14:49
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.

Add search functionality to the Resources view
2 participants