@digital-ai/dot-components 3.22.0 → 3.24.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/index.esm.js CHANGED
@@ -6645,6 +6645,7 @@ const DotAutoComplete = ({
6645
6645
  persistentLabel,
6646
6646
  placeholder,
6647
6647
  popperClassName,
6648
+ popperPlacement,
6648
6649
  preserveGroupOrder = false,
6649
6650
  readOnly = false,
6650
6651
  renderGroup,
@@ -6739,6 +6740,7 @@ const DotAutoComplete = ({
6739
6740
  className: popperClasses,
6740
6741
  disablePortal: disablePortal,
6741
6742
  "$maxHeight": maxHeight,
6743
+ placement: popperPlacement,
6742
6744
  children: jsxs(Paper, Object.assign({}, paperProps, {
6743
6745
  children: [paperChildren, jsx("div", {
6744
6746
  className: "dot-action-item",
@@ -9034,7 +9036,7 @@ class DashboardsService {
9034
9036
  * @param sort Sort ordering to apply to the query.
9035
9037
  * @param filter List of filters (each filter is a separate query param, and they are OR'ed).
9036
9038
  *
9037
- * * **Filterable field names**: author_fullname, author_id, bi_type, categories, created_dt, description, external_embedding_id, external_id, id, is_ootb_dashboard, lifecycle_state, name, target_apps, updated_by_fullname, updated_by_id, updated_dt
9039
+ * * **Filterable field names**: author_fullname, author_id, bi_type, categories, created_dt, description, external_embedding_id, external_id, id, is_ootb_dashboard, lifecycle_state, modified_parent_id, name, target_apps, updated_by_fullname, updated_by_id, updated_dt
9038
9040
  * * **Searchable field names**: author_fullname, categories, description, name, updated_by_fullname
9039
9041
  *
9040
9042
  * @param favorite Boolean flag to only return dashboards marked as favorites.
@@ -9111,19 +9113,24 @@ class DashboardsService {
9111
9113
  * Get one Dashboard definition.
9112
9114
  * Return a single Dashboard definition, selected by ID.
9113
9115
  * @param dashboardId
9116
+ * @param viewModified Return the dashboard with modified changes if they exist for this user.
9114
9117
  * @returns DashboardView OK
9115
9118
  * @returns Error Default error response
9116
9119
  * @throws ApiError
9117
9120
  */
9118
- static getDashboardsService1(dashboardId) {
9121
+ static getDashboardsService1(dashboardId, viewModified = false) {
9119
9122
  return __awaiter(this, void 0, void 0, function* () {
9120
9123
  const result = yield request({
9121
9124
  method: 'GET',
9122
9125
  path: `/metadata/bi/dashboards/${dashboardId}`,
9126
+ query: {
9127
+ view_modified: viewModified
9128
+ },
9123
9129
  errors: {
9124
9130
  400: `An unknown parameter was specified.`,
9125
9131
  401: `Could not resolve a valid Tenant from the provided API Token.`,
9126
- 404: `The dashboard could not be found.`
9132
+ 404: `The dashboard could not be found.`,
9133
+ 422: `Unprocessable Entity`
9127
9134
  }
9128
9135
  });
9129
9136
  return result.body;
@@ -9207,6 +9214,58 @@ class DashboardsService {
9207
9214
  return result.body;
9208
9215
  });
9209
9216
  }
9217
+ /**
9218
+ * Publish modifications to a dashboard
9219
+ * Publish modifications to a dashboard
9220
+ * @param dashboardId
9221
+ * @param requestBody
9222
+ * @param isSync Sync the dashboard with BI
9223
+ * @returns DashboardView Dashboard published.
9224
+ * @returns Error Default error response
9225
+ * @throws ApiError
9226
+ */
9227
+ static postDashboardsService1(dashboardId, requestBody, isSync = null) {
9228
+ return __awaiter(this, void 0, void 0, function* () {
9229
+ const result = yield request({
9230
+ method: 'POST',
9231
+ path: `/metadata/bi/dashboards/${dashboardId}/publish`,
9232
+ query: {
9233
+ is_sync: isSync
9234
+ },
9235
+ body: requestBody,
9236
+ mediaType: 'application/json',
9237
+ errors: {
9238
+ 400: `The provided data is not valid.`,
9239
+ 401: `Could not resolve a valid Tenant from the provided API Token.`,
9240
+ 404: `The dashboard could not be found.`,
9241
+ 422: `Unprocessable Entity`
9242
+ }
9243
+ });
9244
+ return result.body;
9245
+ });
9246
+ }
9247
+ /**
9248
+ * Revert modifications to a dashboard
9249
+ * Revert modifications to a dashboard
9250
+ * @param dashboardId
9251
+ * @returns DashboardView Dashboard changes reverted.
9252
+ * @returns Error Default error response
9253
+ * @throws ApiError
9254
+ */
9255
+ static postDashboardsService2(dashboardId) {
9256
+ return __awaiter(this, void 0, void 0, function* () {
9257
+ const result = yield request({
9258
+ method: 'POST',
9259
+ path: `/metadata/bi/dashboards/${dashboardId}/revert`,
9260
+ errors: {
9261
+ 400: `The provided data is not valid.`,
9262
+ 401: `Could not resolve a valid Tenant from the provided API Token.`,
9263
+ 404: `The dashboard could not be found.`
9264
+ }
9265
+ });
9266
+ return result.body;
9267
+ });
9268
+ }
9210
9269
  /**
9211
9270
  * Create a copy of existing dashboard
9212
9271
  * Create a copy of existing dashboard
@@ -9216,7 +9275,7 @@ class DashboardsService {
9216
9275
  * @returns Error Default error response
9217
9276
  * @throws ApiError
9218
9277
  */
9219
- static postDashboardsService1(dashboardId, requestBody) {
9278
+ static postDashboardsService3(dashboardId, requestBody) {
9220
9279
  return __awaiter(this, void 0, void 0, function* () {
9221
9280
  const result = yield request({
9222
9281
  method: 'POST',
@@ -9240,7 +9299,7 @@ class DashboardsService {
9240
9299
  * @returns Error Default error response
9241
9300
  * @throws ApiError
9242
9301
  */
9243
- static postDashboardsService2(dashboardId) {
9302
+ static postDashboardsService4(dashboardId) {
9244
9303
  return __awaiter(this, void 0, void 0, function* () {
9245
9304
  const result = yield request({
9246
9305
  method: 'POST',
@@ -9428,15 +9487,35 @@ class HelpContentService {
9428
9487
  }
9429
9488
 
9430
9489
  function DotDashboardStatusPill({
9431
- status
9490
+ dashboard,
9491
+ currentUser
9432
9492
  }) {
9433
- if (status === DashboardView.lifecycle_state.DRAFT) {
9493
+ if (dashboard.lifecycle_state === DashboardView.lifecycle_state.DRAFT) {
9434
9494
  return jsx(DotPill, {
9435
9495
  label: "Draft",
9436
9496
  size: "small",
9437
9497
  variant: "outlined",
9438
9498
  status: "in-progress"
9439
9499
  });
9500
+ } else if (dashboard.lifecycle_state === DashboardView.lifecycle_state.PUBLISHED && dashboard.is_being_modified && currentUser) {
9501
+ if (dashboard.modified_author_id === currentUser.id) {
9502
+ return jsx(DotPill, {
9503
+ label: "Edit in progress",
9504
+ size: "small",
9505
+ variant: "outlined",
9506
+ status: "success"
9507
+ });
9508
+ } else {
9509
+ return jsx(DotPill, {
9510
+ label: "Published",
9511
+ icon: jsx(DotIcon, {
9512
+ iconId: "lock"
9513
+ }),
9514
+ size: "small",
9515
+ variant: "outlined",
9516
+ status: "success"
9517
+ });
9518
+ }
9440
9519
  } else {
9441
9520
  return jsx(DotPill, {
9442
9521
  status: "success",
@@ -9466,7 +9545,7 @@ const dashboard1 = {
9466
9545
  lifecycle_state: DashboardView.lifecycle_state.DRAFT,
9467
9546
  application_instances: [],
9468
9547
  categories: [],
9469
- bi_type: DashboardView.bi_type.SUPERSET,
9548
+ bi_type: DashboardView.bi_type.MICROSTRATEGY,
9470
9549
  is_ootb_dashboard: false,
9471
9550
  thumbnail: '',
9472
9551
  external_object: {
@@ -9476,7 +9555,8 @@ const dashboard1 = {
9476
9555
  help_content_id: helpContent.id,
9477
9556
  filter_configuration: [],
9478
9557
  favorite: false,
9479
- updated_dt: '2023-11-22T06:42:07.952000+00:00'
9558
+ updated_dt: '2023-11-22T06:42:07.952000+00:00',
9559
+ is_being_modified: false
9480
9560
  };
9481
9561
  const dashboard2 = {
9482
9562
  author_fullname: 'Dashboard2 Author',
@@ -9578,6 +9658,36 @@ const dashboard4 = {
9578
9658
  favorite: false,
9579
9659
  updated_dt: '2023-11-21T04:42:07.951000+00:00'
9580
9660
  });
9661
+ // Dashboard with in-progress edits
9662
+ ({
9663
+ author_fullname: 'Dashboard6 Author',
9664
+ author_id: 'id6a',
9665
+ target_apps: ['AGILITY'],
9666
+ external_id: '6',
9667
+ name: 'Test dashboard 6',
9668
+ description: '',
9669
+ dashboard_url: 'https://test.com',
9670
+ server_url: 'https://test.com',
9671
+ external_embedding_id: null,
9672
+ created_dt: '2023-11-22T06:42:07.872000+00:00',
9673
+ id: 'id6',
9674
+ lifecycle_state: DashboardView.lifecycle_state.PUBLISHED,
9675
+ application_instances: [],
9676
+ categories: [],
9677
+ bi_type: DashboardView.bi_type.MICROSTRATEGY,
9678
+ is_ootb_dashboard: false,
9679
+ thumbnail: '',
9680
+ external_object: {
9681
+ page_count: 3
9682
+ },
9683
+ embed_config: {},
9684
+ help_content_id: helpContent.id,
9685
+ filter_configuration: [],
9686
+ favorite: false,
9687
+ updated_dt: '2023-11-22T06:42:07.952000+00:00',
9688
+ is_being_modified: true,
9689
+ modified_author_id: 'id123'
9690
+ });
9581
9691
  const getCategoriesMock = {
9582
9692
  categories: {
9583
9693
  AGILITY: ['Scrum Master', 'DevOps Manager', 'Release Train Engineer', 'Agility Analytics'],
@@ -9789,7 +9899,7 @@ const DotMetadataApiProvider = ({
9789
9899
  },
9790
9900
  duplicateDashboard: (dashboardId, dashboard) => {
9791
9901
  setAccountIdHeader(accountId);
9792
- return cancelablePromise(DashboardsService.postDashboardsService1(dashboardId, dashboard)).then(response => {
9902
+ return cancelablePromise(DashboardsService.postDashboardsService3(dashboardId, dashboard)).then(response => {
9793
9903
  setDashboardsError(null);
9794
9904
  setMetadata(null);
9795
9905
  if (dashboards) {
@@ -9804,10 +9914,33 @@ const DotMetadataApiProvider = ({
9804
9914
  return null;
9805
9915
  });
9806
9916
  },
9917
+ publishDashboardChanges: (dashboardId, dashboard, isSync) => __awaiter(void 0, void 0, void 0, function* () {
9918
+ setAccountIdHeader(accountId);
9919
+ return cancelablePromise(DashboardsService.postDashboardsService1(dashboardId, dashboard, isSync)).then(response => {
9920
+ setDashboardsError(null);
9921
+ setDashboards(orig => handleUpdateDashboard(orig, response));
9922
+ return response;
9923
+ }).catch(error => setDashboardsError(error));
9924
+ }),
9925
+ revertDashboardChanges: dashboardId => __awaiter(void 0, void 0, void 0, function* () {
9926
+ setAccountIdHeader(accountId);
9927
+ return cancelablePromise(DashboardsService.postDashboardsService2(dashboardId)).then(response => {
9928
+ setDashboardsError(null);
9929
+ setDashboards(orig => handleUpdateDashboard(orig, response));
9930
+ return response;
9931
+ }).catch(error => setDashboardsError(error));
9932
+ }),
9933
+ getDashboard: (dashboardId, viewModified) => {
9934
+ setAccountIdHeader(accountOverrideId);
9935
+ return cancelablePromise(viewModified === undefined ? DashboardsService.getDashboardsService1(dashboardId) : DashboardsService.getDashboardsService1(dashboardId, viewModified)).then(response => {
9936
+ setDashboardsError(null);
9937
+ return response;
9938
+ }).catch(error => setDashboardsError(error));
9939
+ },
9807
9940
  favoriteDashboard: (dashboardId, favoriteValue) => {
9808
9941
  setAccountIdHeader(accountId);
9809
9942
  if (favoriteValue) {
9810
- return cancelablePromise(DashboardsService.postDashboardsService2(dashboardId)).then(response => {
9943
+ return cancelablePromise(DashboardsService.postDashboardsService4(dashboardId)).then(response => {
9811
9944
  setDashboardsError(null);
9812
9945
  setDashboards(orig => handleUpdateDashboard(orig, response));
9813
9946
  return response;
@@ -10310,7 +10443,8 @@ const DotDashboardDetailsView = ({
10310
10443
  onFavorite,
10311
10444
  open,
10312
10445
  yOffset = 56,
10313
- zIndex = 990
10446
+ zIndex = 990,
10447
+ currentUser
10314
10448
  }) => {
10315
10449
  var _a, _b;
10316
10450
  const rootClasses = useStylesWithRootClass(rootClassName$E, className);
@@ -10395,7 +10529,8 @@ const DotDashboardDetailsView = ({
10395
10529
  className: "dashboard-details-status",
10396
10530
  label: "Status",
10397
10531
  children: jsx(DotDashboardStatusPill, {
10398
- status: dashboard.lifecycle_state
10532
+ dashboard: dashboard,
10533
+ currentUser: currentUser ? currentUser : null
10399
10534
  })
10400
10535
  }), jsx(DashboardDetailsField, {
10401
10536
  className: "dashboard-details-category",
@@ -10439,9 +10574,10 @@ const DotDashboardDetails = _a => {
10439
10574
  var {
10440
10575
  dashboard,
10441
10576
  onClose,
10442
- onFavorite
10577
+ onFavorite,
10578
+ currentUser
10443
10579
  } = _a,
10444
- commonProps = __rest(_a, ["dashboard", "onClose", "onFavorite"]);
10580
+ commonProps = __rest(_a, ["dashboard", "onClose", "onFavorite", "currentUser"]);
10445
10581
  const [_openedDashboard, _setOpenedDashboard] = useState(dashboard);
10446
10582
  const metadataApiContext = useDotMetadataApiContext();
10447
10583
  const {
@@ -10481,7 +10617,8 @@ const DotDashboardDetails = _a => {
10481
10617
  dashboard: openedDashboard,
10482
10618
  open: true,
10483
10619
  onFavorite: favoriteHandler,
10484
- onClose: closeHandler
10620
+ onClose: closeHandler,
10621
+ currentUser: currentUser ? currentUser : null
10485
10622
  }));
10486
10623
  }
10487
10624
  return null;
@@ -10530,7 +10667,9 @@ function DashboardCategoriesAutoComplete(_a) {
10530
10667
  actionItem: customActionItem,
10531
10668
  onInputChange: handleInputChange,
10532
10669
  error: !!errorMessage,
10533
- helperText: errorMessage
10670
+ helperText: errorMessage,
10671
+ popperPlacement: "top",
10672
+ maxHeight: 110
10534
10673
  }));
10535
10674
  }
10536
10675
 
@@ -10575,7 +10714,14 @@ const DotInputSelect = ({
10575
10714
  return typeof option === 'string' ? option : option.option;
10576
10715
  };
10577
10716
  const getValue = option => {
10578
- return typeof option === 'string' ? option : (option === null || option === void 0 ? void 0 : option.value) || option.option;
10717
+ if (typeof option === 'string') {
10718
+ return option;
10719
+ }
10720
+ // Allow empty string as a value. This is useful when the user wants to select an empty option.
10721
+ if ((option === null || option === void 0 ? void 0 : option.value) === '') {
10722
+ return option.value;
10723
+ }
10724
+ return (option === null || option === void 0 ? void 0 : option.value) || option.option;
10579
10725
  };
10580
10726
  return jsxs("div", {
10581
10727
  className: className,
@@ -11136,7 +11282,8 @@ function ActivePublishMessage({
11136
11282
  published,
11137
11283
  publishing,
11138
11284
  onChange,
11139
- requiresApplication
11285
+ requiresApplication,
11286
+ editInProgress
11140
11287
  }) {
11141
11288
  const [selectedApp, setSelectedApp] = useState(applicationList.length > 0 ? applicationList[0] : null);
11142
11289
  const [selectedCategories, setSelectedCategories] = useState([]);
@@ -11220,11 +11367,11 @@ function ActivePublishMessage({
11220
11367
  children: ["To view your newly published dashboard in", ' ', jsxs("strong", {
11221
11368
  children: ["\"", selectedApp.name, "\""]
11222
11369
  }), ", go to the", ' ', jsx("strong", {
11223
- children: "'Digital.ai Analytics'"
11370
+ children: "'Analytics'"
11224
11371
  }), " section and explore."]
11225
11372
  }) : jsxs(DotTypography, {
11226
11373
  children: ["To view your newly published dashboard, go to the", ' ', jsx("strong", {
11227
- children: "'Digital.ai Analytics'"
11374
+ children: "'Analytics'"
11228
11375
  }), " section and explore."]
11229
11376
  })]
11230
11377
  });
@@ -11303,9 +11450,9 @@ function ActivePublishMessage({
11303
11450
  value: selectedCategories,
11304
11451
  filterSelectedOptions: true
11305
11452
  }), requiresApplication && jsxs(DotTypography, {
11306
- children: ["You are about to publish ", jsxs("strong", {
11453
+ children: ["You are about to", ' ', editInProgress ? 'apply changes to ' : 'publish ', ' ', jsxs("strong", {
11307
11454
  children: ["\"", dashboardName, "\""]
11308
- }), ". Click", ' ', "the publish button to promote it to the selected instance."]
11455
+ }), ".", editInProgress ? ' Do you want to proceed with publishing these updates?' : ' Click the publish button to promote it to the selected instance.']
11309
11456
  })]
11310
11457
  })
11311
11458
  });
@@ -11361,7 +11508,8 @@ function DotDashboardPublishConfirm({
11361
11508
  dashboardToPublish,
11362
11509
  dashboardToUnpublish,
11363
11510
  onClose,
11364
- onStatusChanged
11511
+ onStatusChanged,
11512
+ currentUser
11365
11513
  }) {
11366
11514
  const [publishing, setPublishing] = useState(null);
11367
11515
  const [unpublishing, setUnpublishing] = useState(null);
@@ -11376,7 +11524,8 @@ function DotDashboardPublishConfirm({
11376
11524
  });
11377
11525
  const {
11378
11526
  updateDashboard,
11379
- dashboardsError
11527
+ dashboardsError,
11528
+ publishDashboardChanges
11380
11529
  } = useDotMetadataApiContext();
11381
11530
  const {
11382
11531
  cancelablePromise
@@ -11401,20 +11550,26 @@ function DotDashboardPublishConfirm({
11401
11550
  setUnpublished(false);
11402
11551
  }
11403
11552
  }, [dashboardToUnpublish]);
11553
+ const editInProgressByCurrentUser = dashboard => {
11554
+ return currentUser && dashboard.is_being_modified && dashboard.modified_author_id === currentUser.id;
11555
+ };
11404
11556
  const handlePublish = useCallback(() => {
11405
11557
  const patchDashboard = {
11406
11558
  lifecycle_state: DashboardView.lifecycle_state.PUBLISHED,
11407
11559
  application_instances: publishAppInstance ? [publishAppInstance.id] : [],
11408
11560
  categories: publishCategories
11409
11561
  };
11410
- setPublishing(cancelablePromise(updateDashboard(dashboardToPublish.id, patchDashboard).then(updatedDashboard => {
11562
+ // If we're publishing a dashboard that is being modified by the current user, we need to use the
11563
+ // publishDashboardChanges method to commit the changes to the published dashboard.
11564
+ const publishMethod = editInProgressByCurrentUser(dashboardToPublish) ? publishDashboardChanges : updateDashboard;
11565
+ setPublishing(cancelablePromise(publishMethod(dashboardToPublish.id, patchDashboard).then(updatedDashboard => {
11411
11566
  setPublished(true);
11412
11567
  onStatusChanged(updatedDashboard);
11413
11568
  enqueueMessage('Dashboard has been published!', 'success');
11414
11569
  }).catch(() => {
11415
11570
  setPublishing(null);
11416
11571
  })));
11417
- }, [dashboardToPublish, publishAppInstance, publishCategories, updateDashboard]);
11572
+ }, [dashboardToPublish, publishAppInstance, publishCategories, updateDashboard, publishDashboardChanges]);
11418
11573
  const handleCancelPublish = useCallback(() => {
11419
11574
  if (publishing !== null) {
11420
11575
  publishing.cancel();
@@ -11448,17 +11603,26 @@ function DotDashboardPublishConfirm({
11448
11603
  }
11449
11604
  return !(requiresCategories && publishCategories.length === 0);
11450
11605
  }, [publishAppInstance, publishCategories, requiresApplication, requiresCategories]);
11606
+ const getPublishButtonLabel = dashboard => {
11607
+ if (published) {
11608
+ return 'Got it';
11609
+ } else if (editInProgressByCurrentUser(dashboard)) {
11610
+ return 'Yes, publish changes';
11611
+ } else {
11612
+ return 'Publish';
11613
+ }
11614
+ };
11451
11615
  return jsxs(Fragment, {
11452
11616
  children: [dashboardToPublish !== null && jsx(DotDialog, {
11453
11617
  cancelButtonVisible: !published,
11454
11618
  closeOnSubmit: false,
11455
11619
  hasPrimaryAction: publishing === null || published,
11456
11620
  open: dashboardToPublish !== null,
11457
- title: "Publish to application",
11621
+ title: editInProgressByCurrentUser(dashboardToPublish) ? 'Publish changes' : 'Publish to application',
11458
11622
  submitButtonProps: {
11459
11623
  'data-testid': 'publish-confirm-button',
11460
11624
  disabled: !canSubmit(),
11461
- label: published ? 'Got it' : 'Publish'
11625
+ label: getPublishButtonLabel(dashboardToPublish)
11462
11626
  },
11463
11627
  onCancel: handleCancelPublish,
11464
11628
  onSubmit: published ? handleCancelPublish : handlePublish,
@@ -11469,7 +11633,8 @@ function DotDashboardPublishConfirm({
11469
11633
  published: published,
11470
11634
  publishing: publishing !== null,
11471
11635
  onChange: handlePublishChange,
11472
- requiresApplication: requiresApplication
11636
+ requiresApplication: requiresApplication,
11637
+ editInProgress: editInProgressByCurrentUser(dashboardToPublish)
11473
11638
  })
11474
11639
  }), dashboardToUnpublish !== null && jsx(DotDialog, {
11475
11640
  cancelButtonVisible: !unpublished,
@@ -11524,11 +11689,14 @@ const StyledDotMenu = styled(DotMenu)`
11524
11689
 
11525
11690
  function DotDashboardOptionsMenu({
11526
11691
  dashboard,
11692
+ currentUser,
11527
11693
  isEdit = false,
11528
11694
  menuPlacement,
11529
11695
  onStartDelete,
11530
11696
  onStartDuplicate,
11531
11697
  onStartStatusChange,
11698
+ onStartRevert,
11699
+ onViewOriginal,
11532
11700
  onViewMode,
11533
11701
  onDetails
11534
11702
  }) {
@@ -11547,8 +11715,10 @@ function DotDashboardOptionsMenu({
11547
11715
  onViewMode(dashboard, 'edit');
11548
11716
  }, [dashboard, onViewMode]);
11549
11717
  const isDraft = dashboard.lifecycle_state === DashboardView.lifecycle_state.DRAFT;
11718
+ const isPublished = dashboard.lifecycle_state === DashboardView.lifecycle_state.PUBLISHED;
11719
+ const dashboardLocked = isPublished && currentUser && dashboard.is_being_modified && dashboard.modified_author_id !== currentUser.id;
11550
11720
  const menuItems = [];
11551
- if (!isEdit && onViewMode && !dashboard.is_ootb_dashboard) {
11721
+ if (!isEdit && onViewMode && !dashboard.is_ootb_dashboard && !dashboardLocked) {
11552
11722
  menuItems.push({
11553
11723
  children: jsxs(DotLink, {
11554
11724
  ariaLabel: "Edit dashboard",
@@ -11623,6 +11793,62 @@ function DotDashboardOptionsMenu({
11623
11793
  onclick: handleDeleteClick
11624
11794
  });
11625
11795
  }
11796
+ // If this is a published dashboard, with in-progress changes, and the user is the author of the changes,
11797
+ // show the republish, revert, and view original options.
11798
+ if (isEdit && isPublished && currentUser && dashboard.is_being_modified && dashboard.modified_author_id === currentUser.id) {
11799
+ const handlePublishChangesClick = () => {
11800
+ handleMenuClose();
11801
+ onStartStatusChange && onStartStatusChange(dashboard, DashboardView.lifecycle_state.PUBLISHED);
11802
+ };
11803
+ const handleRevertChangesClick = () => {
11804
+ handleMenuClose();
11805
+ onStartRevert && onStartRevert(dashboard);
11806
+ };
11807
+ const handleViewOriginalClick = () => {
11808
+ handleMenuClose();
11809
+ // Move to view mode and display the original dashboard without the changes
11810
+ onViewOriginal && onViewOriginal(dashboard);
11811
+ };
11812
+ menuItems.push({
11813
+ children: jsxs(DotLink, {
11814
+ ariaLabel: "Publish changes",
11815
+ color: "inherit",
11816
+ onClick: handlePublishChangesClick,
11817
+ underline: "none",
11818
+ children: [jsx(DotIcon, {
11819
+ iconId: "send-airplane"
11820
+ }), " Publish changes"]
11821
+ }),
11822
+ key: 'republish',
11823
+ onclick: handlePublishChangesClick
11824
+ });
11825
+ menuItems.push({
11826
+ children: jsxs(DotLink, {
11827
+ ariaLabel: "Revert to original",
11828
+ color: "inherit",
11829
+ onClick: handleRevertChangesClick,
11830
+ underline: "none",
11831
+ children: [jsx(DotIcon, {
11832
+ iconId: "undo"
11833
+ }), " Revert to original"]
11834
+ }),
11835
+ key: 'revert',
11836
+ onclick: handleRevertChangesClick
11837
+ });
11838
+ menuItems.push({
11839
+ children: jsxs(DotLink, {
11840
+ ariaLabel: "Open published dashboard",
11841
+ color: "inherit",
11842
+ onClick: handleViewOriginalClick,
11843
+ underline: "none",
11844
+ children: [jsx(DotIcon, {
11845
+ iconId: "visibility-on"
11846
+ }), " Open published dashboard"]
11847
+ }),
11848
+ key: 'original',
11849
+ onclick: handleViewOriginalClick
11850
+ });
11851
+ }
11626
11852
  if (onDetails) {
11627
11853
  if (menuItems.length > 0) {
11628
11854
  menuItems.push({
@@ -11788,13 +12014,17 @@ function DotDashboardActions({
11788
12014
  onDeleted,
11789
12015
  onDuplicated,
11790
12016
  onToggleFullscreen,
11791
- onViewMode
12017
+ onViewMode,
12018
+ onViewOriginal,
12019
+ onRevertChanges,
12020
+ currentUser
11792
12021
  }) {
11793
12022
  // NOTE: useState functions need to stay at the top of the file so that
11794
12023
  // they are evaluated before any context imports. If they are evaluated
11795
12024
  // after they can cause React state issues when rendering.
11796
12025
  const [dashboardToCopy, setDashboardToCopy] = useState(null);
11797
12026
  const [dashboardToDelete, setDashboardToDelete] = useState(null);
12027
+ const [dashboardToRevert, setDashboardToRevert] = useState(null);
11798
12028
  const [dashboardToPublish, setDashboardToPublish] = useState(null);
11799
12029
  const [dashboardToUnpublish, setDashboardToUnpublish] = useState(null);
11800
12030
  const [appCategories, setAppCategories] = useState(null);
@@ -11802,7 +12032,9 @@ function DotDashboardActions({
11802
12032
  deleteDashboard,
11803
12033
  duplicateDashboard,
11804
12034
  getCategories,
11805
- setOpenedDashboardDetails
12035
+ setOpenedDashboardDetails,
12036
+ revertDashboardChanges,
12037
+ getDashboard
11806
12038
  } = useDotMetadataApiContext();
11807
12039
  const {
11808
12040
  cancelablePromise
@@ -11819,6 +12051,8 @@ function DotDashboardActions({
11819
12051
  setDashboardToPublish(null);
11820
12052
  setDashboardToUnpublish(null);
11821
12053
  onStatusChanged && onStatusChanged(publishedDashboard);
12054
+ // Move to View Mode after publishing
12055
+ onViewMode && onViewMode(publishedDashboard, 'view');
11822
12056
  }, [onStatusChanged]);
11823
12057
  const handlePublishConfirmClose = useCallback(() => {
11824
12058
  setDashboardToPublish(null);
@@ -11854,9 +12088,32 @@ function DotDashboardActions({
11854
12088
  }
11855
12089
  });
11856
12090
  }, [dashboard, onDuplicated]);
12091
+ const handleRevertSubmit = useCallback(() => __awaiter(this, void 0, void 0, function* () {
12092
+ const dashboardId = dashboardToRevert.id;
12093
+ return cancelablePromise(revertDashboardChanges(dashboardId)).then(result => {
12094
+ setDashboardToRevert(null);
12095
+ onRevertChanges && onRevertChanges(result);
12096
+ onStatusChanged && onStatusChanged(result);
12097
+ onViewMode && onViewMode(result, 'view');
12098
+ });
12099
+ }), [dashboardToRevert, onRevertChanges, onStatusChanged]);
12100
+ const handleStartViewOriginal = useCallback(() => __awaiter(this, void 0, void 0, function* () {
12101
+ const dashboardId = dashboard.id;
12102
+ return cancelablePromise(getDashboard(dashboardId, false)).then(result => {
12103
+ onStatusChanged && onStatusChanged(result);
12104
+ onViewMode && onViewMode(result, 'view');
12105
+ onViewOriginal && onViewOriginal(result);
12106
+ });
12107
+ }), [dashboard, onViewOriginal, onStatusChanged]);
11857
12108
  const handleStartDelete = useCallback(dashboardToDel => {
11858
12109
  setDashboardToDelete(dashboardToDel);
11859
12110
  }, []);
12111
+ const handleStartRevert = useCallback(dashboard => {
12112
+ setDashboardToRevert(dashboard);
12113
+ }, []);
12114
+ const handleRevertClose = useCallback(() => {
12115
+ setDashboardToRevert(null);
12116
+ }, []);
11860
12117
  const handleStartDuplicate = useCallback(dashboardToDupe => {
11861
12118
  setDashboardToCopy(dashboardToDupe);
11862
12119
  }, []);
@@ -11864,6 +12121,8 @@ function DotDashboardActions({
11864
12121
  const handleStartStatusChangeIfConfig = onStatusChanged ? handleStartStatusChange : undefined;
11865
12122
  const handleStartDeleteIfConfig = onDeleted ? handleStartDelete : undefined;
11866
12123
  const handleViewModeIfConfig = onViewMode && canEdit ? onViewMode : undefined;
12124
+ const handleRevertChangesIfConfig = onRevertChanges ? handleStartRevert : undefined;
12125
+ const handleViewOriginalIfConfig = onViewOriginal ? handleStartViewOriginal : undefined;
11867
12126
  return jsxs(StyledDashboardActions, {
11868
12127
  "data-testid": "dot-dashboard-actions",
11869
12128
  children: [jsx(DotDashboardPublishConfirm, {
@@ -11871,7 +12130,8 @@ function DotDashboardActions({
11871
12130
  dashboardToPublish: dashboardToPublish,
11872
12131
  dashboardToUnpublish: dashboardToUnpublish,
11873
12132
  onClose: handlePublishConfirmClose,
11874
- onStatusChanged: handlePublishConfirm
12133
+ onStatusChanged: handlePublishConfirm,
12134
+ currentUser: currentUser ? currentUser : null
11875
12135
  }), appCategories && dashboardToCopy && jsx(DotDashboardDialog, {
11876
12136
  title: "Duplicate dashboard",
11877
12137
  availableCategories: appCategories,
@@ -11885,6 +12145,14 @@ function DotDashboardActions({
11885
12145
  record: dashboardToDelete.name,
11886
12146
  impact: dashboardToDelete.lifecycle_state === DashboardView.lifecycle_state.PUBLISHED ? 'high' : 'medium',
11887
12147
  open: true
12148
+ }), dashboardToRevert && jsx(DotImpactDialog, {
12149
+ onCancel: handleRevertClose,
12150
+ onSubmit: handleRevertSubmit,
12151
+ record: dashboardToRevert.name,
12152
+ impact: "medium",
12153
+ action: "revert",
12154
+ actionIcon: "undo",
12155
+ open: true
11888
12156
  }), jsx(HelpButton, {
11889
12157
  dashboard: dashboard
11890
12158
  }), onFavorite && jsx(FavoriteButton, {
@@ -11894,11 +12162,14 @@ function DotDashboardActions({
11894
12162
  dashboard: dashboard,
11895
12163
  isEdit: isEdit,
11896
12164
  menuPlacement: "bottom-start",
12165
+ onViewOriginal: handleViewOriginalIfConfig,
11897
12166
  onViewMode: handleViewModeIfConfig,
11898
12167
  onStartStatusChange: handleStartStatusChangeIfConfig,
11899
12168
  onStartDuplicate: handleStartDuplicateIfConfig,
11900
12169
  onStartDelete: handleStartDeleteIfConfig,
11901
- onDetails: () => setOpenedDashboardDetails(dashboard)
12170
+ onStartRevert: handleRevertChangesIfConfig,
12171
+ onDetails: () => setOpenedDashboardDetails(dashboard),
12172
+ currentUser: currentUser ? currentUser : null
11902
12173
  }), onToggleFullscreen && jsx(FullscreenButton, {
11903
12174
  dashboard: dashboard,
11904
12175
  isFullscreen: isFullscreen,
@@ -11920,6 +12191,22 @@ const StyledDashboardHeader = styled(DotActionToolbar)`
11920
12191
  padding: ${theme.spacing(0, 2)};
11921
12192
  `}
11922
12193
  `;
12194
+ const StyledDashboardBanner = styled.div`
12195
+ ${({
12196
+ theme
12197
+ }) => css`
12198
+ padding: ${theme.spacing(1, 2)};
12199
+ align-items: stretch;
12200
+ .MuiAlert-message {
12201
+ flex: 5;
12202
+ }
12203
+ .dot-typography {
12204
+ display: flex;
12205
+ justify-content: space-between;
12206
+ align-items: center;
12207
+ }
12208
+ `}
12209
+ `;
11923
12210
  const StyledDashboardHeaderTitleSection = styled.div`
11924
12211
  ${({
11925
12212
  theme
@@ -11940,9 +12227,75 @@ const StyledDashboardHeaderTitleSection = styled.div`
11940
12227
  `}
11941
12228
  `;
11942
12229
 
12230
+ function DotDashboardBanner({
12231
+ bannerSeverity,
12232
+ bannerText,
12233
+ buttonText,
12234
+ buttonAction
12235
+ }) {
12236
+ return jsx(StyledDashboardBanner, {
12237
+ children: jsxs(DotAlertBanner, {
12238
+ severity: bannerSeverity,
12239
+ "data-testid": "dashboard-banner",
12240
+ children: [bannerText, buttonText && jsx(DotButton, {
12241
+ type: "outlined",
12242
+ onClick: buttonAction,
12243
+ "data-testid": "dashboard-banner-button",
12244
+ children: buttonText
12245
+ })]
12246
+ })
12247
+ });
12248
+ }
12249
+ function getDashboardBanner(dashboard, isEdit, onExitEditMode, onPublishChanges, currentUser, modifiedAuthorUser) {
12250
+ if (isEdit) {
12251
+ if (dashboard.is_being_modified) {
12252
+ if (dashboard.modified_author_id === currentUser.id) {
12253
+ // We're in Edit mode for a published dashboard, and the dashboard is being modified by the current user.
12254
+ return jsx(DotDashboardBanner, {
12255
+ bannerSeverity: "warning",
12256
+ bannerText: jsx(DotTypography, {
12257
+ children: "The Dashboard is currently in edit mode and only you can make changes. Publish the changes for other users to see."
12258
+ }),
12259
+ buttonText: "Publish changes",
12260
+ buttonAction: () => {
12261
+ onPublishChanges(dashboard);
12262
+ }
12263
+ });
12264
+ }
12265
+ } else {
12266
+ // We're in Edit mode for a published dashboard, but there are no staged changes saved yet.
12267
+ return jsx(DotDashboardBanner, {
12268
+ bannerSeverity: "info",
12269
+ bannerText: jsx(DotTypography, {
12270
+ children: "You are currently in Edit Mode. Any changes you make will not be visible to others until you publish the updated dashboard."
12271
+ }),
12272
+ buttonText: "Exit edit mode",
12273
+ buttonAction: () => {
12274
+ onExitEditMode(dashboard);
12275
+ }
12276
+ });
12277
+ }
12278
+ } else {
12279
+ if (currentUser && dashboard.is_being_modified && dashboard.modified_author_id !== currentUser.id && modifiedAuthorUser) {
12280
+ // We're in View mode for a published dashboard that is being edited by someone else.
12281
+ const bannerText = jsx(DotTypography, {
12282
+ children: jsxs("div", {
12283
+ children: ["This Dashboard is currently being edited by", ' ', jsxs("strong", {
12284
+ children: [modifiedAuthorUser.given_name, " ", modifiedAuthorUser.family_name]
12285
+ }), ". You will be able to see the updated dashboard once the changes are published."]
12286
+ })
12287
+ });
12288
+ return jsx(DotDashboardBanner, {
12289
+ bannerSeverity: "info",
12290
+ bannerText: bannerText
12291
+ });
12292
+ }
12293
+ }
12294
+ }
11943
12295
  function DotDashboardHeader({
11944
12296
  accountId,
11945
12297
  dashboard,
12298
+ currentUser,
11946
12299
  isEdit = false,
11947
12300
  canEdit = false,
11948
12301
  isFullscreen = false,
@@ -11952,10 +12305,14 @@ function DotDashboardHeader({
11952
12305
  onStatusChanged,
11953
12306
  onDeleted,
11954
12307
  onDuplicated,
12308
+ onRevertChanges,
12309
+ onViewOriginal,
11955
12310
  onToggleFullscreen,
11956
12311
  onViewMode,
11957
- showStatus = false
12312
+ showStatus = false,
12313
+ modifiedAuthorUser = null
11958
12314
  }) {
12315
+ const [dashboardToPublish, setDashboardToPublish] = useState(null);
11959
12316
  const {
11960
12317
  applications,
11961
12318
  applicationsError,
@@ -11966,6 +12323,18 @@ function DotDashboardHeader({
11966
12323
  metadataLoading,
11967
12324
  dashboardsError
11968
12325
  } = useDotMetadataApiContext();
12326
+ const handleStartPublishChanges = useCallback(publishDashboard => {
12327
+ setDashboardToPublish(publishDashboard);
12328
+ }, []);
12329
+ const handlePublishConfirmClose = useCallback(() => {
12330
+ setDashboardToPublish(null);
12331
+ }, []);
12332
+ const handlePublishConfirm = useCallback(publishedDashboard => {
12333
+ setDashboardToPublish(null);
12334
+ onStatusChanged && onStatusChanged(publishedDashboard);
12335
+ // Navigate to View Mode after publishing changes
12336
+ onViewMode && onViewMode(publishedDashboard, 'view');
12337
+ }, [onStatusChanged]);
11969
12338
  useEnqueueErrorMessage(!applicationsLoading && applicationsError);
11970
12339
  useEnqueueErrorMessage(!metadataLoading && dashboardsError);
11971
12340
  useEffect(() => {
@@ -11977,29 +12346,45 @@ function DotDashboardHeader({
11977
12346
  iconId: "back-solid",
11978
12347
  onClick: () => onBack(dashboard.id)
11979
12348
  });
11980
- return jsxs(StyledDashboardHeader, {
11981
- children: [jsxs(StyledDashboardHeaderTitleSection, {
11982
- children: [jsxs(DotTypography, {
11983
- component: "h2",
11984
- variant: "h2",
11985
- children: [backButton, dashboard === null || dashboard === void 0 ? void 0 : dashboard.name]
11986
- }), showStatus && jsx(DotDashboardStatusPill, {
11987
- status: dashboard.lifecycle_state
12349
+ const onExitEditMode = dashboardEdit => {
12350
+ onViewMode && onViewMode(dashboardEdit, 'view');
12351
+ };
12352
+ return jsxs(Fragment, {
12353
+ children: [jsx(DotDashboardPublishConfirm, {
12354
+ applicationList: applications,
12355
+ dashboardToPublish: dashboardToPublish,
12356
+ dashboardToUnpublish: null,
12357
+ onClose: handlePublishConfirmClose,
12358
+ onStatusChanged: handlePublishConfirm,
12359
+ currentUser: currentUser ? currentUser : null
12360
+ }), jsxs(StyledDashboardHeader, {
12361
+ children: [jsxs(StyledDashboardHeaderTitleSection, {
12362
+ children: [jsxs(DotTypography, {
12363
+ component: "h2",
12364
+ variant: "h2",
12365
+ children: [backButton, dashboard === null || dashboard === void 0 ? void 0 : dashboard.name]
12366
+ }), showStatus && dashboard && jsx(DotDashboardStatusPill, {
12367
+ dashboard: dashboard,
12368
+ currentUser: currentUser ? currentUser : null
12369
+ })]
12370
+ }), jsx(DotDashboardActions, {
12371
+ applications: applications,
12372
+ canEdit: canEdit,
12373
+ dashboard: dashboard,
12374
+ isEdit: isEdit,
12375
+ isFullscreen: isFullscreen,
12376
+ onClose: onClose,
12377
+ onFavorite: onFavorite,
12378
+ onRevertChanges: onRevertChanges,
12379
+ onStatusChanged: onStatusChanged,
12380
+ onDeleted: onDeleted,
12381
+ onDuplicated: onDuplicated,
12382
+ onToggleFullscreen: onToggleFullscreen,
12383
+ onViewMode: onViewMode,
12384
+ onViewOriginal: onViewOriginal,
12385
+ currentUser: currentUser ? currentUser : null
11988
12386
  })]
11989
- }), jsx(DotDashboardActions, {
11990
- applications: applications,
11991
- canEdit: canEdit,
11992
- dashboard: dashboard,
11993
- isEdit: isEdit,
11994
- isFullscreen: isFullscreen,
11995
- onClose: onClose,
11996
- onFavorite: onFavorite,
11997
- onStatusChanged: onStatusChanged,
11998
- onDeleted: onDeleted,
11999
- onDuplicated: onDuplicated,
12000
- onToggleFullscreen: onToggleFullscreen,
12001
- onViewMode: onViewMode
12002
- })]
12387
+ }), dashboard && dashboard.lifecycle_state === 'PUBLISHED' && getDashboardBanner(dashboard, isEdit, onExitEditMode, handleStartPublishChanges, currentUser ? currentUser : null, modifiedAuthorUser ? modifiedAuthorUser : null)]
12003
12388
  });
12004
12389
  }
12005
12390
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@digital-ai/dot-components",
3
- "version": "3.22.0",
3
+ "version": "3.24.0",
4
4
  "private": false,
5
5
  "license": "SEE LICENSE IN <LICENSE.md>",
6
6
  "contributors": [
@@ -1,7 +1,8 @@
1
- import { ApplicationModel } from '../../core-api/openapi';
1
+ import { ApplicationModel, UserModel } from '../../core-api/openapi';
2
2
  import { DashboardView } from '../metadata-api/openapi/';
3
3
  interface DashboardActionsCommonProps {
4
4
  canEdit?: boolean;
5
+ currentUser?: UserModel;
5
6
  dashboard: DashboardView;
6
7
  isEdit?: boolean;
7
8
  isFullscreen?: boolean;
@@ -9,12 +10,14 @@ interface DashboardActionsCommonProps {
9
10
  onDeleted?: (id: string, result: boolean) => void;
10
11
  onDuplicated?: (dashboard: DashboardView, isDone?: boolean) => void;
11
12
  onFavorite?: (id: string, value: boolean) => void;
13
+ onRevertChanges?: (dashboard: DashboardView) => void;
12
14
  onStatusChanged?: (dashboard: DashboardView) => void;
13
15
  onToggleFullscreen?: (newValue: boolean) => void;
14
16
  onViewMode?: (dashboard: DashboardView, mode: string) => void;
17
+ onViewOriginal?: (dashboard: DashboardView) => void;
15
18
  }
16
19
  interface DashboardActionsProps extends DashboardActionsCommonProps {
17
20
  applications: ApplicationModel[];
18
21
  }
19
- declare function DotDashboardActions({ applications, dashboard, isEdit, canEdit, isFullscreen, onClose, onFavorite, onStatusChanged, onDeleted, onDuplicated, onToggleFullscreen, onViewMode, }: DashboardActionsProps): import("react/jsx-runtime").JSX.Element;
20
- export { DashboardActionsCommonProps, DotDashboardActions };
22
+ declare function DotDashboardActions({ applications, dashboard, isEdit, canEdit, isFullscreen, onClose, onFavorite, onStatusChanged, onDeleted, onDuplicated, onToggleFullscreen, onViewMode, onViewOriginal, onRevertChanges, currentUser, }: DashboardActionsProps): import("react/jsx-runtime").JSX.Element;
23
+ export { DashboardActionsCommonProps, DotDashboardActions, DashboardActionsProps, };
@@ -1,14 +1,18 @@
1
1
  import { PopperPlacement } from '../../menu/Menu';
2
2
  import { DashboardView } from '../metadata-api/openapi';
3
+ import { UserModel } from '../../core-api/openapi';
3
4
  interface DashboardOptionsMenuProps {
5
+ currentUser?: UserModel;
4
6
  dashboard: DashboardView;
5
7
  isEdit?: boolean;
6
8
  menuPlacement?: PopperPlacement;
7
9
  onDetails?: (dashboard: DashboardView) => void;
8
10
  onStartDelete?: (dashboard: DashboardView) => void;
9
11
  onStartDuplicate?: (dashboard: DashboardView) => void;
12
+ onStartRevert?: (dashboard: DashboardView) => void;
10
13
  onStartStatusChange?: (dashboard: DashboardView, status: DashboardView.lifecycle_state) => void;
11
14
  onViewMode?: (dashboard: DashboardView, mode: string) => void;
15
+ onViewOriginal?: (dashboard: DashboardView) => void;
12
16
  }
13
- export declare function DotDashboardOptionsMenu({ dashboard, isEdit, menuPlacement, onStartDelete, onStartDuplicate, onStartStatusChange, onViewMode, onDetails, }: DashboardOptionsMenuProps): import("react/jsx-runtime").JSX.Element;
17
+ export declare function DotDashboardOptionsMenu({ dashboard, currentUser, isEdit, menuPlacement, onStartDelete, onStartDuplicate, onStartStatusChange, onStartRevert, onViewOriginal, onViewMode, onDetails, }: DashboardOptionsMenuProps): import("react/jsx-runtime").JSX.Element;
14
18
  export {};
@@ -1,8 +1,10 @@
1
- import { ApplicationModel } from '../../core-api/openapi';
1
+ import { ApplicationModel, UserModel } from '../../core-api/openapi';
2
2
  import { DashboardView } from '../metadata-api/openapi';
3
3
  interface DashboardPublishConfirmProps {
4
4
  /** List of applications the dashboard can be published to **/
5
5
  applicationList: ApplicationModel[];
6
+ /** Current User, used to determine if they have in-progress edits. **/
7
+ currentUser?: UserModel;
6
8
  /** Dashboard to confirm publishing for **/
7
9
  dashboardToPublish: DashboardView;
8
10
  /** Dashboard to confirm unpublishing for **/
@@ -12,5 +14,5 @@ interface DashboardPublishConfirmProps {
12
14
  /** When a dashboard is updated, this function is called with the updated dashboard **/
13
15
  onStatusChanged: (updatedDashboard: DashboardView) => void;
14
16
  }
15
- export declare function DotDashboardPublishConfirm({ applicationList, dashboardToPublish, dashboardToUnpublish, onClose, onStatusChanged, }: Readonly<DashboardPublishConfirmProps>): import("react/jsx-runtime").JSX.Element;
17
+ export declare function DotDashboardPublishConfirm({ applicationList, dashboardToPublish, dashboardToUnpublish, onClose, onStatusChanged, currentUser, }: Readonly<DashboardPublishConfirmProps>): import("react/jsx-runtime").JSX.Element;
16
18
  export {};
@@ -2,5 +2,5 @@ export declare const dashboardCategoriesContainerClassName = "dashboard-categori
2
2
  export declare const InlineMessage: import("styled-components").StyledComponent<({ ariaLabel, ariaLevel, ariaRole, className, "data-testid": dataTestId, children, component, noMarginBottom, noWrap, variant, }: import("../../typography/Typography").TypographyProps) => import("react/jsx-runtime").JSX.Element, any, {}, never>;
3
3
  export declare const StyledPublishConfirmDiv: import("styled-components").StyledComponent<"div", any, {}, never>;
4
4
  export declare const StyledAppSelectDiv: import("styled-components").StyledComponent<"div", any, {}, never>;
5
- export declare const StyledAppSelectDotAutoComplete: import("styled-components").StyledComponent<(<T extends import("../..").AutoCompleteOption>({ ListboxComponent, actionItem, ariaLabel, autoFocus, autoHighlight, className, "data-pendoid": dataPendoId, "data-testid": dataTestId, defaultValue, dense, disabled, disablePortal, endAdornmentTooltip, error, filterOptions, filterSelectedOptions, freesolo, checkIfOptionDisabled, group, helperText, inputId, inputRef, inputValue, isOptionEqualToValue, label, loading, maxHeight, multiple, onBlur, onChange, onClose, onInputChange, onOpen, open, options, persistentLabel, placeholder, popperClassName, preserveGroupOrder, readOnly, renderGroup, renderOption, renderTags, required, size, value, warning, }: import("../../auto-complete/AutoComplete").AutoCompleteProps<T>) => import("react/jsx-runtime").JSX.Element), any, {}, never>;
5
+ export declare const StyledAppSelectDotAutoComplete: import("styled-components").StyledComponent<(<T extends import("../..").AutoCompleteOption>({ ListboxComponent, actionItem, ariaLabel, autoFocus, autoHighlight, className, "data-pendoid": dataPendoId, "data-testid": dataTestId, defaultValue, dense, disabled, disablePortal, endAdornmentTooltip, error, filterOptions, filterSelectedOptions, freesolo, checkIfOptionDisabled, group, helperText, inputId, inputRef, inputValue, isOptionEqualToValue, label, loading, maxHeight, multiple, onBlur, onChange, onClose, onInputChange, onOpen, open, options, persistentLabel, placeholder, popperClassName, popperPlacement, preserveGroupOrder, readOnly, renderGroup, renderOption, renderTags, required, size, value, warning, }: import("../../auto-complete/AutoComplete").AutoCompleteProps<T>) => import("react/jsx-runtime").JSX.Element), any, {}, never>;
6
6
  export declare const StyledAppSelectAutoCompleteOption: import("styled-components").StyledComponent<"li", any, {}, never>;
@@ -1,6 +1,7 @@
1
1
  import { MouseEvent } from 'react';
2
2
  import { CommonProps } from '../../CommonProps';
3
3
  import { DashboardView } from '../metadata-api/openapi';
4
+ import { UserModel } from '../../core-api/openapi';
4
5
  interface CommonDashboardDetailsProps extends CommonProps {
5
6
  onClose?: (event: MouseEvent | KeyboardEvent) => void;
6
7
  onFavorite?: (dashboardId: string, favoriteValue: boolean) => void;
@@ -8,12 +9,14 @@ interface CommonDashboardDetailsProps extends CommonProps {
8
9
  zIndex?: number;
9
10
  }
10
11
  interface DashboardDetailsViewProps extends CommonDashboardDetailsProps {
12
+ currentUser?: UserModel;
11
13
  dashboard: DashboardView;
12
14
  open: boolean;
13
15
  }
14
- export declare const DotDashboardDetailsView: ({ className, dashboard, onClose, onFavorite, open, yOffset, zIndex, }: DashboardDetailsViewProps) => import("react/jsx-runtime").JSX.Element;
16
+ export declare const DotDashboardDetailsView: ({ className, dashboard, onClose, onFavorite, open, yOffset, zIndex, currentUser, }: DashboardDetailsViewProps) => import("react/jsx-runtime").JSX.Element;
15
17
  export interface DashboardDetailsProps extends CommonDashboardDetailsProps {
18
+ currentUser?: UserModel;
16
19
  dashboard?: DashboardView;
17
20
  }
18
- export declare const DotDashboardDetails: ({ dashboard, onClose, onFavorite, ...commonProps }: DashboardDetailsProps) => import("react/jsx-runtime").JSX.Element;
21
+ export declare const DotDashboardDetails: ({ dashboard, onClose, onFavorite, currentUser, ...commonProps }: DashboardDetailsProps) => import("react/jsx-runtime").JSX.Element;
19
22
  export {};
@@ -1,5 +1,8 @@
1
+ import { DashboardView } from '../metadata-api/openapi';
2
+ import { UserModel } from '../../core-api/openapi';
1
3
  interface DashboardStatusPillProps {
2
- status: string;
4
+ currentUser?: UserModel;
5
+ dashboard: DashboardView;
3
6
  }
4
- declare function DotDashboardStatusPill({ status, }: Readonly<DashboardStatusPillProps>): import("react/jsx-runtime").JSX.Element;
7
+ declare function DotDashboardStatusPill({ dashboard, currentUser, }: Readonly<DashboardStatusPillProps>): import("react/jsx-runtime").JSX.Element;
5
8
  export { DashboardStatusPillProps, DotDashboardStatusPill };
@@ -1,8 +1,10 @@
1
+ import { UserModel } from '../../core-api/openapi';
1
2
  import { DashboardActionsCommonProps } from '../dashboard-actions/DashboardActions';
2
3
  interface DashboardHeaderProps extends DashboardActionsCommonProps {
3
4
  accountId?: string;
5
+ modifiedAuthorUser?: UserModel;
4
6
  onBack?: (dashboardId?: string) => void;
5
7
  showStatus?: boolean;
6
8
  }
7
- declare function DotDashboardHeader({ accountId, dashboard, isEdit, canEdit, isFullscreen, onBack, onClose, onFavorite, onStatusChanged, onDeleted, onDuplicated, onToggleFullscreen, onViewMode, showStatus, }: DashboardHeaderProps): import("react/jsx-runtime").JSX.Element;
9
+ declare function DotDashboardHeader({ accountId, dashboard, currentUser, isEdit, canEdit, isFullscreen, onBack, onClose, onFavorite, onStatusChanged, onDeleted, onDuplicated, onRevertChanges, onViewOriginal, onToggleFullscreen, onViewMode, showStatus, modifiedAuthorUser, }: DashboardHeaderProps): import("react/jsx-runtime").JSX.Element;
8
10
  export { DashboardHeaderProps, DotDashboardHeader };
@@ -1,2 +1,3 @@
1
1
  export declare const StyledDashboardHeader: import("styled-components").StyledComponent<({ ariaLabel, children, className, "data-testid": dataTestId, variant, }: import("../../action-toolbar/ActionToolbar").DotActionBarProps) => import("react/jsx-runtime").JSX.Element, any, {}, never>;
2
+ export declare const StyledDashboardBanner: import("styled-components").StyledComponent<"div", any, {}, never>;
2
3
  export declare const StyledDashboardHeaderTitleSection: import("styled-components").StyledComponent<"div", any, {}, never>;
@@ -14,10 +14,13 @@ interface DotMetadataApiContextProps {
14
14
  favoriteDashboard: (dashboardId: string, favoriteValue: boolean) => Promise<DashboardView>;
15
15
  getAuthors: (appType: string, publishedOnly?: boolean) => Promise<Author[]>;
16
16
  getCategories: (appType: string, publishedOnly?: boolean) => Promise<string[]>;
17
+ getDashboard: (dashboardId: string, viewModified?: boolean) => Promise<DashboardView>;
17
18
  getDashboardHelpContent: (helpContentId: string) => Promise<string>;
18
19
  metadataLoading: boolean;
19
20
  openedDashboardDetails: DashboardView;
20
21
  platformConsoleUrl: string;
22
+ publishDashboardChanges: (dashboardId: string, dashboard: DashboardPatchBody, isSync?: boolean) => Promise<DashboardView>;
23
+ revertDashboardChanges: (dashboardId: string) => Promise<DashboardView>;
21
24
  searchDashboards: (search: DashboardFilters) => Promise<DashboardView[]>;
22
25
  setOpenedDashboardDetails: (dashboard: DashboardView) => void;
23
26
  setOverrideAccountId: (accountId: string) => void;
@@ -99,6 +99,14 @@ export type DashboardView = {
99
99
  * Timestamp of the latest modification
100
100
  */
101
101
  updated_dt?: string | null;
102
+ /**
103
+ * Whether a published dashboard is currently being modified.
104
+ */
105
+ is_being_modified?: boolean | null;
106
+ /**
107
+ * The platform id of the author currently modifying the dashboard.
108
+ */
109
+ modified_author_id?: string | null;
102
110
  };
103
111
  export declare namespace DashboardView {
104
112
  /**
@@ -15,7 +15,7 @@ export declare class DashboardsService {
15
15
  * @param sort Sort ordering to apply to the query.
16
16
  * @param filter List of filters (each filter is a separate query param, and they are OR'ed).
17
17
  *
18
- * * **Filterable field names**: author_fullname, author_id, bi_type, categories, created_dt, description, external_embedding_id, external_id, id, is_ootb_dashboard, lifecycle_state, name, target_apps, updated_by_fullname, updated_by_id, updated_dt
18
+ * * **Filterable field names**: author_fullname, author_id, bi_type, categories, created_dt, description, external_embedding_id, external_id, id, is_ootb_dashboard, lifecycle_state, modified_parent_id, name, target_apps, updated_by_fullname, updated_by_id, updated_dt
19
19
  * * **Searchable field names**: author_fullname, categories, description, name, updated_by_fullname
20
20
  *
21
21
  * @param favorite Boolean flag to only return dashboards marked as favorites.
@@ -47,11 +47,12 @@ export declare class DashboardsService {
47
47
  * Get one Dashboard definition.
48
48
  * Return a single Dashboard definition, selected by ID.
49
49
  * @param dashboardId
50
+ * @param viewModified Return the dashboard with modified changes if they exist for this user.
50
51
  * @returns DashboardView OK
51
52
  * @returns Error Default error response
52
53
  * @throws ApiError
53
54
  */
54
- static getDashboardsService1(dashboardId: string): Promise<DashboardView | Error>;
55
+ static getDashboardsService1(dashboardId: string, viewModified?: boolean): Promise<DashboardView | Error>;
55
56
  /**
56
57
  * Sets a single Dashboard definition.
57
58
  * Sets a Dashboard definition, selected by ID.
@@ -82,6 +83,26 @@ export declare class DashboardsService {
82
83
  * @throws ApiError
83
84
  */
84
85
  static deleteDashboardsService(dashboardId: string): Promise<Error>;
86
+ /**
87
+ * Publish modifications to a dashboard
88
+ * Publish modifications to a dashboard
89
+ * @param dashboardId
90
+ * @param requestBody
91
+ * @param isSync Sync the dashboard with BI
92
+ * @returns DashboardView Dashboard published.
93
+ * @returns Error Default error response
94
+ * @throws ApiError
95
+ */
96
+ static postDashboardsService1(dashboardId: string, requestBody: DashboardPatchBody, isSync?: boolean): Promise<DashboardView | Error>;
97
+ /**
98
+ * Revert modifications to a dashboard
99
+ * Revert modifications to a dashboard
100
+ * @param dashboardId
101
+ * @returns DashboardView Dashboard changes reverted.
102
+ * @returns Error Default error response
103
+ * @throws ApiError
104
+ */
105
+ static postDashboardsService2(dashboardId: string): Promise<DashboardView | Error>;
85
106
  /**
86
107
  * Create a copy of existing dashboard
87
108
  * Create a copy of existing dashboard
@@ -91,7 +112,7 @@ export declare class DashboardsService {
91
112
  * @returns Error Default error response
92
113
  * @throws ApiError
93
114
  */
94
- static postDashboardsService1(dashboardId: string, requestBody?: DashboardCopyBody): Promise<DashboardView | Error>;
115
+ static postDashboardsService3(dashboardId: string, requestBody?: DashboardCopyBody): Promise<DashboardView | Error>;
95
116
  /**
96
117
  * Favorite a dashboard
97
118
  * Favorite a dashboard
@@ -100,7 +121,7 @@ export declare class DashboardsService {
100
121
  * @returns Error Default error response
101
122
  * @throws ApiError
102
123
  */
103
- static postDashboardsService2(dashboardId: string): Promise<DashboardView | Error>;
124
+ static postDashboardsService4(dashboardId: string): Promise<DashboardView | Error>;
104
125
  /**
105
126
  * Un-favorite a dashboard
106
127
  * Un-favorite a dashboard
@@ -1,5 +1,5 @@
1
1
  import { ChangeEvent, FocusEvent, HTMLAttributes, JSXElementConstructor, ReactNode, Ref } from 'react';
2
- import { AutocompleteCloseReason, AutocompleteGetTagProps, AutocompleteRenderGroupParams, AutocompleteRenderOptionState, FilterOptionsState } from '@mui/material';
2
+ import { AutocompleteCloseReason, AutocompleteGetTagProps, AutocompleteRenderGroupParams, AutocompleteRenderOptionState, FilterOptionsState, type PopperPlacementType } from '@mui/material';
3
3
  import { CommonProps } from '../CommonProps';
4
4
  import { inputSizeOptions } from '../input-form-fields/InputFormFields.propTypes';
5
5
  import { ActionItem, AutoCompleteOption, AutoCompleteValue } from './utils/interface';
@@ -75,6 +75,8 @@ export interface AutoCompleteProps<T extends AutoCompleteOption = AutoCompleteOp
75
75
  placeholder?: string;
76
76
  /** Classname to be included in the autocomplete popper **/
77
77
  popperClassName?: string;
78
+ /** Placement of the popper */
79
+ popperPlacement?: PopperPlacementType;
78
80
  /** If true, group order (as specified by the consumer) will be preserved. Default group sorting is used when not specified. */
79
81
  preserveGroupOrder?: boolean;
80
82
  /** If true: popper cannot be opened, TextField is in read only mode, change is not allowed */
@@ -94,4 +96,4 @@ export interface AutoCompleteProps<T extends AutoCompleteOption = AutoCompleteOp
94
96
  /** If true, the label will be displayed in a warning state. */
95
97
  warning?: boolean;
96
98
  }
97
- export declare const DotAutoComplete: <T extends AutoCompleteOption>({ ListboxComponent, actionItem, ariaLabel, autoFocus, autoHighlight, className, "data-pendoid": dataPendoId, "data-testid": dataTestId, defaultValue, dense, disabled, disablePortal, endAdornmentTooltip, error, filterOptions, filterSelectedOptions, freesolo, checkIfOptionDisabled, group, helperText, inputId, inputRef, inputValue, isOptionEqualToValue, label, loading, maxHeight, multiple, onBlur, onChange, onClose, onInputChange, onOpen, open, options, persistentLabel, placeholder, popperClassName, preserveGroupOrder, readOnly, renderGroup, renderOption, renderTags, required, size, value, warning, }: AutoCompleteProps<T>) => import("react/jsx-runtime").JSX.Element;
99
+ export declare const DotAutoComplete: <T extends AutoCompleteOption>({ ListboxComponent, actionItem, ariaLabel, autoFocus, autoHighlight, className, "data-pendoid": dataPendoId, "data-testid": dataTestId, defaultValue, dense, disabled, disablePortal, endAdornmentTooltip, error, filterOptions, filterSelectedOptions, freesolo, checkIfOptionDisabled, group, helperText, inputId, inputRef, inputValue, isOptionEqualToValue, label, loading, maxHeight, multiple, onBlur, onChange, onClose, onInputChange, onOpen, open, options, persistentLabel, placeholder, popperClassName, popperPlacement, preserveGroupOrder, readOnly, renderGroup, renderOption, renderTags, required, size, value, warning, }: AutoCompleteProps<T>) => import("react/jsx-runtime").JSX.Element;
@@ -10,3 +10,4 @@ export type { ApplicationModelWrapper } from './models/ApplicationModelWrapper';
10
10
  export type { PaginationModel } from './models/PaginationModel';
11
11
  export { AccountsService } from './services/AccountsService';
12
12
  export { ApplicationsService } from './services/ApplicationsService';
13
+ export type { UserModel } from './models/UserModel';
@@ -0,0 +1,70 @@
1
+ export type UserModel = {
2
+ /**
3
+ * UUID Account Identifier
4
+ */
5
+ account_id: string;
6
+ /**
7
+ * The user creation date in ISO format
8
+ */
9
+ created_date: string;
10
+ /**
11
+ * Email address
12
+ */
13
+ email?: string;
14
+ /**
15
+ * Whether the user is enabled or not
16
+ */
17
+ enabled: boolean;
18
+ /**
19
+ * A message when problems arise retrieving details of a user
20
+ */
21
+ readonly error?: string;
22
+ /**
23
+ * A numerical code when problems occur retrieving details of a user
24
+ */
25
+ readonly error_code?: number;
26
+ /**
27
+ * User's last name
28
+ */
29
+ family_name?: string;
30
+ /**
31
+ * User's first name
32
+ */
33
+ given_name?: string;
34
+ /**
35
+ * List of Group names
36
+ */
37
+ groups?: Array<string>;
38
+ /**
39
+ * UUID User Identifier
40
+ */
41
+ id: string;
42
+ /**
43
+ * The date of the user's most recent login in ISO format
44
+ */
45
+ last_login_date: string;
46
+ /**
47
+ * Whether the user is created via API
48
+ */
49
+ readonly local: boolean;
50
+ /**
51
+ * Whether the user is locked out or not
52
+ */
53
+ readonly locked?: boolean;
54
+ /**
55
+ * The date that the user was last modified on in ISO format
56
+ */
57
+ modified_date: string;
58
+ /**
59
+ * Whether the user is invited and not yet logged in
60
+ */
61
+ pending: boolean;
62
+ /**
63
+ * List of Role names
64
+ */
65
+ roles?: Array<string>;
66
+ /**
67
+ * Username
68
+ */
69
+ username: string;
70
+ };