Skip to content

Commit 1f933b1

Browse files
Merge pull request #895 from gadget-inc/mill/preventSearchPropsInAutoTableWhenModelIsUnsearchable
AutoTable - Auto disable search and error on search props when the model has search disabled
2 parents f46472c + 678339a commit 1f933b1

File tree

10 files changed

+537
-16
lines changed

10 files changed

+537
-16
lines changed

packages/react/cypress/component/auto/table/metadata/widgetMetadata.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export const widgetModelMetadata = {
66
apiIdentifier: "widget",
77
namespace: [],
88
name: "Widget",
9+
searchable: true,
910
fields: [
1011
{
1112
name: "Id",

packages/react/spec/auto/storybook/SelectableDesignSystemUtils.tsx

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,11 @@ export const DesignSystemSelectionControl = ({ children }: { children: React.Rea
2929
return (
3030
<DesignSystemContext.Provider value={{ designSystem, updateDesignSystem }}>
3131
<AppProvider i18n={translations}>
32-
<div style={{ marginBottom: "16px", gap: "16px", display: "flex", flexDirection: "row" }}>
33-
<body>
34-
<elements.Button onClick={() => updateDesignSystem(SUITE_NAMES.SHADCN)} variant="outline">
35-
{designSystem === SUITE_NAMES.SHADCN ? "✅ " : ""}Shadcn
36-
</elements.Button>
37-
</body>
32+
<div style={{ margin: "16px", gap: "16px", display: "flex", flexDirection: "row" }}>
33+
<elements.Button onClick={() => updateDesignSystem(SUITE_NAMES.SHADCN)} variant="outline">
34+
{designSystem === SUITE_NAMES.SHADCN ? "✅ " : ""}Shadcn
35+
</elements.Button>
36+
3837
<Button onClick={() => updateDesignSystem(SUITE_NAMES.POLARIS)}>
3938
{designSystem === SUITE_NAMES.POLARIS ? "✅ " : ""}Polaris
4039
</Button>
@@ -65,14 +64,14 @@ export const ShadcnAutoComponentsThemeControlWrapper = ({ children }: { children
6564
}, []);
6665

6766
return (
68-
<body>
67+
<>
6968
{darkModeEnabled && (
7069
<div className="flex items-center gap-2 p-2">
7170
<elements.Button onClick={toggleDarkMode}>Toggle dark mode</elements.Button>
7271
</div>
7372
)}
7473

7574
{children}
76-
</body>
75+
</>
7776
);
7877
};

packages/react/src/auto/AutoTableValidators.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { type ModelMetadata } from "src/metadata.js";
12
import type { useTable } from "../useTable.js";
23

34
export const InvalidModelErrorMessage = `"model" is not a valid Gadget model`;
@@ -7,3 +8,22 @@ export const validateAutoTableProps = (manager: Parameters<typeof useTable>[0])
78
throw new Error(InvalidModelErrorMessage);
89
}
910
};
11+
12+
export const validateAutoTableOptions = (props: { options: Parameters<typeof useTable>[1]; metadata?: ModelMetadata }) => {
13+
const { options, metadata } = props;
14+
15+
if (!options) {
16+
return;
17+
}
18+
19+
const cannotSearchInModel = metadata && !metadata.searchable;
20+
21+
if (cannotSearchInModel) {
22+
if (options.searchable === true) {
23+
throw new Error(`Model "${metadata.apiIdentifier}" is not searchable and cannot have "searchable" set to true`);
24+
}
25+
if (options.search) {
26+
throw new Error(`Model "${metadata.apiIdentifier}" is not searchable and cannot have a passed in search value`);
27+
}
28+
}
29+
};

packages/react/src/auto/polaris/PolarisAutoTable.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ const PolarisAutoTableComponent = <
121121
initialSort: props.initialSort,
122122
filter: props.filter,
123123
search: props.searchValue,
124+
searchable: props.searchable,
124125
} as any);
125126

126127
const { columns, rows, page, fetching, error, search, selection, sort, metadata, data: rawRecords } = methods;
@@ -214,7 +215,7 @@ const PolarisAutoTableComponent = <
214215
ids={selection.recordIds}
215216
clearSelection={selection.clearAll}
216217
/>
217-
{searchable && (
218+
{searchable && search && (
218219
<IndexFilters
219220
mode={mode}
220221
setMode={setMode}

packages/react/src/auto/shadcn/ShadcnAutoTable.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ export const makeAutoTable = (elements: ShadcnElements) => {
234234
initialSort: props.initialSort,
235235
filter: props.filter,
236236
search: props.searchValue,
237+
searchable: props.searchable,
237238
} as any);
238239

239240
const {
@@ -297,7 +298,7 @@ export const makeAutoTable = (elements: ShadcnElements) => {
297298
/>
298299

299300
<div className="flex flex-row gap-2 items-center mb-2">
300-
{searchable && <ShadcnAutoTableSearch search={search} />}
301+
{searchable && search && <ShadcnAutoTableSearch search={search} />}
301302
{hasSelectedRecords && (
302303
<div className="ml-auto">
303304
<div className="flex flex-row ml-auto gap-2 items-center">

packages/react/src/internal/gql/gql.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import * as types from "./graphql.js";
1515
const documents = {
1616
"\n fragment FieldMetadata on GadgetField {\n name\n apiIdentifier\n fieldType\n requiredArgumentForInput\n ... on GadgetModelField {\n sortable\n filterable\n }\n configuration {\n __typename\n fieldType\n validations {\n __typename\n ... on GadgetRegexFieldValidation {\n name\n specID\n pattern\n }\n ... on GadgetRangeFieldValidation {\n name\n specID\n min\n max\n }\n ... on GadgetOnlyImageFileFieldValidation {\n name\n specID\n allowAnimatedImages\n }\n ... on GadgetGenericFieldValidation {\n name\n specID\n }\n }\n ... on GadgetHasManyThroughConfig {\n relatedModel {\n key\n name\n apiIdentifier\n namespace\n }\n inverseField {\n apiIdentifier\n }\n joinModel {\n key\n apiIdentifier\n namespace\n }\n inverseJoinModelField {\n apiIdentifier\n }\n inverseRelatedModelField {\n apiIdentifier\n }\n joinModelHasManyFieldApiIdentifier\n }\n ... on GadgetHasManyConfig {\n isJoinModelHasManyField\n relatedModel {\n key\n name\n apiIdentifier\n namespace\n }\n inverseField {\n apiIdentifier\n }\n }\n ... on GadgetHasOneConfig {\n relatedModel {\n key\n name\n apiIdentifier\n namespace\n }\n inverseField {\n apiIdentifier\n }\n }\n ... on GadgetBelongsToConfig {\n relatedModel {\n key\n name\n apiIdentifier\n namespace\n }\n }\n ... on GadgetEnumConfig {\n allowMultiple\n allowOther\n options {\n name\n color\n }\n }\n ... on GadgetDateTimeConfig {\n includeTime\n }\n ... on GadgetNumberConfig {\n decimals\n }\n }\n }\n":
1717
types.FieldMetadataFragmentDoc,
18-
"\n query GetModelMetadata($apiIdentifier: String!, $namespace: [String!]) {\n gadgetMeta {\n modelAndRelatedModels(apiIdentifier: $apiIdentifier, namespace: $namespace) {\n key\n apiIdentifier\n namespace\n name\n fields {\n ...FieldMetadata\n }\n defaultDisplayField {\n name\n apiIdentifier\n fieldType\n }\n }\n }\n }\n":
18+
"\n query GetModelMetadata($apiIdentifier: String!, $namespace: [String!]) {\n gadgetMeta {\n modelAndRelatedModels(apiIdentifier: $apiIdentifier, namespace: $namespace) {\n key\n apiIdentifier\n namespace\n name\n fields {\n ...FieldMetadata\n }\n searchable\n defaultDisplayField {\n name\n apiIdentifier\n fieldType\n }\n }\n }\n }\n":
1919
types.GetModelMetadataDocument,
2020
"\n fragment SubFields on GadgetField {\n configuration {\n __typename\n ... on GadgetObjectFieldConfig {\n name\n fields {\n ...FieldMetadata\n configuration {\n __typename\n ... on GadgetObjectFieldConfig {\n name\n fields {\n ...FieldMetadata\n configuration {\n __typename\n ... on GadgetObjectFieldConfig {\n name\n fields {\n ...FieldMetadata\n }\n }\n }\n }\n }\n }\n }\n }\n }\n }\n":
2121
types.SubFieldsFragmentDoc,
@@ -51,8 +51,8 @@ export function graphql(
5151
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
5252
*/
5353
export function graphql(
54-
source: "\n query GetModelMetadata($apiIdentifier: String!, $namespace: [String!]) {\n gadgetMeta {\n modelAndRelatedModels(apiIdentifier: $apiIdentifier, namespace: $namespace) {\n key\n apiIdentifier\n namespace\n name\n fields {\n ...FieldMetadata\n }\n defaultDisplayField {\n name\n apiIdentifier\n fieldType\n }\n }\n }\n }\n"
55-
): (typeof documents)["\n query GetModelMetadata($apiIdentifier: String!, $namespace: [String!]) {\n gadgetMeta {\n modelAndRelatedModels(apiIdentifier: $apiIdentifier, namespace: $namespace) {\n key\n apiIdentifier\n namespace\n name\n fields {\n ...FieldMetadata\n }\n defaultDisplayField {\n name\n apiIdentifier\n fieldType\n }\n }\n }\n }\n"];
54+
source: "\n query GetModelMetadata($apiIdentifier: String!, $namespace: [String!]) {\n gadgetMeta {\n modelAndRelatedModels(apiIdentifier: $apiIdentifier, namespace: $namespace) {\n key\n apiIdentifier\n namespace\n name\n fields {\n ...FieldMetadata\n }\n searchable\n defaultDisplayField {\n name\n apiIdentifier\n fieldType\n }\n }\n }\n }\n"
55+
): (typeof documents)["\n query GetModelMetadata($apiIdentifier: String!, $namespace: [String!]) {\n gadgetMeta {\n modelAndRelatedModels(apiIdentifier: $apiIdentifier, namespace: $namespace) {\n key\n apiIdentifier\n namespace\n name\n fields {\n ...FieldMetadata\n }\n searchable\n defaultDisplayField {\n name\n apiIdentifier\n fieldType\n }\n }\n }\n }\n"];
5656
/**
5757
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
5858
*/

0 commit comments

Comments
 (0)