namirasoft-site-react 1.4.535 → 1.4.537
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/NSBoxBuilder.js +1 -1
- package/dist/NSBoxBuilder.js.map +1 -1
- package/dist/components/NSBoxDate.d.ts +8 -8
- package/dist/components/NSBoxDate.js +25 -8
- package/dist/components/NSBoxDate.js.map +1 -1
- package/dist/components/NSBoxDateRange.d.ts +2 -2
- package/dist/components/NSBoxDateRange.js +16 -10
- package/dist/components/NSBoxDateRange.js.map +1 -1
- package/dist/components/NSBoxDateRangeBase.d.ts +4 -4
- package/dist/components/NSBoxDateRangeBase.js +15 -9
- package/dist/components/NSBoxDateRangeBase.js.map +1 -1
- package/dist/components/NSBoxDateTimeRange.d.ts +2 -2
- package/dist/components/NSBoxDateTimeRange.js +11 -15
- package/dist/components/NSBoxDateTimeRange.js.map +1 -1
- package/dist/components/NSBoxTimeRange.d.ts +28 -13
- package/dist/components/NSBoxTimeRange.js +80 -18
- package/dist/components/NSBoxTimeRange.js.map +1 -1
- package/dist/components/NSTable.js +9 -0
- package/dist/components/NSTable.js.map +1 -1
- package/package.json +2 -2
- package/src/NSBoxBuilder.tsx +1 -1
- package/src/components/NSBoxDate.tsx +40 -23
- package/src/components/NSBoxDateRange.tsx +17 -9
- package/src/components/NSBoxDateRangeBase.tsx +19 -13
- package/src/components/NSBoxDateTimeRange.tsx +11 -15
- package/src/components/NSBoxTimeRange.tsx +155 -30
- package/src/components/NSTable.tsx +11 -0
|
@@ -15,50 +15,46 @@ export class NSBoxDateTimeRange extends NSBoxDateRangeBase<NSBoxDateTimeRangePro
|
|
|
15
15
|
|
|
16
16
|
getError(): string | null
|
|
17
17
|
{
|
|
18
|
-
const
|
|
19
|
-
const { title, required } = this.props;
|
|
18
|
+
const { title, required, minDate, maxDate } = this.props;
|
|
20
19
|
const { value } = this.state;
|
|
21
20
|
if (required && (!value || !value.from || !value.to))
|
|
22
21
|
return `${title} is required.`;
|
|
23
|
-
const minDate = this.props.minDate ? TimeOperation.format(this.props.minDate, fmt) : undefined;
|
|
24
|
-
const maxDate = this.props.maxDate ? TimeOperation.format(this.props.maxDate, fmt) : undefined;
|
|
25
22
|
if (minDate && value?.from && value.from < minDate)
|
|
26
|
-
return `${title} (from) must not be before ${minDate}.`;
|
|
23
|
+
return `${title} (from) must not be before ${TimeOperation.format(minDate, this.getFormat())}.`;
|
|
27
24
|
if (maxDate && value?.to && value.to > maxDate)
|
|
28
|
-
return `${title} (to) must not be after ${maxDate}.`;
|
|
25
|
+
return `${title} (to) must not be after ${TimeOperation.format(maxDate, this.getFormat())}.`;
|
|
29
26
|
return null;
|
|
30
27
|
}
|
|
31
28
|
|
|
32
29
|
protected getBuiltinPresets()
|
|
33
30
|
{
|
|
34
|
-
const fmt = this.getFormat();
|
|
35
31
|
const now = new Date();
|
|
36
32
|
now.setSeconds(0, 0);
|
|
37
|
-
const to = TimeOperation.format(now, fmt);
|
|
38
33
|
return [
|
|
39
|
-
{ label: '1H', title: 'Last 1 Hour', from: TimeOperation.
|
|
40
|
-
{ label: '6H', title: 'Last 6 Hours', from: TimeOperation.
|
|
41
|
-
{ label: '12H', title: 'Last 12 Hours', from: TimeOperation.
|
|
42
|
-
{ label: '1D', title: 'Last 1 Day', from: TimeOperation.
|
|
43
|
-
{ label: '1W', title: 'Last 1 Week', from: TimeOperation.
|
|
34
|
+
{ label: '1H', title: 'Last 1 Hour', from: TimeOperation.hoursAgo(1, now), to: now },
|
|
35
|
+
{ label: '6H', title: 'Last 6 Hours', from: TimeOperation.hoursAgo(6, now), to: now },
|
|
36
|
+
{ label: '12H', title: 'Last 12 Hours', from: TimeOperation.hoursAgo(12, now), to: now },
|
|
37
|
+
{ label: '1D', title: 'Last 1 Day', from: TimeOperation.daysAgo(1, now), to: now },
|
|
38
|
+
{ label: '1W', title: 'Last 1 Week', from: TimeOperation.weeksAgo(1, now), to: now },
|
|
44
39
|
];
|
|
45
40
|
}
|
|
46
41
|
|
|
47
42
|
protected renderPicker()
|
|
48
43
|
{
|
|
44
|
+
const fmt = this.getFormat();
|
|
49
45
|
return (
|
|
50
46
|
<DatePicker.RangePicker
|
|
51
47
|
className={`${StylesNSBox.ns_box_input} ${Styles.ns_picker}`}
|
|
52
48
|
variant="borderless"
|
|
53
49
|
showTime
|
|
54
50
|
value={this.toDayjsValue()}
|
|
55
|
-
format={
|
|
51
|
+
format={fmt}
|
|
56
52
|
minDate={this.props.minDate ? dayjs(this.props.minDate) : undefined}
|
|
57
53
|
maxDate={this.props.maxDate ? dayjs(this.props.maxDate) : undefined}
|
|
58
54
|
onChange={(_, dateStrings) =>
|
|
59
55
|
{
|
|
60
56
|
if (dateStrings?.[0] && dateStrings?.[1])
|
|
61
|
-
this.setValue({ from: dateStrings[0], to: dateStrings[1] });
|
|
57
|
+
this.setValue({ from: dayjs(dateStrings[0], fmt).toDate(), to: dayjs(dateStrings[1], fmt).toDate() });
|
|
62
58
|
else
|
|
63
59
|
this.setValue(null);
|
|
64
60
|
}}
|
|
@@ -4,21 +4,53 @@ import { TimePicker } from 'antd';
|
|
|
4
4
|
import type { Dayjs } from 'dayjs';
|
|
5
5
|
import dayjs from 'dayjs';
|
|
6
6
|
import { TimeOperation } from 'namirasoft-core';
|
|
7
|
+
import { Component, createRef } from 'react';
|
|
8
|
+
import { IBaseComponentProps } from '../props/IBaseComponentProps';
|
|
9
|
+
import { IValidationProps } from '../props/IValidationProps';
|
|
7
10
|
import { Validator } from '../Validator';
|
|
11
|
+
import { INSBox } from './INSBox';
|
|
8
12
|
import StylesNSBox from './NSBox.module.css';
|
|
9
|
-
import {
|
|
13
|
+
import { INSBoxBaseLayoutProps, NSBoxBaseLayout } from './NSBoxBaseLayout';
|
|
10
14
|
import Styles from './NSBoxDateRangeBase.module.css';
|
|
15
|
+
import { NSBoxDateRangePreset } from './NSBoxDateRangeBase';
|
|
16
|
+
import { safeMenuMenuItem } from './NSMenuButton';
|
|
11
17
|
|
|
12
|
-
export interface
|
|
18
|
+
export interface NSBoxTimeRangeValue
|
|
13
19
|
{
|
|
20
|
+
from: string;
|
|
21
|
+
to: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface NSBoxTimeRangeProps extends IBaseComponentProps, IValidationProps, INSBoxBaseLayoutProps<NSBoxTimeRange, NSBoxTimeRangeValue>
|
|
25
|
+
{
|
|
26
|
+
preset?: boolean;
|
|
27
|
+
presets?: NSBoxDateRangePreset[];
|
|
14
28
|
maxRangeSeconds?: number;
|
|
15
29
|
}
|
|
16
30
|
|
|
17
|
-
export
|
|
31
|
+
export interface NSBoxTimeRangeState
|
|
18
32
|
{
|
|
19
|
-
|
|
33
|
+
value: NSBoxTimeRangeValue | null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export class NSBoxTimeRange extends Component<NSBoxTimeRangeProps, NSBoxTimeRangeState> implements INSBox
|
|
37
|
+
{
|
|
38
|
+
NSBoxBaseLayout_Main = createRef<NSBoxBaseLayout>();
|
|
39
|
+
private static readonly FORMAT = 'HH:mm:ss';
|
|
40
|
+
|
|
41
|
+
constructor(props: NSBoxTimeRangeProps)
|
|
42
|
+
{
|
|
43
|
+
super(props);
|
|
44
|
+
this.state = { value: props.defaultValue ?? null };
|
|
45
|
+
this.isEmpty = this.isEmpty.bind(this);
|
|
46
|
+
this.getError = this.getError.bind(this);
|
|
47
|
+
this.getValue = this.getValue.bind(this);
|
|
48
|
+
this.setValue = this.setValue.bind(this);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
isEmpty(value: NSBoxTimeRangeValue): boolean
|
|
20
52
|
{
|
|
21
|
-
return
|
|
53
|
+
return !value || !value.from || !value.to;
|
|
22
54
|
}
|
|
23
55
|
|
|
24
56
|
getError(): string | null
|
|
@@ -29,12 +61,10 @@ export class NSBoxTimeRange extends NSBoxDateRangeBase<NSBoxTimeRangeProps>
|
|
|
29
61
|
return `${title} is required.`;
|
|
30
62
|
|
|
31
63
|
const fromErr = Validator.getErrorTime(title, value?.from, false);
|
|
32
|
-
if (fromErr)
|
|
33
|
-
return fromErr;
|
|
64
|
+
if (fromErr) return fromErr;
|
|
34
65
|
|
|
35
66
|
const toErr = Validator.getErrorTime(title, value?.to, false);
|
|
36
|
-
if (toErr)
|
|
37
|
-
return toErr;
|
|
67
|
+
if (toErr) return toErr;
|
|
38
68
|
|
|
39
69
|
if (maxRangeSeconds && value?.from && value?.to)
|
|
40
70
|
{
|
|
@@ -50,9 +80,40 @@ export class NSBoxTimeRange extends NSBoxDateRangeBase<NSBoxTimeRangeProps>
|
|
|
50
80
|
return null;
|
|
51
81
|
}
|
|
52
82
|
|
|
53
|
-
|
|
83
|
+
getValue(checkError: boolean = true): NSBoxTimeRangeValue | null
|
|
84
|
+
{
|
|
85
|
+
if (this.props.nullable)
|
|
86
|
+
if (this.NSBoxBaseLayout_Main.current?.isNull())
|
|
87
|
+
return null;
|
|
88
|
+
return NSBoxBaseLayout.checkGetValue(this, checkError, () => this.state.value);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
setValue(value: NSBoxTimeRangeValue | null, callback?: () => void): void
|
|
92
|
+
{
|
|
93
|
+
if (this.props.nullable)
|
|
94
|
+
this.NSBoxBaseLayout_Main.current?.setNull(value == null);
|
|
95
|
+
this.setState({ value }, () =>
|
|
96
|
+
{
|
|
97
|
+
this.props.onChanged?.(this);
|
|
98
|
+
callback?.();
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
setDisabled(disabled: boolean): void
|
|
103
|
+
{
|
|
104
|
+
this.NSBoxBaseLayout_Main.current?.setDisabled(disabled);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
private toDayjsValue(): [Dayjs, Dayjs] | null
|
|
54
108
|
{
|
|
55
|
-
const
|
|
109
|
+
const { value } = this.state;
|
|
110
|
+
if (!value?.from || !value?.to) return null;
|
|
111
|
+
return [dayjs(value.from, NSBoxTimeRange.FORMAT), dayjs(value.to, NSBoxTimeRange.FORMAT)];
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
private getBuiltinPresets(): { label: string; title: string; from: string; to: string }[]
|
|
115
|
+
{
|
|
116
|
+
const fmt = NSBoxTimeRange.FORMAT;
|
|
56
117
|
const now = new Date();
|
|
57
118
|
now.setSeconds(0, 0);
|
|
58
119
|
const to = TimeOperation.format(now, fmt);
|
|
@@ -65,30 +126,94 @@ export class NSBoxTimeRange extends NSBoxDateRangeBase<NSBoxTimeRangeProps>
|
|
|
65
126
|
];
|
|
66
127
|
}
|
|
67
128
|
|
|
68
|
-
|
|
129
|
+
private renderPresets(): React.ReactNode
|
|
69
130
|
{
|
|
70
|
-
const {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
131
|
+
const { preset, presets: customPresets } = this.props;
|
|
132
|
+
const fmt = NSBoxTimeRange.FORMAT;
|
|
133
|
+
|
|
134
|
+
const builtinPresets = preset ? this.getBuiltinPresets() : [];
|
|
135
|
+
|
|
136
|
+
const resolvedCustom = (customPresets ?? []).map(p => ({
|
|
137
|
+
shortName: p.shortName,
|
|
138
|
+
title: p.title,
|
|
139
|
+
from: TimeOperation.format(p.getFrom(), fmt),
|
|
140
|
+
to: TimeOperation.format(p.getTo(), fmt),
|
|
141
|
+
}));
|
|
142
|
+
|
|
143
|
+
const showDivider = builtinPresets.length > 0 && resolvedCustom.length > 0;
|
|
144
|
+
|
|
145
|
+
return (
|
|
146
|
+
<div className={Styles.ns_preset_container}>
|
|
147
|
+
{builtinPresets.map(p =>
|
|
148
|
+
{
|
|
149
|
+
const isActive = this.state.value?.from === p.from && this.state.value?.to === p.to;
|
|
150
|
+
return (
|
|
151
|
+
<button
|
|
152
|
+
key={p.label}
|
|
153
|
+
type="button"
|
|
154
|
+
title={p.title}
|
|
155
|
+
className={`${Styles.ns_preset_btn} ${isActive ? Styles.ns_preset_btn_active : ''}`}
|
|
156
|
+
onClick={() => this.setValue({ from: p.from, to: p.to })}
|
|
157
|
+
>
|
|
158
|
+
{p.label}
|
|
159
|
+
</button>
|
|
160
|
+
);
|
|
161
|
+
})}
|
|
162
|
+
{showDivider && <div className={Styles.ns_preset_divider} />}
|
|
163
|
+
{resolvedCustom.map(p =>
|
|
164
|
+
{
|
|
165
|
+
const isActive = this.state.value?.from === p.from && this.state.value?.to === p.to;
|
|
166
|
+
return (
|
|
167
|
+
<button
|
|
168
|
+
key={p.shortName}
|
|
169
|
+
type="button"
|
|
170
|
+
title={p.title}
|
|
171
|
+
className={`${Styles.ns_preset_btn} ${isActive ? Styles.ns_preset_btn_active : ''}`}
|
|
172
|
+
onClick={() => this.setValue({ from: p.from, to: p.to })}
|
|
173
|
+
>
|
|
174
|
+
{p.shortName}
|
|
175
|
+
</button>
|
|
176
|
+
);
|
|
177
|
+
})}
|
|
178
|
+
</div>
|
|
179
|
+
);
|
|
74
180
|
}
|
|
75
181
|
|
|
76
|
-
|
|
182
|
+
override render()
|
|
77
183
|
{
|
|
184
|
+
let menu = safeMenuMenuItem(this.props, () => { });
|
|
185
|
+
if (!menu.builtin.copy)
|
|
186
|
+
menu.builtin.copy = {
|
|
187
|
+
enabled: true,
|
|
188
|
+
getValue: () => this.state.value ? `${this.state.value.from} to ${this.state.value.to}` : '',
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
const showPresets = this.props.preset || (this.props.presets && this.props.presets.length > 0);
|
|
192
|
+
|
|
78
193
|
return (
|
|
79
|
-
<
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
{
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
this.
|
|
90
|
-
|
|
91
|
-
|
|
194
|
+
<NSBoxBaseLayout
|
|
195
|
+
ref={this.NSBoxBaseLayout_Main}
|
|
196
|
+
{...this.props}
|
|
197
|
+
menu={menu}
|
|
198
|
+
getValue={() => this.state.value ? `${this.state.value.from} - ${this.state.value.to}` : null}
|
|
199
|
+
>
|
|
200
|
+
<div className={Styles.ns_wrapper}>
|
|
201
|
+
<TimePicker.RangePicker
|
|
202
|
+
className={`${StylesNSBox.ns_box_input} ${Styles.ns_picker}`}
|
|
203
|
+
variant="borderless"
|
|
204
|
+
value={this.toDayjsValue()}
|
|
205
|
+
format={NSBoxTimeRange.FORMAT}
|
|
206
|
+
onChange={(_, timeStrings) =>
|
|
207
|
+
{
|
|
208
|
+
if (timeStrings?.[0] && timeStrings?.[1])
|
|
209
|
+
this.setValue({ from: timeStrings[0], to: timeStrings[1] });
|
|
210
|
+
else
|
|
211
|
+
this.setValue(null);
|
|
212
|
+
}}
|
|
213
|
+
/>
|
|
214
|
+
</div>
|
|
215
|
+
{showPresets && this.renderPresets()}
|
|
216
|
+
</NSBoxBaseLayout>
|
|
92
217
|
);
|
|
93
218
|
}
|
|
94
219
|
}
|
|
@@ -219,6 +219,17 @@ export class NSTable<RowType> extends Component<NSTableProps<RowType>, NSTableSt
|
|
|
219
219
|
{
|
|
220
220
|
let columns: TableColumnInfo[] = [];
|
|
221
221
|
this.foreachColumn(visible, c => columns.push(c));
|
|
222
|
+
if (visible === true)
|
|
223
|
+
{
|
|
224
|
+
let vs = this.getVisibleColumns();
|
|
225
|
+
if (vs.length > 0)
|
|
226
|
+
columns.sort((a, b) =>
|
|
227
|
+
{
|
|
228
|
+
let ai = vs.findIndex(v => v.table === a.table.name && v.column === a.name);
|
|
229
|
+
let bi = vs.findIndex(v => v.table === b.table.name && v.column === b.name);
|
|
230
|
+
return ai - bi;
|
|
231
|
+
});
|
|
232
|
+
}
|
|
222
233
|
return columns;
|
|
223
234
|
}
|
|
224
235
|
private showModal(description: string, title?: string)
|