mig-schema-table 3.0.63 → 3.0.65
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/SchemaTable/{Th → SchemaTableTh}/index.d.ts +4 -4
- package/dist/SchemaTable/SchemaTableTh/index.js +85 -0
- package/dist/SchemaTable/{SchemaColumnFilterPopover/FilterFormComponent → SchemaTableThMenu/FilterMenuComponent}/index.d.ts +3 -3
- package/dist/SchemaTable/SchemaTableThMenu/FilterMenuComponent/index.js +107 -0
- package/dist/SchemaTable/SchemaTableThMenu/index.d.ts +23 -0
- package/dist/SchemaTable/SchemaTableThMenu/index.js +54 -0
- package/dist/SchemaTable/index.d.ts +1 -1
- package/dist/SchemaTable/index.js +40 -31
- package/dist/inc/data.js +28 -2
- package/dist/index.css +25 -55
- package/dist/types.d.ts +2 -2
- package/package.json +1 -1
- package/dist/SchemaTable/SchemaColumnFilterPopover/FilterFormComponent/index.js +0 -84
- package/dist/SchemaTable/SchemaColumnFilterPopover/index.d.ts +0 -20
- package/dist/SchemaTable/SchemaColumnFilterPopover/index.js +0 -38
- package/dist/SchemaTable/Th/index.js +0 -95
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { oas31 } from "openapi3-ts";
|
|
2
2
|
import React, { CSSProperties, Dispatch, SetStateAction } from "react";
|
|
3
3
|
import { IColumnConfig } from "../../types";
|
|
4
|
-
import
|
|
4
|
+
import "./index.scss";
|
|
5
|
+
import { ISchemaTableThMenuConfig } from "../SchemaTableThMenu";
|
|
5
6
|
export declare enum EColumnFilterStatus {
|
|
6
7
|
UNAVAILABLE = "UNAVAILABLE",
|
|
7
8
|
AVAILABLE = "AVAILABLE",
|
|
@@ -9,7 +10,6 @@ export declare enum EColumnFilterStatus {
|
|
|
9
10
|
}
|
|
10
11
|
interface IThProps {
|
|
11
12
|
columnFilterStatus: EColumnFilterStatus;
|
|
12
|
-
disableColumnFilter: (propName: string) => void;
|
|
13
13
|
isAllChecked?: boolean;
|
|
14
14
|
isSortable: boolean;
|
|
15
15
|
numberOfSelectedRows?: number;
|
|
@@ -18,11 +18,11 @@ interface IThProps {
|
|
|
18
18
|
propIsRequired: boolean;
|
|
19
19
|
propName: string;
|
|
20
20
|
schema?: oas31.SchemaObject;
|
|
21
|
-
|
|
21
|
+
setMenuConfig: Dispatch<SetStateAction<ISchemaTableThMenuConfig | undefined>>;
|
|
22
22
|
setSortAsc: Dispatch<SetStateAction<boolean>>;
|
|
23
23
|
setSortColumn: Dispatch<SetStateAction<string>>;
|
|
24
24
|
sortAsc?: boolean;
|
|
25
25
|
style: CSSProperties;
|
|
26
26
|
}
|
|
27
|
-
declare const _default: ({ columnFilterStatus,
|
|
27
|
+
declare const _default: ({ columnFilterStatus, isAllChecked, isSortable, numberOfSelectedRows, onSelectAllIndexesHandler, propConfig, propIsRequired, propName, schema, setMenuConfig, setSortAsc, setSortColumn, sortAsc, style, }: IThProps) => import("react/jsx-runtime").JSX.Element;
|
|
28
28
|
export default _default;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { t, uncamel } from "../../inc/string";
|
|
4
|
+
import { SELECT_ALL_COLUMN_NAME } from "../constants";
|
|
5
|
+
import { timeZone } from "../../inc/date";
|
|
6
|
+
import "./index.scss";
|
|
7
|
+
export var EColumnFilterStatus;
|
|
8
|
+
(function (EColumnFilterStatus) {
|
|
9
|
+
EColumnFilterStatus["UNAVAILABLE"] = "UNAVAILABLE";
|
|
10
|
+
EColumnFilterStatus["AVAILABLE"] = "AVAILABLE";
|
|
11
|
+
EColumnFilterStatus["ACTIVE"] = "ACTIVE";
|
|
12
|
+
})(EColumnFilterStatus || (EColumnFilterStatus = {}));
|
|
13
|
+
const SchemaTableTh = ({ columnFilterStatus, isAllChecked, isSortable, numberOfSelectedRows, onSelectAllIndexesHandler, propConfig, propIsRequired, propName, schema, setMenuConfig, setSortAsc, setSortColumn, sortAsc, style, }) => {
|
|
14
|
+
const classNames = [
|
|
15
|
+
`schema-table-th`,
|
|
16
|
+
`schema-table-th--filter-${columnFilterStatus}`,
|
|
17
|
+
];
|
|
18
|
+
classNames.push(isSortable ? "schema-table-th--sortable" : "schema-table-th--unsortable");
|
|
19
|
+
if (sortAsc !== undefined) {
|
|
20
|
+
classNames.push("schema-table-th--sorted");
|
|
21
|
+
}
|
|
22
|
+
const onLabelClick = React.useCallback(() => {
|
|
23
|
+
if (sortAsc === undefined) {
|
|
24
|
+
setSortColumn(propName);
|
|
25
|
+
setSortAsc(!(propConfig === null || propConfig === void 0 ? void 0 : propConfig.defaultSortDesc));
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
setSortAsc((sortAsc) => !sortAsc);
|
|
29
|
+
}, [
|
|
30
|
+
propConfig === null || propConfig === void 0 ? void 0 : propConfig.defaultSortDesc,
|
|
31
|
+
propName,
|
|
32
|
+
setSortAsc,
|
|
33
|
+
setSortColumn,
|
|
34
|
+
sortAsc,
|
|
35
|
+
]);
|
|
36
|
+
const onTriggerClick = React.useCallback((e) => {
|
|
37
|
+
const referenceElement = e.currentTarget;
|
|
38
|
+
setMenuConfig((menuConfig) => {
|
|
39
|
+
if ((menuConfig === null || menuConfig === void 0 ? void 0 : menuConfig.propName) === propName) {
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
propConfig,
|
|
44
|
+
propIsRequired,
|
|
45
|
+
propName,
|
|
46
|
+
referenceElement,
|
|
47
|
+
};
|
|
48
|
+
});
|
|
49
|
+
}, [propConfig, propIsRequired, propName, setMenuConfig]);
|
|
50
|
+
const labelBody = React.useMemo(() => {
|
|
51
|
+
if ((propConfig === null || propConfig === void 0 ? void 0 : propConfig.title) !== undefined) {
|
|
52
|
+
return propConfig.title;
|
|
53
|
+
}
|
|
54
|
+
if ((schema === null || schema === void 0 ? void 0 : schema.format) &&
|
|
55
|
+
schema.format.startsWith("date") &&
|
|
56
|
+
(propConfig === null || propConfig === void 0 ? void 0 : propConfig.showTimezones) !== false) {
|
|
57
|
+
return `${uncamel(propName)} (${t(timeZone)})`;
|
|
58
|
+
}
|
|
59
|
+
return uncamel(propName);
|
|
60
|
+
}, [propConfig, propName, schema === null || schema === void 0 ? void 0 : schema.format]);
|
|
61
|
+
if (propName === SELECT_ALL_COLUMN_NAME) {
|
|
62
|
+
return (_jsx("div", Object.assign({ style: style, className: classNames.join(" ") }, { children: _jsx("div", Object.assign({ style: {
|
|
63
|
+
width: "100%",
|
|
64
|
+
textAlign: "center",
|
|
65
|
+
}, title: `${numberOfSelectedRows || 0} selected` }, { children: _jsx("input", { type: "checkbox", checked: isAllChecked, onChange: onSelectAllIndexesHandler }) })) })));
|
|
66
|
+
}
|
|
67
|
+
if (!schema && !(propConfig === null || propConfig === void 0 ? void 0 : propConfig.renderData) && !(propConfig === null || propConfig === void 0 ? void 0 : propConfig.renderCell)) {
|
|
68
|
+
return _jsx("div", { style: style, className: classNames.join(" ") });
|
|
69
|
+
}
|
|
70
|
+
switch (schema === null || schema === void 0 ? void 0 : schema.type) {
|
|
71
|
+
case "boolean":
|
|
72
|
+
classNames.push(`text-${(propConfig === null || propConfig === void 0 ? void 0 : propConfig.align) || "center"}`, `justify-content-${(propConfig === null || propConfig === void 0 ? void 0 : propConfig.align) || "center"}`);
|
|
73
|
+
break;
|
|
74
|
+
case "integer":
|
|
75
|
+
case "number":
|
|
76
|
+
classNames.push(`text-${(propConfig === null || propConfig === void 0 ? void 0 : propConfig.align) || "end"}`, `justify-content-${(propConfig === null || propConfig === void 0 ? void 0 : propConfig.align) || "end"}`);
|
|
77
|
+
break;
|
|
78
|
+
default:
|
|
79
|
+
if (propConfig === null || propConfig === void 0 ? void 0 : propConfig.align) {
|
|
80
|
+
classNames.push(`text-${propConfig.align}`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return (_jsxs("div", Object.assign({ style: style, className: classNames.join(" ") }, { children: [_jsxs("div", Object.assign({ className: "schema-table-th__label-body", style: { lineHeight: "44px" }, onClick: onLabelClick }, { children: [_jsx("span", Object.assign({ className: "schema-table-th__label-body-text" }, { children: labelBody })), sortAsc === undefined ? null : (_jsx("span", Object.assign({ className: "schema-table-th__sort-icon" }, { children: sortAsc ? "↓" : "↑" })))] })), _jsx("button", Object.assign({ className: "schema-table-th__trigger-el", onClick: onTriggerClick }, { children: "\u2304" }))] })));
|
|
84
|
+
};
|
|
85
|
+
export default React.memo(SchemaTableTh);
|
|
@@ -2,14 +2,14 @@ import React from "react";
|
|
|
2
2
|
import { oas31 } from "openapi3-ts";
|
|
3
3
|
import { TColumnFilterValue } from "../../index";
|
|
4
4
|
import { IColumnConfig } from "../../../types";
|
|
5
|
-
export interface
|
|
5
|
+
export interface IFilterMenuComponentProps {
|
|
6
6
|
columnFilterValue: TColumnFilterValue;
|
|
7
|
-
onChange: (newValue
|
|
7
|
+
onChange: (newValue: TColumnFilterValue | undefined, persistState: boolean) => void;
|
|
8
8
|
onInputKeyDown: (e: React.KeyboardEvent) => void;
|
|
9
9
|
propConfig?: IColumnConfig<any>;
|
|
10
10
|
propIsRequired: boolean;
|
|
11
11
|
propName: string;
|
|
12
12
|
propSchema?: oas31.SchemaObject;
|
|
13
13
|
}
|
|
14
|
-
declare const _default: React.MemoExoticComponent<({ columnFilterValue, onChange, onInputKeyDown, propConfig, propIsRequired, propName, propSchema, }:
|
|
14
|
+
declare const _default: React.MemoExoticComponent<({ columnFilterValue, onChange, onInputKeyDown, propConfig, propIsRequired, propName, propSchema, }: IFilterMenuComponentProps) => import("react/jsx-runtime").JSX.Element>;
|
|
15
15
|
export default _default;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
2
|
+
var t = {};
|
|
3
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
4
|
+
t[p] = s[p];
|
|
5
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
6
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
7
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
8
|
+
t[p[i]] = s[p[i]];
|
|
9
|
+
}
|
|
10
|
+
return t;
|
|
11
|
+
};
|
|
12
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
13
|
+
import React from "react";
|
|
14
|
+
import { t } from "../../../inc/string";
|
|
15
|
+
import { DEFAULT_DATE_FORMAT, DEFAULT_DATE_TIME_FORMAT, } from "../../../inc/constant";
|
|
16
|
+
import DatePicker from "react-datepicker";
|
|
17
|
+
import nl from "date-fns/locale/nl";
|
|
18
|
+
import { endOfDay } from "date-fns";
|
|
19
|
+
const FilterMenuComponent = ({ columnFilterValue, onChange, onInputKeyDown, propConfig, propIsRequired, propName, propSchema, }) => {
|
|
20
|
+
const { type, format, minimum, maximum } = propSchema || {};
|
|
21
|
+
const value = columnFilterValue;
|
|
22
|
+
switch (type) {
|
|
23
|
+
case "integer":
|
|
24
|
+
return (_jsx("ol", Object.assign({ className: "schema-table-menu schema-table-th-menu__filter-menu-component" }, { children: _jsx("li", { children: _jsx("input", { autoFocus: true, className: "form-control", type: "number", value: (value || ""), "data-prop-name": propName, onChange: (e) => {
|
|
25
|
+
onChange(e.currentTarget.value === ""
|
|
26
|
+
? undefined
|
|
27
|
+
: parseInt(e.currentTarget.value), false);
|
|
28
|
+
}, onBlur: (e) => {
|
|
29
|
+
onChange(e.currentTarget.value === ""
|
|
30
|
+
? undefined
|
|
31
|
+
: parseInt(e.currentTarget.value), true);
|
|
32
|
+
}, onKeyDown: onInputKeyDown, placeholder: `Search ${propName}`, min: minimum, max: maximum }) }) })));
|
|
33
|
+
case "boolean":
|
|
34
|
+
let selectValue = value ? "✓" : "✕";
|
|
35
|
+
if (value === undefined) {
|
|
36
|
+
selectValue = "";
|
|
37
|
+
}
|
|
38
|
+
return (_jsx("ol", Object.assign({ className: "schema-table-menu schema-table-th-menu__filter-menu-component" }, { children: _jsx("li", { children: _jsxs("select", Object.assign({ autoFocus: true, className: "form-select", value: selectValue, "data-prop-name": propName, onChange: (e) => {
|
|
39
|
+
switch (e.currentTarget.value) {
|
|
40
|
+
case "✓":
|
|
41
|
+
onChange(true, true);
|
|
42
|
+
break;
|
|
43
|
+
case "✕":
|
|
44
|
+
onChange(false, true);
|
|
45
|
+
break;
|
|
46
|
+
default:
|
|
47
|
+
onChange(undefined, true);
|
|
48
|
+
}
|
|
49
|
+
} }, { children: [_jsx("option", Object.assign({ value: "" }, { children: "All" }), "all"), ["✓", "✕"].map((optionValue) => (_jsx("option", Object.assign({ value: optionValue }, { children: optionValue }), `column-filter-select-${optionValue}`)))] })) }) })));
|
|
50
|
+
// @ts-ignore
|
|
51
|
+
case "string":
|
|
52
|
+
if (propSchema === null || propSchema === void 0 ? void 0 : propSchema.enum) {
|
|
53
|
+
return (_jsx("ol", Object.assign({ className: "schema-table-menu schema-table-th-menu__filter-menu-component" }, { children: _jsx("li", { children: _jsxs("select", Object.assign({ autoFocus: true, className: "form-select", value: value, "data-prop-name": propName, onChange: (e) => {
|
|
54
|
+
onChange(e.currentTarget.value || undefined, true);
|
|
55
|
+
} }, { children: [_jsx("option", Object.assign({ value: "" }, { children: "All" }), "all"), propSchema.enum.map((name) => {
|
|
56
|
+
const rowName = !(propConfig === null || propConfig === void 0 ? void 0 : propConfig.translation)
|
|
57
|
+
? name
|
|
58
|
+
: t(name, propConfig.translation);
|
|
59
|
+
return (_jsx("option", Object.assign({ value: rowName }, { children: rowName }), `column-filter-select-${rowName}`));
|
|
60
|
+
})] })) }) })));
|
|
61
|
+
}
|
|
62
|
+
if (format === "date-time" || format === "date") {
|
|
63
|
+
const dateFormat = format === "date" ? DEFAULT_DATE_FORMAT : DEFAULT_DATE_TIME_FORMAT;
|
|
64
|
+
const dateRangeValue = (columnFilterValue || {
|
|
65
|
+
from: undefined,
|
|
66
|
+
to: undefined,
|
|
67
|
+
filterEmpty: undefined,
|
|
68
|
+
});
|
|
69
|
+
return (_jsxs("ol", Object.assign({ className: "schema-table-menu schema-table-th-menu__filter-menu-component" }, { children: [propIsRequired ? null : (_jsxs("li", Object.assign({ style: { padding: 8 } }, { children: [_jsxs("label", Object.assign({ className: "d-flex" }, { children: [_jsx("input", { type: "checkbox", className: "m-0 me-1", checked: !!dateRangeValue.filterEmpty, onChange: () => {
|
|
70
|
+
const { filterEmpty } = dateRangeValue, newDateRangeValue = __rest(dateRangeValue, ["filterEmpty"]);
|
|
71
|
+
if (!filterEmpty) {
|
|
72
|
+
newDateRangeValue.filterEmpty = true;
|
|
73
|
+
}
|
|
74
|
+
onChange(Object.keys(newDateRangeValue).length
|
|
75
|
+
? newDateRangeValue
|
|
76
|
+
: undefined, true);
|
|
77
|
+
} }), "Hide empty values"] })), _jsx("hr", {})] }))), _jsxs("li", Object.assign({ style: { padding: 8 } }, { children: [_jsx("label", Object.assign({ style: { width: 120, paddingLeft: 4 } }, { children: "Start date-time" })), _jsx(DatePicker, { dateFormat: dateFormat, "data-prop-name": propName, locale: nl, selected: dateRangeValue.from, onChange: (date) => {
|
|
78
|
+
if (!date && !dateRangeValue.to) {
|
|
79
|
+
onChange(undefined, true);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
if (dateRangeValue.to && date && date > dateRangeValue.to) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
onChange(Object.assign(Object.assign({}, columnFilterValue), { from: date || undefined }), true);
|
|
86
|
+
}, placeholderText: dateFormat, isClearable: true, selectsStart: true, showTimeSelect: format === "date-time", timeIntervals: 15, shouldCloseOnSelect: format === "date" })] })), _jsxs("li", Object.assign({ style: { padding: 8 } }, { children: [_jsx("label", Object.assign({ style: { width: 120, paddingLeft: 4 } }, { children: "End date-time" })), _jsx(DatePicker, { id: "filter-date", dateFormat: dateFormat, "data-prop-name": propName, locale: nl, selectsEnd: true, selected: dateRangeValue.to, onChange: (date) => {
|
|
87
|
+
if (!date && !dateRangeValue.from) {
|
|
88
|
+
onChange(undefined, true);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const to = date ? endOfDay(date) : undefined;
|
|
92
|
+
if (dateRangeValue.from && to && to < dateRangeValue.from) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
onChange(Object.assign(Object.assign({}, columnFilterValue), { to }), true);
|
|
96
|
+
}, placeholderText: dateFormat, isClearable: true, startDate: dateRangeValue.from, endDate: dateRangeValue.to, showTimeSelect: format === "date-time", timeIntervals: 15, shouldCloseOnSelect: format === "date" })] }))] })));
|
|
97
|
+
}
|
|
98
|
+
// falls through
|
|
99
|
+
default:
|
|
100
|
+
return (_jsx("ol", Object.assign({ className: "schema-table-menu schema-table-th-menu__filter-menu-component" }, { children: _jsx("li", { children: _jsx("input", { autoFocus: true, type: "text", className: "form-control", placeholder: `Search ${propName}`, "aria-label": `Search ${propName}`, value: (value || ""), "data-prop-name": propName, onChange: (e) => {
|
|
101
|
+
onChange(e.currentTarget.value || undefined, false);
|
|
102
|
+
}, onKeyDown: onInputKeyDown, onBlur: (e) => {
|
|
103
|
+
onChange(e.currentTarget.value || undefined, true);
|
|
104
|
+
} }) }) })));
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
export default React.memo(FilterMenuComponent);
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import React, { Dispatch, SetStateAction } from "react";
|
|
2
|
+
import { oas31 } from "openapi3-ts";
|
|
3
|
+
import { TColumnFilterValue } from "../index";
|
|
4
|
+
import { IColumnConfig } from "../../types";
|
|
5
|
+
import "./index.scss";
|
|
6
|
+
export interface ISchemaTableThMenuConfig {
|
|
7
|
+
referenceElement: HTMLElement;
|
|
8
|
+
propName: string;
|
|
9
|
+
propConfig?: IColumnConfig<any>;
|
|
10
|
+
propIsRequired: boolean;
|
|
11
|
+
}
|
|
12
|
+
type TSchemaTableThMenuProps = ISchemaTableThMenuConfig & {
|
|
13
|
+
onChange: (newValue: TColumnFilterValue | undefined, persistState: boolean) => void;
|
|
14
|
+
onInputKeyDown: (e: React.KeyboardEvent) => void;
|
|
15
|
+
propIsRequired: boolean;
|
|
16
|
+
propSchema: oas31.SchemaObject;
|
|
17
|
+
setSortColumn: Dispatch<SetStateAction<string>>;
|
|
18
|
+
setSortAsc: Dispatch<SetStateAction<boolean>>;
|
|
19
|
+
value: TColumnFilterValue;
|
|
20
|
+
onClose: (e: MouseEvent | React.MouseEvent) => void;
|
|
21
|
+
};
|
|
22
|
+
declare const _default: React.MemoExoticComponent<({ onChange, onClose, onInputKeyDown, propConfig, propIsRequired, propName, propSchema, referenceElement, setSortAsc, setSortColumn, value, }: TSchemaTableThMenuProps) => import("react/jsx-runtime").JSX.Element>;
|
|
23
|
+
export default _default;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import FilterMenuComponent from "./FilterMenuComponent";
|
|
4
|
+
import { usePopper } from "react-popper";
|
|
5
|
+
import "./index.scss";
|
|
6
|
+
const SchemaTableThMenu = ({ onChange, onClose, onInputKeyDown, propConfig, propIsRequired, propName, propSchema, referenceElement, setSortAsc, setSortColumn, value, }) => {
|
|
7
|
+
const [menu, setMenu] = React.useState(null);
|
|
8
|
+
const [subMenu, setSubMenu] = React.useState(null);
|
|
9
|
+
const [subMenuReferenceElement, setSubMenuReferenceElement] = React.useState(null);
|
|
10
|
+
const menuPopper = usePopper(referenceElement, menu, {
|
|
11
|
+
placement: "bottom-end",
|
|
12
|
+
});
|
|
13
|
+
const subMenuPopper = usePopper(subMenuReferenceElement, subMenu, {
|
|
14
|
+
placement: "right-start",
|
|
15
|
+
});
|
|
16
|
+
React.useEffect(() => {
|
|
17
|
+
const onWindowClick = (e) => {
|
|
18
|
+
if (!menu) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
let parent = e.target;
|
|
22
|
+
while (parent && menu) {
|
|
23
|
+
if (parent === menu || parent === subMenu) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
parent =
|
|
27
|
+
parent.parentNode === window.document ? null : parent.parentNode;
|
|
28
|
+
}
|
|
29
|
+
onClose(e);
|
|
30
|
+
};
|
|
31
|
+
window.addEventListener("click", onWindowClick, { capture: true });
|
|
32
|
+
return () => {
|
|
33
|
+
window.removeEventListener("click", onWindowClick, { capture: true });
|
|
34
|
+
};
|
|
35
|
+
}, [onClose, menu, subMenu]);
|
|
36
|
+
const FilterMenu = (propConfig === null || propConfig === void 0 ? void 0 : propConfig.FilterMenu) || FilterMenuComponent;
|
|
37
|
+
const onSortAscendingClick = React.useCallback((e) => {
|
|
38
|
+
setSortColumn(propName);
|
|
39
|
+
setSortAsc(true);
|
|
40
|
+
onClose(e);
|
|
41
|
+
}, [onClose, propName, setSortAsc, setSortColumn]);
|
|
42
|
+
const onSortDescendingClick = React.useCallback((e) => {
|
|
43
|
+
setSortColumn(propName);
|
|
44
|
+
setSortAsc(false);
|
|
45
|
+
onClose(e);
|
|
46
|
+
}, [onClose, propName, setSortAsc, setSortColumn]);
|
|
47
|
+
const onFilterCheckboxChange = React.useCallback(() => {
|
|
48
|
+
onChange(undefined, true);
|
|
49
|
+
}, [onChange]);
|
|
50
|
+
return (_jsxs(_Fragment, { children: [_jsx("div", Object.assign({ className: "schema-table-th-menu", ref: setMenu, style: menuPopper.styles.popper }, menuPopper.attributes.popper, { children: _jsxs("ol", Object.assign({ className: "schema-table-menu" }, { children: [_jsxs("li", Object.assign({ onClick: onSortAscendingClick, style: { padding: 8 } }, { children: [_jsx("span", Object.assign({ className: "schema-table-th-menu__icon" }, { children: "\u2193" })), " Sort ascending"] })), _jsxs("li", Object.assign({ onClick: onSortDescendingClick, style: { padding: 8 } }, { children: [_jsx("span", Object.assign({ className: "schema-table-th-menu__icon" }, { children: "\u2191" })), " Sort descending"] })), _jsxs("li", Object.assign({ style: { padding: 8 }, onMouseOver: (e) => {
|
|
51
|
+
setSubMenuReferenceElement(e.currentTarget);
|
|
52
|
+
} }, { children: [_jsx("span", Object.assign({ className: "schema-table-th-menu__icon" }, { children: _jsx("input", { type: "checkbox", id: "schema-table-th-menu__filters", checked: value !== undefined, disabled: value === undefined, onChange: onFilterCheckboxChange }) })), _jsx("label", Object.assign({ htmlFor: "schema-table-th-menu__filters" }, { children: "Filters" })), _jsx("div", Object.assign({ className: "schema-table-th-menu__sub-menu-indicator" }, { children: ">" }))] }))] })) })), subMenuReferenceElement ? (_jsx("div", Object.assign({ className: "schema-table-th-menu__sub-menu", ref: setSubMenu, style: subMenuPopper.styles.popper }, subMenuPopper.attributes.popper, { children: _jsx(FilterMenu, { columnFilterValue: value, onChange: onChange, onInputKeyDown: onInputKeyDown, propConfig: propConfig, propIsRequired: propIsRequired, propName: propName, propSchema: propSchema }) }))) : null] }));
|
|
53
|
+
};
|
|
54
|
+
export default React.memo(SchemaTableThMenu);
|
|
@@ -44,7 +44,7 @@ export interface ISchemaTableProps<T> {
|
|
|
44
44
|
export interface IDateColumnFilterValue {
|
|
45
45
|
from?: Date;
|
|
46
46
|
to?: Date;
|
|
47
|
-
filterEmpty?:
|
|
47
|
+
filterEmpty?: true;
|
|
48
48
|
}
|
|
49
49
|
export type TColumnFilterValue = string | number | boolean | IDateColumnFilterValue;
|
|
50
50
|
declare function SchemaTable<T>({ Heading, checkedIndexes, config, customElement, data, defaultColumnFilters, defaultSortAsc, defaultSortColumn, disabledCheckedIndexes, enableAutoFocus, getRowClassName, getRowSelected, isColumnFilterable, isSearchable, isSortable, maxHeight, onCheckedIndexesChange, onRowClick, onRowDoubleClick, rowHeight, schema, searchPlaceholder, style, useFilterStateHash, width, }: ISchemaTableProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
@@ -3,12 +3,12 @@ import React from "react";
|
|
|
3
3
|
import { VariableSizeGrid, VariableSizeList } from "react-window";
|
|
4
4
|
import { localeFormat } from "../inc/date";
|
|
5
5
|
import { t, uncamel } from "../inc/string";
|
|
6
|
-
import Th, { EColumnFilterStatus } from "./Th";
|
|
7
6
|
import { SELECT_ALL_COLUMN_NAME, SELECT_ALL_COLUMN_WIDTH } from "./constants";
|
|
8
7
|
import Td from "./Td";
|
|
9
8
|
import { DEFAULT_DATE_FORMAT, DEFAULT_DATE_TIME_FORMAT } from "../inc/constant";
|
|
10
|
-
import SchemaColumnFilterPopover from "./SchemaColumnFilterPopover";
|
|
11
9
|
import { parseLocationHash, serializeLocationHash } from "../inc/data";
|
|
10
|
+
import SchemaTableTh, { EColumnFilterStatus } from "./SchemaTableTh";
|
|
11
|
+
import SchemaTableThMenu from "./SchemaTableThMenu";
|
|
12
12
|
const startOfTheWorldDate = new Date("1000-01-01 00:00:00Z");
|
|
13
13
|
function getSortByValue(propSchema, propConfig) {
|
|
14
14
|
var _a;
|
|
@@ -27,7 +27,7 @@ function getSortByValue(propSchema, propConfig) {
|
|
|
27
27
|
function SchemaTable({ Heading = VariableSizeList, checkedIndexes, config, customElement, data, defaultColumnFilters = {}, defaultSortAsc = false, defaultSortColumn, disabledCheckedIndexes, enableAutoFocus, getRowClassName, getRowSelected, isColumnFilterable, isSearchable, isSortable, maxHeight, onCheckedIndexesChange, onRowClick, onRowDoubleClick, rowHeight = 36, schema, searchPlaceholder, style, useFilterStateHash, width, }) {
|
|
28
28
|
const [sortColumn, setSortColumn] = React.useState(defaultSortColumn);
|
|
29
29
|
const [sortAsc, setSortAsc] = React.useState(defaultSortAsc);
|
|
30
|
-
const [
|
|
30
|
+
const [schemaTableThMenuConfig, setSchemaTableThMenuConfig] = React.useState();
|
|
31
31
|
const isDataFunction = data instanceof Function;
|
|
32
32
|
const [sourceData, setSourceData] = React.useState(isDataFunction ? undefined : data);
|
|
33
33
|
const [locationHash, setLocationHash] = React.useState(parseLocationHash(window.location.hash));
|
|
@@ -367,27 +367,29 @@ function SchemaTable({ Heading = VariableSizeList, checkedIndexes, config, custo
|
|
|
367
367
|
}
|
|
368
368
|
setSortAsc(x);
|
|
369
369
|
}, [isDataFunction]);
|
|
370
|
-
const
|
|
370
|
+
const ConfiguredSchemaTableTh = React.useCallback(({ style, index }) => {
|
|
371
371
|
const propName = columnNames[index];
|
|
372
372
|
const propSchema = (propName === SELECT_ALL_COLUMN_NAME
|
|
373
373
|
? { type: "boolean" }
|
|
374
374
|
: properties[propName]);
|
|
375
375
|
const propConfig = config ? config[propName] : undefined;
|
|
376
376
|
let columnFilterStatus = isColumnFilterable &&
|
|
377
|
-
(propSchema || (propConfig === null || propConfig === void 0 ? void 0 : propConfig.
|
|
377
|
+
(propSchema || (propConfig === null || propConfig === void 0 ? void 0 : propConfig.FilterMenu)) &&
|
|
378
378
|
(propConfig === null || propConfig === void 0 ? void 0 : propConfig.isFilterable) !== false
|
|
379
379
|
? EColumnFilterStatus.AVAILABLE
|
|
380
380
|
: EColumnFilterStatus.UNAVAILABLE;
|
|
381
381
|
if (columnFilterMap[propName] !== undefined) {
|
|
382
382
|
columnFilterStatus = EColumnFilterStatus.ACTIVE;
|
|
383
383
|
}
|
|
384
|
-
return (_jsx(
|
|
384
|
+
return (_jsx(SchemaTableTh, { columnFilterStatus: columnFilterStatus,
|
|
385
|
+
// disableColumnFilter={disableColumnFilter}
|
|
386
|
+
isAllChecked: isAllRowsChecked, isSortable: !!isSortable, numberOfSelectedRows: checkedIndexes === null || checkedIndexes === void 0 ? void 0 : checkedIndexes.length, onSelectAllIndexesHandler: onSelectAllIndexesHandler, propConfig: propConfig, propIsRequired: required.includes(propName), propName: propName, schema: propSchema, setMenuConfig: setSchemaTableThMenuConfig, setSortAsc: onSetSortAsc, setSortColumn: onSetSortColumn, sortAsc: sortColumn === propName ? sortAsc : undefined, style: style }));
|
|
385
387
|
}, [
|
|
386
388
|
checkedIndexes === null || checkedIndexes === void 0 ? void 0 : checkedIndexes.length,
|
|
387
389
|
columnFilterMap,
|
|
388
390
|
columnNames,
|
|
389
391
|
config,
|
|
390
|
-
disableColumnFilter,
|
|
392
|
+
// disableColumnFilter,
|
|
391
393
|
isAllRowsChecked,
|
|
392
394
|
isColumnFilterable,
|
|
393
395
|
isSortable,
|
|
@@ -424,19 +426,15 @@ function SchemaTable({ Heading = VariableSizeList, checkedIndexes, config, custo
|
|
|
424
426
|
if (isDataFunction) {
|
|
425
427
|
setIsDirty(true);
|
|
426
428
|
}
|
|
427
|
-
if (useFilterStateHash) {
|
|
428
|
-
window.location.hash = serializeLocationHash(Object.assign(Object.assign({}, locationHash), { searchQuery: e.currentTarget.value }));
|
|
429
|
-
return;
|
|
430
|
-
}
|
|
431
429
|
setSearchQuery(e.currentTarget.value);
|
|
432
|
-
}, [isDataFunction
|
|
430
|
+
}, [isDataFunction]);
|
|
433
431
|
const refreshData = React.useCallback(() => {
|
|
434
432
|
setIsDirty(false);
|
|
435
433
|
setSourceData(undefined);
|
|
436
434
|
}, []);
|
|
437
435
|
const onInputKeyDown = React.useCallback((e) => {
|
|
438
436
|
if (e.key === "Enter") {
|
|
439
|
-
|
|
437
|
+
setSchemaTableThMenuConfig(undefined);
|
|
440
438
|
if (isDirty) {
|
|
441
439
|
refreshData();
|
|
442
440
|
}
|
|
@@ -452,8 +450,10 @@ function SchemaTable({ Heading = VariableSizeList, checkedIndexes, config, custo
|
|
|
452
450
|
? rowsMaxHeight
|
|
453
451
|
: rowsHeight;
|
|
454
452
|
}, [maxHeight, isSearchable, rowCount, rowHeight]);
|
|
455
|
-
const onPopoverClose = React.useCallback(() => {
|
|
456
|
-
|
|
453
|
+
const onPopoverClose = React.useCallback((e) => {
|
|
454
|
+
setSchemaTableThMenuConfig(undefined);
|
|
455
|
+
e.preventDefault();
|
|
456
|
+
e.stopPropagation();
|
|
457
457
|
}, []);
|
|
458
458
|
React.useEffect(() => {
|
|
459
459
|
if (!useFilterStateHash) {
|
|
@@ -471,35 +471,31 @@ function SchemaTable({ Heading = VariableSizeList, checkedIndexes, config, custo
|
|
|
471
471
|
if (!useFilterStateHash) {
|
|
472
472
|
return;
|
|
473
473
|
}
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
}
|
|
477
|
-
if (locationHash.searchQuery !== undefined) {
|
|
478
|
-
setSearchQuery(locationHash.searchQuery);
|
|
479
|
-
}
|
|
474
|
+
setColumnFilterMap(locationHash.columnFilterMap || {});
|
|
475
|
+
setSearchQuery(locationHash.searchQuery || "");
|
|
480
476
|
}, [locationHash, useFilterStateHash]);
|
|
481
|
-
const onSchemaColumnFilterChange = React.useCallback((newColumnFilterValue) => {
|
|
482
|
-
if (!
|
|
477
|
+
const onSchemaColumnFilterChange = React.useCallback((newColumnFilterValue, persistState) => {
|
|
478
|
+
if (!schemaTableThMenuConfig) {
|
|
483
479
|
return;
|
|
484
480
|
}
|
|
485
481
|
if (isDataFunction) {
|
|
486
482
|
setIsDirty(true);
|
|
487
483
|
}
|
|
488
|
-
if (
|
|
489
|
-
|
|
484
|
+
if (useFilterStateHash && persistState) {
|
|
485
|
+
window.location.hash = serializeLocationHash(Object.assign(Object.assign({}, locationHash), { columnFilterMap: Object.assign(Object.assign({}, columnFilterMap), { [schemaTableThMenuConfig.propName]: newColumnFilterValue }) }));
|
|
490
486
|
return;
|
|
491
487
|
}
|
|
492
|
-
if (
|
|
493
|
-
|
|
488
|
+
if (newColumnFilterValue === undefined) {
|
|
489
|
+
disableColumnFilter(schemaTableThMenuConfig.propName);
|
|
494
490
|
return;
|
|
495
491
|
}
|
|
496
|
-
setColumnFilterMap((columnFilterMap) => (Object.assign(Object.assign({}, columnFilterMap), { [
|
|
492
|
+
setColumnFilterMap((columnFilterMap) => (Object.assign(Object.assign({}, columnFilterMap), { [schemaTableThMenuConfig.propName]: newColumnFilterValue })));
|
|
497
493
|
}, [
|
|
498
494
|
columnFilterMap,
|
|
499
495
|
disableColumnFilter,
|
|
500
496
|
isDataFunction,
|
|
501
497
|
locationHash,
|
|
502
|
-
|
|
498
|
+
schemaTableThMenuConfig,
|
|
503
499
|
useFilterStateHash,
|
|
504
500
|
]);
|
|
505
501
|
const searchInputAutoFocus = React.useMemo(() => {
|
|
@@ -508,7 +504,20 @@ function SchemaTable({ Heading = VariableSizeList, checkedIndexes, config, custo
|
|
|
508
504
|
}
|
|
509
505
|
return enableAutoFocus;
|
|
510
506
|
}, [enableAutoFocus]);
|
|
511
|
-
|
|
507
|
+
const onClearFiltersButtonClick = React.useCallback(() => {
|
|
508
|
+
if (useFilterStateHash) {
|
|
509
|
+
window.location.hash = "";
|
|
510
|
+
return;
|
|
511
|
+
}
|
|
512
|
+
setColumnFilterMap({});
|
|
513
|
+
setSearchQuery("");
|
|
514
|
+
}, [useFilterStateHash]);
|
|
515
|
+
const onSearchBlur = React.useCallback(() => {
|
|
516
|
+
if (useFilterStateHash && searchQuery !== locationHash.searchQuery) {
|
|
517
|
+
window.location.hash = serializeLocationHash(Object.assign(Object.assign({}, locationHash), { searchQuery }));
|
|
518
|
+
}
|
|
519
|
+
}, [locationHash, searchQuery, useFilterStateHash]);
|
|
520
|
+
return (_jsxs("div", Object.assign({ className: `schema-table${onRowClick ? " schema-table--clickable-rows" : ""}`, style: Object.assign(Object.assign({}, style), { width: rowWidth }), role: "table" }, { children: [_jsxs("div", Object.assign({ className: "schema-table__action-container" }, { children: [_jsx("div", Object.assign({ style: { flex: 1 } }, { children: isSearchable ? (_jsx("input", { type: "text", placeholder: searchPlaceholder || "Search...", value: searchQuery, onChange: onSearchChange, onKeyDown: onInputKeyDown, autoFocus: searchInputAutoFocus, onBlur: onSearchBlur })) : null })), customElement, _jsx("button", Object.assign({ onClick: onClearFiltersButtonClick, disabled: Object.keys(columnFilterMap).length + searchQuery.length === 0 }, { children: "Clear filters" }))] })), _jsx(Heading, Object.assign({ height: 50, itemCount: columnCount, itemSize: getColumnWidth, layout: "horizontal", width: rowWidth, sortAsc: sortAsc, setSortAsc: onSetSortAsc, setSortColumn: onSetSortColumn, sortColumn: sortColumn, sortedRenderData: sortedRenderData, className: "schema-table__th-row" }, { children: ConfiguredSchemaTableTh }), `thead_${rowWidth}_${sortColumn}_${sortAsc}_${searchQuery}`), sourceData && !isDirty ? (_jsx(VariableSizeGrid, Object.assign({ className: "schema-table__tbody", height: tableBodyHeight, width: rowWidth, columnWidth: getColumnWidth, rowHeight: getRowHeight, columnCount: columnCount, rowCount: rowCount }, { children: SchemaTableTd }), `tbody_${tableBodyHeight}_${rowWidth}_${sortColumn}_${sortAsc}_${searchQuery}_${columnCount}`)) : (_jsx("div", Object.assign({ style: {
|
|
512
521
|
width: rowWidth,
|
|
513
522
|
height: Math.max(50, tableBodyHeight),
|
|
514
523
|
border: "1px solid #BBB",
|
|
@@ -517,6 +526,6 @@ function SchemaTable({ Heading = VariableSizeList, checkedIndexes, config, custo
|
|
|
517
526
|
backgroundColor: "#CCC",
|
|
518
527
|
alignItems: "center",
|
|
519
528
|
justifyContent: "center",
|
|
520
|
-
} }, { children: isDirty ? (_jsx("button", Object.assign({ onClick: refreshData, className: "btn border" }, { children: "Refresh data" }))) : (_jsx("div", { children: "\u231B Loading..." })) }))),
|
|
529
|
+
} }, { children: isDirty ? (_jsx("button", Object.assign({ onClick: refreshData, className: "btn border" }, { children: "Refresh data" }))) : (_jsx("div", { children: "\u231B Loading..." })) }))), schemaTableThMenuConfig ? (_jsx(SchemaTableThMenu, { onChange: onSchemaColumnFilterChange, onClose: onPopoverClose, onInputKeyDown: onInputKeyDown, propConfig: schemaTableThMenuConfig.propConfig, propIsRequired: schemaTableThMenuConfig.propIsRequired, propName: schemaTableThMenuConfig.propName, propSchema: schema.properties[schemaTableThMenuConfig.propName], referenceElement: schemaTableThMenuConfig.referenceElement, setSortAsc: setSortAsc, setSortColumn: setSortColumn, value: columnFilterMap[schemaTableThMenuConfig.propName] })) : null] })));
|
|
521
530
|
}
|
|
522
531
|
export default React.memo(SchemaTable);
|
package/dist/inc/data.js
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
const unserializeDates = (serializedObject) => {
|
|
2
|
+
if (serializedObject instanceof Object) {
|
|
3
|
+
if (serializedObject.$Date) {
|
|
4
|
+
return new Date(serializedObject.$Date);
|
|
5
|
+
}
|
|
6
|
+
return Object.entries(serializedObject).reduce((prev, [prop, value]) => {
|
|
7
|
+
prev[prop] = unserializeDates(value);
|
|
8
|
+
return prev;
|
|
9
|
+
}, {});
|
|
10
|
+
}
|
|
11
|
+
return serializedObject;
|
|
12
|
+
};
|
|
1
13
|
export const parseLocationHash = (search) => {
|
|
2
14
|
if (!search.length) {
|
|
3
15
|
return {};
|
|
@@ -15,10 +27,24 @@ export const parseLocationHash = (search) => {
|
|
|
15
27
|
return;
|
|
16
28
|
}
|
|
17
29
|
// @ts-ignore
|
|
18
|
-
result[decodeURIComponent(splitPair[0])] = JSON.parse(decodeURIComponent(splitPair[1]));
|
|
30
|
+
result[decodeURIComponent(splitPair[0])] = unserializeDates(JSON.parse(decodeURIComponent(splitPair[1])));
|
|
19
31
|
});
|
|
20
32
|
return result;
|
|
21
33
|
};
|
|
34
|
+
const serializeDates = (object) => {
|
|
35
|
+
if (!(object instanceof Object)) {
|
|
36
|
+
return object;
|
|
37
|
+
}
|
|
38
|
+
if (object instanceof Date) {
|
|
39
|
+
return {
|
|
40
|
+
$Date: object.toISOString(),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
return Object.entries(object).reduce((prev, [prop, value]) => {
|
|
44
|
+
prev[prop] = serializeDates(value);
|
|
45
|
+
return prev;
|
|
46
|
+
}, {});
|
|
47
|
+
};
|
|
22
48
|
export const serializeLocationHash = (params) => `${Object.entries(params)
|
|
23
|
-
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(JSON.stringify(value))}`)
|
|
49
|
+
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(JSON.stringify(serializeDates(value)))}`)
|
|
24
50
|
.join("&")}`;
|
package/dist/index.css
CHANGED
|
@@ -1,58 +1,36 @@
|
|
|
1
|
-
.schema-table
|
|
2
|
-
|
|
1
|
+
.schema-table,
|
|
2
|
+
.schema-table * {
|
|
3
|
+
box-sizing: border-box;
|
|
3
4
|
}
|
|
4
|
-
.schema-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
width: 100%;
|
|
8
|
-
}
|
|
9
|
-
.schema-table__th-row {
|
|
10
|
-
overflow: hidden !important;
|
|
11
|
-
}
|
|
12
|
-
.schema-table .schema-column-filter-popover {
|
|
13
|
-
background-color: #eee;
|
|
5
|
+
.schema-table button {
|
|
6
|
+
border: 1px solid #e4e4e4;
|
|
7
|
+
padding: 8px;
|
|
14
8
|
}
|
|
15
|
-
.schema-table
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
padding: 3px;
|
|
19
|
-
margin-top: 3px;
|
|
20
|
-
border-radius: 5px;
|
|
9
|
+
.schema-table button:enabled {
|
|
10
|
+
background-color: #f6f6f6;
|
|
11
|
+
color: #404040;
|
|
21
12
|
}
|
|
22
|
-
.schema-table
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
margin-left: 30px;
|
|
13
|
+
.schema-table button:enabled:hover {
|
|
14
|
+
border-color: #dbdbdb;
|
|
15
|
+
background-color: #ececec;
|
|
26
16
|
}
|
|
27
|
-
.schema-table
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
min-width: 150px;
|
|
17
|
+
.schema-table input {
|
|
18
|
+
padding: 8px;
|
|
19
|
+
border: 1px solid #888;
|
|
31
20
|
}
|
|
32
|
-
.schema-table
|
|
33
|
-
|
|
21
|
+
.schema-table input:hover {
|
|
22
|
+
border-color: lightblue;
|
|
34
23
|
}
|
|
35
|
-
.schema-
|
|
36
|
-
|
|
37
|
-
align-items: center;
|
|
38
|
-
padding-left: 8px;
|
|
39
|
-
padding-right: 8px;
|
|
24
|
+
.schema-table select {
|
|
25
|
+
height: 33px;
|
|
40
26
|
}
|
|
41
|
-
.schema-
|
|
42
|
-
overflow: hidden;
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
.schema-table__th,
|
|
47
|
-
.schema-table__th button {
|
|
48
|
-
font-weight: bold;
|
|
49
|
-
display: flex;
|
|
50
|
-
}
|
|
51
|
-
.schema-table__th--column-filter-status-ACTIVE button {
|
|
52
|
-
font-style: italic;
|
|
27
|
+
.schema-table__tbody {
|
|
28
|
+
overflow-x: hidden !important;
|
|
29
|
+
border-collapse: collapse;
|
|
30
|
+
width: 100%;
|
|
53
31
|
}
|
|
54
|
-
.schema-table__th
|
|
55
|
-
|
|
32
|
+
.schema-table__th-row {
|
|
33
|
+
overflow: hidden !important;
|
|
56
34
|
}
|
|
57
35
|
.schema-table__td {
|
|
58
36
|
overflow: hidden;
|
|
@@ -81,16 +59,8 @@
|
|
|
81
59
|
.schema-table--clickable-rows .schema-table__td {
|
|
82
60
|
cursor: pointer;
|
|
83
61
|
}
|
|
84
|
-
.schema-table button {
|
|
85
|
-
border: 1px solid transparent;
|
|
86
|
-
}
|
|
87
62
|
.schema-table__action-container {
|
|
88
63
|
display: flex;
|
|
89
64
|
flex-direction: row;
|
|
90
65
|
padding-bottom: 1rem;
|
|
91
66
|
}
|
|
92
|
-
.schema-table__action-container input {
|
|
93
|
-
width: 30%;
|
|
94
|
-
border-radius: 8px;
|
|
95
|
-
padding: 4px 10px;
|
|
96
|
-
}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { IFilterFormComponentProps } from "./SchemaTable/SchemaColumnFilterPopover/FilterFormComponent";
|
|
3
2
|
import { TColumnFilterValue } from "./SchemaTable";
|
|
3
|
+
import { IFilterMenuComponentProps } from "./SchemaTable/SchemaTableThMenu/FilterMenuComponent";
|
|
4
4
|
export interface IColumnConfig<T> {
|
|
5
|
-
|
|
5
|
+
FilterMenu?: (props: IFilterMenuComponentProps) => React.ReactElement | null;
|
|
6
6
|
align?: "start" | "center" | "end";
|
|
7
7
|
dateFormat?: string;
|
|
8
8
|
defaultSortDesc?: boolean;
|
package/package.json
CHANGED
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import React from "react";
|
|
3
|
-
import { t } from "../../../inc/string";
|
|
4
|
-
import { DEFAULT_DATE_FORMAT, DEFAULT_DATE_TIME_FORMAT, } from "../../../inc/constant";
|
|
5
|
-
import DatePicker from "react-datepicker";
|
|
6
|
-
import nl from "date-fns/locale/nl";
|
|
7
|
-
import { endOfDay } from "date-fns";
|
|
8
|
-
const FilterFormComponent = ({ columnFilterValue, onChange, onInputKeyDown, propConfig, propIsRequired, propName, propSchema, }) => {
|
|
9
|
-
const { type, format, minimum, maximum } = propSchema || {};
|
|
10
|
-
const value = columnFilterValue;
|
|
11
|
-
switch (type) {
|
|
12
|
-
case "integer":
|
|
13
|
-
return (_jsx("div", Object.assign({ className: "input-group" }, { children: _jsx("input", { autoFocus: true, className: "form-control", type: "number", value: (value || ""), "data-prop-name": propName, onChange: (e) => {
|
|
14
|
-
onChange(e.currentTarget.value === ""
|
|
15
|
-
? undefined
|
|
16
|
-
: parseInt(e.currentTarget.value));
|
|
17
|
-
}, onKeyDown: onInputKeyDown, placeholder: `Search ${propName}`, min: minimum, max: maximum }) })));
|
|
18
|
-
case "boolean":
|
|
19
|
-
let selectValue = value ? "✓" : "✕";
|
|
20
|
-
if (value === undefined) {
|
|
21
|
-
selectValue = "";
|
|
22
|
-
}
|
|
23
|
-
return (_jsxs("select", Object.assign({ autoFocus: true, className: "form-select", value: selectValue, "data-prop-name": propName, onChange: (e) => {
|
|
24
|
-
switch (e.currentTarget.value) {
|
|
25
|
-
case "✓":
|
|
26
|
-
onChange(true);
|
|
27
|
-
break;
|
|
28
|
-
case "✕":
|
|
29
|
-
onChange(false);
|
|
30
|
-
break;
|
|
31
|
-
default:
|
|
32
|
-
onChange(undefined);
|
|
33
|
-
}
|
|
34
|
-
} }, { children: [_jsx("option", Object.assign({ value: "" }, { children: "All" }), "all"), ["✓", "✕"].map((optionValue) => (_jsx("option", Object.assign({ value: optionValue }, { children: optionValue }), `column-filter-select-${optionValue}`)))] })));
|
|
35
|
-
// @ts-ignore
|
|
36
|
-
case "string":
|
|
37
|
-
if (propSchema === null || propSchema === void 0 ? void 0 : propSchema.enum) {
|
|
38
|
-
return (_jsxs("select", Object.assign({ autoFocus: true, className: "form-select", value: value, "data-prop-name": propName, onChange: (e) => {
|
|
39
|
-
onChange(e.currentTarget.value || undefined);
|
|
40
|
-
} }, { children: [_jsx("option", Object.assign({ value: "" }, { children: "All" }), "all"), propSchema.enum.map((name) => {
|
|
41
|
-
const rowName = !(propConfig === null || propConfig === void 0 ? void 0 : propConfig.translation)
|
|
42
|
-
? name
|
|
43
|
-
: t(name, propConfig.translation);
|
|
44
|
-
return (_jsx("option", Object.assign({ value: rowName }, { children: rowName }), `column-filter-select-${rowName}`));
|
|
45
|
-
})] })));
|
|
46
|
-
}
|
|
47
|
-
if (format === "date-time" || format === "date") {
|
|
48
|
-
const dateFormat = format === "date" ? DEFAULT_DATE_FORMAT : DEFAULT_DATE_TIME_FORMAT;
|
|
49
|
-
const dateRangeValue = (columnFilterValue || {
|
|
50
|
-
from: undefined,
|
|
51
|
-
to: undefined,
|
|
52
|
-
filterEmpty: undefined,
|
|
53
|
-
});
|
|
54
|
-
return (_jsxs("div", { children: [propIsRequired ? null : (_jsxs("div", { children: [_jsxs("label", Object.assign({ className: "d-flex" }, { children: [_jsx("input", { type: "checkbox", className: "m-0 me-1", checked: !!dateRangeValue.filterEmpty, onChange: () => {
|
|
55
|
-
onChange(Object.assign(Object.assign({}, dateRangeValue), { filterEmpty: !dateRangeValue.filterEmpty }));
|
|
56
|
-
} }), "Hide empty values"] })), _jsx("hr", {})] })), _jsxs("div", Object.assign({ className: "input-group d-flex" }, { children: [_jsxs("div", Object.assign({ className: "d-flex flex-column m-1" }, { children: [_jsx("label", { children: "Start date-time" }), _jsx(DatePicker, { autoFocus: true, dateFormat: dateFormat, "data-prop-name": propName, locale: nl, selected: dateRangeValue.from, onChange: (date) => {
|
|
57
|
-
if (!date && !dateRangeValue.to) {
|
|
58
|
-
onChange(undefined);
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
if (dateRangeValue.to && date && date > dateRangeValue.to) {
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
onChange(Object.assign(Object.assign({}, columnFilterValue), { from: date || undefined }));
|
|
65
|
-
}, placeholderText: dateFormat, isClearable: true, selectsStart: true, showTimeSelect: format === "date-time", timeIntervals: 15, shouldCloseOnSelect: format === "date" })] })), _jsxs("div", Object.assign({ className: "d-flex flex-column m-1" }, { children: [_jsx("label", { children: "End date-time" }), _jsx(DatePicker, { id: "filter-date", dateFormat: dateFormat, "data-prop-name": propName, locale: nl, selectsEnd: true, selected: dateRangeValue.to, onChange: (date) => {
|
|
66
|
-
if (!date && !dateRangeValue.from) {
|
|
67
|
-
onChange(undefined);
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
const to = date ? endOfDay(date) : undefined;
|
|
71
|
-
if (dateRangeValue.from && to && to < dateRangeValue.from) {
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
onChange(Object.assign(Object.assign({}, columnFilterValue), { to }));
|
|
75
|
-
}, placeholderText: dateFormat, isClearable: true, startDate: dateRangeValue.from, endDate: dateRangeValue.to, showTimeSelect: format === "date-time", timeIntervals: 15, shouldCloseOnSelect: format === "date" })] }))] }))] }));
|
|
76
|
-
}
|
|
77
|
-
// falls through
|
|
78
|
-
default:
|
|
79
|
-
return (_jsx("div", Object.assign({ className: "input-group" }, { children: _jsx("input", { autoFocus: true, type: "text", className: "form-control", placeholder: `Search ${propName}`, "aria-label": `Search ${propName}`, value: (value || ""), "data-prop-name": propName, onChange: (e) => {
|
|
80
|
-
onChange(e.currentTarget.value || undefined);
|
|
81
|
-
}, onKeyDown: onInputKeyDown }) })));
|
|
82
|
-
}
|
|
83
|
-
};
|
|
84
|
-
export default React.memo(FilterFormComponent);
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { oas31 } from "openapi3-ts";
|
|
3
|
-
import { TColumnFilterValue } from "../index";
|
|
4
|
-
import { IColumnConfig } from "../../types";
|
|
5
|
-
export interface ISchemaColumnFilterPopoverConfig {
|
|
6
|
-
referenceElement: HTMLElement;
|
|
7
|
-
propName: string;
|
|
8
|
-
propConfig?: IColumnConfig<any>;
|
|
9
|
-
propIsRequired: boolean;
|
|
10
|
-
}
|
|
11
|
-
type TSchemaColumnFilterPopoverProps = ISchemaColumnFilterPopoverConfig & {
|
|
12
|
-
onChange: (newValue?: TColumnFilterValue) => void;
|
|
13
|
-
onInputKeyDown: (e: React.KeyboardEvent) => void;
|
|
14
|
-
propIsRequired: boolean;
|
|
15
|
-
propSchema: oas31.SchemaObject;
|
|
16
|
-
value: TColumnFilterValue;
|
|
17
|
-
onClose: () => void;
|
|
18
|
-
};
|
|
19
|
-
declare const _default: React.MemoExoticComponent<({ onChange, onClose, onInputKeyDown, propIsRequired, propName, propSchema, referenceElement, value, propConfig, }: TSchemaColumnFilterPopoverProps) => import("react/jsx-runtime").JSX.Element>;
|
|
20
|
-
export default _default;
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import React from "react";
|
|
3
|
-
import FilterFormComponent from "./FilterFormComponent";
|
|
4
|
-
import { usePopper } from "react-popper";
|
|
5
|
-
const SchemaColumnFilterPopover = ({ onChange, onClose, onInputKeyDown, propIsRequired, propName, propSchema, referenceElement, value, propConfig, }) => {
|
|
6
|
-
const [popperElement, setPopperElement] = React.useState(null);
|
|
7
|
-
const [arrowElement, setArrowElement] = React.useState(null);
|
|
8
|
-
const { styles, attributes } = usePopper(referenceElement, popperElement, {
|
|
9
|
-
modifiers: [{ name: "arrow", options: { element: arrowElement } }],
|
|
10
|
-
});
|
|
11
|
-
React.useEffect(() => {
|
|
12
|
-
const onWindowClick = (e) => {
|
|
13
|
-
if (!popperElement) {
|
|
14
|
-
return;
|
|
15
|
-
}
|
|
16
|
-
let parent = e.target;
|
|
17
|
-
while (parent && popperElement) {
|
|
18
|
-
if (parent === popperElement) {
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
|
-
parent =
|
|
22
|
-
parent.parentNode === window.document ? null : parent.parentNode;
|
|
23
|
-
}
|
|
24
|
-
onClose();
|
|
25
|
-
};
|
|
26
|
-
window.addEventListener("click", onWindowClick, { capture: true });
|
|
27
|
-
return () => {
|
|
28
|
-
window.removeEventListener("click", onWindowClick, { capture: true });
|
|
29
|
-
};
|
|
30
|
-
}, [onClose, popperElement]);
|
|
31
|
-
const classNames = ["popover", "schema-column-filter-popover"];
|
|
32
|
-
if (attributes.popper) {
|
|
33
|
-
classNames.push(`bs-popover-${attributes.popper["data-popper-placement"]}`);
|
|
34
|
-
}
|
|
35
|
-
const FilterForm = (propConfig === null || propConfig === void 0 ? void 0 : propConfig.FilterForm) || FilterFormComponent;
|
|
36
|
-
return (_jsxs("div", Object.assign({ className: classNames.join(" "), role: "tooltip", ref: setPopperElement, style: styles.popper }, attributes.popper, { children: [_jsx("div", { className: "popover-arrow", ref: setArrowElement, style: styles.arrow }), _jsx("div", Object.assign({ className: "popover-body" }, { children: _jsx(FilterForm, { columnFilterValue: value, onChange: onChange, onInputKeyDown: onInputKeyDown, propConfig: propConfig, propIsRequired: propIsRequired, propName: propName, propSchema: propSchema }) }))] })));
|
|
37
|
-
};
|
|
38
|
-
export default React.memo(SchemaColumnFilterPopover);
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import React from "react";
|
|
3
|
-
import { t, uncamel } from "../../inc/string";
|
|
4
|
-
import { SELECT_ALL_COLUMN_NAME } from "../constants";
|
|
5
|
-
import { timeZone } from "../../inc/date";
|
|
6
|
-
export var EColumnFilterStatus;
|
|
7
|
-
(function (EColumnFilterStatus) {
|
|
8
|
-
EColumnFilterStatus["UNAVAILABLE"] = "UNAVAILABLE";
|
|
9
|
-
EColumnFilterStatus["AVAILABLE"] = "AVAILABLE";
|
|
10
|
-
EColumnFilterStatus["ACTIVE"] = "ACTIVE";
|
|
11
|
-
})(EColumnFilterStatus || (EColumnFilterStatus = {}));
|
|
12
|
-
const Th = ({ columnFilterStatus, disableColumnFilter, isAllChecked, isSortable, numberOfSelectedRows, onSelectAllIndexesHandler, propConfig, propIsRequired, propName, schema, setPopoverConfig, setSortAsc, setSortColumn, sortAsc, style, }) => {
|
|
13
|
-
const thDivProps = {
|
|
14
|
-
style,
|
|
15
|
-
className: `schema-table__th schema-table__th--column-filter-status-${columnFilterStatus} ${isSortable ? "schema-table__th--sortable" : "schema-table__th--unsortable"}`,
|
|
16
|
-
};
|
|
17
|
-
const onSortButtonClick = React.useCallback(() => {
|
|
18
|
-
if (sortAsc === undefined) {
|
|
19
|
-
setSortColumn(propName);
|
|
20
|
-
setSortAsc(!(propConfig === null || propConfig === void 0 ? void 0 : propConfig.defaultSortDesc));
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
setSortAsc((sortAsc) => !sortAsc);
|
|
24
|
-
}, [
|
|
25
|
-
propConfig === null || propConfig === void 0 ? void 0 : propConfig.defaultSortDesc,
|
|
26
|
-
propName,
|
|
27
|
-
setSortAsc,
|
|
28
|
-
setSortColumn,
|
|
29
|
-
sortAsc,
|
|
30
|
-
]);
|
|
31
|
-
const onFilterButtonClick = React.useCallback((e) => {
|
|
32
|
-
if (columnFilterStatus === EColumnFilterStatus.ACTIVE &&
|
|
33
|
-
disableColumnFilter) {
|
|
34
|
-
disableColumnFilter(propName);
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
if (!setPopoverConfig) {
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
const referenceElement = e.currentTarget;
|
|
41
|
-
setPopoverConfig((popoverConfig) => {
|
|
42
|
-
if (popoverConfig) {
|
|
43
|
-
return undefined;
|
|
44
|
-
}
|
|
45
|
-
return {
|
|
46
|
-
propConfig,
|
|
47
|
-
propIsRequired,
|
|
48
|
-
propName,
|
|
49
|
-
referenceElement,
|
|
50
|
-
};
|
|
51
|
-
});
|
|
52
|
-
}, [
|
|
53
|
-
columnFilterStatus,
|
|
54
|
-
disableColumnFilter,
|
|
55
|
-
propConfig,
|
|
56
|
-
propIsRequired,
|
|
57
|
-
propName,
|
|
58
|
-
setPopoverConfig,
|
|
59
|
-
]);
|
|
60
|
-
const labelBody = React.useMemo(() => {
|
|
61
|
-
if ((propConfig === null || propConfig === void 0 ? void 0 : propConfig.title) !== undefined) {
|
|
62
|
-
return propConfig.title;
|
|
63
|
-
}
|
|
64
|
-
if ((schema === null || schema === void 0 ? void 0 : schema.format) &&
|
|
65
|
-
schema.format.startsWith("date") &&
|
|
66
|
-
(propConfig === null || propConfig === void 0 ? void 0 : propConfig.showTimezones) !== false) {
|
|
67
|
-
return `${uncamel(propName)} (${t(timeZone)})`;
|
|
68
|
-
}
|
|
69
|
-
return uncamel(propName);
|
|
70
|
-
}, [propConfig, propName, schema === null || schema === void 0 ? void 0 : schema.format]);
|
|
71
|
-
if (propName === SELECT_ALL_COLUMN_NAME) {
|
|
72
|
-
return (_jsx("div", Object.assign({}, thDivProps, { children: _jsx("div", Object.assign({ style: {
|
|
73
|
-
width: "100%",
|
|
74
|
-
textAlign: "center",
|
|
75
|
-
}, title: `${numberOfSelectedRows || 0} selected` }, { children: _jsx("input", { type: "checkbox", checked: isAllChecked, onChange: onSelectAllIndexesHandler }) })) })));
|
|
76
|
-
}
|
|
77
|
-
if (!schema && !(propConfig === null || propConfig === void 0 ? void 0 : propConfig.renderData) && !(propConfig === null || propConfig === void 0 ? void 0 : propConfig.renderCell)) {
|
|
78
|
-
return _jsx("div", Object.assign({}, thDivProps));
|
|
79
|
-
}
|
|
80
|
-
switch (schema === null || schema === void 0 ? void 0 : schema.type) {
|
|
81
|
-
case "boolean":
|
|
82
|
-
thDivProps.className += ` text-${(propConfig === null || propConfig === void 0 ? void 0 : propConfig.align) || "center"} justify-content-${(propConfig === null || propConfig === void 0 ? void 0 : propConfig.align) || "center"}`;
|
|
83
|
-
break;
|
|
84
|
-
case "integer":
|
|
85
|
-
case "number":
|
|
86
|
-
thDivProps.className += ` text-${(propConfig === null || propConfig === void 0 ? void 0 : propConfig.align) || "end"} justify-content-${(propConfig === null || propConfig === void 0 ? void 0 : propConfig.align) || "end"}`;
|
|
87
|
-
break;
|
|
88
|
-
default:
|
|
89
|
-
if (propConfig === null || propConfig === void 0 ? void 0 : propConfig.align) {
|
|
90
|
-
thDivProps.className += ` text-${propConfig.align}`;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
return (_jsxs("div", Object.assign({}, thDivProps, { children: [isSortable ? (_jsxs("button", Object.assign({ className: "px-0", disabled: (propConfig === null || propConfig === void 0 ? void 0 : propConfig.sortable) === false, onClick: onSortButtonClick }, { children: [labelBody, sortAsc === undefined ? null : sortAsc ? "▲" : "▼"] }))) : (_jsx("div", Object.assign({ style: { lineHeight: "44px" } }, { children: labelBody }))), columnFilterStatus !== EColumnFilterStatus.UNAVAILABLE ? (_jsx("button", Object.assign({ onClick: onFilterButtonClick, "data-bs-toggle": "dropdown" }, { children: _jsx("svg", Object.assign({ viewBox: "0 0 36 36", xmlns: "http://www.w3.org/2000/svg", height: 16, width: 16, style: { display: "block" }, fill: "currentColor" }, { children: _jsx("polygon", { points: "14,30 22,25 22,17 35.999,0 17.988,0 0,0 14,17 " }) })) }))) : null] })));
|
|
94
|
-
};
|
|
95
|
-
export default React.memo(Th);
|