mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2026-01-11 05:29:54 +00:00
implemented search bar
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
import { Tree, TreeItemValue, TreeOpenChangeData, TreeOpenChangeEvent } from "@fluentui/react-components";
|
import { Input, Tree, TreeItemValue, TreeOpenChangeData, TreeOpenChangeEvent } from "@fluentui/react-components";
|
||||||
import { Home16Regular } from "@fluentui/react-icons";
|
import { Home16Regular, Search20Regular } from "@fluentui/react-icons";
|
||||||
import { AuthType } from "AuthType";
|
import { AuthType } from "AuthType";
|
||||||
import { useTreeStyles } from "Explorer/Controls/TreeComponent/Styles";
|
import { useTreeStyles } from "Explorer/Controls/TreeComponent/Styles";
|
||||||
import { TreeNode, TreeNodeComponent } from "Explorer/Controls/TreeComponent/TreeNodeComponent";
|
import { TreeNode, TreeNodeComponent } from "Explorer/Controls/TreeComponent/TreeNodeComponent";
|
||||||
@@ -55,6 +55,8 @@ export const ResourceTree: React.FC<ResourceTreeProps> = ({ explorer }: Resource
|
|||||||
sampleDataResourceTokenCollection: state.sampleDataResourceTokenCollection,
|
sampleDataResourceTokenCollection: state.sampleDataResourceTokenCollection,
|
||||||
}));
|
}));
|
||||||
const databasesFetchedSuccessfully = useDatabases((state) => state.databasesFetchedSuccessfully);
|
const databasesFetchedSuccessfully = useDatabases((state) => state.databasesFetchedSuccessfully);
|
||||||
|
const searchText = useDatabases((state) => state.searchText);
|
||||||
|
const setSearchText = useDatabases((state) => state.setSearchText);
|
||||||
const { isCopilotEnabled, isCopilotSampleDBEnabled } = useQueryCopilot((state) => ({
|
const { isCopilotEnabled, isCopilotSampleDBEnabled } = useQueryCopilot((state) => ({
|
||||||
isCopilotEnabled: state.copilotEnabled,
|
isCopilotEnabled: state.copilotEnabled,
|
||||||
isCopilotSampleDBEnabled: state.copilotSampleDBEnabled,
|
isCopilotSampleDBEnabled: state.copilotSampleDBEnabled,
|
||||||
@@ -63,8 +65,8 @@ export const ResourceTree: React.FC<ResourceTreeProps> = ({ explorer }: Resource
|
|||||||
const databaseTreeNodes = useMemo(() => {
|
const databaseTreeNodes = useMemo(() => {
|
||||||
return userContext.authType === AuthType.ResourceToken
|
return userContext.authType === AuthType.ResourceToken
|
||||||
? createResourceTokenTreeNodes(resourceTokenCollection)
|
? createResourceTokenTreeNodes(resourceTokenCollection)
|
||||||
: createDatabaseTreeNodes(explorer, isNotebookEnabled, databases, refreshActiveTab);
|
: createDatabaseTreeNodes(explorer, isNotebookEnabled, databases, refreshActiveTab, searchText);
|
||||||
}, [resourceTokenCollection, databases, isNotebookEnabled, refreshActiveTab]);
|
}, [resourceTokenCollection, databases, isNotebookEnabled, refreshActiveTab, searchText]);
|
||||||
|
|
||||||
const isSampleDataEnabled =
|
const isSampleDataEnabled =
|
||||||
isCopilotEnabled &&
|
isCopilotEnabled &&
|
||||||
@@ -81,19 +83,19 @@ export const ResourceTree: React.FC<ResourceTreeProps> = ({ explorer }: Resource
|
|||||||
const headerNodes: TreeNode[] = isFabricMirrored()
|
const headerNodes: TreeNode[] = isFabricMirrored()
|
||||||
? []
|
? []
|
||||||
: [
|
: [
|
||||||
{
|
{
|
||||||
id: "home",
|
id: "home",
|
||||||
iconSrc: <Home16Regular />,
|
iconSrc: <Home16Regular />,
|
||||||
label: "Home",
|
label: "Home",
|
||||||
isSelected: () =>
|
isSelected: () =>
|
||||||
useSelectedNode.getState().selectedNode === undefined &&
|
useSelectedNode.getState().selectedNode === undefined &&
|
||||||
useTabs.getState().activeReactTab === ReactTabKind.Home,
|
useTabs.getState().activeReactTab === ReactTabKind.Home,
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
useSelectedNode.getState().setSelectedNode(undefined);
|
useSelectedNode.getState().setSelectedNode(undefined);
|
||||||
useTabs.getState().openAndActivateReactTab(ReactTabKind.Home);
|
useTabs.getState().openAndActivateReactTab(ReactTabKind.Home);
|
||||||
},
|
|
||||||
},
|
},
|
||||||
];
|
},
|
||||||
|
];
|
||||||
|
|
||||||
const rootNodes: TreeNode[] = useMemo(() => {
|
const rootNodes: TreeNode[] = useMemo(() => {
|
||||||
if (sampleDataNodes.length > 0) {
|
if (sampleDataNodes.length > 0) {
|
||||||
@@ -154,6 +156,17 @@ export const ResourceTree: React.FC<ResourceTreeProps> = ({ explorer }: Resource
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={treeStyles.treeContainer}>
|
<div className={treeStyles.treeContainer}>
|
||||||
|
{userContext.authType !== AuthType.ResourceToken && databases.length > 0 && (
|
||||||
|
<div style={{ padding: "8px" }}>
|
||||||
|
<Input
|
||||||
|
placeholder="Search databases only"
|
||||||
|
value={searchText}
|
||||||
|
onChange={(_, data) => setSearchText(data?.value || "")}
|
||||||
|
size="small"
|
||||||
|
contentBefore={<Search20Regular />}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<Tree
|
<Tree
|
||||||
aria-label="CosmosDB resources"
|
aria-label="CosmosDB resources"
|
||||||
openItems={openItems}
|
openItems={openItems}
|
||||||
|
|||||||
@@ -363,7 +363,7 @@ describe("createDatabaseTreeNodes", () => {
|
|||||||
},
|
},
|
||||||
} as never,
|
} as never,
|
||||||
});
|
});
|
||||||
nodes = createDatabaseTreeNodes(explorer, false, useDatabases.getState().databases, refreshActiveTab);
|
nodes = createDatabaseTreeNodes(explorer, false, useDatabases.getState().databases, refreshActiveTab, "");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("creates expected tree", () => {
|
it("creates expected tree", () => {
|
||||||
@@ -445,6 +445,7 @@ describe("createDatabaseTreeNodes", () => {
|
|||||||
isNotebookEnabled,
|
isNotebookEnabled,
|
||||||
useDatabases.getState().databases,
|
useDatabases.getState().databases,
|
||||||
refreshActiveTab,
|
refreshActiveTab,
|
||||||
|
"",
|
||||||
);
|
);
|
||||||
expect(nodes).toMatchSnapshot();
|
expect(nodes).toMatchSnapshot();
|
||||||
},
|
},
|
||||||
@@ -455,7 +456,7 @@ describe("createDatabaseTreeNodes", () => {
|
|||||||
// The goal is to cover some key behaviors like loading child nodes, opening tabs/side panels, etc.
|
// The goal is to cover some key behaviors like loading child nodes, opening tabs/side panels, etc.
|
||||||
|
|
||||||
it("adds new collections to database as they appear", () => {
|
it("adds new collections to database as they appear", () => {
|
||||||
const nodes = createDatabaseTreeNodes(explorer, false, useDatabases.getState().databases, refreshActiveTab);
|
const nodes = createDatabaseTreeNodes(explorer, false, useDatabases.getState().databases, refreshActiveTab, "");
|
||||||
const giganticDbNode = nodes.find((node) => node.label === giganticDb.id());
|
const giganticDbNode = nodes.find((node) => node.label === giganticDb.id());
|
||||||
expect(giganticDbNode).toBeDefined();
|
expect(giganticDbNode).toBeDefined();
|
||||||
expect(giganticDbNode.children.map((node) => node.label)).toStrictEqual(["schemaCollection", "load more"]);
|
expect(giganticDbNode.children.map((node) => node.label)).toStrictEqual(["schemaCollection", "load more"]);
|
||||||
@@ -487,7 +488,7 @@ describe("createDatabaseTreeNodes", () => {
|
|||||||
},
|
},
|
||||||
} as unknown as DataModels.DatabaseAccount,
|
} as unknown as DataModels.DatabaseAccount,
|
||||||
});
|
});
|
||||||
nodes = createDatabaseTreeNodes(explorer, false, useDatabases.getState().databases, refreshActiveTab);
|
nodes = createDatabaseTreeNodes(explorer, false, useDatabases.getState().databases, refreshActiveTab, "");
|
||||||
standardDbNode = nodes.find((node) => node.label === standardDb.id());
|
standardDbNode = nodes.find((node) => node.label === standardDb.id());
|
||||||
sharedDbNode = nodes.find((node) => node.label === sharedDb.id());
|
sharedDbNode = nodes.find((node) => node.label === sharedDb.id());
|
||||||
giganticDbNode = nodes.find((node) => node.label === giganticDb.id());
|
giganticDbNode = nodes.find((node) => node.label === giganticDb.id());
|
||||||
@@ -642,7 +643,7 @@ describe("createDatabaseTreeNodes", () => {
|
|||||||
setup();
|
setup();
|
||||||
|
|
||||||
// Rebuild the nodes after changing the user/config context.
|
// Rebuild the nodes after changing the user/config context.
|
||||||
nodes = createDatabaseTreeNodes(explorer, false, useDatabases.getState().databases, refreshActiveTab);
|
nodes = createDatabaseTreeNodes(explorer, false, useDatabases.getState().databases, refreshActiveTab, "");
|
||||||
standardDbNode = nodes.find((node) => node.label === standardDb.id());
|
standardDbNode = nodes.find((node) => node.label === standardDb.id());
|
||||||
standardCollectionNode = standardDbNode.children.find((node) => node.label === standardCollection.id());
|
standardCollectionNode = standardDbNode.children.find((node) => node.label === standardCollection.id());
|
||||||
|
|
||||||
|
|||||||
@@ -131,8 +131,14 @@ export const createDatabaseTreeNodes = (
|
|||||||
isNotebookEnabled: boolean,
|
isNotebookEnabled: boolean,
|
||||||
databases: ViewModels.Database[],
|
databases: ViewModels.Database[],
|
||||||
refreshActiveTab: (comparator: (tab: TabsBase) => boolean) => void,
|
refreshActiveTab: (comparator: (tab: TabsBase) => boolean) => void,
|
||||||
|
searchText = "",
|
||||||
): TreeNode[] => {
|
): TreeNode[] => {
|
||||||
const databaseTreeNodes: TreeNode[] = databases.map((database: ViewModels.Database) => {
|
// Filter databases based on search text
|
||||||
|
const filteredDatabases = searchText
|
||||||
|
? databases.filter((db) => db.id().toLowerCase().includes(searchText.toLowerCase()))
|
||||||
|
: databases;
|
||||||
|
|
||||||
|
const databaseTreeNodes: TreeNode[] = filteredDatabases.map((database: ViewModels.Database) => {
|
||||||
const buildDatabaseChildNodes = (databaseNode: TreeNode) => {
|
const buildDatabaseChildNodes = (databaseNode: TreeNode) => {
|
||||||
databaseNode.children = [];
|
databaseNode.children = [];
|
||||||
if (database.isDatabaseShared() && configContext.platform !== Platform.Fabric) {
|
if (database.isDatabaseShared() && configContext.platform !== Platform.Fabric) {
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ interface DatabasesState {
|
|||||||
resourceTokenCollection: ViewModels.CollectionBase;
|
resourceTokenCollection: ViewModels.CollectionBase;
|
||||||
sampleDataResourceTokenCollection: ViewModels.CollectionBase;
|
sampleDataResourceTokenCollection: ViewModels.CollectionBase;
|
||||||
databasesFetchedSuccessfully: boolean; // Track if last database fetch was successful
|
databasesFetchedSuccessfully: boolean; // Track if last database fetch was successful
|
||||||
|
searchText: string;
|
||||||
|
setSearchText: (searchText: string) => void;
|
||||||
updateDatabase: (database: ViewModels.Database) => void;
|
updateDatabase: (database: ViewModels.Database) => void;
|
||||||
addDatabases: (databases: ViewModels.Database[]) => void;
|
addDatabases: (databases: ViewModels.Database[]) => void;
|
||||||
deleteDatabase: (database: ViewModels.Database) => void;
|
deleteDatabase: (database: ViewModels.Database) => void;
|
||||||
@@ -32,6 +34,8 @@ export const useDatabases: UseStore<DatabasesState> = create((set, get) => ({
|
|||||||
resourceTokenCollection: undefined,
|
resourceTokenCollection: undefined,
|
||||||
sampleDataResourceTokenCollection: undefined,
|
sampleDataResourceTokenCollection: undefined,
|
||||||
databasesFetchedSuccessfully: false,
|
databasesFetchedSuccessfully: false,
|
||||||
|
searchText: "",
|
||||||
|
setSearchText: (searchText: string) => set({ searchText }),
|
||||||
updateDatabase: (updatedDatabase: ViewModels.Database) =>
|
updateDatabase: (updatedDatabase: ViewModels.Database) =>
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const updatedDatabases = state.databases.map((database: ViewModels.Database) => {
|
const updatedDatabases = state.databases.map((database: ViewModels.Database) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user