@wipco/sdui 1.4.2 → 1.5.0
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.
- package/dist/index.d.ts +79 -2
- package/dist/index.js +106 -6
- package/dist/meta.js +50 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -738,6 +738,19 @@ interface RemotePageState {
|
|
|
738
738
|
* 그래서 늦게 도착한 응답은 아래 `alive` 검사로 한 번 더 버린다.
|
|
739
739
|
*/
|
|
740
740
|
declare function useRemoteSearchPage(endpoint: string, params: URLSearchParams): RemotePageState;
|
|
741
|
+
interface RemoteSummaryState {
|
|
742
|
+
/** 합계 응답 객체 — 첫 응답 전·실패 시 null (직전 값은 재조회 중에도 유지) */
|
|
743
|
+
values: Record<string, unknown> | null;
|
|
744
|
+
isLoading: boolean;
|
|
745
|
+
error: Error | null;
|
|
746
|
+
}
|
|
747
|
+
/**
|
|
748
|
+
* 목록 위 합계 칸(`summary.endpoint`) 조회 — 응답은 `{ data, total }` 이 아니라 객체 하나라
|
|
749
|
+
* 목록 fetcher(toPage)를 거치지 않고 어댑터 fetch(없으면 same-origin fetch)로 직접 받는다.
|
|
750
|
+
* 목록과 같은 재조회 신호(invalidate 접두어·SSE)를 받도록 자기 endpoint 로 구독한다.
|
|
751
|
+
* endpoint 가 null 이면 아무것도 하지 않는다.
|
|
752
|
+
*/
|
|
753
|
+
declare function useRemoteSearchSummary(endpoint: string | null, params: URLSearchParams): RemoteSummaryState;
|
|
741
754
|
|
|
742
755
|
/**
|
|
743
756
|
* 검색 툴바 — ERP `app/components/search/SearchToolbar.tsx`의 계약(타입·헬퍼·동작)을
|
|
@@ -881,6 +894,22 @@ interface SearchFilter {
|
|
|
881
894
|
value: string;
|
|
882
895
|
}[];
|
|
883
896
|
}
|
|
897
|
+
/**
|
|
898
|
+
* 목록 맨 위의 구분 탭 — 한 쿼리 키의 값을 탭으로 고른다(전체/용역/상품/기타 같은).
|
|
899
|
+
*
|
|
900
|
+
* 필터 칩(leftFilters)과 같은 파라미터 규칙이다: 고른 탭의 `value` 가 `key` 파라미터가
|
|
901
|
+
* 되고, 빈 문자열 탭은 파라미터를 지운다(= 전체). 값에 쉼표를 넣으면 여러 값 중 하나
|
|
902
|
+
* (`기타,미수주`)라는 뜻이다 — 서버 `=` 필터와 로컬 재필터가 둘 다 그렇게 읽는다.
|
|
903
|
+
* 탭을 바꾸면 1페이지로 돌아간다.
|
|
904
|
+
*/
|
|
905
|
+
interface SearchTabs {
|
|
906
|
+
key: string;
|
|
907
|
+
items: {
|
|
908
|
+
value: string;
|
|
909
|
+
label: string;
|
|
910
|
+
icon?: string;
|
|
911
|
+
}[];
|
|
912
|
+
}
|
|
884
913
|
/**
|
|
885
914
|
* 목록/카드 전환 버튼 한 칸.
|
|
886
915
|
*
|
|
@@ -925,6 +954,10 @@ interface SearchResultsProps<T> {
|
|
|
925
954
|
gridConfig?: GridCardConfig<T>;
|
|
926
955
|
leftFilters?: SearchFilter[];
|
|
927
956
|
rightFilters?: SearchFilter[];
|
|
957
|
+
/** 목록 맨 위(툴바 위)의 구분 탭 */
|
|
958
|
+
tabs?: SearchTabs;
|
|
959
|
+
/** 탭보다도 위에 놓이는 요약 영역 — 합계 칸(SearchSummaryCards) 자리 */
|
|
960
|
+
summary?: React__default.ReactNode;
|
|
928
961
|
initialView?: 'grid' | 'list';
|
|
929
962
|
/**
|
|
930
963
|
* 노출할 보기 목록. 생략하면 목록/카드 두 칸이 기본값이고,
|
|
@@ -966,7 +999,7 @@ interface SearchResultsProps<T> {
|
|
|
966
999
|
declare function normalizePageSizes(sizes: number[] | undefined): number[] | undefined;
|
|
967
1000
|
declare function SearchResults<T extends {
|
|
968
1001
|
id: string;
|
|
969
|
-
}>({ item, columns, gridConfig, leftFilters, rightFilters, initialView, views, pageSizes, className, style, searchParams, onParamsChange, actions, disableGrid, disableList, onRowClick, title, headerActions, isLoading, hideHeader, advancedSearchFields: rawAdvancedSearchFields, searchPlaceholder, virtual, }: SearchResultsProps<T>): React__default.JSX.Element;
|
|
1002
|
+
}>({ item, columns, gridConfig, leftFilters, rightFilters, tabs, summary, initialView, views, pageSizes, className, style, searchParams, onParamsChange, actions, disableGrid, disableList, onRowClick, title, headerActions, isLoading, hideHeader, advancedSearchFields: rawAdvancedSearchFields, searchPlaceholder, virtual, }: SearchResultsProps<T>): React__default.JSX.Element;
|
|
970
1003
|
|
|
971
1004
|
/**
|
|
972
1005
|
* 셀 표현 어휘 — 목록 컬럼의 셀과 카드 행의 값이 **같은 규칙**을 쓴다.
|
|
@@ -1099,6 +1132,43 @@ declare function imageRenderer(cell: SduiImageCell, key: string, width?: number
|
|
|
1099
1132
|
*/
|
|
1100
1133
|
declare function cellRenderer(cell: SduiCell | undefined, key: string, dispatch: SduiDispatch): ((row: SearchRow) => React__default.ReactNode) | undefined;
|
|
1101
1134
|
|
|
1135
|
+
/**
|
|
1136
|
+
* 목록 위 합계 칸 — "지금 검색된 결과 전체"의 합(계약금액·공급가액·세액 같은)을 숫자 카드로.
|
|
1137
|
+
*
|
|
1138
|
+
* 값은 목록과 **같은 쿼리**로 따로 조회한다(`summary.endpoint`). 현재 페이지 행을 더하면
|
|
1139
|
+
* 10건짜리 부분합이 전체 합처럼 보이므로 로컬 합산은 하지 않는다 — 합은 서버가 낸다.
|
|
1140
|
+
* 쿼리에서 빠지는 것은 page/limit 둘뿐이다(`summaryParams`): 검색어·상세검색·필터·탭이
|
|
1141
|
+
* 전부 합계에도 걸려야 "검색된 결과에 따른 합"이 된다.
|
|
1142
|
+
*/
|
|
1143
|
+
|
|
1144
|
+
interface SduiSearchSummaryItem {
|
|
1145
|
+
/** 응답 객체에서 읽을 필드 — 점 경로 허용 */
|
|
1146
|
+
key: string;
|
|
1147
|
+
label: string;
|
|
1148
|
+
/** 값 뒤 단위 — "원", "건" */
|
|
1149
|
+
unit?: string;
|
|
1150
|
+
icon?: string;
|
|
1151
|
+
/** 값 표현 — 컬럼 셀과 같은 어휘(주로 `{ type: 'number' }`). 생략하면 숫자는 천 단위 구분 */
|
|
1152
|
+
cell?: SduiCell;
|
|
1153
|
+
}
|
|
1154
|
+
interface SduiSearchSummary {
|
|
1155
|
+
/**
|
|
1156
|
+
* 합계 endpoint — 목록의 쿼리(page/limit 제외)가 그대로 붙는다. 응답은 객체 하나이고
|
|
1157
|
+
* 칸마다 `items[].key` 로 값을 꺼낸다.
|
|
1158
|
+
*/
|
|
1159
|
+
endpoint: string;
|
|
1160
|
+
items: SduiSearchSummaryItem[];
|
|
1161
|
+
}
|
|
1162
|
+
/** 합계 조회에 넘길 쿼리 — 목록 쿼리에서 페이지 축(page/limit)만 뺀다. */
|
|
1163
|
+
declare function summaryParams(params: URLSearchParams): URLSearchParams;
|
|
1164
|
+
interface SearchSummaryCardsProps {
|
|
1165
|
+
items: SduiSearchSummaryItem[];
|
|
1166
|
+
/** 합계 응답 객체 — 아직 없으면 값 자리에 '—' */
|
|
1167
|
+
values: Record<string, unknown> | null | undefined;
|
|
1168
|
+
dispatch: SduiDispatch;
|
|
1169
|
+
}
|
|
1170
|
+
declare function SearchSummaryCards({ items, values, dispatch }: SearchSummaryCardsProps): React__default.JSX.Element | null;
|
|
1171
|
+
|
|
1102
1172
|
/** JSON 컬럼 정의 — render 함수 대신 선언적 cell 스펙을 쓴다 */
|
|
1103
1173
|
interface SduiSearchColumn {
|
|
1104
1174
|
key: string;
|
|
@@ -1181,6 +1251,8 @@ interface SduiSearchCommonProps {
|
|
|
1181
1251
|
fields?: SearchField[];
|
|
1182
1252
|
leftFilters?: SearchFilter[];
|
|
1183
1253
|
rightFilters?: SearchFilter[];
|
|
1254
|
+
/** 목록 맨 위의 구분 탭 — 한 쿼리 키의 값을 탭으로 고른다. 빈 값 탭 = 전체 */
|
|
1255
|
+
tabs?: SearchTabs;
|
|
1184
1256
|
gridCard?: SduiGridCard;
|
|
1185
1257
|
actions?: SduiSearchAction[];
|
|
1186
1258
|
initialView?: 'grid' | 'list';
|
|
@@ -1235,6 +1307,11 @@ interface RemoteSearchResultsProps extends SduiSearchCommonProps {
|
|
|
1235
1307
|
searchParams?: URLSearchParams;
|
|
1236
1308
|
/** 파라미터 변경 통지 — searchParams 없이 쓰면 내부 상태를 유지한 채 관찰만 한다 */
|
|
1237
1309
|
onParamsChange?: (next: URLSearchParams) => void;
|
|
1310
|
+
/**
|
|
1311
|
+
* 탭 위 합계 칸 — 목록과 같은 쿼리(page/limit 제외)로 `summary.endpoint` 를 조회해
|
|
1312
|
+
* 응답 객체의 `items[].key` 값을 숫자 카드로 보인다. 검색·상세검색·탭을 바꾸면 따라 바뀐다.
|
|
1313
|
+
*/
|
|
1314
|
+
summary?: SduiSearchSummary;
|
|
1238
1315
|
}
|
|
1239
1316
|
/** 바깥에서 온 `style`·`className`을 뿌리에 얹어 내보낸다. 까닭은 {@link ../boxed.tsx}에 있다. */
|
|
1240
1317
|
declare const SduiSearchResults: React__default.FC<SduiSearchResultsProps & SduiBoxProps>;
|
|
@@ -2085,4 +2162,4 @@ interface ImageViewerProps {
|
|
|
2085
2162
|
*/
|
|
2086
2163
|
declare function ImageViewer({ src, alt, open, onClose }: ImageViewerProps): React__default.ReactPortal | null;
|
|
2087
2164
|
|
|
2088
|
-
export { Actions, type ActionsProps, Alert, type AlertProps, Avatar, type AvatarProps, Badge, type BadgeProps, type BadgeTone, Breadcrumb, type BreadcrumbItem, type BreadcrumbProps, Button, type ButtonProps, CALC_OPS, Can, type CanProps, Card, type CardProps, type CascadingSearchOption, Checkbox, type CheckboxProps, Col, type ColProps, type CustomActionHandler, type CustomValidator, DatePickerProps, DateRangePickerProps, Dialog, type DialogProps, Divider, EmptyState, type EmptyStateProps, Field, type FieldProps, Grid, type GridCardConfig, type GridCardRow, type GridProps, ICON_NAMES, Icon, IconButton, type IconButtonProps, type IconProps, ImageViewer, type ImageViewerProps, Input, type InputProps, type Justify, type KeyValueItem, KeyValueList, type KeyValueListProps, type MeterTone, NodeErrorBoundary, OverlayContainerContext, OverlayLayer, PageHead, type PageHeadProps, Pagination, type PaginationProps, ProgressBar, type ProgressBarProps, Radio, type RadioProps, type RemotePageState, RemoteSearchResults, type RemoteSearchResultsProps, type ResolvedPatternSpec, ResultTable, type ResultTableColumn, type ResultTableProps, Row, type RowProps, SduiAction, type SduiAdapter, type SduiAssetContext, type SduiAssetResolver, type SduiBadgeCell, SduiBoxProps, type SduiCanFn, type SduiCanQuery, type SduiCanSetting, type SduiCell, SduiColumnsScale, SduiContainerLayoutProps, type SduiContainerRoleProps, type SduiDateCell, SduiDialog, type SduiDispatch, SduiForm, type SduiFormConfig, type SduiFormProps, SduiGapScale, type SduiGridCard, type SduiGridCardAction, type SduiGridCardRow, type SduiIconCell, type SduiImageCell, type SduiLinkCell, type SduiNumberCell, SduiPage, SduiPermissionProvider, type SduiProgressCell, SduiPropValue, type SduiRegistry, SduiRenderer, type SduiRendererProps, type SduiRowCondition, SduiRule, type SduiRuntime, type SduiSearchAction, type SduiSearchColumn, SduiSearchDataProvider, SduiSearchInvalidationProvider, SduiSearchResults, type SduiSearchResultsProps, type SduiTagCell, SduiTextAlignScale, type SduiTextCell, type SduiUseSpec, SduiWeightScale, type SearchAction, type SearchColumn, type SearchFetcher, type SearchField, type SearchFilter, type SearchInvalidator, type SearchOption, type SearchPage, SearchResults, type SearchResultsProps, type SearchRow, SearchToolbar, type SearchValues, type SearchViewItem, Section, type SectionProps, SegmentedControl, type SegmentedControlProps, type SegmentedItem, Select, type SelectOption, type SelectOptionRecord, type SelectProps, Show, type ShowProps, SidebarNav, type SidebarNavItem, type SidebarNavProps, type SidebarNavSection, type SortDir, SortHandle, type SortHandleProps, SortableList, type SortableListProps, Spacer, type SpacerProps, type SpecIdCandidate, type SpecIssue, Spinner, type SpinnerProps, StatCard, type StatCardProps, Switch, type SwitchProps, type TabItem, Table, type TableColumn, type TableProps, Tabs, type TabsProps, Tag, type TagProps, Text, type TextPreset, type TextProps, Textarea, type TextareaProps, TimePickerProps, Toast, type ToastProps, Tooltip, type TooltipProps, boxed, cascadingValuePaths, cellRenderer, cleanSearchValues, createRegistry, createSearchInvalidator, defaultAdapter, defaultRegistry, getOverlayRoot, imageRenderer, includesLooseSearch, isValidSpecId, joinMultiValue, loadOptionalModule, mapActions, mapCardRows, mapColumns, mapGridCard, mapViews, matchesCondition, normalizePageSizes, normalizeSearchText, patternSpecCandidates, resolvePatternSpec, searchFieldKeys, searchValuesFromParams, sortableDropIndex, sortableMove, splitMultiValue, useOverlayLayer, useRemoteSearchPage, useSduiAssetResolver, useSduiCan, useSduiDispatch, useSduiRuntime, useSduiSandbox, useSearchFetcher, validateSpec, withProps };
|
|
2165
|
+
export { Actions, type ActionsProps, Alert, type AlertProps, Avatar, type AvatarProps, Badge, type BadgeProps, type BadgeTone, Breadcrumb, type BreadcrumbItem, type BreadcrumbProps, Button, type ButtonProps, CALC_OPS, Can, type CanProps, Card, type CardProps, type CascadingSearchOption, Checkbox, type CheckboxProps, Col, type ColProps, type CustomActionHandler, type CustomValidator, DatePickerProps, DateRangePickerProps, Dialog, type DialogProps, Divider, EmptyState, type EmptyStateProps, Field, type FieldProps, Grid, type GridCardConfig, type GridCardRow, type GridProps, ICON_NAMES, Icon, IconButton, type IconButtonProps, type IconProps, ImageViewer, type ImageViewerProps, Input, type InputProps, type Justify, type KeyValueItem, KeyValueList, type KeyValueListProps, type MeterTone, NodeErrorBoundary, OverlayContainerContext, OverlayLayer, PageHead, type PageHeadProps, Pagination, type PaginationProps, ProgressBar, type ProgressBarProps, Radio, type RadioProps, type RemotePageState, RemoteSearchResults, type RemoteSearchResultsProps, type RemoteSummaryState, type ResolvedPatternSpec, ResultTable, type ResultTableColumn, type ResultTableProps, Row, type RowProps, SduiAction, type SduiAdapter, type SduiAssetContext, type SduiAssetResolver, type SduiBadgeCell, SduiBoxProps, type SduiCanFn, type SduiCanQuery, type SduiCanSetting, type SduiCell, SduiColumnsScale, SduiContainerLayoutProps, type SduiContainerRoleProps, type SduiDateCell, SduiDialog, type SduiDispatch, SduiForm, type SduiFormConfig, type SduiFormProps, SduiGapScale, type SduiGridCard, type SduiGridCardAction, type SduiGridCardRow, type SduiIconCell, type SduiImageCell, type SduiLinkCell, type SduiNumberCell, SduiPage, SduiPermissionProvider, type SduiProgressCell, SduiPropValue, type SduiRegistry, SduiRenderer, type SduiRendererProps, type SduiRowCondition, SduiRule, type SduiRuntime, type SduiSearchAction, type SduiSearchColumn, SduiSearchDataProvider, SduiSearchInvalidationProvider, SduiSearchResults, type SduiSearchResultsProps, type SduiSearchSummary, type SduiSearchSummaryItem, type SduiTagCell, SduiTextAlignScale, type SduiTextCell, type SduiUseSpec, SduiWeightScale, type SearchAction, type SearchColumn, type SearchFetcher, type SearchField, type SearchFilter, type SearchInvalidator, type SearchOption, type SearchPage, SearchResults, type SearchResultsProps, type SearchRow, SearchSummaryCards, type SearchSummaryCardsProps, type SearchTabs, SearchToolbar, type SearchValues, type SearchViewItem, Section, type SectionProps, SegmentedControl, type SegmentedControlProps, type SegmentedItem, Select, type SelectOption, type SelectOptionRecord, type SelectProps, Show, type ShowProps, SidebarNav, type SidebarNavItem, type SidebarNavProps, type SidebarNavSection, type SortDir, SortHandle, type SortHandleProps, SortableList, type SortableListProps, Spacer, type SpacerProps, type SpecIdCandidate, type SpecIssue, Spinner, type SpinnerProps, StatCard, type StatCardProps, Switch, type SwitchProps, type TabItem, Table, type TableColumn, type TableProps, Tabs, type TabsProps, Tag, type TagProps, Text, type TextPreset, type TextProps, Textarea, type TextareaProps, TimePickerProps, Toast, type ToastProps, Tooltip, type TooltipProps, boxed, cascadingValuePaths, cellRenderer, cleanSearchValues, createRegistry, createSearchInvalidator, defaultAdapter, defaultRegistry, getOverlayRoot, imageRenderer, includesLooseSearch, isValidSpecId, joinMultiValue, loadOptionalModule, mapActions, mapCardRows, mapColumns, mapGridCard, mapViews, matchesCondition, normalizePageSizes, normalizeSearchText, patternSpecCandidates, resolvePatternSpec, searchFieldKeys, searchValuesFromParams, sortableDropIndex, sortableMove, splitMultiValue, summaryParams, useOverlayLayer, useRemoteSearchPage, useRemoteSearchSummary, useSduiAssetResolver, useSduiCan, useSduiDispatch, useSduiRuntime, useSduiSandbox, useSearchFetcher, validateSpec, withProps };
|
package/dist/index.js
CHANGED
|
@@ -11,9 +11,9 @@ import { parseYmd, YMD_RE, TimePicker, DateRangePicker, DatePicker } from './chu
|
|
|
11
11
|
export { DatePicker, DateRangePicker, TimePicker } from './chunk-RWSH2MBU.js';
|
|
12
12
|
import { HoistedStyle } from './chunk-RIZRM7OO.js';
|
|
13
13
|
export { OverlayContainerContext, OverlayLayer, getOverlayRoot, useOverlayLayer } from './chunk-XQPTSEJC.js';
|
|
14
|
-
import { DEV,
|
|
14
|
+
import { DEV, useSduiAdapter, hostFetchOf, isSafeNavigationTarget, useSduiSandbox, resolveAdapter, assetResolverOf, SduiAdapterContext } from './chunk-KO6OEY3G.js';
|
|
15
15
|
export { defaultAdapter, useSduiAssetResolver, useSduiSandbox } from './chunk-KO6OEY3G.js';
|
|
16
|
-
import { EmptyState, Button, Checkbox, SegmentedControl, Spinner, Select, Pagination, fieldOf, Icon, Card, Badge, ProgressBar, Tag, Toast, Textarea,
|
|
16
|
+
import { EmptyState, Button, Checkbox, Tabs, SegmentedControl, Spinner, Select, Pagination, fieldOf, StatCard, Icon, Card, Badge, ProgressBar, Tag, Toast, Textarea, Table, Switch, Input, IconButton, Field, Alert, warnOnce, isPlainObject, CALC_OPS, evaluateCalc, ICON_NODES, toNumber } from './chunk-RNOUXUBO.js';
|
|
17
17
|
export { Alert, Avatar, Badge, Breadcrumb, Button, CALC_OPS, Card, Checkbox, Dialog, EmptyState, Field, Icon, IconButton, Input, Pagination, ProgressBar, Radio, SegmentedControl, Select, SidebarNav, Spinner, StatCard, Switch, Table, Tabs, Tag, Textarea, Toast, Tooltip } from './chunk-RNOUXUBO.js';
|
|
18
18
|
import { boxed, LAYOUT_CSS, childLayoutFrom, CHILD_LAYOUT_PROPS } from './chunk-5WW4MBRO.js';
|
|
19
19
|
export { CHILD_LAYOUT_PROPS, LAYOUT_CSS, boxed, childLayoutFrom, columnsClass, containerLayoutStyle, joinClass, mergeStyle, typographyStyle } from './chunk-5WW4MBRO.js';
|
|
@@ -471,6 +471,78 @@ function useRemoteSearchPage(endpoint, params) {
|
|
|
471
471
|
const reload = useCallback(() => setReloadKey((value) => value + 1), []);
|
|
472
472
|
return { page, isLoading, error, reload };
|
|
473
473
|
}
|
|
474
|
+
function useRemoteSearchSummary(endpoint, params) {
|
|
475
|
+
const adapter = useSduiAdapter();
|
|
476
|
+
const invalidator = useContext(SearchInvalidationContext);
|
|
477
|
+
const [values, setValues] = useState(null);
|
|
478
|
+
const [isLoading, setIsLoading] = useState(endpoint !== null);
|
|
479
|
+
const [error, setError] = useState(null);
|
|
480
|
+
const [reloadKey, setReloadKey] = useState(0);
|
|
481
|
+
useEffect(() => {
|
|
482
|
+
if (!invalidator || endpoint === null) return void 0;
|
|
483
|
+
return invalidator.subscribe(endpoint, () => setReloadKey((value) => value + 1));
|
|
484
|
+
}, [invalidator, endpoint]);
|
|
485
|
+
const query = params.toString();
|
|
486
|
+
const hostFetchRef = useRef(hostFetchOf(adapter));
|
|
487
|
+
hostFetchRef.current = hostFetchOf(adapter);
|
|
488
|
+
useEffect(() => {
|
|
489
|
+
if (endpoint === null) return void 0;
|
|
490
|
+
const controller = new AbortController();
|
|
491
|
+
let alive = true;
|
|
492
|
+
const url = searchUrl(endpoint, new URLSearchParams(query));
|
|
493
|
+
setIsLoading(true);
|
|
494
|
+
const hostFetch = hostFetchRef.current;
|
|
495
|
+
const request = hostFetch ? hostFetch(url, { method: "GET", signal: controller.signal }) : fetch(url, { headers: { accept: "application/json" }, credentials: "same-origin", signal: controller.signal }).then(
|
|
496
|
+
async (response) => {
|
|
497
|
+
const body = await response.json().catch(() => null);
|
|
498
|
+
if (!response.ok) throw new Error(body?.message ?? `\uD569\uACC4\uB97C \uBD88\uB7EC\uC624\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4 (${response.status})`);
|
|
499
|
+
return body;
|
|
500
|
+
}
|
|
501
|
+
);
|
|
502
|
+
request.then(
|
|
503
|
+
(body) => {
|
|
504
|
+
if (!alive) return;
|
|
505
|
+
setValues(body && typeof body === "object" && !Array.isArray(body) ? body : null);
|
|
506
|
+
setError(null);
|
|
507
|
+
setIsLoading(false);
|
|
508
|
+
},
|
|
509
|
+
(cause) => {
|
|
510
|
+
if (!alive || controller.signal.aborted) return;
|
|
511
|
+
setError(cause instanceof Error ? cause : new Error("\uD569\uACC4\uB97C \uBD88\uB7EC\uC624\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4"));
|
|
512
|
+
setIsLoading(false);
|
|
513
|
+
}
|
|
514
|
+
);
|
|
515
|
+
return () => {
|
|
516
|
+
alive = false;
|
|
517
|
+
controller.abort();
|
|
518
|
+
};
|
|
519
|
+
}, [endpoint, query, reloadKey]);
|
|
520
|
+
return { values, isLoading, error };
|
|
521
|
+
}
|
|
522
|
+
function summaryParams(params) {
|
|
523
|
+
const next = new URLSearchParams(params);
|
|
524
|
+
next.delete("page");
|
|
525
|
+
next.delete("limit");
|
|
526
|
+
return next;
|
|
527
|
+
}
|
|
528
|
+
function plainValue(value) {
|
|
529
|
+
if (value === null || value === void 0 || value === "") return "\u2014";
|
|
530
|
+
if (typeof value === "number") return value.toLocaleString("ko-KR");
|
|
531
|
+
if (typeof value === "string" && /^-?\d+(\.\d+)?$/.test(value)) return Number(value).toLocaleString("ko-KR");
|
|
532
|
+
return String(value);
|
|
533
|
+
}
|
|
534
|
+
function SearchSummaryCards({ items, values, dispatch }) {
|
|
535
|
+
const list = Array.isArray(items) ? items.filter((item) => item && typeof item.key === "string") : [];
|
|
536
|
+
if (list.length === 0) return null;
|
|
537
|
+
const columns = Math.min(Math.max(list.length, 2), 4);
|
|
538
|
+
const row = values ?? {};
|
|
539
|
+
return /* @__PURE__ */ jsx("div", { className: `wp-grid wp-grid--${columns}`, "aria-label": "\uAC80\uC0C9 \uACB0\uACFC \uD569\uACC4", children: list.map((item) => {
|
|
540
|
+
const render = item.cell ? cellRenderer(item.cell, item.key, dispatch) : void 0;
|
|
541
|
+
const raw = values ? fieldOf(row, item.key) : void 0;
|
|
542
|
+
const value = values && render && raw !== void 0 && raw !== null ? render(row) : plainValue(raw);
|
|
543
|
+
return /* @__PURE__ */ jsx(StatCard, { size: "sm", label: item.label, icon: item.icon, value, unit: item.unit }, item.key);
|
|
544
|
+
}) });
|
|
545
|
+
}
|
|
474
546
|
var OVERSCAN = 10;
|
|
475
547
|
var CLIP_CSS = `.wp-table--clip tbody td{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}`;
|
|
476
548
|
function ResultTable({
|
|
@@ -606,6 +678,8 @@ function SearchResults({
|
|
|
606
678
|
gridConfig,
|
|
607
679
|
leftFilters = EMPTY_FILTERS,
|
|
608
680
|
rightFilters = EMPTY_FILTERS,
|
|
681
|
+
tabs,
|
|
682
|
+
summary,
|
|
609
683
|
initialView = "list",
|
|
610
684
|
views,
|
|
611
685
|
pageSizes,
|
|
@@ -668,8 +742,12 @@ function SearchResults({
|
|
|
668
742
|
const values = splitMultiValue(searchParams.get(filter.key) ?? "");
|
|
669
743
|
if (values.length > 0) entries.push({ key: filter.key, values });
|
|
670
744
|
}
|
|
745
|
+
if (tabs && typeof tabs.key === "string") {
|
|
746
|
+
const values = splitMultiValue(searchParams.get(tabs.key) ?? "");
|
|
747
|
+
if (values.length > 0) entries.push({ key: tabs.key, values });
|
|
748
|
+
}
|
|
671
749
|
return entries;
|
|
672
|
-
}, [leftFilters, rightFilters, searchParams]);
|
|
750
|
+
}, [leftFilters, rightFilters, tabs, searchParams]);
|
|
673
751
|
const hasAllRows = item.data.length >= item.total;
|
|
674
752
|
const processed = useMemo(() => {
|
|
675
753
|
const cell = (row, key) => fieldOf(row, key);
|
|
@@ -708,7 +786,8 @@ function SearchResults({
|
|
|
708
786
|
if (max !== null) rows = rows.filter((row) => (numericValue(cell(row, field.key)) ?? Infinity) <= max);
|
|
709
787
|
} else {
|
|
710
788
|
const keyword = advancedValues[field.key];
|
|
711
|
-
const
|
|
789
|
+
const suffix = ["_contains", "Contains"].find((s) => field.key.endsWith(s));
|
|
790
|
+
const baseKey = suffix ? field.key.slice(0, -suffix.length) : field.key;
|
|
712
791
|
if (keyword) rows = rows.filter((row) => includesLooseSearch(String(cell(row, baseKey) ?? ""), keyword));
|
|
713
792
|
}
|
|
714
793
|
}
|
|
@@ -804,6 +883,16 @@ function SearchResults({
|
|
|
804
883
|
};
|
|
805
884
|
const empty = /* @__PURE__ */ jsx(ResultEmptyState, { title });
|
|
806
885
|
return /* @__PURE__ */ jsxs("div", { className: ["wp-col", className].filter(Boolean).join(" "), style, "aria-label": title, children: [
|
|
886
|
+
summary ?? null,
|
|
887
|
+
tabs && Array.isArray(tabs.items) && tabs.items.length > 0 ? /* @__PURE__ */ jsx(
|
|
888
|
+
Tabs,
|
|
889
|
+
{
|
|
890
|
+
"aria-label": `${title} \uAD6C\uBD84`,
|
|
891
|
+
items: tabs.items.map((tab) => ({ value: tab.value ?? "", label: tab.label, icon: tab.icon })),
|
|
892
|
+
value: searchParams.get(tabs.key) ?? "",
|
|
893
|
+
onChange: (value) => updateParams({ [tabs.key]: value || null, page: null })
|
|
894
|
+
}
|
|
895
|
+
) : null,
|
|
807
896
|
!hideHeader ? /* @__PURE__ */ jsxs("div", { className: "wp-row wp-row--between", style: { flexWrap: "wrap" }, children: [
|
|
808
897
|
/* @__PURE__ */ jsxs("span", { className: "wp-caption", children: [
|
|
809
898
|
"\uCD1D ",
|
|
@@ -1140,6 +1229,7 @@ function SduiSearchResultsImpl({
|
|
|
1140
1229
|
fields,
|
|
1141
1230
|
leftFilters,
|
|
1142
1231
|
rightFilters,
|
|
1232
|
+
tabs,
|
|
1143
1233
|
gridCard,
|
|
1144
1234
|
actions,
|
|
1145
1235
|
initialView,
|
|
@@ -1164,6 +1254,7 @@ function SduiSearchResultsImpl({
|
|
|
1164
1254
|
gridConfig: mapGridCard(gridCard, dispatch),
|
|
1165
1255
|
leftFilters,
|
|
1166
1256
|
rightFilters,
|
|
1257
|
+
tabs,
|
|
1167
1258
|
actions: mapActions(actions, dispatch),
|
|
1168
1259
|
initialView,
|
|
1169
1260
|
views: mapViews(views, gridCard, disableGrid, disableList),
|
|
@@ -1187,6 +1278,7 @@ function RemoteSearchResultsImpl({
|
|
|
1187
1278
|
fields,
|
|
1188
1279
|
leftFilters,
|
|
1189
1280
|
rightFilters,
|
|
1281
|
+
tabs,
|
|
1190
1282
|
gridCard,
|
|
1191
1283
|
actions,
|
|
1192
1284
|
initialView,
|
|
@@ -1200,7 +1292,8 @@ function RemoteSearchResultsImpl({
|
|
|
1200
1292
|
virtual,
|
|
1201
1293
|
pageSize,
|
|
1202
1294
|
searchParams: controlledParams,
|
|
1203
|
-
onParamsChange
|
|
1295
|
+
onParamsChange,
|
|
1296
|
+
summary
|
|
1204
1297
|
}) {
|
|
1205
1298
|
const dispatch = useSduiDispatch();
|
|
1206
1299
|
const defaultPageSize = normalizePageSizes(pageSizes)?.[0] ?? 10;
|
|
@@ -1221,6 +1314,11 @@ function RemoteSearchResultsImpl({
|
|
|
1221
1314
|
return next;
|
|
1222
1315
|
}, [params, defaultPageSize]);
|
|
1223
1316
|
const { page, isLoading, error, reload } = useRemoteSearchPage(endpoint, query);
|
|
1317
|
+
const summaryQuery = useMemo(() => summaryParams(params), [params]);
|
|
1318
|
+
const summaryState = useRemoteSearchSummary(
|
|
1319
|
+
summary && typeof summary.endpoint === "string" ? summary.endpoint : null,
|
|
1320
|
+
summaryQuery
|
|
1321
|
+
);
|
|
1224
1322
|
if (error && page.data.length === 0) {
|
|
1225
1323
|
return /* @__PURE__ */ jsx(
|
|
1226
1324
|
EmptyState,
|
|
@@ -1241,6 +1339,7 @@ function RemoteSearchResultsImpl({
|
|
|
1241
1339
|
gridConfig: mapGridCard(gridCard, dispatch),
|
|
1242
1340
|
leftFilters,
|
|
1243
1341
|
rightFilters,
|
|
1342
|
+
tabs,
|
|
1244
1343
|
actions: mapActions(actions, dispatch),
|
|
1245
1344
|
initialView,
|
|
1246
1345
|
views: mapViews(views, gridCard, disableGrid, disableList),
|
|
@@ -1252,6 +1351,7 @@ function RemoteSearchResultsImpl({
|
|
|
1252
1351
|
headerActions,
|
|
1253
1352
|
virtual,
|
|
1254
1353
|
isLoading,
|
|
1354
|
+
summary: summary ? /* @__PURE__ */ jsx(SearchSummaryCards, { items: summary.items, values: summaryState.values, dispatch }) : void 0,
|
|
1255
1355
|
onRowClick: rowClick ? (row) => toList(rowClick).forEach((a) => dispatch(a, row)) : void 0,
|
|
1256
1356
|
searchParams: params,
|
|
1257
1357
|
onParamsChange: handleParamsChange
|
|
@@ -3119,4 +3219,4 @@ async function resolvePatternSpec(id, load) {
|
|
|
3119
3219
|
// src/icon-names.ts
|
|
3120
3220
|
var ICON_NAMES = Object.keys(ICON_NODES);
|
|
3121
3221
|
|
|
3122
|
-
export { Can, ICON_NAMES, NodeErrorBoundary, RemoteSearchResults, ResultTable, SduiForm, SduiRenderer, SduiSearchDataProvider, SduiSearchInvalidationProvider, SduiSearchResults, SearchResults, SortHandle, SortableList, cellRenderer, createRegistry, createSearchInvalidator, defaultRegistry, imageRenderer, isValidSpecId, mapActions, mapCardRows, mapColumns, mapGridCard, mapViews, matchesCondition, normalizePageSizes, patternSpecCandidates, resolvePatternSpec, sortableDropIndex, sortableMove, useRemoteSearchPage, useSduiRuntime, useSearchFetcher, validateSpec, withProps };
|
|
3222
|
+
export { Can, ICON_NAMES, NodeErrorBoundary, RemoteSearchResults, ResultTable, SduiForm, SduiRenderer, SduiSearchDataProvider, SduiSearchInvalidationProvider, SduiSearchResults, SearchResults, SearchSummaryCards, SortHandle, SortableList, cellRenderer, createRegistry, createSearchInvalidator, defaultRegistry, imageRenderer, isValidSpecId, mapActions, mapCardRows, mapColumns, mapGridCard, mapViews, matchesCondition, normalizePageSizes, patternSpecCandidates, resolvePatternSpec, sortableDropIndex, sortableMove, summaryParams, useRemoteSearchPage, useRemoteSearchSummary, useSduiRuntime, useSearchFetcher, validateSpec, withProps };
|
package/dist/meta.js
CHANGED
|
@@ -2174,6 +2174,27 @@ var searchCommonProps = [
|
|
|
2174
2174
|
{ name: "options", kind: "array", label: "\uC635\uC158", description: "{ key, label, value }" }
|
|
2175
2175
|
]
|
|
2176
2176
|
},
|
|
2177
|
+
{
|
|
2178
|
+
name: "tabs",
|
|
2179
|
+
kind: "object",
|
|
2180
|
+
label: "\uAD6C\uBD84 \uD0ED",
|
|
2181
|
+
description: "\uBAA9\uB85D \uB9E8 \uC704(\uD234\uBC14 \uC704)\uC758 \uD0ED. \uACE0\uB978 \uD0ED\uC758 value\uAC00 key \uD30C\uB77C\uBBF8\uD130\uAC00 \uB418\uACE0 \uBE48 value \uD0ED\uC740 \uD30C\uB77C\uBBF8\uD130\uB97C \uC9C0\uC6B4\uB2E4(= \uC804\uCCB4). value\uC5D0 \uC27C\uD45C\uB97C \uB123\uC73C\uBA74 \uC5EC\uB7EC \uAC12 \uC911 \uD558\uB098. \uD0ED\uC744 \uBC14\uAFB8\uBA74 1\uD398\uC774\uC9C0\uB85C \uB3CC\uC544\uAC04\uB2E4.",
|
|
2182
|
+
group: "data",
|
|
2183
|
+
fields: [
|
|
2184
|
+
{ name: "key", kind: "string", label: "\uCFFC\uB9AC \uD0A4", required: true },
|
|
2185
|
+
{
|
|
2186
|
+
name: "items",
|
|
2187
|
+
kind: "array",
|
|
2188
|
+
label: "\uD0ED",
|
|
2189
|
+
required: true,
|
|
2190
|
+
item: [
|
|
2191
|
+
{ name: "value", kind: "string", label: "\uAC12", description: "\uBE48 \uBB38\uC790\uC5F4 = \uC804\uCCB4", required: true },
|
|
2192
|
+
{ name: "label", kind: "string", label: "\uB77C\uBCA8", required: true },
|
|
2193
|
+
{ name: "icon", kind: "icon", label: "\uC544\uC774\uCF58" }
|
|
2194
|
+
]
|
|
2195
|
+
}
|
|
2196
|
+
]
|
|
2197
|
+
},
|
|
2177
2198
|
{
|
|
2178
2199
|
name: "gridCard",
|
|
2179
2200
|
kind: "object",
|
|
@@ -2360,6 +2381,35 @@ var RemoteSearchResultsMeta = {
|
|
|
2360
2381
|
group: "data"
|
|
2361
2382
|
},
|
|
2362
2383
|
{ name: "pageSize", kind: "number", label: "\uD398\uC774\uC9C0\uB2F9 \uD589 \uC218", default: 10, group: "data" },
|
|
2384
|
+
{
|
|
2385
|
+
name: "summary",
|
|
2386
|
+
kind: "object",
|
|
2387
|
+
label: "\uD569\uACC4 \uCE78",
|
|
2388
|
+
description: "\uD0ED \uC704 \uC22B\uC790 \uCE74\uB4DC. \uBAA9\uB85D\uACFC \uAC19\uC740 \uCFFC\uB9AC(page/limit \uC81C\uC678)\uB85C endpoint\uB97C \uC870\uD68C\uD574 \uC751\uB2F5 \uAC1D\uCCB4\uC758 items[].key \uAC12\uC744 \uBCF4\uC778\uB2E4 \u2014 \uAC80\uC0C9\xB7\uC0C1\uC138\uAC80\uC0C9\xB7\uD0ED\uC744 \uB530\uB77C \uBC14\uB010\uB2E4.",
|
|
2389
|
+
group: "data",
|
|
2390
|
+
fields: [
|
|
2391
|
+
{ name: "endpoint", kind: "string", label: "\uD569\uACC4 endpoint", required: true },
|
|
2392
|
+
{
|
|
2393
|
+
name: "items",
|
|
2394
|
+
kind: "array",
|
|
2395
|
+
label: "\uCE78",
|
|
2396
|
+
required: true,
|
|
2397
|
+
item: [
|
|
2398
|
+
{ name: "key", kind: "string", label: "\uC751\uB2F5 \uD544\uB4DC", required: true },
|
|
2399
|
+
{ name: "label", kind: "string", label: "\uB77C\uBCA8", required: true },
|
|
2400
|
+
{ name: "unit", kind: "string", label: "\uB2E8\uC704" },
|
|
2401
|
+
{ name: "icon", kind: "icon", label: "\uC544\uC774\uCF58" },
|
|
2402
|
+
{
|
|
2403
|
+
name: "cell",
|
|
2404
|
+
kind: "object",
|
|
2405
|
+
label: "\uAC12 \uD45C\uD604",
|
|
2406
|
+
description: "\uCEEC\uB7FC \uC140\uACFC \uAC19\uC740 \uC5B4\uD718. \uC0DD\uB7B5\uD558\uBA74 \uC22B\uC790\uB294 \uCC9C \uB2E8\uC704 \uAD6C\uBD84.",
|
|
2407
|
+
fields: searchCellFields
|
|
2408
|
+
}
|
|
2409
|
+
]
|
|
2410
|
+
}
|
|
2411
|
+
]
|
|
2412
|
+
},
|
|
2363
2413
|
...searchCommonProps
|
|
2364
2414
|
],
|
|
2365
2415
|
slots: searchSlots,
|