@boarteam/boar-pack-common-frontend 4.0.0 → 4.1.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.
Files changed (60) hide show
  1. package/dist/tools/safetyRun.d.ts +2 -1
  2. package/dist/tools/safetyRun.js +2 -1
  3. package/dist/tools/safetyRun.js.map +1 -1
  4. package/package.json +2 -3
  5. package/src/components/ChangesModal/ChangesModal.tsx +0 -260
  6. package/src/components/ChangesModal/ChangesTab.tsx +0 -51
  7. package/src/components/ChangesModal/ConflictsTab.tsx +0 -176
  8. package/src/components/ChangesModal/ErrorsTab.tsx +0 -49
  9. package/src/components/ChangesModal/NewRecordsTab.tsx +0 -48
  10. package/src/components/ChangesModal/ResultsTab.tsx +0 -28
  11. package/src/components/ChangesModal/index.ts +0 -1
  12. package/src/components/Comment/Comment.tsx +0 -53
  13. package/src/components/Comment/CommentAvatar.tsx +0 -34
  14. package/src/components/Comment/CommentForm.tsx +0 -36
  15. package/src/components/Comment/CommentFormModal.tsx +0 -31
  16. package/src/components/Comment/index.ts +0 -5
  17. package/src/components/Descriptions/Descriptions.tsx +0 -328
  18. package/src/components/Descriptions/DescriptionsCreateModal.tsx +0 -65
  19. package/src/components/Descriptions/descriptionTypes.ts +0 -73
  20. package/src/components/Descriptions/index.ts +0 -5
  21. package/src/components/Descriptions/useContentViewMode.tsx +0 -28
  22. package/src/components/Descriptions/useDescriptionColumns.ts +0 -42
  23. package/src/components/Inputs/DateRange.tsx +0 -75
  24. package/src/components/Inputs/MultiStringSelect.tsx +0 -20
  25. package/src/components/Inputs/NumberInputHandlingNewRecord.tsx +0 -11
  26. package/src/components/Inputs/NumberSwitcher.tsx +0 -27
  27. package/src/components/Inputs/Password.tsx +0 -33
  28. package/src/components/Inputs/RelationSelect.tsx +0 -108
  29. package/src/components/Inputs/SearchSelect.tsx +0 -93
  30. package/src/components/Inputs/filterDropdowns.tsx +0 -144
  31. package/src/components/Inputs/index.ts +0 -9
  32. package/src/components/Inputs/useCheckConnection.tsx +0 -79
  33. package/src/components/List/List.tsx +0 -266
  34. package/src/components/List/index.ts +0 -3
  35. package/src/components/List/listTypes.ts +0 -31
  36. package/src/components/QuestionMarkHint/QuestionMarkHint.tsx +0 -33
  37. package/src/components/QuestionMarkHint/index.ts +0 -1
  38. package/src/components/Table/BulkDeleteButton.tsx +0 -55
  39. package/src/components/Table/BulkEditButton.tsx +0 -160
  40. package/src/components/Table/CreateEntityModal.tsx +0 -85
  41. package/src/components/Table/DeleteButton.tsx +0 -44
  42. package/src/components/Table/Table.tsx +0 -294
  43. package/src/components/Table/getTableDataQueryParams.ts +0 -79
  44. package/src/components/Table/index.ts +0 -7
  45. package/src/components/Table/tableTools.ts +0 -244
  46. package/src/components/Table/tableTypes.ts +0 -148
  47. package/src/components/Table/useBulkEditing.tsx +0 -128
  48. package/src/components/Table/useColumnsSets.tsx +0 -142
  49. package/src/components/Table/useCreation.tsx +0 -114
  50. package/src/components/Table/useEditableTable.tsx +0 -86
  51. package/src/components/Table/useImportExport.tsx +0 -315
  52. package/src/components/index.ts +0 -6
  53. package/src/index.ts +0 -2
  54. package/src/tools/ApiError.ts +0 -18
  55. package/src/tools/WebsocketClient.ts +0 -146
  56. package/src/tools/index.ts +0 -6
  57. package/src/tools/numberTools.ts +0 -6
  58. package/src/tools/safetyRun.ts +0 -5
  59. package/src/tools/useFullscreen.tsx +0 -62
  60. package/src/tools/useTabs.ts +0 -17
@@ -1,42 +0,0 @@
1
- import { ProColumns } from "@ant-design/pro-components";
2
- import { ProDescriptionsItemProps } from "@ant-design/pro-descriptions";
3
-
4
- export type TDescriptionSection<T> = {
5
- title: ProColumns<T>['title'] | null;
6
- // 'general' is a special value for the main section including only columns without children
7
- key: string | 'general';
8
- columns: ProDescriptionsItemProps<T>[];
9
- }
10
-
11
- export function columnsToDescriptionItemProps<T>(
12
- columns: ProColumns<T>[],
13
- mainTitle: ProColumns<T>['title'] | null = null,
14
- key: string | 'general' = 'general'
15
- ): TDescriptionSection<T>[] {
16
- const baseSection: TDescriptionSection<T> = {
17
- title: mainTitle,
18
- key,
19
- columns: [],
20
- }
21
- const result: TDescriptionSection<T>[] = [baseSection];
22
-
23
- columns.forEach((column) => {
24
- if (column.valueType === 'option') {
25
- return;
26
- }
27
-
28
- if (column.children) {
29
- const dataIndex = String(Array.isArray(column.dataIndex) ? column.dataIndex[0] : column.dataIndex);
30
- result.push(...columnsToDescriptionItemProps(column.children, column.title, dataIndex));
31
- } else {
32
- const {
33
- children,
34
- ...rest
35
- } = column;
36
- // @ts-ignore-next-line
37
- baseSection.columns.push(rest as ProDescriptionsItemProps<T>);
38
- }
39
- });
40
-
41
- return result;
42
- }
@@ -1,75 +0,0 @@
1
- // antd switch but not for boolean, for numbers 0 and 1
2
- import React from "react";
3
- import dayjs from "dayjs";
4
- import { DatePicker } from "antd";
5
-
6
- interface RangePickerProps extends Omit<React.ComponentProps<typeof DatePicker.RangePicker>, 'value' | 'onChange'> {
7
- value? : [string | null, string | null] | null;
8
- onChange? : (value?: [string | null, string | null] | null) => void;
9
- }
10
-
11
- export const DateRange: React.FC<RangePickerProps> = ({
12
- value,
13
- onChange,
14
- ...props
15
- }) => {
16
- return (
17
- <DatePicker.RangePicker
18
- showTime={{
19
- showNow: true,
20
- showHour: true,
21
- showMinute: true,
22
- showSecond: true,
23
- showMillisecond: true,
24
- }}
25
- allowEmpty={[true, true]}
26
- presets={[
27
- {
28
- label: 'Today',
29
- value: [dayjs().startOf('day'), dayjs().endOf('day')],
30
- },
31
- {
32
- label: 'Yesterday',
33
- value: [dayjs().subtract(1, 'day').startOf('day'), dayjs().subtract(1, 'day').endOf('day')],
34
- },
35
- {
36
- label: 'Last 15 minutes',
37
- value: [dayjs().subtract(15, 'minute'), dayjs()],
38
- },
39
- {
40
- label: 'Last 30 minutes',
41
- value: [dayjs().subtract(30, 'minute'), dayjs()],
42
- },
43
- {
44
- label: 'Last 1 hour',
45
- value: [dayjs().subtract(1, 'hour'), dayjs()],
46
- },
47
- {
48
- label: 'Last 24 hours',
49
- value: [dayjs().subtract(1, 'day'), dayjs()],
50
- },
51
- {
52
- label: 'Last 7 days',
53
- value: [dayjs().subtract(7, 'day'), dayjs()],
54
- },
55
- {
56
- label: 'Last 30 days',
57
- value: [dayjs().subtract(30, 'day'), dayjs()],
58
- },
59
- {
60
- label: 'This month',
61
- value: [dayjs().startOf('month'), dayjs().endOf('month')],
62
- },
63
- {
64
- label: 'Last month',
65
- value: [dayjs().subtract(1, 'month').startOf('month'), dayjs().subtract(1, 'month').endOf('month')],
66
- },
67
- ]}
68
- value={value?.map(date => dayjs(date)) as [dayjs.Dayjs, dayjs.Dayjs] | undefined}
69
- onChange={(dates) => {
70
- onChange?.(dates?.map(date => date?.toISOString() ?? null) as [string | null, string | null] | null);
71
- }}
72
- {...props}
73
- />
74
- );
75
- }
@@ -1,20 +0,0 @@
1
- import { Select } from "antd";
2
- import React from "react";
3
-
4
- export const MultiStringSelect: React.FC<{
5
- value?: string[];
6
- onChange?: (value: string[]) => void;
7
- }> = ({ value, onChange }) => {
8
- return (
9
- <Select<string[]>
10
- dropdownStyle={{ minWidth: 200 }}
11
- allowClear={true}
12
- mode="tags"
13
- style={{ minWidth: 200 }}
14
- maxTagCount='responsive'
15
- value={value}
16
- onChange={onChange}
17
- notFoundContent='Enter manually'
18
- />
19
- )
20
- }
@@ -1,11 +0,0 @@
1
- import React from "react";
2
- import { InputNumberProps } from "antd/es/input-number";
3
- import { InputNumber } from "antd";
4
- import { isRecordNew } from "../Table";
5
-
6
- export const NumberInputHandlingNewRecord: React.FC<InputNumberProps> = ({ value, onChange }) => {
7
- return <InputNumber
8
- value={isRecordNew({ id: value }) ? '' : value}
9
- onChange={onChange}
10
- />
11
- }
@@ -1,27 +0,0 @@
1
- // antd switch but not for boolean, for numbers 0 and 1
2
- import { Switch } from "antd";
3
- import React from "react";
4
- import { SwitchProps } from "antd/es/switch";
5
-
6
- interface NumberSwitcherProps extends Omit<SwitchProps, 'value' | 'onChange'> {
7
- value?: number;
8
- onChange?: (value?: number) => void;
9
- }
10
-
11
- export const NumberSwitch: React.FC<NumberSwitcherProps> = ({
12
- value,
13
- onChange,
14
- ...props
15
- }) => {
16
- return (
17
- <Switch
18
- checkedChildren="1"
19
- unCheckedChildren="0"
20
- checked={value === 1}
21
- onChange={(checked) => {
22
- onChange?.(checked ? 1 : 0);
23
- }}
24
- {...props}
25
- />
26
- );
27
- }
@@ -1,33 +0,0 @@
1
- import React from "react";
2
- import { Button, Input, Tooltip } from "antd";
3
- import { ThunderboltOutlined } from "@ant-design/icons";
4
- import { Typography } from "antd";
5
- import { PasswordProps } from "antd/es/input/Password";
6
-
7
- const { Paragraph } = Typography;
8
-
9
- export const Password: React.FC<PasswordProps> = ({ value, onChange }) => {
10
- return (
11
- <Input.Group compact={true}>
12
- <Input.Password
13
- placeholder={'Enter password'}
14
- onChange={onChange}
15
- value={value}
16
- style={{ width: 'calc(100% - 80px)' }}
17
- autoComplete={'one-time-code'}
18
- />
19
- <Tooltip title="Generate password">
20
- <Button
21
- onClick={(e) => {
22
- const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!@#$%&';
23
- const pass = Array(10).fill('').map(x => chars[Math.floor(Math.random() * chars.length)]).join('');
24
- // @ts-ignore
25
- onChange?.(pass);
26
- }}
27
- icon={<ThunderboltOutlined color={'var(--ant-primary)'} />}
28
- />
29
- </Tooltip>
30
- <Button icon={<Paragraph copyable={{ text: String(value) }} />} />
31
- </Input.Group>
32
- );
33
- }
@@ -1,108 +0,0 @@
1
- import { ProFormSelect, ProFormSelectProps } from "@ant-design/pro-components";
2
- import { useState } from "react";
3
- import { useCreation } from "../Table";
4
- import { Space } from "antd";
5
-
6
- type RelationSelectProps<T, CreateDto = T> = ProFormSelectProps & {
7
- selectedItem: T | null | undefined,
8
- onChange?: (type: T | null) => void,
9
- filter?: string[],
10
- fetchItems: (filter: string[], keyword?: string) => Promise<{ data: T[] }>,
11
- fieldNames?: {
12
- value: string,
13
- label: string,
14
- },
15
- onCreate?: ({}: { requestBody: CreateDto }) => Promise<T>,
16
- creationColumns?: any[], // TODO: any specified in the createEntityModal. Need to fix it in the both places
17
- idColumnName?: string & keyof T | (string & keyof T)[],
18
- createPopupTitle?: string,
19
- };
20
-
21
- export const RelationSelect = function <T, CreateDto = T>({
22
- selectedItem,
23
- onCreate,
24
- creationColumns,
25
- // @ts-ignore
26
- idColumnName = 'id',
27
- createPopupTitle = 'Add new record',
28
- onChange,
29
- filter = [],
30
- fetchItems,
31
- fieldNames = {
32
- value: 'id',
33
- label: 'name',
34
- },
35
- ...rest
36
- }: RelationSelectProps<T, CreateDto>) {
37
- const { value: valueKey, label: labelKey } = fieldNames;
38
- const [value, setValue] = useState(selectedItem ? {
39
- label: selectedItem[labelKey as keyof T],
40
- value: selectedItem[valueKey as keyof T],
41
- } : undefined);
42
-
43
- const {
44
- creationModal,
45
- createButton,
46
- } = useCreation<T, CreateDto>({
47
- onCreate,
48
- columns: creationColumns,
49
- popupCreation: !!onCreate,
50
- createNewDefaultParams: {},
51
- createButtonSize: 'small',
52
- pathParams: {},
53
- entityToCreateDto: (entity: T) => entity as unknown as CreateDto,
54
- title: createPopupTitle,
55
- idColumnName
56
- });
57
-
58
- const request = async ({ keyWords: keyword }: { keyWords: string }) => {
59
- const reqFilter = [...filter];
60
- if (keyword) {
61
- reqFilter.push(labelKey + '||$contL||' + keyword);
62
- }
63
- const resp = await fetchItems(reqFilter, keyword);
64
- return resp.data;
65
- }
66
-
67
- return (
68
- <div style={{ display: 'flex', alignItems: 'center', gap: 5 }}>
69
- <ProFormSelect.SearchSelect
70
- showSearch
71
- mode={'single'}
72
- request={request}
73
- className='relational-select'
74
- formItemProps={{
75
- style: {
76
- margin: 0,
77
- display: 'inline-block',
78
- }
79
- }}
80
- style={{ minWidth: 160 }}
81
- placeholder='Please choose'
82
- fieldProps={{
83
- fieldNames: {
84
- value: valueKey,
85
- label: labelKey,
86
- },
87
- value,
88
- onChange(value, row) {
89
- setValue(value);
90
- onChange?.(row ? value : null);
91
- },
92
- dropdownRender: (menu) => (
93
- <>
94
- {menu}
95
- {onCreate && (
96
- <Space style={{ padding: '0 8px 4px', display: 'flex', justifyContent: 'center' }}>
97
- {createButton}
98
- </Space>
99
- )}
100
- </>
101
- ),
102
- }}
103
- {...rest}
104
- />
105
- {creationModal}
106
- </div>
107
- );
108
- }
@@ -1,93 +0,0 @@
1
- import { useState, useEffect } from "react";
2
- import { SearchOutlined } from "@ant-design/icons";
3
- import { Checkbox, Empty, Input, Menu } from "antd";
4
- import { FilterDropdownProps } from "antd/es/table/interface";
5
-
6
- export const SearchSelect = function<T>({
7
- selectedKeys,
8
- setSelectedKeys,
9
- filter = [],
10
- limit = 7,
11
- fetchItems,
12
- fieldNames = {
13
- value: 'id',
14
- label: 'name',
15
- },
16
- }: Pick<FilterDropdownProps, 'selectedKeys' | 'setSelectedKeys'> & {
17
- filter?: string[],
18
- limit?: number,
19
- fetchItems: (filter: string[], limit?: number, keyword?: string) => Promise<{ data: T[] }>,
20
- fieldNames?: {
21
- value: string,
22
- label: string,
23
- },
24
- }) {
25
- const { value: valueKey, label: labelKey } = fieldNames;
26
-
27
- const [availableItems, setAvailableItems] = useState<T[]>([]);
28
- const request = async (keyword: string) => {
29
- const reqFilter = [...filter];
30
- if (keyword) {
31
- reqFilter.push(labelKey + '||$contL||' + keyword);
32
- }
33
-
34
- const resp = await fetchItems(reqFilter, limit, keyword);
35
- setAvailableItems(resp.data);
36
- }
37
-
38
- useEffect(() => {
39
- request('');
40
- }, []);
41
-
42
- return (
43
- <>
44
- <div className={`ant-table-filter-dropdown-search`}>
45
- <Input
46
- prefix={<SearchOutlined />}
47
- placeholder={'Search in filters'}
48
- onChange={e => request(e.target.value)}
49
- className={`ant-table-filter-dropdown-search-input`}
50
- />
51
- </div>
52
- {
53
- availableItems.length === 0
54
- ? (
55
- <Empty
56
- image={Empty.PRESENTED_IMAGE_SIMPLE}
57
- description={'Not Found'}
58
- imageStyle={{
59
- height: 24,
60
- }}
61
- style={{
62
- margin: 0,
63
- padding: '16px 0',
64
- }}
65
- />
66
- )
67
- : (
68
- <Menu
69
- selectable
70
- multiple
71
- prefixCls={`ant-dropdown-menu`}
72
- className={'ant-dropdown-menu'}
73
- onSelect={({ key }) => setSelectedKeys([...selectedKeys, key])}
74
- onDeselect={({ key }) => setSelectedKeys(selectedKeys.filter(selectedKey => selectedKey !== key))}
75
- // @ts-ignore
76
- selectedKeys={selectedKeys}
77
- items={availableItems.map(item => (
78
- {
79
- key: String(item?.[valueKey as keyof T]),
80
- label: (
81
- <>
82
- <Checkbox checked={selectedKeys?.includes(String(item?.[valueKey as keyof T]))} />
83
- <span>{String(item?.[labelKey as keyof T])}</span>
84
- </>
85
- ),
86
- }
87
- ))}
88
- />
89
- )
90
- }
91
- </>
92
- );
93
- }
@@ -1,144 +0,0 @@
1
- import { Tag, Input, InputNumber, Space, Button, Switch, Descriptions, Checkbox, Typography } from "antd";
2
- import { ColumnFilterItem, FilterDropdownProps } from "antd/es/table/interface";
3
- import { ReactNode, useEffect, useState } from "react";
4
-
5
- const { Text } = Typography;
6
-
7
- export const booleanFilters: ColumnFilterItem[] = [
8
- { text: <Tag color='red'>Disabled</Tag>, value: 0 },
9
- { text: <Tag color='green'>Enabled</Tag>, value: 1 },
10
- ];
11
-
12
- export function NumberFilterDropdown({ setSelectedKeys, selectedKeys, confirm, clearFilters, close }: FilterDropdownProps) {
13
- return (
14
- <DynamicOptionsFilterDropdown confirm={confirm} clearFilters={clearFilters}>
15
- <InputNumber
16
- value={selectedKeys.length ? Number(selectedKeys[0]) : undefined}
17
- onChange={(value) => setSelectedKeys(value === undefined ? [] : [value])}
18
- onPressEnter={() => confirm()}
19
- step={1}
20
- style={{ margin: 4, width: 250 }}
21
- placeholder="Please Enter"
22
- />
23
- </DynamicOptionsFilterDropdown>
24
- )
25
- }
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([Number(value)])}
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([Number(event.target.checked)])}
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
-
63
- export function NumberRangeFilterDropdown({ setSelectedKeys, selectedKeys, confirm, clearFilters, close }: FilterDropdownProps) {
64
- const toRange = (keys: React.Key[]): [number, number] | undefined =>
65
- keys.length >= 2 ? [Number(keys[0]), Number(keys[1])] : undefined;
66
-
67
- const [range, updateRange] = useState<[number, number] | undefined>(toRange(selectedKeys));
68
-
69
- useEffect(() => {
70
- updateRange(toRange(selectedKeys));
71
- }, [selectedKeys]);
72
-
73
- useEffect(() => {
74
- setSelectedKeys(range ?? []);
75
- }, [range]);
76
-
77
- return (
78
- <DynamicOptionsFilterDropdown confirm={confirm} clearFilters={clearFilters}>
79
- <InputNumber
80
- value={range?.[0]}
81
- onChange={value => updateRange(prev => ([value, prev[1]]))}
82
- onPressEnter={() => confirm()}
83
- step={1}
84
- style={{ margin: 4, width: 250 }}
85
- placeholder="From"
86
- />
87
- <InputNumber
88
- value={range?.[1]}
89
- onChange={value => updateRange(prev => ([prev[0], value]))}
90
- onPressEnter={() => confirm()}
91
- step={1}
92
- style={{ margin: 4, width: 250 }}
93
- placeholder="To"
94
- />
95
- </DynamicOptionsFilterDropdown>
96
- )
97
- }
98
-
99
- export function StringFilterDropdown({ setSelectedKeys, selectedKeys, confirm, clearFilters, close }: FilterDropdownProps) {
100
- return (
101
- <DynamicOptionsFilterDropdown confirm={confirm} clearFilters={clearFilters}>
102
- <Input
103
- value={selectedKeys.length ? String(selectedKeys[0]) : undefined}
104
- onChange={(event) => setSelectedKeys(event.target.value === undefined ? [] : [event.target.value])}
105
- onPressEnter={() => confirm()}
106
- style={{ margin: 4, width: 250 }}
107
- placeholder="Please Enter"
108
- />
109
- </DynamicOptionsFilterDropdown>
110
- )
111
- }
112
-
113
- export const DynamicOptionsFilterDropdown = ({
114
- children,
115
- confirm,
116
- clearFilters,
117
- }: Partial<FilterDropdownProps> & { children: ReactNode}) => {
118
- return (
119
- <div style={{ display: 'flex', flexDirection: 'column' }} onKeyDown={(e) => e.stopPropagation()}>
120
- {children}
121
- <Space className="ant-table-filter-dropdown-btns">
122
- <Button
123
- type="link"
124
- onClick={() => {
125
- clearFilters();
126
- confirm();
127
- }}
128
- size="small"
129
- >
130
- Reset
131
- </Button>
132
- <Button
133
- type="primary"
134
- size="small"
135
- onClick={() => {
136
- confirm();
137
- }}
138
- >
139
- OK
140
- </Button>
141
- </Space>
142
- </div>
143
- )
144
- };
@@ -1,9 +0,0 @@
1
- export * from './MultiStringSelect';
2
- export * from './NumberInputHandlingNewRecord';
3
- export * from './NumberSwitcher';
4
- export * from './Password';
5
- export * from './RelationSelect';
6
- export * from './useCheckConnection';
7
- export * from './filterDropdowns';
8
- export * from './SearchSelect';
9
- export * from './DateRange';
@@ -1,79 +0,0 @@
1
- import React, { useState } from "react";
2
- import { Button, message } from "antd";
3
- import { CheckOutlined, WarningOutlined } from "@ant-design/icons";
4
- import { green, red } from "@ant-design/colors";
5
-
6
- type TCheckConnection = {
7
- defaultSuccessMessage: string;
8
- defaultErrorMessage: string;
9
- request: () => Promise<{
10
- success: boolean;
11
- message?: string;
12
- }>;
13
- }
14
-
15
- export const useCheckConnection = ({
16
- defaultSuccessMessage,
17
- defaultErrorMessage,
18
- request,
19
- }: TCheckConnection): {
20
- button: React.ReactElement;
21
- } => {
22
- const [timer, setTimer] = useState<NodeJS.Timeout | null>(null);
23
- const [loading, setLoading] = useState<boolean>(false);
24
- const [error, setError] = useState<string | null | undefined>(undefined);
25
- const [messageApi, contextHolder] = message.useMessage();
26
-
27
- const checkConnection = () => {
28
- if (timer) {
29
- clearTimeout(timer);
30
- setTimer(null);
31
- }
32
-
33
- setLoading(true);
34
- setError(null);
35
-
36
- request().then(({
37
- success,
38
- message,
39
- }) => {
40
- if (success) {
41
- setError(null);
42
- messageApi.success(message || defaultSuccessMessage);
43
- } else {
44
- const err = message || defaultErrorMessage;
45
- setError(err);
46
- messageApi.error(err);
47
- }
48
- }).catch(e => {
49
- console.error(e);
50
- }).finally(() => {
51
- setLoading(false);
52
- setTimer(setTimeout(() => {
53
- setError(undefined);
54
- }, 3000));
55
- });
56
- };
57
-
58
- let icon = null;
59
- if (error === null) {
60
- icon = <CheckOutlined style={{ color: green.primary }} />;
61
- } else if (error !== undefined) {
62
- icon = <WarningOutlined style={{ color: red.primary }} />;
63
- }
64
-
65
- const button = <>
66
- {contextHolder}
67
- <Button
68
- size={'small'}
69
- loading={loading}
70
- danger={!!error}
71
- icon={icon}
72
- onClick={checkConnection}
73
- >Test</Button>
74
- </>;
75
-
76
- return {
77
- button,
78
- };
79
- }