@boarteam/boar-pack-common-frontend 2.1.0 → 2.4.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@boarteam/boar-pack-common-frontend",
3
- "version": "2.1.0",
3
+ "version": "2.4.0",
4
4
  "description": "Common frontend package for Boar Pack",
5
5
  "repository": "git@github.com:boarteam/boar-pack.git",
6
6
  "author": "Andrew Balakirev <balakirev.andrey@gmail.com>",
@@ -46,5 +46,5 @@
46
46
  "scripts": {
47
47
  "yalc:push": "yalc push"
48
48
  },
49
- "gitHead": "ff8bb25f429f1e0a7d20038c9094e1bed9e37321"
49
+ "gitHead": "29f4f6c6598c7422bef8e02dfd1e679b471a4aa4"
50
50
  }
@@ -4,7 +4,7 @@ import { TDescriptionsCreateModalProps } from "./descriptionTypes";
4
4
  import { ProDescriptions } from "@ant-design/pro-components";
5
5
  import { columnsToDescriptionItemProps } from "./useDescriptionColumns";
6
6
  import { useForm } from "antd/es/form/Form";
7
- import { buildFieldsFromColumns } from "../Table";
7
+ import { buildFieldsFromColumnsForDescriptionsDisplay } from "../Table";
8
8
 
9
9
  const DescriptionsCreateModal = <Entity extends Record<string | symbol, any>>({
10
10
  idColumnName,
@@ -19,7 +19,7 @@ const DescriptionsCreateModal = <Entity extends Record<string | symbol, any>>({
19
19
 
20
20
  const editableKeys = useMemo(() => {
21
21
  return [
22
- ...buildFieldsFromColumns(
22
+ ...buildFieldsFromColumnsForDescriptionsDisplay(
23
23
  columns,
24
24
  idColumnName,
25
25
  ),
@@ -1,7 +1,9 @@
1
- import { Tag, Input, InputNumber, Space, Button } from "antd";
1
+ import { Tag, Input, InputNumber, Space, Button, Switch, Descriptions, Checkbox, Typography } from "antd";
2
2
  import { ColumnFilterItem, FilterDropdownProps } from "antd/es/table/interface";
3
3
  import { ReactNode, useEffect, useState } from "react";
4
4
 
5
+ const { Text } = Typography;
6
+
5
7
  export const booleanFilters: ColumnFilterItem[] = [
6
8
  { text: <Tag color='red'>Disabled</Tag>, value: 0 },
7
9
  { text: <Tag color='green'>Enabled</Tag>, value: 1 },
@@ -22,9 +24,45 @@ export function NumberFilterDropdown({ setSelectedKeys, selectedKeys, confirm, c
22
24
  )
23
25
  }
24
26
 
27
+ export function SwitchFilterDropdown({ setSelectedKeys, selectedKeys, confirm, clearFilters, close }: FilterDropdownProps) {
28
+ return (
29
+ <DynamicOptionsFilterDropdown confirm={confirm} clearFilters={clearFilters}>
30
+ <Descriptions
31
+ style={{ margin: '8px 16px', width: 200 }}
32
+ items={[
33
+ {
34
+ label: 'Only filled values',
35
+ children: <Switch
36
+ checked={selectedKeys.length ? Boolean(selectedKeys[0]) : undefined}
37
+ onChange={(value) => setSelectedKeys([value as any])}
38
+ />,
39
+ style: { padding: 0 },
40
+ contentStyle: { justifyContent: 'flex-end' },
41
+ }
42
+ ]}
43
+ />
44
+ </DynamicOptionsFilterDropdown>
45
+ )
46
+ }
47
+
48
+ export function CheckboxFilterDropdown({ setSelectedKeys, selectedKeys, confirm, clearFilters, close }: FilterDropdownProps) {
49
+ return (
50
+ <DynamicOptionsFilterDropdown confirm={confirm} clearFilters={clearFilters}>
51
+ <Checkbox
52
+ checked={selectedKeys.length ? Boolean(selectedKeys[0]) : undefined}
53
+ onChange={(event) => setSelectedKeys([event.target.checked as any])}
54
+ indeterminate={selectedKeys.length === 0}
55
+ style={{ margin: '8px 16px', width: 250 }}
56
+ >
57
+ {selectedKeys.length ? (selectedKeys[0] ? 'Will show only filled values' : 'Will show only empty values') : <Text type="secondary">Click to filter</Text>}
58
+ </Checkbox>
59
+ </DynamicOptionsFilterDropdown>
60
+ )
61
+ }
62
+
25
63
  export function NumberRangeFilterDropdown({ setSelectedKeys, selectedKeys, confirm, clearFilters, close }: FilterDropdownProps) {
26
64
  const [range, updateRange] = useState<[number, number] | undefined>(selectedKeys);
27
-
65
+
28
66
  useEffect(() => {
29
67
  updateRange(selectedKeys);
30
68
  }, [selectedKeys]);
@@ -71,8 +109,8 @@ export function StringFilterDropdown({ setSelectedKeys, selectedKeys, confirm, c
71
109
 
72
110
  export const DynamicOptionsFilterDropdown = ({
73
111
  children,
74
- confirm,
75
- clearFilters,
112
+ confirm,
113
+ clearFilters,
76
114
  }: Partial<FilterDropdownProps> & { children: ReactNode}) => {
77
115
  return (
78
116
  <div style={{ display: 'flex', flexDirection: 'column' }} onKeyDown={(e) => e.stopPropagation()}>
@@ -80,8 +118,8 @@ export const DynamicOptionsFilterDropdown = ({
80
118
  <Space className="ant-table-filter-dropdown-btns">
81
119
  <Button
82
120
  type="link"
83
- onClick={() => {
84
- clearFilters();
121
+ onClick={() => {
122
+ clearFilters();
85
123
  confirm();
86
124
  }}
87
125
  size="small"
@@ -68,6 +68,7 @@ const Table = <Entity extends Record<string | symbol, any>,
68
68
  popupCreation = false,
69
69
  toolBarRender,
70
70
  params,
71
+ popupDataState,
71
72
  ...rest
72
73
  }: TTableProps<Entity,
73
74
  CreateDto,
@@ -77,7 +78,7 @@ const Table = <Entity extends Record<string | symbol, any>,
77
78
  ) => {
78
79
  const actionRefComponent = useRef<ActionType>();
79
80
  const actionRef = actionRefProp || actionRefComponent;
80
- const [createPopupData, setCreatePopupData] = useState<Partial<Entity> | undefined>();
81
+ const [createPopupData, setCreatePopupData] = popupDataState ?? useState<Partial<Entity> | undefined>();
81
82
  const [editableKeys, setEditableRowKeys] = useState<React.Key[]>([]);
82
83
  const [selectedRecords, setSelectedRecords] = useState<Entity[]>([]);
83
84
  const [lastRequest, setLastRequest] = useState<[TGetAllParams & TPathParams, any] | []>([]);
@@ -20,19 +20,44 @@ export function getFiltersSearch({
20
20
  let operator = col.filterOperator || col.operator;
21
21
  let value = filters[colDataIndex] || baseFilters[colDataIndex];
22
22
  filterKeys.delete(colDataIndex);
23
- if (!value || col.numeric && !Number.isFinite(Number(value))) {
23
+ if (value === '' || value === undefined || col.numeric && !Number.isFinite(Number(value))) {
24
24
  return;
25
25
  }
26
26
 
27
- if (operator === Operators.between) {
28
- if (value?.[0] === undefined) {
29
- operator = Operators.lowerOrEquals;
30
- value = value?.[1];
31
- }
32
- else if (value?.[1] === undefined) {
33
- operator = Operators.greaterOrEquals;
34
- value = value?.[0];
35
- }
27
+ switch (operator) {
28
+ case Operators.between:
29
+ if (Array.isArray(value)) {
30
+ if (value?.[0] === undefined) {
31
+ operator = Operators.lowerOrEquals;
32
+ value = value?.[1];
33
+ } else if (value?.[1] === undefined) {
34
+ operator = Operators.greaterOrEquals;
35
+ value = value?.[0];
36
+ }
37
+ }
38
+ break;
39
+
40
+ case Operators.isNull:
41
+ if (Array.isArray(value)) {
42
+ value = value[0];
43
+ }
44
+
45
+ if (value !== true) {
46
+ operator = Operators.notNull;
47
+ value = true;
48
+ }
49
+ break;
50
+
51
+ case Operators.notNull:
52
+ if (Array.isArray(value)) {
53
+ value = value[0];
54
+ }
55
+
56
+ if (value !== true) {
57
+ operator = Operators.isNull;
58
+ value = true;
59
+ }
60
+ break;
36
61
  }
37
62
 
38
63
  search.$and?.push({ [field]: { [operator]: value } });
@@ -54,6 +79,8 @@ export const Operators = {
54
79
  between: CondOperator.BETWEEN,
55
80
  greaterOrEquals: CondOperator.GREATER_THAN_EQUALS,
56
81
  lowerOrEquals: CondOperator.LOWER_THAN_EQUALS,
82
+ isNull: CondOperator.IS_NULL,
83
+ notNull: CondOperator.NOT_NULL,
57
84
  } as const;
58
85
 
59
86
  export function applyKeywordToSearch(
@@ -113,6 +140,21 @@ export function collectFieldsFromColumns<T>(
113
140
  return [Array.from(buildFieldsFromColumns<T>(columns, idColumnName, joinFields, fields)).join(',')];
114
141
  }
115
142
 
143
+ export function buildFieldsFromColumnsForDescriptionsDisplay<T>(
144
+ columns: TIndexableRecord[] | undefined,
145
+ idColumnName: string | string[],
146
+ fields: Set<string> = new Set,
147
+ ): Set<string> {
148
+ columns?.forEach(col => {
149
+ if ('children' in col && Array.isArray(col.children)) {
150
+ buildFieldsFromColumnsForDescriptionsDisplay(col.children, idColumnName, fields);
151
+ }
152
+ fields.add(String(Array.isArray(col.dataIndex) ? col.dataIndex[0] : col.dataIndex));
153
+ });
154
+
155
+ return fields;
156
+ }
157
+
116
158
  export function buildFieldsFromColumns<T>(
117
159
  columns: TIndexableRecord[] | undefined,
118
160
  idColumnName: string | string[],
@@ -98,6 +98,7 @@ interface BaseProps<Entity,
98
98
  popupCreation?: boolean;
99
99
  columnsState?: ColumnStateType;
100
100
  columnsSetSelect?: () => React.ReactNode;
101
+ popupDataState?: [Partial<Entity>, React.Dispatch<React.SetStateAction<Partial<Entity>>>]
101
102
  }
102
103
 
103
104
  interface EditableProps<Entity, CreateDto, UpdateDto, TPathParams = {}> {