@oneuptime/common 7.0.3163 → 7.0.3172
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/UI/Components/Filters/FilterViewer.tsx +3 -8
- package/UI/Components/ModelTable/BaseModelTable.tsx +38 -21
- package/UI/Components/ModelTable/TableView.tsx +144 -60
- package/UI/Components/MoreMenu/MoreMenu.tsx +79 -39
- package/UI/Components/MoreMenu/MoreMenuItem.tsx +5 -3
- package/UI/Components/MoreMenu/MoreMenuSection.tsx +2 -2
- package/UI/Components/Table/Table.tsx +7 -2
- package/UI/Components/Table/TableHeader.tsx +13 -20
- package/UI/Types/FunctionTypes.ts +2 -0
- package/build/dist/UI/Components/Filters/FilterViewer.js +2 -5
- package/build/dist/UI/Components/Filters/FilterViewer.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +20 -21
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/TableView.js +64 -25
- package/build/dist/UI/Components/ModelTable/TableView.js.map +1 -1
- package/build/dist/UI/Components/MoreMenu/MoreMenu.js +29 -8
- package/build/dist/UI/Components/MoreMenu/MoreMenu.js.map +1 -1
- package/build/dist/UI/Components/MoreMenu/MoreMenuItem.js +3 -3
- package/build/dist/UI/Components/MoreMenu/MoreMenuItem.js.map +1 -1
- package/build/dist/UI/Components/MoreMenu/MoreMenuSection.js +1 -1
- package/build/dist/UI/Components/MoreMenu/MoreMenuSection.js.map +1 -1
- package/build/dist/UI/Components/Table/Table.js +2 -2
- package/build/dist/UI/Components/Table/Table.js.map +1 -1
- package/build/dist/UI/Components/Table/TableHeader.js +9 -16
- package/build/dist/UI/Components/Table/TableHeader.js.map +1 -1
- package/package.json +2 -2
|
@@ -28,7 +28,7 @@ export interface ComponentProps<T extends GenericObject> {
|
|
|
28
28
|
onFilterModalOpen: () => void;
|
|
29
29
|
isModalLoading?: boolean;
|
|
30
30
|
onFilterRefreshClick?: undefined | (() => void);
|
|
31
|
-
|
|
31
|
+
filterData?: FilterData<T> | undefined;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
type FilterComponentFunction = <T extends GenericObject>(
|
|
@@ -38,9 +38,6 @@ type FilterComponentFunction = <T extends GenericObject>(
|
|
|
38
38
|
const FilterComponent: FilterComponentFunction = <T extends GenericObject>(
|
|
39
39
|
props: ComponentProps<T>,
|
|
40
40
|
): ReactElement => {
|
|
41
|
-
const [filterData, setFilterData] = useState<FilterData<T>>(
|
|
42
|
-
props.initialFilterData || {},
|
|
43
|
-
);
|
|
44
41
|
const [tempFilterDataForModal, setTempFilterDataForModal] = useState<
|
|
45
42
|
FilterData<T>
|
|
46
43
|
>({});
|
|
@@ -50,14 +47,13 @@ const FilterComponent: FilterComponentFunction = <T extends GenericObject>(
|
|
|
50
47
|
const changeFilterData: ChangeFilterDataFunction = (
|
|
51
48
|
filterData: FilterData<T>,
|
|
52
49
|
) => {
|
|
53
|
-
setFilterData(filterData);
|
|
54
50
|
setTempFilterDataForModal(filterData);
|
|
55
51
|
props.onFilterChanged?.(filterData);
|
|
56
52
|
};
|
|
57
53
|
|
|
58
54
|
useEffect(() => {
|
|
59
55
|
if (props.showFilterModal) {
|
|
60
|
-
setTempFilterDataForModal({ ...filterData });
|
|
56
|
+
setTempFilterDataForModal({ ...props.filterData });
|
|
61
57
|
}
|
|
62
58
|
}, [props.showFilterModal]);
|
|
63
59
|
|
|
@@ -337,7 +333,7 @@ const FilterComponent: FilterComponentFunction = <T extends GenericObject>(
|
|
|
337
333
|
|
|
338
334
|
const filterTexts: Array<ReactElement> = translateFilterToText({
|
|
339
335
|
filters: props.filters,
|
|
340
|
-
filterData: filterData,
|
|
336
|
+
filterData: props.filterData || {},
|
|
341
337
|
});
|
|
342
338
|
|
|
343
339
|
if (props.filterError) {
|
|
@@ -419,7 +415,6 @@ const FilterComponent: FilterComponentFunction = <T extends GenericObject>(
|
|
|
419
415
|
props.onFilterModalClose();
|
|
420
416
|
}}
|
|
421
417
|
onSubmit={() => {
|
|
422
|
-
setFilterData({ ...tempFilterDataForModal });
|
|
423
418
|
setTempFilterDataForModal({});
|
|
424
419
|
if (props.onFilterChanged) {
|
|
425
420
|
props.onFilterChanged({
|
|
@@ -233,6 +233,8 @@ const BaseModelTable: <TBaseModel extends BaseModel | AnalyticsBaseModel>(
|
|
|
233
233
|
) => ReactElement = <TBaseModel extends BaseModel | AnalyticsBaseModel>(
|
|
234
234
|
props: ComponentProps<TBaseModel>,
|
|
235
235
|
): ReactElement => {
|
|
236
|
+
const [tableView, setTableView] = useState<TableView | null>(null);
|
|
237
|
+
|
|
236
238
|
const matchBulkSelectedItemByField: keyof TBaseModel =
|
|
237
239
|
props.bulkActions?.matchBulkSelectedItemByField || "_id";
|
|
238
240
|
|
|
@@ -800,23 +802,17 @@ const BaseModelTable: <TBaseModel extends BaseModel | AnalyticsBaseModel>(
|
|
|
800
802
|
}
|
|
801
803
|
|
|
802
804
|
if (props.saveFilterProps && props.saveFilterProps.tableId) {
|
|
803
|
-
const currentTableView: TableView = new TableView();
|
|
804
|
-
currentTableView.query = (query || {}) as any;
|
|
805
|
-
currentTableView.itemsOnPage = itemsOnPage || 10;
|
|
806
|
-
|
|
807
|
-
if (sortBy && sortOrder) {
|
|
808
|
-
currentTableView.sort = {
|
|
809
|
-
[sortBy as string]: sortOrder,
|
|
810
|
-
};
|
|
811
|
-
} else {
|
|
812
|
-
currentTableView.sort = {};
|
|
813
|
-
}
|
|
814
|
-
|
|
815
805
|
return (
|
|
816
806
|
<TableViewElement
|
|
817
807
|
tableId={props.saveFilterProps.tableId}
|
|
818
|
-
|
|
819
|
-
|
|
808
|
+
tableView={tableView}
|
|
809
|
+
currentQuery={query}
|
|
810
|
+
currentSortBy={sortBy}
|
|
811
|
+
currentItemsOnPage={itemsOnPage}
|
|
812
|
+
currentSortOrder={sortOrder}
|
|
813
|
+
onViewChange={async (tableView: TableView | null) => {
|
|
814
|
+
setTableView(tableView);
|
|
815
|
+
|
|
820
816
|
if (tableView) {
|
|
821
817
|
const sortBy: string | undefined = Object.keys(
|
|
822
818
|
tableView.sort || {},
|
|
@@ -831,9 +827,14 @@ const BaseModelTable: <TBaseModel extends BaseModel | AnalyticsBaseModel>(
|
|
|
831
827
|
|
|
832
828
|
// then set query, sort and items on the page
|
|
833
829
|
setQuery(tableView.query || {});
|
|
830
|
+
setFilterData(tableView.query || {});
|
|
834
831
|
setItemsOnPage(tableView.itemsOnPage || 10);
|
|
835
|
-
setSortBy(sortBy as keyof TBaseModel);
|
|
832
|
+
setSortBy((sortBy as keyof TBaseModel) || null);
|
|
836
833
|
setSortOrder(sortOrder);
|
|
834
|
+
|
|
835
|
+
if (classicTableFilters.length === 0) {
|
|
836
|
+
await getFilterDropdownItems();
|
|
837
|
+
}
|
|
837
838
|
} else {
|
|
838
839
|
setQuery({});
|
|
839
840
|
setSortBy(null);
|
|
@@ -906,9 +907,7 @@ const BaseModelTable: <TBaseModel extends BaseModel | AnalyticsBaseModel>(
|
|
|
906
907
|
headerbuttons.push({
|
|
907
908
|
title: "",
|
|
908
909
|
buttonStyle: ButtonStyleType.ICON,
|
|
909
|
-
className:
|
|
910
|
-
? "p-1 px-1 pr-0 pl-0 py-0 mt-1"
|
|
911
|
-
: "py-0 pr-0 pl-1 mt-1",
|
|
910
|
+
className: "py-0 pr-0 pl-1 mt-1",
|
|
912
911
|
onClick: () => {
|
|
913
912
|
setQuery({});
|
|
914
913
|
setShowFilterModal(true);
|
|
@@ -1238,6 +1237,10 @@ const BaseModelTable: <TBaseModel extends BaseModel | AnalyticsBaseModel>(
|
|
|
1238
1237
|
setActionButtonSchema(actionsSchema);
|
|
1239
1238
|
};
|
|
1240
1239
|
|
|
1240
|
+
const [filterData, setFilterData] = useState<FilterData<TBaseModel>>(
|
|
1241
|
+
props.initialFilterData || {},
|
|
1242
|
+
);
|
|
1243
|
+
|
|
1241
1244
|
type OnFilterChangedFunction = (filterData: FilterData<TBaseModel>) => void;
|
|
1242
1245
|
|
|
1243
1246
|
const onFilterChanged: OnFilterChangedFunction = (
|
|
@@ -1245,6 +1248,8 @@ const BaseModelTable: <TBaseModel extends BaseModel | AnalyticsBaseModel>(
|
|
|
1245
1248
|
): void => {
|
|
1246
1249
|
const newQuery: Query<TBaseModel> = {};
|
|
1247
1250
|
|
|
1251
|
+
setFilterData(filterData);
|
|
1252
|
+
|
|
1248
1253
|
for (const key in filterData) {
|
|
1249
1254
|
if (filterData[key] && typeof filterData[key] === Typeof.String) {
|
|
1250
1255
|
newQuery[key as keyof TBaseModel] = (filterData[key] || "").toString();
|
|
@@ -1349,8 +1354,9 @@ const BaseModelTable: <TBaseModel extends BaseModel | AnalyticsBaseModel>(
|
|
|
1349
1354
|
<Table
|
|
1350
1355
|
onFilterChanged={(filterData: FilterData<TBaseModel>) => {
|
|
1351
1356
|
onFilterChanged(filterData);
|
|
1357
|
+
setTableView(null);
|
|
1352
1358
|
}}
|
|
1353
|
-
|
|
1359
|
+
filterData={filterData}
|
|
1354
1360
|
className={
|
|
1355
1361
|
props.cardProps
|
|
1356
1362
|
? ""
|
|
@@ -1400,6 +1406,8 @@ const BaseModelTable: <TBaseModel extends BaseModel | AnalyticsBaseModel>(
|
|
|
1400
1406
|
}),
|
|
1401
1407
|
);
|
|
1402
1408
|
}}
|
|
1409
|
+
sortBy={sortBy}
|
|
1410
|
+
sortOrder={sortOrder}
|
|
1403
1411
|
onBulkSelectItemsOnCurrentPage={() => {
|
|
1404
1412
|
const items: TBaseModel[] = [...bulkSelectedItems, ...data];
|
|
1405
1413
|
|
|
@@ -1452,6 +1460,7 @@ const BaseModelTable: <TBaseModel extends BaseModel | AnalyticsBaseModel>(
|
|
|
1452
1460
|
) => {
|
|
1453
1461
|
setSortBy(sortBy);
|
|
1454
1462
|
setSortOrder(sortOrder);
|
|
1463
|
+
setTableView(null);
|
|
1455
1464
|
}}
|
|
1456
1465
|
singularLabel={props.singularName || model.singularName || "Item"}
|
|
1457
1466
|
pluralLabel={props.pluralName || model.pluralName || "Items"}
|
|
@@ -1483,9 +1492,17 @@ const BaseModelTable: <TBaseModel extends BaseModel | AnalyticsBaseModel>(
|
|
|
1483
1492
|
await fetchItems();
|
|
1484
1493
|
}}
|
|
1485
1494
|
disablePagination={props.disablePagination || false}
|
|
1486
|
-
onNavigateToPage={async (
|
|
1495
|
+
onNavigateToPage={async (
|
|
1496
|
+
pageNumber: number,
|
|
1497
|
+
newItemsOnPage: number,
|
|
1498
|
+
) => {
|
|
1487
1499
|
setCurrentPageNumber(pageNumber);
|
|
1488
|
-
|
|
1500
|
+
|
|
1501
|
+
if (newItemsOnPage !== itemsOnPage) {
|
|
1502
|
+
setTableView(null);
|
|
1503
|
+
}
|
|
1504
|
+
|
|
1505
|
+
setItemsOnPage(newItemsOnPage);
|
|
1489
1506
|
}}
|
|
1490
1507
|
noItemsMessage={props.noItemsMessage || ""}
|
|
1491
1508
|
onRefreshClick={async () => {
|
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
FunctionComponent,
|
|
3
|
-
ReactElement,
|
|
4
|
-
useEffect,
|
|
5
|
-
useState,
|
|
6
|
-
} from "react";
|
|
1
|
+
import React, { ReactElement, useEffect, useRef, useState } from "react";
|
|
7
2
|
import TableView from "../../../Models/DatabaseModels/TableView";
|
|
8
3
|
import ObjectID from "../../../Types/ObjectID";
|
|
9
4
|
import MoreMenu from "../MoreMenu/MoreMenu";
|
|
@@ -14,7 +9,7 @@ import { LIMIT_PER_PROJECT } from "../../../Types/Database/LimitMax";
|
|
|
14
9
|
import SortOrder from "../../../Types/BaseDatabase/SortOrder";
|
|
15
10
|
import API from "../../../Utils/API";
|
|
16
11
|
import MoreMenuSection from "../MoreMenu/MoreMenuSection";
|
|
17
|
-
import
|
|
12
|
+
import { ButtonStyleType } from "../Button/Button";
|
|
18
13
|
import IconProp from "../../../Types/Icon/IconProp";
|
|
19
14
|
import { BarLoader } from "react-spinners";
|
|
20
15
|
import ConfirmModal from "../Modal/ConfirmModal";
|
|
@@ -22,18 +17,30 @@ import ModelFormModal from "../ModelFormModal/ModelFormModal";
|
|
|
22
17
|
import { FormType } from "../Forms/ModelForm";
|
|
23
18
|
import FormFieldSchemaType from "../Forms/Types/FormFieldSchemaType";
|
|
24
19
|
import { PromiseVoidFunction } from "../../../Types/FunctionTypes";
|
|
25
|
-
import {
|
|
20
|
+
import { GetReactElementArrayFunction } from "../../Types/FunctionTypes";
|
|
26
21
|
import ProjectUtil from "../../Utils/Project";
|
|
27
22
|
import User from "../../Utils/User";
|
|
23
|
+
import Icon, { SizeProp, ThickProp } from "../Icon/Icon";
|
|
24
|
+
import GenericObject from "../../../Types/GenericObject";
|
|
25
|
+
import Query from "../../../Types/BaseDatabase/Query";
|
|
26
|
+
import DatabaseBaseModel from "../../../Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
|
|
27
|
+
import AnalyticsBaseModel from "../../../Models/AnalyticsModels/AnalyticsBaseModel/AnalyticsBaseModel";
|
|
28
|
+
import Sort from "../../../Types/BaseDatabase/Sort";
|
|
28
29
|
|
|
29
|
-
export interface ComponentProps {
|
|
30
|
+
export interface ComponentProps<T extends GenericObject> {
|
|
30
31
|
tableId: string;
|
|
31
32
|
onViewChange: (tableView: TableView | null) => void;
|
|
32
|
-
|
|
33
|
+
currentQuery: Query<T>;
|
|
34
|
+
currentSortOrder: SortOrder | null;
|
|
35
|
+
currentSortBy: keyof T | null;
|
|
36
|
+
currentItemsOnPage: number;
|
|
37
|
+
tableView: TableView | null;
|
|
33
38
|
}
|
|
34
39
|
|
|
35
|
-
const TableViewElement:
|
|
36
|
-
props: ComponentProps
|
|
40
|
+
const TableViewElement: <T extends DatabaseBaseModel | AnalyticsBaseModel>(
|
|
41
|
+
props: ComponentProps<T>,
|
|
42
|
+
) => ReactElement = <T extends DatabaseBaseModel | AnalyticsBaseModel>(
|
|
43
|
+
props: ComponentProps<T>,
|
|
37
44
|
): ReactElement => {
|
|
38
45
|
const [error, setError] = useState<string>("");
|
|
39
46
|
const [isLoading, setIsLoading] = useState<boolean>(false);
|
|
@@ -47,9 +54,15 @@ const TableViewElement: FunctionComponent<ComponentProps> = (
|
|
|
47
54
|
const [showCreateNewViewModal, setShowCreateNewViewModel] =
|
|
48
55
|
useState<boolean>(false);
|
|
49
56
|
|
|
57
|
+
const moreMenuRef: React.MutableRefObject<undefined> = useRef();
|
|
58
|
+
|
|
50
59
|
const [currentlySelectedView, setCurrentlySelectedView] =
|
|
51
60
|
useState<TableView | null>(null);
|
|
52
61
|
|
|
62
|
+
useEffect(() => {
|
|
63
|
+
setCurrentlySelectedView(props.tableView);
|
|
64
|
+
}, [props.tableView]);
|
|
65
|
+
|
|
53
66
|
// load all the filters for this user and for this project.
|
|
54
67
|
const fetchTableViews: PromiseVoidFunction = async (): Promise<void> => {
|
|
55
68
|
try {
|
|
@@ -122,21 +135,28 @@ const TableViewElement: FunctionComponent<ComponentProps> = (
|
|
|
122
135
|
(item: TableView): ReactElement => {
|
|
123
136
|
return (
|
|
124
137
|
<div className="flex">
|
|
125
|
-
<
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
138
|
+
<div className="h-4 w-4 mr-2">
|
|
139
|
+
<Icon
|
|
140
|
+
icon={IconProp.Edit}
|
|
141
|
+
className="text-gray-400 hover:text-gray-600"
|
|
142
|
+
size={SizeProp.Regular}
|
|
143
|
+
thick={ThickProp.Thick}
|
|
144
|
+
onClick={() => {
|
|
145
|
+
setTableViewToEdit(item);
|
|
146
|
+
}}
|
|
147
|
+
/>
|
|
148
|
+
</div>
|
|
149
|
+
<div className="h-4 w-4">
|
|
150
|
+
<Icon
|
|
151
|
+
className="text-gray-400 hover:text-gray-600"
|
|
152
|
+
icon={IconProp.Trash}
|
|
153
|
+
size={SizeProp.Regular}
|
|
154
|
+
thick={ThickProp.Thick}
|
|
155
|
+
onClick={() => {
|
|
156
|
+
setTableViewToDelete(item);
|
|
157
|
+
}}
|
|
158
|
+
/>
|
|
159
|
+
</div>
|
|
140
160
|
</div>
|
|
141
161
|
);
|
|
142
162
|
};
|
|
@@ -150,6 +170,8 @@ const TableViewElement: FunctionComponent<ComponentProps> = (
|
|
|
150
170
|
key={index}
|
|
151
171
|
rightElement={getRightElementForTableViewMenuItem(item)}
|
|
152
172
|
text={item.name || ""}
|
|
173
|
+
className="text-gray-600 hover:text-gray-800"
|
|
174
|
+
icon={IconProp.Window}
|
|
153
175
|
onClick={() => {
|
|
154
176
|
props.onViewChange && props.onViewChange(item);
|
|
155
177
|
setCurrentlySelectedView(item);
|
|
@@ -159,42 +181,36 @@ const TableViewElement: FunctionComponent<ComponentProps> = (
|
|
|
159
181
|
});
|
|
160
182
|
};
|
|
161
183
|
|
|
162
|
-
const getMenuContents:
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
184
|
+
const getMenuContents: GetReactElementArrayFunction =
|
|
185
|
+
(): Array<ReactElement> => {
|
|
186
|
+
if (isLoading) {
|
|
187
|
+
return [<BarLoader />];
|
|
188
|
+
}
|
|
166
189
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
190
|
+
const elements: Array<ReactElement> = [];
|
|
191
|
+
|
|
192
|
+
if (allTableViews.length > 0) {
|
|
193
|
+
elements.push(
|
|
170
194
|
<MoreMenuSection title="Saved Views">
|
|
171
195
|
{getViewItems()}
|
|
172
|
-
</MoreMenuSection
|
|
173
|
-
)
|
|
174
|
-
|
|
175
|
-
)}
|
|
176
|
-
|
|
177
|
-
{currentlySelectedView ? (
|
|
178
|
-
<MoreMenuItem
|
|
179
|
-
text="Deselect View"
|
|
180
|
-
onClick={() => {
|
|
181
|
-
setCurrentlySelectedView(null);
|
|
182
|
-
props.onViewChange && props.onViewChange(null);
|
|
183
|
-
}}
|
|
184
|
-
></MoreMenuItem>
|
|
185
|
-
) : (
|
|
186
|
-
<></>
|
|
187
|
-
)}
|
|
196
|
+
</MoreMenuSection>,
|
|
197
|
+
);
|
|
198
|
+
}
|
|
188
199
|
|
|
200
|
+
elements.push(
|
|
189
201
|
<MoreMenuItem
|
|
190
|
-
text="Save View"
|
|
202
|
+
text="Save as New View"
|
|
203
|
+
className="bg-gray-50 hover:bg-gray-100 text-gray-700 hover:text-gray-900 font-medium -mt-2"
|
|
204
|
+
icon={IconProp.Add}
|
|
205
|
+
iconClassName=""
|
|
191
206
|
onClick={() => {
|
|
192
207
|
setShowCreateNewViewModel(true);
|
|
193
208
|
}}
|
|
194
|
-
></MoreMenuItem
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
209
|
+
></MoreMenuItem>,
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
return elements;
|
|
213
|
+
};
|
|
198
214
|
|
|
199
215
|
if (error) {
|
|
200
216
|
return (
|
|
@@ -224,6 +240,7 @@ const TableViewElement: FunctionComponent<ComponentProps> = (
|
|
|
224
240
|
submitButtonText="Save Changes"
|
|
225
241
|
onSuccess={async () => {
|
|
226
242
|
setTableViewToEdit(undefined);
|
|
243
|
+
|
|
227
244
|
await fetchTableViews();
|
|
228
245
|
}}
|
|
229
246
|
formProps={{
|
|
@@ -279,15 +296,28 @@ const TableViewElement: FunctionComponent<ComponentProps> = (
|
|
|
279
296
|
}}
|
|
280
297
|
submitButtonText="Save Changes"
|
|
281
298
|
onBeforeCreate={(tableView: TableView) => {
|
|
299
|
+
let sort: Sort<T> = {};
|
|
300
|
+
|
|
301
|
+
if (props.currentSortOrder && props.currentSortBy) {
|
|
302
|
+
sort = {
|
|
303
|
+
[props.currentSortBy]: props.currentSortOrder,
|
|
304
|
+
} as Sort<T>;
|
|
305
|
+
}
|
|
306
|
+
|
|
282
307
|
tableView.tableId = props.tableId;
|
|
283
|
-
tableView.query =
|
|
284
|
-
|
|
285
|
-
|
|
308
|
+
tableView.query =
|
|
309
|
+
(props.currentQuery as Query<
|
|
310
|
+
DatabaseBaseModel | AnalyticsBaseModel
|
|
311
|
+
>) || {};
|
|
312
|
+
tableView.itemsOnPage = props?.currentItemsOnPage || 10;
|
|
313
|
+
tableView.sort = sort || {};
|
|
286
314
|
return Promise.resolve(tableView);
|
|
287
315
|
}}
|
|
288
|
-
onSuccess={async () => {
|
|
316
|
+
onSuccess={async (tableView: TableView) => {
|
|
289
317
|
setShowCreateNewViewModel(false);
|
|
290
318
|
await fetchTableViews();
|
|
319
|
+
// set as current view
|
|
320
|
+
props.onViewChange && props.onViewChange(tableView);
|
|
291
321
|
}}
|
|
292
322
|
formProps={{
|
|
293
323
|
name: "Save New View",
|
|
@@ -311,7 +341,61 @@ const TableViewElement: FunctionComponent<ComponentProps> = (
|
|
|
311
341
|
);
|
|
312
342
|
}
|
|
313
343
|
|
|
314
|
-
|
|
344
|
+
type GetElementToBeShownInsteadOfButtonFunction = () =>
|
|
345
|
+
| ReactElement
|
|
346
|
+
| undefined;
|
|
347
|
+
|
|
348
|
+
const getElementToBeShownInsteadOfButton: GetElementToBeShownInsteadOfButtonFunction =
|
|
349
|
+
(): ReactElement | undefined => {
|
|
350
|
+
if (!currentlySelectedView) {
|
|
351
|
+
return undefined;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
return (
|
|
355
|
+
<div className="ml-2 mt-1 cursor-pointer font-semibold flex rounded-full border-2 border-gray-600 text-gray-600 text-xs p-1 pl-2 pr-2">
|
|
356
|
+
<div
|
|
357
|
+
onClick={() => {
|
|
358
|
+
flipDropdown();
|
|
359
|
+
}}
|
|
360
|
+
>
|
|
361
|
+
{currentlySelectedView.name}
|
|
362
|
+
</div>
|
|
363
|
+
<div className="h-4 w-4 rounded-full bg-gray-500 text-white hover:bg-gray-800 ml-3 -mr-1 p-1">
|
|
364
|
+
<Icon
|
|
365
|
+
icon={IconProp.Close}
|
|
366
|
+
size={SizeProp.Regular}
|
|
367
|
+
thick={ThickProp.Thick}
|
|
368
|
+
onClick={() => {
|
|
369
|
+
setCurrentlySelectedView(null);
|
|
370
|
+
props.onViewChange && props.onViewChange(null);
|
|
371
|
+
closeDropdownMenu();
|
|
372
|
+
}}
|
|
373
|
+
/>
|
|
374
|
+
</div>
|
|
375
|
+
</div>
|
|
376
|
+
);
|
|
377
|
+
};
|
|
378
|
+
|
|
379
|
+
const closeDropdownMenu: VoidFunction = (): void => {
|
|
380
|
+
if (moreMenuRef.current) {
|
|
381
|
+
(moreMenuRef.current as any).closeDropdown();
|
|
382
|
+
}
|
|
383
|
+
};
|
|
384
|
+
|
|
385
|
+
const flipDropdown: VoidFunction = (): void => {
|
|
386
|
+
if (moreMenuRef.current) {
|
|
387
|
+
(moreMenuRef.current as any).flipDropdown();
|
|
388
|
+
}
|
|
389
|
+
};
|
|
390
|
+
|
|
391
|
+
return (
|
|
392
|
+
<MoreMenu
|
|
393
|
+
elementToBeShownInsteadOfButton={getElementToBeShownInsteadOfButton()}
|
|
394
|
+
ref={moreMenuRef}
|
|
395
|
+
>
|
|
396
|
+
{getMenuContents()}
|
|
397
|
+
</MoreMenu>
|
|
398
|
+
);
|
|
315
399
|
};
|
|
316
400
|
|
|
317
401
|
export default TableViewElement;
|
|
@@ -1,54 +1,94 @@
|
|
|
1
1
|
import React, {
|
|
2
|
-
|
|
2
|
+
forwardRef,
|
|
3
3
|
ReactElement,
|
|
4
4
|
useEffect,
|
|
5
|
+
useImperativeHandle,
|
|
5
6
|
useState,
|
|
6
7
|
} from "react";
|
|
7
|
-
import Button, { ButtonStyleType } from "../Button/Button";
|
|
8
8
|
import IconProp from "../../../Types/Icon/IconProp";
|
|
9
9
|
import useComponentOutsideClick from "../../Types/UseComponentOutsideClick";
|
|
10
|
+
import Icon from "../Icon/Icon";
|
|
10
11
|
|
|
11
12
|
export interface ComponentProps {
|
|
12
|
-
children: Array<ReactElement
|
|
13
|
+
children: Array<ReactElement>;
|
|
14
|
+
elementToBeShownInsteadOfButton?: ReactElement | undefined;
|
|
13
15
|
}
|
|
14
16
|
|
|
15
|
-
const MoreMenu:
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
17
|
+
const MoreMenu: React.ForwardRefExoticComponent<
|
|
18
|
+
ComponentProps & React.RefAttributes<unknown>
|
|
19
|
+
> = forwardRef(
|
|
20
|
+
(props: ComponentProps, componentRef: React.ForwardedRef<unknown>) => {
|
|
21
|
+
const { ref, isComponentVisible, setIsComponentVisible } =
|
|
22
|
+
useComponentOutsideClick(false);
|
|
23
|
+
|
|
24
|
+
useImperativeHandle(componentRef, () => {
|
|
25
|
+
return {
|
|
26
|
+
closeDropdown() {
|
|
27
|
+
setIsComponentVisible(false);
|
|
28
|
+
},
|
|
29
|
+
openDropdown() {
|
|
30
|
+
setIsComponentVisible(true);
|
|
31
|
+
},
|
|
32
|
+
flipDropdown() {
|
|
33
|
+
setIsComponentVisible(!isDropdownVisible);
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const [isDropdownVisible, setDropdownVisible] = useState<boolean>(false);
|
|
39
|
+
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
setDropdownVisible(isComponentVisible);
|
|
42
|
+
}, [isComponentVisible]);
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<div className="relative inline-block text-left">
|
|
46
|
+
{!props.elementToBeShownInsteadOfButton && (
|
|
47
|
+
<div className="h-7 w-7 text-gray-600 mt-1 cursor-pointer">
|
|
48
|
+
<Icon
|
|
49
|
+
icon={IconProp.More}
|
|
50
|
+
className="p-1"
|
|
51
|
+
onClick={() => {
|
|
52
|
+
setIsComponentVisible(!isDropdownVisible);
|
|
53
|
+
}}
|
|
54
|
+
/>
|
|
55
|
+
</div>
|
|
56
|
+
)}
|
|
57
|
+
|
|
58
|
+
{props.elementToBeShownInsteadOfButton && (
|
|
59
|
+
<div>{props.elementToBeShownInsteadOfButton}</div>
|
|
60
|
+
)}
|
|
61
|
+
|
|
62
|
+
{isComponentVisible && (
|
|
63
|
+
<div
|
|
64
|
+
ref={ref}
|
|
65
|
+
className="absolute right-0 z-10 mt-2 w-56 origin-top-right divide-y divide-gray-100 rounded-md bg-white shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none"
|
|
66
|
+
role="menu"
|
|
67
|
+
aria-orientation="vertical"
|
|
68
|
+
aria-labelledby="menu-button"
|
|
69
|
+
>
|
|
70
|
+
{props.children.map((child: ReactElement, index: number) => {
|
|
71
|
+
return (
|
|
72
|
+
<div
|
|
73
|
+
key={index}
|
|
74
|
+
role="menuitem"
|
|
75
|
+
onClick={() => {
|
|
76
|
+
if (isComponentVisible) {
|
|
77
|
+
setIsComponentVisible(false);
|
|
78
|
+
}
|
|
79
|
+
}}
|
|
80
|
+
>
|
|
81
|
+
{child}
|
|
82
|
+
</div>
|
|
83
|
+
);
|
|
84
|
+
})}
|
|
85
|
+
</div>
|
|
86
|
+
)}
|
|
37
87
|
</div>
|
|
88
|
+
);
|
|
89
|
+
},
|
|
90
|
+
);
|
|
38
91
|
|
|
39
|
-
|
|
40
|
-
<div
|
|
41
|
-
ref={ref}
|
|
42
|
-
className="absolute right-0 z-10 mt-2 w-56 origin-top-right divide-y divide-gray-100 rounded-md bg-white shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none"
|
|
43
|
-
role="menu"
|
|
44
|
-
aria-orientation="vertical"
|
|
45
|
-
aria-labelledby="menu-button"
|
|
46
|
-
>
|
|
47
|
-
{props.children}
|
|
48
|
-
</div>
|
|
49
|
-
)}
|
|
50
|
-
</div>
|
|
51
|
-
);
|
|
52
|
-
};
|
|
92
|
+
MoreMenu.displayName = "MoreMenu";
|
|
53
93
|
|
|
54
94
|
export default MoreMenu;
|
|
@@ -7,6 +7,8 @@ export interface ComponentProps {
|
|
|
7
7
|
text: string;
|
|
8
8
|
onClick: () => void;
|
|
9
9
|
rightElement?: Array<ReactElement> | ReactElement | undefined;
|
|
10
|
+
className?: string | undefined;
|
|
11
|
+
iconClassName?: string | undefined;
|
|
10
12
|
}
|
|
11
13
|
|
|
12
14
|
const MoreMenuItem: FunctionComponent<ComponentProps> = (
|
|
@@ -14,7 +16,7 @@ const MoreMenuItem: FunctionComponent<ComponentProps> = (
|
|
|
14
16
|
): ReactElement => {
|
|
15
17
|
return (
|
|
16
18
|
<a
|
|
17
|
-
className=
|
|
19
|
+
className={`cursor-pointer group flex items-center px-4 py-2 text-sm text-gray-600 hover:text-gray-700 hover:bg-gray-50 ${props.className}`}
|
|
18
20
|
role="menuitem"
|
|
19
21
|
onClick={() => {
|
|
20
22
|
props.onClick();
|
|
@@ -23,10 +25,10 @@ const MoreMenuItem: FunctionComponent<ComponentProps> = (
|
|
|
23
25
|
{props.icon && (
|
|
24
26
|
<Icon
|
|
25
27
|
icon={props.icon}
|
|
26
|
-
className=
|
|
28
|
+
className={`mr-3 h-5 w-5 text-gray-400 text-gray-700 hover:text-gray-900 ${props.iconClassName}`}
|
|
27
29
|
/>
|
|
28
30
|
)}
|
|
29
|
-
<div className="flex justify-between">
|
|
31
|
+
<div className="flex w-full justify-between">
|
|
30
32
|
<div>{props.text}</div>
|
|
31
33
|
<div>{props.rightElement}</div>
|
|
32
34
|
</div>
|
|
@@ -10,8 +10,8 @@ const MoreMenuSection: FunctionComponent<ComponentProps> = (
|
|
|
10
10
|
): ReactElement => {
|
|
11
11
|
return (
|
|
12
12
|
<div>
|
|
13
|
-
<div className="text-gray-400 text-
|
|
14
|
-
{props.title.
|
|
13
|
+
<div className="text-gray-400 text-xs font-medium pt-2 pl-3 pr-3 pb-2">
|
|
14
|
+
{props.title.toUpperCase()}
|
|
15
15
|
</div>
|
|
16
16
|
{props.children}
|
|
17
17
|
<MoreMenuDivider />
|