@journeyapps-labs/reactor-mod-data-browser 3.5.0 → 3.6.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 (49) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/@types/actions/schema-model/DeleteSchemaModelAction.d.ts +12 -0
  3. package/dist/@types/core/AbstractConnection.d.ts +1 -0
  4. package/dist/@types/core/delete-schema-models.d.ts +8 -0
  5. package/dist/@types/forms/types/shared/ui.d.ts +6 -0
  6. package/dist/@types/panels/query/PageResultsWidget.d.ts +5 -1
  7. package/dist/@types/panels/query/QueryPanelFactory.d.ts +8 -0
  8. package/dist/@types/panels/query/TableControlsWidget.d.ts +2 -0
  9. package/dist/@types/panels/query/table-controls/SelectionControlsWidget.d.ts +6 -0
  10. package/dist/DataBrowserModule.js +2 -0
  11. package/dist/DataBrowserModule.js.map +1 -1
  12. package/dist/actions/schema-model/DeleteSchemaModelAction.js +27 -0
  13. package/dist/actions/schema-model/DeleteSchemaModelAction.js.map +1 -0
  14. package/dist/core/AbstractConnection.js +21 -0
  15. package/dist/core/AbstractConnection.js.map +1 -1
  16. package/dist/core/delete-schema-models.js +101 -0
  17. package/dist/core/delete-schema-models.js.map +1 -0
  18. package/dist/core/query/query-simple/SimpleQueryColumns.js +0 -2
  19. package/dist/core/query/query-simple/SimpleQueryColumns.js.map +1 -1
  20. package/dist/entities/SchemaModelObjectEntityDefinition.js +5 -0
  21. package/dist/entities/SchemaModelObjectEntityDefinition.js.map +1 -1
  22. package/dist/panels/model/ModelPanelWidget.js +12 -8
  23. package/dist/panels/model/ModelPanelWidget.js.map +1 -1
  24. package/dist/panels/query/PageResultsWidget.js +26 -6
  25. package/dist/panels/query/PageResultsWidget.js.map +1 -1
  26. package/dist/panels/query/QueryPanelFactory.js +39 -4
  27. package/dist/panels/query/QueryPanelFactory.js.map +1 -1
  28. package/dist/panels/query/QueryPanelWidget.js +12 -2
  29. package/dist/panels/query/QueryPanelWidget.js.map +1 -1
  30. package/dist/panels/query/TableControlsWidget.js +2 -0
  31. package/dist/panels/query/TableControlsWidget.js.map +1 -1
  32. package/dist/panels/query/table-controls/SelectionControlsWidget.js +11 -0
  33. package/dist/panels/query/table-controls/SelectionControlsWidget.js.map +1 -0
  34. package/dist/tsconfig.tsbuildinfo +1 -1
  35. package/dist-module/bundle.js +56 -56
  36. package/dist-module/bundle.js.map +1 -1
  37. package/package.json +3 -3
  38. package/src/DataBrowserModule.ts +2 -0
  39. package/src/actions/schema-model/DeleteSchemaModelAction.ts +43 -0
  40. package/src/core/AbstractConnection.ts +21 -0
  41. package/src/core/delete-schema-models.ts +131 -0
  42. package/src/core/query/query-simple/SimpleQueryColumns.tsx +0 -2
  43. package/src/entities/SchemaModelObjectEntityDefinition.ts +4 -0
  44. package/src/panels/model/ModelPanelWidget.tsx +15 -8
  45. package/src/panels/query/PageResultsWidget.tsx +45 -8
  46. package/src/panels/query/QueryPanelFactory.tsx +23 -0
  47. package/src/panels/query/QueryPanelWidget.tsx +14 -0
  48. package/src/panels/query/TableControlsWidget.tsx +4 -0
  49. package/src/panels/query/table-controls/SelectionControlsWidget.tsx +34 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@journeyapps-labs/reactor-mod-data-browser",
3
- "version": "3.5.0",
3
+ "version": "3.6.0",
4
4
  "main": "./dist/index.js",
5
5
  "typings": "./dist/@types/index",
6
6
  "publishConfig": {
@@ -21,8 +21,8 @@
21
21
  "@journeyapps-labs/common-sdk": "^1.0.3",
22
22
  "@journeyapps-labs/common-utils": "^1.0.1",
23
23
  "@journeyapps-labs/lib-reactor-data-layer": "1.0.11",
24
- "@journeyapps-labs/reactor-mod": "5.4.0",
25
- "@journeyapps-labs/reactor-mod-editor": "2.2.2",
24
+ "@journeyapps-labs/reactor-mod": "5.6.0",
25
+ "@journeyapps-labs/reactor-mod-editor": "2.2.4",
26
26
  "@journeyapps/db": "^8.1.1",
27
27
  "@journeyapps/parser-schema": "^8.2.5",
28
28
  "@projectstorm/react-workspaces-core": "4.2.3",
@@ -18,6 +18,7 @@ import { EditSchemaModelAction } from './actions/schema-model/EditSchemaModelAct
18
18
  import { TypeEngine } from './forms/TypeEngine';
19
19
  import { ViewSchemaModelAsJsonAction } from './actions/schema-model/ViewSchemaModelAsJsonAction';
20
20
  import { ViewHasManyAction } from './actions/schema-model/ViewHasManyAction';
21
+ import { DeleteSchemaModelAction } from './actions/schema-model/DeleteSchemaModelAction';
21
22
  import { ModelJsonPanelFactory } from './panels/model-json/ModelJsonPanelFactory';
22
23
  import { SchemaModelIndexDefinition } from './entities/SchemaModelIndexDefinition';
23
24
  import { SavedQueryStore } from './stores/SavedQueryStore';
@@ -52,6 +53,7 @@ export class DataBrowserModule extends AbstractReactorModule {
52
53
  actionStore.registerAction(new EditSchemaModelAction());
53
54
  actionStore.registerAction(new ViewSchemaModelAsJsonAction());
54
55
  actionStore.registerAction(new ViewHasManyAction());
56
+ actionStore.registerAction(new DeleteSchemaModelAction());
55
57
  actionStore.registerAction(new OpenSavedQueryAction());
56
58
  actionStore.registerAction(new RemoveSavedQueryAction());
57
59
 
@@ -0,0 +1,43 @@
1
+ import {
2
+ ActionStore,
3
+ EntityAction,
4
+ EntityActionEvent,
5
+ ioc,
6
+ setupDeleteConfirmation
7
+ } from '@journeyapps-labs/reactor-mod';
8
+ import { DataBrowserEntities } from '../../entities';
9
+ import { SchemaModelObject } from '../../core/SchemaModelObject';
10
+ import { runDeleteSchemaModels } from '../../core/delete-schema-models';
11
+ import { ModelPanelModel } from '../../panels/model/ModelPanelFactory';
12
+
13
+ export interface DeleteSchemaModelActionEvent extends EntityActionEvent<SchemaModelObject> {
14
+ sourcePanel?: ModelPanelModel;
15
+ }
16
+
17
+ export class DeleteSchemaModelAction extends EntityAction<SchemaModelObject, DeleteSchemaModelActionEvent> {
18
+ static ID = 'DELETE_SCHEMA_MODEL';
19
+
20
+ constructor() {
21
+ super({
22
+ id: DeleteSchemaModelAction.ID,
23
+ name: 'Delete schema model',
24
+ icon: 'trash',
25
+ target: DataBrowserEntities.SCHEMA_MODEL_OBJECT
26
+ });
27
+
28
+ setupDeleteConfirmation({
29
+ action: this
30
+ });
31
+ }
32
+
33
+ async fireEvent(event: DeleteSchemaModelActionEvent): Promise<any> {
34
+ await runDeleteSchemaModels({
35
+ models: [event.targetEntity],
36
+ sourcePanel: event.sourcePanel
37
+ });
38
+ }
39
+
40
+ static get() {
41
+ return ioc.get(ActionStore).getActionByID<DeleteSchemaModelAction>(DeleteSchemaModelAction.ID);
42
+ }
43
+ }
@@ -94,6 +94,27 @@ export abstract class AbstractConnection extends BaseObserver<AbstractConnection
94
94
  }
95
95
  }
96
96
 
97
+ async batchDelete(models: SchemaModelObject[]) {
98
+ if (models.length === 0) {
99
+ return;
100
+ }
101
+ const database = await this.getConnection();
102
+ let batch = new database.Batch();
103
+ for (let model of models) {
104
+ if (!model?.model?.persisted) {
105
+ continue;
106
+ }
107
+ batch.destroy(model.model);
108
+ }
109
+ await batch.execute();
110
+ for (let model of models) {
111
+ if (!model?.model?.persisted) {
112
+ continue;
113
+ }
114
+ model.definition.cache.delete(model.id);
115
+ }
116
+ }
117
+
97
118
  getSchemaModelDefinitionByName(name: string) {
98
119
  return this.schema_models.items.find((i) => i.definition.name === name);
99
120
  }
@@ -0,0 +1,131 @@
1
+ import { CrudError } from '@journeyapps/db';
2
+ import {
3
+ DialogStore,
4
+ ioc,
5
+ NotificationStore,
6
+ NotificationType,
7
+ ReactorPanelModel,
8
+ WorkspaceStore
9
+ } from '@journeyapps-labs/reactor-mod';
10
+ import * as _ from 'lodash';
11
+ import { SchemaModelObject } from './SchemaModelObject';
12
+ import { QueryPanelModel } from '../panels/query/QueryPanelFactory';
13
+ import { ModelPanelModel } from '../panels/model/ModelPanelFactory';
14
+
15
+ export interface DeleteSchemaModelsOptions {
16
+ models: SchemaModelObject[];
17
+ sourcePanel?: ReactorPanelModel;
18
+ }
19
+
20
+ const normalizeModels = (models: SchemaModelObject[]) => {
21
+ return _.uniqBy(
22
+ models.filter((model) => model?.model?.persisted),
23
+ (model) => model.id
24
+ );
25
+ };
26
+
27
+ const getErrorMessage = (error: unknown) => {
28
+ if (error instanceof CrudError) {
29
+ return error.firstError()?.detail || error.message;
30
+ }
31
+ if (error instanceof Error) {
32
+ return error.message;
33
+ }
34
+ return 'An unknown error occurred while deleting the selected models.';
35
+ };
36
+
37
+ const buildDeleteMarkdown = (models: SchemaModelObject[]) => {
38
+ if (models.length === 1) {
39
+ const model = models[0];
40
+ const display = model.data?.display || model.id;
41
+ return `Delete **${display}**?\n\nThis action cannot be undone.`;
42
+ }
43
+
44
+ return `Delete **${models.length}** models?\n\nThis action cannot be undone.`;
45
+ };
46
+
47
+ export const runDeleteSchemaModels = async (options: DeleteSchemaModelsOptions): Promise<boolean> => {
48
+ const models = normalizeModels(options.models);
49
+
50
+ if (models.length === 0) {
51
+ return false;
52
+ }
53
+
54
+ const definition = models[0].definition;
55
+ const mismatchedModel = models.find((model) => model.definition.connection !== definition.connection);
56
+ if (mismatchedModel) {
57
+ ioc.get(NotificationStore).showNotification({
58
+ title: 'Cannot delete models',
59
+ description: 'Selected models must come from the same connection.',
60
+ type: NotificationType.ERROR
61
+ });
62
+ return false;
63
+ }
64
+
65
+ try {
66
+ await definition.connection.batchDelete(models);
67
+ const sourcePanelID = options.sourcePanel?.id;
68
+ if (options.sourcePanel instanceof ModelPanelModel) {
69
+ options.sourcePanel.delete();
70
+ }
71
+ await Promise.all(
72
+ ioc
73
+ .get(WorkspaceStore)
74
+ .flatten(ioc.get(WorkspaceStore).getRoot())
75
+ .map(async (panel) => {
76
+ if (panel.id === sourcePanelID) {
77
+ return;
78
+ }
79
+ if (panel instanceof QueryPanelModel) {
80
+ await panel.reloadQuery();
81
+ return;
82
+ }
83
+ if (panel instanceof ModelPanelModel && models.some((model) => model.id === panel.model?.id)) {
84
+ panel.delete();
85
+ }
86
+ })
87
+ );
88
+ ioc.get(NotificationStore).showNotification({
89
+ title: models.length === 1 ? 'Model deleted' : 'Models deleted',
90
+ description:
91
+ models.length === 1
92
+ ? 'The selected model has been deleted.'
93
+ : `${models.length} selected models have been deleted.`,
94
+ type: NotificationType.SUCCESS
95
+ });
96
+ return true;
97
+ } catch (error) {
98
+ ioc.get(NotificationStore).showNotification({
99
+ title: 'Delete failed',
100
+ description: getErrorMessage(error),
101
+ type: NotificationType.ERROR
102
+ });
103
+ return false;
104
+ }
105
+ };
106
+
107
+ export const deleteSchemaModels = async (options: DeleteSchemaModelsOptions): Promise<boolean> => {
108
+ const models = normalizeModels(options.models);
109
+
110
+ if (models.length <= 1) {
111
+ return false;
112
+ }
113
+
114
+ const confirmed = await ioc.get(DialogStore).showConfirmDialog({
115
+ title: 'Delete selected models',
116
+ markdown: buildDeleteMarkdown(models),
117
+ yesBtn: {
118
+ label: `Delete ${models.length} models`,
119
+ icon: 'trash'
120
+ }
121
+ });
122
+
123
+ if (!confirmed) {
124
+ return false;
125
+ }
126
+
127
+ return runDeleteSchemaModels({
128
+ ...options,
129
+ models
130
+ });
131
+ };
@@ -112,7 +112,6 @@ export const buildSimpleQueryColumns = (options: BuildSimpleQueryColumnsOptions)
112
112
  />
113
113
  ),
114
114
  noWrap: true,
115
- shrink: true,
116
115
  accessor: (cell, row: PageRow) => {
117
116
  return (
118
117
  <SmartBelongsToDisplayWidget
@@ -160,7 +159,6 @@ export const buildSimpleQueryColumns = (options: BuildSimpleQueryColumnsOptions)
160
159
  />
161
160
  ),
162
161
  noWrap: true,
163
- shrink: true,
164
162
  accessor: (cell, row: PageRow) => {
165
163
  return <SmartCellDisplayWidget name={attribute.name} row={row} />;
166
164
  }
@@ -13,6 +13,7 @@ import { SchemaModelObject } from '../core/SchemaModelObject';
13
13
  import { SchemaModelDefinition } from '../core/SchemaModelDefinition';
14
14
  import { validate as validateUUID } from 'uuid';
15
15
  import { ViewHasManyAction } from '../actions/schema-model/ViewHasManyAction';
16
+ import { DeleteSchemaModelAction } from '../actions/schema-model/DeleteSchemaModelAction';
16
17
 
17
18
  export interface SchemaModelObjectEntityDefinitionEncoded {
18
19
  connection_id: string;
@@ -98,6 +99,9 @@ export class SchemaModelObjectEntityDefinition extends EntityDefinition<SchemaMo
98
99
  }
99
100
 
100
101
  isActionAllowedForEntity(action: Action, entity: SchemaModelObject) {
102
+ if (action.id === DeleteSchemaModelAction.ID) {
103
+ return !!entity.model?.persisted;
104
+ }
101
105
  if (action.id === ViewHasManyAction.ID) {
102
106
  return Object.keys(entity.definition.definition.hasMany || {}).length > 0;
103
107
  }
@@ -4,6 +4,7 @@ import { observer } from 'mobx-react';
4
4
  import styled from '@emotion/styled';
5
5
  import {
6
6
  BorderLayoutWidget,
7
+ Btn,
7
8
  ioc,
8
9
  LoadingPanelWidget,
9
10
  PANEL_CONTENT_PADDING,
@@ -15,6 +16,7 @@ import {
15
16
  } from '@journeyapps-labs/reactor-mod';
16
17
  import { SchemaModelForm } from '../../forms/SchemaModelForm';
17
18
  import { ModelPanelModel } from './ModelPanelFactory';
19
+ import { DeleteSchemaModelAction } from '../../actions/schema-model/DeleteSchemaModelAction';
18
20
 
19
21
  export interface QueryPanelWidgetProps {
20
22
  model: ModelPanelModel;
@@ -55,16 +57,21 @@ export const ModelPanelWidget: React.FC<QueryPanelWidgetProps> = observer((props
55
57
 
56
58
  let top = null;
57
59
  if (props.model.model) {
60
+ const toolbarButtons: Btn[] = props.model.model.model?.persisted
61
+ ? [
62
+ DeleteSchemaModelAction.get().representAsButton(
63
+ {
64
+ targetEntity: props.model.model,
65
+ sourcePanel: props.model
66
+ },
67
+ true
68
+ )
69
+ ].filter((button): button is Btn => !!button)
70
+ : [];
71
+
58
72
  top = (
59
73
  <PanelToolbarWidget
60
- btns={
61
- [
62
- // {
63
- // label: 'Delete object',
64
- // action: () => {}
65
- // }
66
- ]
67
- }
74
+ btns={toolbarButtons}
68
75
  meta={[
69
76
  {
70
77
  label: 'ID',
@@ -1,15 +1,27 @@
1
1
  import * as React from 'react';
2
2
  import { useEffect, useRef } from 'react';
3
- import { Page } from '../../core/query/Page';
4
- import { themed, ioc, ScrollableDivCss, System, TableWidget, LoadingPanelWidget } from '@journeyapps-labs/reactor-mod';
3
+ import { Page, PageRow } from '../../core/query/Page';
4
+ import {
5
+ ComboBoxItem,
6
+ themed,
7
+ ioc,
8
+ ScrollableDivCss,
9
+ System,
10
+ MultiSelectChangeEvent,
11
+ MultiSelectTableWidget,
12
+ LoadingPanelWidget
13
+ } from '@journeyapps-labs/reactor-mod';
5
14
  import { AbstractQuery } from '../../core/query/AbstractQuery';
6
15
  import { observer } from 'mobx-react';
7
16
  import { DataBrowserEntities } from '../../entities';
8
17
  import { SchemaModelObject } from '../../core/SchemaModelObject';
18
+ import { deleteSchemaModels } from '../../core/delete-schema-models';
9
19
 
10
20
  export interface PageResultsWidgetProps {
11
21
  page: Page;
12
22
  query: AbstractQuery;
23
+ selectedModels: SchemaModelObject[];
24
+ onSelectionChange: (event: MultiSelectChangeEvent<PageRow>) => void;
13
25
  scrollTop: number;
14
26
  scrollLeft: number;
15
27
  onScroll: (offsets: { top: number; left: number }) => void;
@@ -18,8 +30,35 @@ export interface PageResultsWidgetProps {
18
30
  export const PageResultsWidget: React.FC<PageResultsWidgetProps> = observer((props) => {
19
31
  const system = ioc.get(System);
20
32
  const rows = props.page.loading ? [] : props.page.asRows();
33
+ const selectedRowKeys = props.selectedModels.map((model) => model.id);
21
34
  const ref = useRef<HTMLDivElement>(null);
22
35
 
36
+ const showContextMenu = (event: React.MouseEvent, row: PageRow) => {
37
+ const definition = system.getDefinition<SchemaModelObject>(DataBrowserEntities.SCHEMA_MODEL_OBJECT);
38
+ const isSelectedRow = props.selectedModels.some((model) => model.id === row.model.id);
39
+
40
+ const selectedItems: ComboBoxItem[] =
41
+ isSelectedRow && props.selectedModels.length > 1
42
+ ? [
43
+ {
44
+ key: 'delete-selected',
45
+ title: `Delete selected [${props.selectedModels.length}]`,
46
+ group: 'Selected',
47
+ icon: 'trash',
48
+ action: async () => {
49
+ await deleteSchemaModels({
50
+ models: props.selectedModels
51
+ });
52
+ }
53
+ }
54
+ ]
55
+ : [];
56
+
57
+ definition.showContextMenuForEntity(row.model, event, {
58
+ additionalItems: selectedItems
59
+ } as any);
60
+ };
61
+
23
62
  useEffect(() => {
24
63
  if (!ref.current) {
25
64
  return;
@@ -43,12 +82,10 @@ export const PageResultsWidget: React.FC<PageResultsWidgetProps> = observer((pro
43
82
  });
44
83
  }}
45
84
  >
46
- <TableWidget
47
- onContextMenu={(event, row) => {
48
- system
49
- .getDefinition<SchemaModelObject>(DataBrowserEntities.SCHEMA_MODEL_OBJECT)
50
- .showContextMenuForEntity(row.model, event);
51
- }}
85
+ <MultiSelectTableWidget
86
+ onContextMenu={showContextMenu}
87
+ selectedRowKeys={selectedRowKeys}
88
+ onSelectionChange={props.onSelectionChange}
52
89
  rows={rows}
53
90
  columns={props.query.getColumns()}
54
91
  />
@@ -10,6 +10,9 @@ import { SavedQueryStore } from '../../stores/SavedQueryStore';
10
10
  import { AbstractConnection } from '../../core/AbstractConnection';
11
11
  import { SharedConnectionPanelFactory } from '../_shared/SharedConnectionPanelFactory';
12
12
  import { Page } from '../../core/query/Page';
13
+ import { SchemaModelObject } from '../../core/SchemaModelObject';
14
+ import { action } from 'mobx';
15
+ import * as _ from 'lodash';
13
16
 
14
17
  export class QueryPanelModel extends ReactorPanelModel {
15
18
  @inject(ConnectionStore)
@@ -24,6 +27,9 @@ export class QueryPanelModel extends ReactorPanelModel {
24
27
  @observable.ref
25
28
  accessor current_page_data: Page | null;
26
29
 
30
+ @observable.ref
31
+ accessor selected_models: SchemaModelObject[];
32
+
27
33
  accessor table_scroll_top: number;
28
34
  accessor table_scroll_left: number;
29
35
 
@@ -33,10 +39,26 @@ export class QueryPanelModel extends ReactorPanelModel {
33
39
  this.query = query;
34
40
  this.current_page = 0;
35
41
  this.current_page_data = null;
42
+ this.selected_models = [];
36
43
  this.table_scroll_top = 0;
37
44
  this.table_scroll_left = 0;
38
45
  }
39
46
 
47
+ @action clearSelection() {
48
+ this.selected_models = [];
49
+ }
50
+
51
+ @action mergeSelectionForPage(event: { page: Page; models: SchemaModelObject[] }) {
52
+ const pageRowKeys = new Set(event.page.asRows().map((row) => row.key));
53
+ const nextSelectedModels = this.selected_models.filter((model) => !pageRowKeys.has(model.id));
54
+ this.selected_models = _.uniqBy([...nextSelectedModels, ...event.models], (model) => model.id);
55
+ }
56
+
57
+ @action async reloadQuery() {
58
+ this.clearSelection();
59
+ await this.query.load();
60
+ }
61
+
40
62
  isSerializable() {
41
63
  return this.query instanceof AbstractSerializableQuery;
42
64
  }
@@ -71,6 +93,7 @@ export class QueryPanelModel extends ReactorPanelModel {
71
93
  }
72
94
  this.current_page = 0;
73
95
  this.current_page_data = null;
96
+ this.clearSelection();
74
97
  this.query = query;
75
98
  await query.load();
76
99
  }
@@ -9,6 +9,7 @@ import { PageResultsWidget } from './PageResultsWidget';
9
9
  import { TableControlsWidget } from './TableControlsWidget';
10
10
  import { autorun } from 'mobx';
11
11
  import { TableControlsPositionPreference, TableControlsPositionValue } from '../../preferences/QueryControlPreferences';
12
+ import { deleteSchemaModels } from '../../core/delete-schema-models';
12
13
 
13
14
  export interface QueryPanelWidgetProps {
14
15
  model: QueryPanelModel;
@@ -101,6 +102,12 @@ export const QueryPanelWidget: React.FC<QueryPanelWidgetProps> = observer((props
101
102
  query={props.model.query}
102
103
  current_page={activePage}
103
104
  loading={loading}
105
+ selectedCount={props.model.selected_models.length}
106
+ onDeleteSelected={async () => {
107
+ await deleteSchemaModels({
108
+ models: props.model.selected_models
109
+ });
110
+ }}
104
111
  onLoadSavedQuery={async (id) => {
105
112
  await props.model.loadSavedQuery(id);
106
113
  }}
@@ -132,6 +139,13 @@ export const QueryPanelWidget: React.FC<QueryPanelWidgetProps> = observer((props
132
139
  <PageResultsWidget
133
140
  query={props.model.query}
134
141
  page={activePage}
142
+ selectedModels={props.model.selected_models}
143
+ onSelectionChange={(event) => {
144
+ props.model.mergeSelectionForPage({
145
+ page: activePage,
146
+ models: event.rows.map((row) => row.model)
147
+ });
148
+ }}
135
149
  scrollTop={props.model.table_scroll_top}
136
150
  scrollLeft={props.model.table_scroll_left}
137
151
  onScroll={({ top, left }) => {
@@ -12,6 +12,7 @@ import { SortControlsWidget } from './table-controls/SortControlsWidget';
12
12
  import { ChangesControlsWidget } from './table-controls/ChangesControlsWidget';
13
13
  import { FilterControlsWidget } from './table-controls/FilterControlsWidget';
14
14
  import { QueryControlPreferences } from '../../preferences/QueryControlPreferences';
15
+ import { SelectionControlsWidget } from './table-controls/SelectionControlsWidget';
15
16
 
16
17
  export interface TableControlsWidgetProps {
17
18
  current_page: Page;
@@ -20,6 +21,8 @@ export interface TableControlsWidgetProps {
20
21
  query: AbstractQuery;
21
22
  onLoadSavedQuery?: (id: string) => Promise<any> | any;
22
23
  loading?: boolean;
24
+ selectedCount: number;
25
+ onDeleteSelected: () => Promise<void>;
23
26
  }
24
27
 
25
28
  export const TableControlsWidget: React.FC<TableControlsWidgetProps> = observer((props) => {
@@ -52,6 +55,7 @@ export const TableControlsWidget: React.FC<TableControlsWidgetProps> = observer(
52
55
  {simpleQuery && showSortControls ? (
53
56
  <SortControlsWidget simpleQuery={simpleQuery} goToPage={props.goToPage} />
54
57
  ) : null}
58
+ <SelectionControlsWidget selectedCount={props.selectedCount} onDeleteSelected={props.onDeleteSelected} />
55
59
  <ChangesControlsWidget query={props.query} currentPage={props.current_page} />
56
60
  {props.loading ? <S.Loading icon="spinner" spin={true} /> : null}
57
61
  </S.Container>
@@ -0,0 +1,34 @@
1
+ import * as React from 'react';
2
+ import {
3
+ InputContainerWidget,
4
+ ioc,
5
+ PanelButtonMode,
6
+ PanelButtonWidget,
7
+ theme,
8
+ ThemeStore
9
+ } from '@journeyapps-labs/reactor-mod';
10
+
11
+ export interface SelectionControlsWidgetProps {
12
+ selectedCount: number;
13
+ onDeleteSelected: () => Promise<void>;
14
+ }
15
+
16
+ export const SelectionControlsWidget: React.FC<SelectionControlsWidgetProps> = (props) => {
17
+ const _theme = ioc.get(ThemeStore).getCurrentTheme(theme);
18
+
19
+ if (props.selectedCount === 0) {
20
+ return null;
21
+ }
22
+
23
+ return (
24
+ <InputContainerWidget label="Selection">
25
+ <PanelButtonWidget
26
+ mode={PanelButtonMode.PRIMARY}
27
+ label={`Delete selected [${props.selectedCount}]`}
28
+ icon="trash"
29
+ iconColor={_theme.status.failed}
30
+ action={props.onDeleteSelected}
31
+ />
32
+ </InputContainerWidget>
33
+ );
34
+ };