Add bootstrap typeahead

This commit is contained in:
Laurent Nguyen 2024-07-24 15:22:41 +02:00
parent 582d581edf
commit 0524328077
4 changed files with 183 additions and 12 deletions

125
package-lock.json generated
View File

@ -94,6 +94,7 @@
"q": "1.5.1", "q": "1.5.1",
"react": "16.14.0", "react": "16.14.0",
"react-animate-height": "2.0.8", "react-animate-height": "2.0.8",
"react-bootstrap-typeahead": "6.3.2",
"react-dnd": "14.0.2", "react-dnd": "14.0.2",
"react-dnd-html5-backend": "14.0.0", "react-dnd-html5-backend": "14.0.0",
"react-dom": "16.14.0", "react-dom": "16.14.0",
@ -10261,6 +10262,15 @@
"integrity": "sha512-C16M+IYz0rgRhWZdCmK+h58JMv8vijAA61gmz2rspCSwKwzBebpdcsiUmwrtJRdphuY30i6BSLEOP8ppbNLyLg==", "integrity": "sha512-C16M+IYz0rgRhWZdCmK+h58JMv8vijAA61gmz2rspCSwKwzBebpdcsiUmwrtJRdphuY30i6BSLEOP8ppbNLyLg==",
"dev": true "dev": true
}, },
"node_modules/@popperjs/core": {
"version": "2.11.8",
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/popperjs"
}
},
"node_modules/@react-dnd/asap": { "node_modules/@react-dnd/asap": {
"version": "4.0.1", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/@react-dnd/asap/-/asap-4.0.1.tgz", "resolved": "https://registry.npmjs.org/@react-dnd/asap/-/asap-4.0.1.tgz",
@ -11819,6 +11829,25 @@
"dev": true, "dev": true,
"peer": true "peer": true
}, },
"node_modules/@restart/hooks": {
"version": "0.4.16",
"resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.16.tgz",
"integrity": "sha512-f7aCv7c+nU/3mF7NWLtVVr0Ra80RqsO89hO72r+Y/nvQr5+q0UFGkocElTH6MJApvReVh6JHUFYn2cw1WdHF3w==",
"dependencies": {
"dequal": "^2.0.3"
},
"peerDependencies": {
"react": ">=16.8.0"
}
},
"node_modules/@restart/hooks/node_modules/dequal": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
"integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
"engines": {
"node": ">=6"
}
},
"node_modules/@rjsf/core": { "node_modules/@rjsf/core": {
"version": "3.2.1", "version": "3.2.1",
"resolved": "https://registry.npmjs.org/@rjsf/core/-/core-3.2.1.tgz", "resolved": "https://registry.npmjs.org/@rjsf/core/-/core-3.2.1.tgz",
@ -13628,6 +13657,11 @@
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz",
"integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==" "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw=="
}, },
"node_modules/@types/warning": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.3.tgz",
"integrity": "sha512-D1XC7WK8K+zZEveUPY+cf4+kgauk8N4eHr/XIHXGlGYkHLud6hK9lYfZk1ry1TNh798cZUCgb6MqGEG8DkJt6Q=="
},
"node_modules/@types/ws": { "node_modules/@types/ws": {
"version": "8.5.10", "version": "8.5.10",
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz",
@ -16511,6 +16545,11 @@
"validate.io-integer-array": "^1.0.0" "validate.io-integer-array": "^1.0.0"
} }
}, },
"node_modules/compute-scroll-into-view": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-3.1.0.tgz",
"integrity": "sha512-rj8l8pD4bJ1nx+dAkMhV1xB5RuZEyVysfxJqB1pRchh1KVvwOv9b7CGB8ZfjTImVv2oF+sYMUkMZq6Na5Ftmbg=="
},
"node_modules/concat-map": { "node_modules/concat-map": {
"version": "0.0.1", "version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@ -33580,6 +33619,46 @@
"pure-color": "^1.2.0" "pure-color": "^1.2.0"
} }
}, },
"node_modules/react-bootstrap-typeahead": {
"version": "6.3.2",
"resolved": "https://registry.npmjs.org/react-bootstrap-typeahead/-/react-bootstrap-typeahead-6.3.2.tgz",
"integrity": "sha512-N5Mb0WlSSMcD7Z0pcCypILgIuECybev0hl4lsnCa5lbXTnN4QdkuHLGuTLSlXBwm1ZMFpOc2SnsdSRgeFiF+Ow==",
"dependencies": {
"@babel/runtime": "^7.14.6",
"@popperjs/core": "^2.10.2",
"@restart/hooks": "^0.4.0",
"classnames": "^2.2.0",
"fast-deep-equal": "^3.1.1",
"invariant": "^2.2.1",
"lodash.debounce": "^4.0.8",
"prop-types": "^15.5.8",
"react-overlays": "^5.2.0",
"react-popper": "^2.2.5",
"scroll-into-view-if-needed": "^3.1.0",
"warning": "^4.0.1"
},
"engines": {
"node": ">=18.0.0"
},
"peerDependencies": {
"react": ">=16.8.0",
"react-dom": ">=16.8.0"
}
},
"node_modules/react-bootstrap-typeahead/node_modules/react-popper": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/react-popper/-/react-popper-2.3.0.tgz",
"integrity": "sha512-e1hj8lL3uM+sgSR4Lxzn5h1GxBlpa4CQz0XLF8kx4MDrDRWY0Ena4c97PUeSX9i5W3UAfDP0z0FXCTQkoXUl3Q==",
"dependencies": {
"react-fast-compare": "^3.0.1",
"warning": "^4.0.2"
},
"peerDependencies": {
"@popperjs/core": "^2.0.0",
"react": "^16.8.0 || ^17 || ^18",
"react-dom": "^16.8.0 || ^17 || ^18"
}
},
"node_modules/react-color": { "node_modules/react-color": {
"version": "2.19.3", "version": "2.19.3",
"resolved": "https://registry.npmjs.org/react-color/-/react-color-2.19.3.tgz", "resolved": "https://registry.npmjs.org/react-color/-/react-color-2.19.3.tgz",
@ -33897,6 +33976,11 @@
"integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==", "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==",
"dev": true "dev": true
}, },
"node_modules/react-fast-compare": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz",
"integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ=="
},
"node_modules/react-hot-loader": { "node_modules/react-hot-loader": {
"version": "4.13.1", "version": "4.13.1",
"resolved": "https://registry.npmjs.org/react-hot-loader/-/react-hot-loader-4.13.1.tgz", "resolved": "https://registry.npmjs.org/react-hot-loader/-/react-hot-loader-4.13.1.tgz",
@ -34032,6 +34116,25 @@
"react-dom": "0.14.x || ^15.0.0 || ^16.0.0" "react-dom": "0.14.x || ^15.0.0 || ^16.0.0"
} }
}, },
"node_modules/react-overlays": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/react-overlays/-/react-overlays-5.2.1.tgz",
"integrity": "sha512-GLLSOLWr21CqtJn8geSwQfoJufdt3mfdsnIiQswouuQ2MMPns+ihZklxvsTDKD3cR2tF8ELbi5xUsvqVhR6WvA==",
"dependencies": {
"@babel/runtime": "^7.13.8",
"@popperjs/core": "^2.11.6",
"@restart/hooks": "^0.4.7",
"@types/warning": "^3.0.0",
"dom-helpers": "^5.2.0",
"prop-types": "^15.7.2",
"uncontrollable": "^7.2.1",
"warning": "^4.0.3"
},
"peerDependencies": {
"react": ">=16.3.0",
"react-dom": ">=16.3.0"
}
},
"node_modules/react-popper": { "node_modules/react-popper": {
"version": "1.3.11", "version": "1.3.11",
"resolved": "https://registry.npmjs.org/react-popper/-/react-popper-1.3.11.tgz", "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-1.3.11.tgz",
@ -35510,6 +35613,14 @@
"url": "https://opencollective.com/webpack" "url": "https://opencollective.com/webpack"
} }
}, },
"node_modules/scroll-into-view-if-needed": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-3.1.0.tgz",
"integrity": "sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ==",
"dependencies": {
"compute-scroll-into-view": "^3.0.2"
}
},
"node_modules/select": { "node_modules/select": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz", "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz",
@ -37864,6 +37975,20 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/uncontrollable": {
"version": "7.2.1",
"resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-7.2.1.tgz",
"integrity": "sha512-svtcfoTADIB0nT9nltgjujTi7BzVmwjZClOmskKu/E8FW9BXzg9os8OLr4f8Dlnk0rYWJIWr4wv9eKUXiQvQwQ==",
"dependencies": {
"@babel/runtime": "^7.6.3",
"@types/react": ">=16.9.11",
"invariant": "^2.2.4",
"react-lifecycles-compat": "^3.0.4"
},
"peerDependencies": {
"react": ">=15.0.0"
}
},
"node_modules/underscore": { "node_modules/underscore": {
"version": "1.12.1", "version": "1.12.1",
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.12.1.tgz", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.12.1.tgz",

View File

@ -89,6 +89,7 @@
"q": "1.5.1", "q": "1.5.1",
"react": "16.14.0", "react": "16.14.0",
"react-animate-height": "2.0.8", "react-animate-height": "2.0.8",
"react-bootstrap-typeahead": "6.3.2",
"react-dnd": "14.0.2", "react-dnd": "14.0.2",
"react-dnd-html5-backend": "14.0.0", "react-dnd-html5-backend": "14.0.0",
"react-dom": "16.14.0", "react-dom": "16.14.0",
@ -98,8 +99,8 @@
"react-redux": "7.1.3", "react-redux": "7.1.3",
"react-splitter-layout": "4.0.0", "react-splitter-layout": "4.0.0",
"react-string-format": "1.0.1", "react-string-format": "1.0.1",
"react-youtube": "9.0.1",
"react-window": "1.8.10", "react-window": "1.8.10",
"react-youtube": "9.0.1",
"reflect-metadata": "0.1.13", "reflect-metadata": "0.1.13",
"rx-jupyter": "5.5.12", "rx-jupyter": "5.5.12",
"sanitize-html": "2.3.3", "sanitize-html": "2.3.3",

View File

@ -69,7 +69,7 @@ jest.mock("Explorer/Controls/Dialog", () => ({
useDialog: { useDialog: {
getState: jest.fn(() => ({ getState: jest.fn(() => ({
showOkCancelModalDialog: (title: string, subText: string, okLabel: string, onOk: () => void) => onOk(), showOkCancelModalDialog: (title: string, subText: string, okLabel: string, onOk: () => void) => onOk(),
showOkModalDialog: () => {}, showOkModalDialog: () => { },
})), })),
}, },
})); }));
@ -480,11 +480,30 @@ describe("Documents tab (noSql API)", () => {
}); });
describe("Documents tab", () => { describe("Documents tab", () => {
it("should add strings to array without duplicate", () => { describe("addStringsNoDuplicate", () => {
const array1 = ["a", "b", "c"]; it("should add strings to array without duplicate", () => {
const array2 = ["b", "c", "d"]; const array1 = ["a", "b", "c"];
const array2 = ["b", "c", "d"];
const array3 = addStringsNoDuplicate(array1, array2);
expect(array3).toEqual(["a", "b", "c", "d"]);
});
it("should handle initial empty arrays", () => {
const array1: string[] = [];
const array2 = ["b", "c", "d"];
const array3 = addStringsNoDuplicate(array1, array2);
expect(array3).toEqual(["b", "c", "d"]);
});
it("should handle adding empty arrays", () => {
const array1 = ["a", "b", "c"];
const array2: string[] = [];
const array3 = addStringsNoDuplicate(array1, array2);
expect(array3).toEqual(["a", "b", "c"]);
});
const array3 = addStringsNoDuplicate(array1, array2);
expect(array3).toEqual(["a", "b", "c", "d"]);
}); });
}); });

View File

@ -1,5 +1,5 @@
import { Item, ItemDefinition, PartitionKey, PartitionKeyDefinition, QueryIterator, Resource } from "@azure/cosmos"; import { Item, ItemDefinition, PartitionKey, PartitionKeyDefinition, QueryIterator, Resource } from "@azure/cosmos";
import { Button, FluentProvider, Input, TableRowId } from "@fluentui/react-components"; import { Button, FluentProvider, TableRowId } from "@fluentui/react-components";
import { ArrowClockwise16Filled, Dismiss16Filled } from "@fluentui/react-icons"; import { ArrowClockwise16Filled, Dismiss16Filled } from "@fluentui/react-icons";
import Split from "@uiw/react-split"; import Split from "@uiw/react-split";
import { KeyCodes, QueryCopilotSampleContainerId, QueryCopilotSampleDatabaseId } from "Common/Constants"; import { KeyCodes, QueryCopilotSampleContainerId, QueryCopilotSampleDatabaseId } from "Common/Constants";
@ -36,6 +36,8 @@ import { Action } from "Shared/Telemetry/TelemetryConstants";
import { userContext } from "UserContext"; import { userContext } from "UserContext";
import { logConsoleError } from "Utils/NotificationConsoleUtils"; import { logConsoleError } from "Utils/NotificationConsoleUtils";
import React, { KeyboardEventHandler, useCallback, useEffect, useMemo, useRef, useState } from "react"; import React, { KeyboardEventHandler, useCallback, useEffect, useMemo, useRef, useState } from "react";
import { Typeahead } from 'react-bootstrap-typeahead';
import 'react-bootstrap-typeahead/css/Typeahead.css';
import { format } from "react-string-format"; import { format } from "react-string-format";
import { CSSProperties } from "styled-components"; import { CSSProperties } from "styled-components";
import DeleteDocumentIcon from "../../../../images/DeleteDocument.svg"; import DeleteDocumentIcon from "../../../../images/DeleteDocument.svg";
@ -950,8 +952,8 @@ export const DocumentsTabComponent: React.FunctionComponent<IDocumentsTabCompone
? `the selected ${selectedRows.size} items` ? `the selected ${selectedRows.size} items`
: "the selected item" : "the selected item"
: isPlural : isPlural
? `the selected ${selectedRows.size} documents` ? `the selected ${selectedRows.size} documents`
: "the selected document"; : "the selected document";
const msg = `Are you sure you want to delete ${documentName}?`; const msg = `Are you sure you want to delete ${documentName}?`;
useDialog useDialog
@ -1727,6 +1729,7 @@ export const DocumentsTabComponent: React.FunctionComponent<IDocumentsTabCompone
return ( return (
<FluentProvider theme={getPlatformTheme(configContext.platform)} style={{ height: "100%" }}> <FluentProvider theme={getPlatformTheme(configContext.platform)} style={{ height: "100%" }}>
<div className="tab-pane active documentsTab" role="tabpanel" style={{ display: "flex" }}> <div className="tab-pane active documentsTab" role="tabpanel" style={{ display: "flex" }}>
filterContent: {filterContent}
{isFilterCreated && ( {isFilterCreated && (
<div className="filterdivs"> <div className="filterdivs">
{!isFilterExpanded && !isPreferredApiMongoDB && ( {!isFilterExpanded && !isPreferredApiMongoDB && (
@ -1753,7 +1756,30 @@ export const DocumentsTabComponent: React.FunctionComponent<IDocumentsTabCompone
<div> <div>
<div className="editFilterContainer"> <div className="editFilterContainer">
{!isPreferredApiMongoDB && <span className="filterspan"> SELECT * FROM c </span>} {!isPreferredApiMongoDB && <span className="filterspan"> SELECT * FROM c </span>}
<Input <Typeahead
id="filterInput"
style={{ width: "100%", display: "block" }}
// ref={filterInput}
allowNew
// onChange={sel => console.log(`onChange ${JSON.stringify(sel)}`) /*setFilterContent(sel[0] as string)*/}
onChange={sel => setFilterContent(sel[0] as string)}
// onInputChange={text => console.log(`onInputChange ${text}`) /*setFilterContent(sel[0] as string)*/}
onInputChange={text => setFilterContent(text)}
className={`${!filterContent || filterContent.length === 0 ? "placeholderVisible" : ""}`}
// title="Type a query predicate or choose one from the list."
options={addStringsNoDuplicate(
lastFilterContents,
isPreferredApiMongoDB ? defaultMongoFilters : defaultSqlFilters,
)}
placeholder={
isPreferredApiMongoDB
? "Type a query predicate (e.g., {´a´:´foo´}), or choose one from the drop down list, or leave empty to query all documents."
: "Type a query predicate (e.g., WHERE c.id=´1´), or choose one from the drop down list, or leave empty to query all documents."
}
autoFocus={true}
selected={[filterContent]}
/>
{/* <Input
id="filterInput" id="filterInput"
ref={filterInput} ref={filterInput}
type="text" type="text"
@ -1780,7 +1806,7 @@ export const DocumentsTabComponent: React.FunctionComponent<IDocumentsTabCompone
).map((filter) => ( ).map((filter) => (
<option key={filter} value={filter} /> <option key={filter} value={filter} />
))} ))}
</datalist> </datalist> */}
<span className="filterbuttonpad"> <span className="filterbuttonpad">
<Button <Button