@salesforce/webapp-template-app-react-template-b2e-experimental 1.112.6 → 1.112.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (21) hide show
  1. package/dist/CHANGELOG.md +16 -0
  2. package/dist/force-app/main/default/webapplications/appreacttemplateb2e/package.json +3 -3
  3. package/dist/force-app/main/default/webapplications/appreacttemplateb2e/src/api/graphqlClient.ts +25 -0
  4. package/dist/force-app/main/default/webapplications/appreacttemplateb2e/src/features/object-search/__examples__/pages/AccountSearch.tsx +82 -54
  5. package/dist/force-app/main/default/webapplications/appreacttemplateb2e/src/features/object-search/components/FilterContext.tsx +73 -0
  6. package/dist/force-app/main/default/webapplications/appreacttemplateb2e/src/features/object-search/components/PaginationControls.tsx +45 -87
  7. package/dist/force-app/main/default/webapplications/appreacttemplateb2e/src/features/object-search/components/filters/BooleanFilter.tsx +16 -36
  8. package/dist/force-app/main/default/webapplications/appreacttemplateb2e/src/features/object-search/components/filters/DateFilter.tsx +33 -77
  9. package/dist/force-app/main/default/webapplications/appreacttemplateb2e/src/features/object-search/components/filters/DateRangeFilter.tsx +14 -23
  10. package/dist/force-app/main/default/webapplications/appreacttemplateb2e/src/features/object-search/components/filters/MultiSelectFilter.tsx +18 -26
  11. package/dist/force-app/main/default/webapplications/appreacttemplateb2e/src/features/object-search/components/filters/NumericRangeFilter.tsx +22 -39
  12. package/dist/force-app/main/default/webapplications/appreacttemplateb2e/src/features/object-search/components/filters/SearchFilter.tsx +12 -15
  13. package/dist/force-app/main/default/webapplications/appreacttemplateb2e/src/features/object-search/components/filters/SelectFilter.tsx +30 -34
  14. package/dist/force-app/main/default/webapplications/appreacttemplateb2e/src/features/object-search/components/filters/TextFilter.tsx +27 -30
  15. package/dist/force-app/main/default/webapplications/appreacttemplateb2e/src/features/object-search/hooks/useAsyncData.ts +1 -0
  16. package/dist/force-app/main/default/webapplications/appreacttemplateb2e/src/features/object-search/hooks/useCachedAsyncData.ts +1 -0
  17. package/dist/force-app/main/default/webapplications/appreacttemplateb2e/src/features/object-search/hooks/useObjectSearchParams.ts +22 -0
  18. package/dist/package-lock.json +2 -2
  19. package/dist/package.json +1 -1
  20. package/package.json +1 -1
  21. package/dist/force-app/main/default/webapplications/appreacttemplateb2e/src/features/object-search/components/FilterPanel.tsx +0 -127
@@ -1,41 +1,36 @@
1
1
  import { Input } from "../../../../components/ui/input";
2
2
  import { Label } from "../../../../components/ui/label";
3
3
  import { cn } from "../../../../lib/utils";
4
- import type { FilterFieldConfig, ActiveFilterValue } from "../../utils/filterUtils";
4
+ import { useFilterField } from "../FilterContext";
5
+ import type { ActiveFilterValue } from "../../utils/filterUtils";
5
6
 
6
7
  interface TextFilterProps extends Omit<React.ComponentProps<"div">, "onChange"> {
7
- config: FilterFieldConfig;
8
- value: ActiveFilterValue | undefined;
9
- onChange: (value: ActiveFilterValue | undefined) => void;
10
- labelProps?: React.ComponentProps<typeof Label>;
11
- inputProps?: Omit<React.ComponentProps<typeof TextFilterInput>, "config" | "value" | "onChange">;
12
- helpTextProps?: React.ComponentProps<"p">;
8
+ field: string;
9
+ label: string;
10
+ placeholder?: string;
11
+ helpText?: string;
13
12
  }
14
13
 
15
14
  export function TextFilter({
16
- config,
17
- value,
18
- onChange,
15
+ field,
16
+ label,
17
+ placeholder,
18
+ helpText,
19
19
  className,
20
- labelProps,
21
- inputProps,
22
- helpTextProps,
23
20
  ...props
24
21
  }: TextFilterProps) {
22
+ const { value, onChange } = useFilterField(field);
25
23
  return (
26
24
  <div className={cn("space-y-1.5", className)} {...props}>
27
- <Label htmlFor={`filter-${config.field}`} {...labelProps}>
28
- {labelProps?.children ?? config.label}
29
- </Label>
30
- <TextFilterInput config={config} value={value} onChange={onChange} {...inputProps} />
31
- {config.helpText && (
32
- <p
33
- {...helpTextProps}
34
- className={cn("text-xs text-muted-foreground", helpTextProps?.className)}
35
- >
36
- {helpTextProps?.children ?? config.helpText}
37
- </p>
38
- )}
25
+ <Label htmlFor={`filter-${field}`}>{label}</Label>
26
+ <TextFilterInput
27
+ field={field}
28
+ label={label}
29
+ placeholder={placeholder}
30
+ value={value}
31
+ onChange={onChange}
32
+ />
33
+ {helpText && <p className="text-xs text-muted-foreground">{helpText}</p>}
39
34
  </div>
40
35
  );
41
36
  }
@@ -44,13 +39,15 @@ interface TextFilterInputProps extends Omit<
44
39
  React.ComponentProps<typeof Input>,
45
40
  "onChange" | "value"
46
41
  > {
47
- config: FilterFieldConfig;
42
+ field: string;
43
+ label: string;
48
44
  value: ActiveFilterValue | undefined;
49
45
  onChange: (value: ActiveFilterValue | undefined) => void;
50
46
  }
51
47
 
52
48
  export function TextFilterInput({
53
- config,
49
+ field,
50
+ label,
54
51
  value,
55
52
  onChange,
56
53
  className,
@@ -58,14 +55,14 @@ export function TextFilterInput({
58
55
  }: TextFilterInputProps) {
59
56
  return (
60
57
  <Input
61
- id={`filter-${config.field}`}
58
+ id={`filter-${field}`}
62
59
  type="text"
63
- placeholder={config.placeholder ?? `Filter by ${config.label.toLowerCase()}...`}
60
+ placeholder={props.placeholder ?? `Filter by ${label.toLowerCase()}...`}
64
61
  value={value?.value ?? ""}
65
62
  onChange={(e) => {
66
63
  const v = e.target.value;
67
64
  if (v) {
68
- onChange({ field: config.field, label: config.label, type: "text", value: v });
65
+ onChange({ field, label, type: "text", value: v });
69
66
  } else {
70
67
  onChange(undefined);
71
68
  }
@@ -38,6 +38,7 @@ export function useAsyncData<T>(
38
38
  if (!cancelled) setData(result);
39
39
  })
40
40
  .catch((err) => {
41
+ console.error(err);
41
42
  if (!cancelled) setError(err instanceof Error ? err.message : "An error occurred");
42
43
  })
43
44
  .finally(() => {
@@ -166,6 +166,7 @@ export function useCachedAsyncData<T>(
166
166
  }
167
167
  })
168
168
  .catch((err) => {
169
+ console.error(err);
169
170
  if (!cancelled) setError(err instanceof Error ? err.message : "An error occurred");
170
171
  })
171
172
  .finally(() => {
@@ -14,6 +14,28 @@ export interface PaginationConfig {
14
14
  validPageSizes: number[];
15
15
  }
16
16
 
17
+ export interface UseObjectSearchParamsReturn<TFilter, TOrderBy> {
18
+ filters: {
19
+ active: ActiveFilterValue[];
20
+ set: (field: string, value: ActiveFilterValue | undefined) => void;
21
+ remove: (field: string) => void;
22
+ };
23
+ sort: {
24
+ current: SortState | null;
25
+ set: (sort: SortState | null) => void;
26
+ };
27
+ query: { where: TFilter; orderBy: TOrderBy };
28
+ pagination: {
29
+ pageSize: number;
30
+ pageIndex: number;
31
+ afterCursor: string | undefined;
32
+ setPageSize: (size: number) => void;
33
+ goToNextPage: (cursor: string) => void;
34
+ goToPreviousPage: () => void;
35
+ };
36
+ resetAll: () => void;
37
+ }
38
+
17
39
  /**
18
40
  * Manages filter, sort, and cursor-based pagination state for an object search page.
19
41
  *
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@salesforce/webapp-template-base-sfdx-project-experimental",
3
- "version": "1.112.6",
3
+ "version": "1.112.8",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@salesforce/webapp-template-base-sfdx-project-experimental",
9
- "version": "1.112.6",
9
+ "version": "1.112.8",
10
10
  "license": "SEE LICENSE IN LICENSE.txt",
11
11
  "devDependencies": {
12
12
  "@lwc/eslint-plugin-lwc": "^3.3.0",
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce/webapp-template-base-sfdx-project-experimental",
3
- "version": "1.112.6",
3
+ "version": "1.112.8",
4
4
  "description": "Base SFDX project template",
5
5
  "license": "SEE LICENSE IN LICENSE.txt",
6
6
  "publishConfig": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce/webapp-template-app-react-template-b2e-experimental",
3
- "version": "1.112.6",
3
+ "version": "1.112.8",
4
4
  "description": "B2E template app (from BYO)",
5
5
  "license": "SEE LICENSE IN LICENSE.txt",
6
6
  "author": "",
@@ -1,127 +0,0 @@
1
- import { Card, CardContent, CardHeader, CardTitle } from "../../../components/ui/card";
2
- import { Button } from "../../../components/ui/button";
3
- import {
4
- Collapsible,
5
- CollapsibleContent,
6
- CollapsibleTrigger,
7
- } from "../../../components/ui/collapsible";
8
- import { cn } from "../../../lib/utils";
9
- import { ChevronDown } from "lucide-react";
10
- import { useState } from "react";
11
- import type { FilterFieldConfig, ActiveFilterValue } from "../utils/filterUtils";
12
- import { TextFilter } from "./filters/TextFilter";
13
- import { SelectFilter } from "./filters/SelectFilter";
14
- import { NumericRangeFilter } from "./filters/NumericRangeFilter";
15
- import { BooleanFilter } from "./filters/BooleanFilter";
16
- import { DateFilter } from "./filters/DateFilter";
17
- import { DateRangeFilter } from "./filters/DateRangeFilter";
18
- import { MultiSelectFilter } from "./filters/MultiSelectFilter";
19
- import { SearchFilter } from "./filters/SearchFilter";
20
-
21
- interface FilterPanelProps extends Omit<React.ComponentProps<"div">, "onReset"> {
22
- configs: FilterFieldConfig[];
23
- filters: ActiveFilterValue[];
24
- onFilterChange: (field: string, value: ActiveFilterValue | undefined) => void;
25
- onReset: () => void;
26
- headerProps?: React.ComponentProps<typeof CardHeader>;
27
- titleProps?: React.ComponentProps<typeof CardTitle>;
28
- contentProps?: React.ComponentProps<typeof CardContent>;
29
- resetButtonProps?: React.ComponentProps<typeof Button>;
30
- toggleButtonProps?: React.ComponentProps<typeof Button>;
31
- }
32
-
33
- function getFilterValue(
34
- filters: ActiveFilterValue[],
35
- field: string,
36
- ): ActiveFilterValue | undefined {
37
- return filters.find((f) => f.field === field);
38
- }
39
-
40
- function renderFilter(
41
- config: FilterFieldConfig,
42
- value: ActiveFilterValue | undefined,
43
- onChange: (value: ActiveFilterValue | undefined) => void,
44
- ) {
45
- switch (config.type) {
46
- case "text":
47
- return <TextFilter config={config} value={value} onChange={onChange} />;
48
- case "picklist":
49
- return <SelectFilter config={config} value={value} onChange={onChange} />;
50
- case "numeric":
51
- return <NumericRangeFilter config={config} value={value} onChange={onChange} />;
52
- case "boolean":
53
- return <BooleanFilter config={config} value={value} onChange={onChange} />;
54
- case "date":
55
- return <DateFilter config={config} value={value} onChange={onChange} />;
56
- case "daterange":
57
- return <DateRangeFilter config={config} value={value} onChange={onChange} />;
58
- case "multipicklist":
59
- return <MultiSelectFilter config={config} value={value} onChange={onChange} />;
60
- case "search":
61
- return <SearchFilter config={config} value={value} onChange={onChange} />;
62
- }
63
- }
64
-
65
- export function FilterPanel({
66
- configs,
67
- filters,
68
- onFilterChange,
69
- onReset,
70
- className,
71
- headerProps,
72
- titleProps,
73
- contentProps,
74
- resetButtonProps,
75
- toggleButtonProps,
76
- ...props
77
- }: FilterPanelProps) {
78
- const [open, setOpen] = useState(true);
79
- const hasActiveFilters = filters.length > 0;
80
-
81
- return (
82
- <Card className={cn(className)} {...props}>
83
- <Collapsible open={open} onOpenChange={setOpen}>
84
- <CardHeader
85
- {...headerProps}
86
- className={cn(
87
- "flex flex-row items-center justify-between space-y-0 pb-2",
88
- headerProps?.className,
89
- )}
90
- >
91
- <CardTitle
92
- {...titleProps}
93
- className={cn("text-base font-semibold", titleProps?.className)}
94
- >
95
- {titleProps?.children ?? <h2>Filters</h2>}
96
- </CardTitle>
97
- <div className="flex items-center gap-1">
98
- {hasActiveFilters && (
99
- <Button variant="destructive" size="sm" onClick={onReset} {...resetButtonProps}>
100
- {resetButtonProps?.children ?? "Reset"}
101
- </Button>
102
- )}
103
- <CollapsibleTrigger asChild>
104
- <Button variant="ghost" size="icon" {...toggleButtonProps}>
105
- <ChevronDown
106
- className={`h-4 w-4 transition-transform ${open ? "" : "-rotate-90"}`}
107
- />
108
- <span className="sr-only">Toggle filters</span>
109
- </Button>
110
- </CollapsibleTrigger>
111
- </div>
112
- </CardHeader>
113
- <CollapsibleContent>
114
- <CardContent {...contentProps} className={cn("space-y-4 pt-0", contentProps?.className)}>
115
- {configs.map((config) => (
116
- <div key={config.field}>
117
- {renderFilter(config, getFilterValue(filters, config.field), (value) =>
118
- onFilterChange(config.field, value),
119
- )}
120
- </div>
121
- ))}
122
- </CardContent>
123
- </CollapsibleContent>
124
- </Collapsible>
125
- </Card>
126
- );
127
- }