From 63d57d27ca90319a179cf2fa2ff30887b5785cde Mon Sep 17 00:00:00 2001 From: Steve-Mcl Date: Tue, 7 May 2024 16:07:37 +0100 Subject: [PATCH 1/8] Add front end API for accessing new snapshots api --- frontend/src/api/snapshots.js | 61 +++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 frontend/src/api/snapshots.js diff --git a/frontend/src/api/snapshots.js b/frontend/src/api/snapshots.js new file mode 100644 index 0000000000..b0c9d4359b --- /dev/null +++ b/frontend/src/api/snapshots.js @@ -0,0 +1,61 @@ +import product from '../services/product.js' +import daysSince from '../utils/daysSince.js' + +import client from './client.js' + +/** + * Get summary of a snapshot + */ +const getSummary = (snapshotId) => { + return client.get(`/api/v1/snapshots/${snapshotId}`).then(res => { + res.data.createdSince = daysSince(res.data.createdAt) + res.data.updatedSince = daysSince(res.data.updatedAt) + return res.data + }) +} + +/** + * Get full snapshot + */ +const getFullSnapshot = (snapshotId) => { + return client.get(`/api/v1/snapshots/${snapshotId}/full`).then(res => { + res.data.createdSince = daysSince(res.data.createdAt) + res.data.updatedSince = daysSince(res.data.updatedAt) + return res.data + }) +} + +/** + * Export a snapshot for later import in another project or platform + */ +const exportSnapshot = (snapshotId, options) => { + return client.post(`/api/v1/snapshots/${snapshotId}/export`, options).then(res => { + const props = { + 'snapshot-id': res.data.id + } + product.capture('$ff-snapshot-export', props, {}) + return res.data + }) +} + +/** + * Delete a snapshot + * @param {String} snapshotId - id of the snapshot + */ +const deleteSnapshot = async (snapshotId) => { + return client.delete(`/api/v1/snapshots/${snapshotId}`).then(res => { + const props = { + 'snapshot-id': snapshotId, + 'deleted-at': (new Date()).toISOString() + } + product.capture('$ff-snapshot-deleted', props, {}) + return res.data + }) +} + +export default { + deleteSnapshot, + getFullSnapshot, + exportSnapshot, + getSummary +} From b9cf130379abac324b28340a86cfba8ef1548ca5 Mon Sep 17 00:00:00 2001 From: Steve-Mcl Date: Tue, 7 May 2024 16:18:09 +0100 Subject: [PATCH 2/8] add snapshot view dialog --- .../dialogs/SnapshotViewerDialog.vue | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 frontend/src/components/dialogs/SnapshotViewerDialog.vue diff --git a/frontend/src/components/dialogs/SnapshotViewerDialog.vue b/frontend/src/components/dialogs/SnapshotViewerDialog.vue new file mode 100644 index 0000000000..e14ef74858 --- /dev/null +++ b/frontend/src/components/dialogs/SnapshotViewerDialog.vue @@ -0,0 +1,68 @@ + + + + From 44526e66ca05a26cff54c7049b7e4399d8fe2936 Mon Sep 17 00:00:00 2001 From: Steve-Mcl Date: Tue, 7 May 2024 17:06:50 +0100 Subject: [PATCH 3/8] allow custom styles on dialog boc --- frontend/src/ui-components/components/DialogBox.vue | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/frontend/src/ui-components/components/DialogBox.vue b/frontend/src/ui-components/components/DialogBox.vue index 45d6692dc4..0da16717a9 100644 --- a/frontend/src/ui-components/components/DialogBox.vue +++ b/frontend/src/ui-components/components/DialogBox.vue @@ -1,8 +1,8 @@ + @@ -60,9 +62,11 @@ import { mapState } from 'vuex' import InstanceApi from '../../../api/instances.js' import SnapshotApi from '../../../api/projectSnapshots.js' +import SnapshotsApi from '../../../api/snapshots.js' import EmptyState from '../../../components/EmptyState.vue' import SectionTopMenu from '../../../components/SectionTopMenu.vue' +import SnapshotViewerDialog from '../../../components/dialogs/SnapshotViewerDialog.vue' import UserCell from '../../../components/tables/cells/UserCell.vue' import permissionsMixin from '../../../mixins/Permissions.js' import Alerts from '../../../services/alerts.js' @@ -81,6 +85,7 @@ export default { EmptyState, SnapshotCreateDialog, SnapshotExportDialog, + SnapshotViewerDialog, PlusSmIcon }, mixins: [permissionsMixin], @@ -102,7 +107,7 @@ export default { computed: { ...mapState('account', ['teamMembership']), showContextMenu: function () { - return this.hasPermission('project:snapshot:rollback') || this.hasPermission('project:snapshot:set-target') || this.hasPermission('project:snapshot:delete') || this.hasPermission('project:snapshot:export') + return this.hasPermission('project:snapshot:rollback') || this.hasPermission('project:snapshot:set-target') || this.hasPermission('project:snapshot:delete') || this.hasPermission('project:snapshot:export') || this.hasPermission('snapshot:full') }, columns () { const cols = [ @@ -259,6 +264,14 @@ export default { }, showDownloadSnapshotDialog (snapshot) { this.$refs.snapshotExportDialog.show(snapshot) + }, + showViewSnapshotDialog (snapshot) { + SnapshotsApi.getFullSnapshot(snapshot.id).then((data) => { + this.$refs.snapshotViewerDialog.show(data) + }).catch(err => { + console.error(err) + Alerts.emit('Failed to get snapshot.', 'warning') + }) } } } From e204187331c2da2f43d6747490ce43ca2719ed1a Mon Sep 17 00:00:00 2001 From: Steve-Mcl Date: Tue, 7 May 2024 17:07:57 +0100 Subject: [PATCH 5/8] add "view snapshot" kebab menu entry for "device" --- frontend/src/pages/device/Snapshots/index.vue | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/frontend/src/pages/device/Snapshots/index.vue b/frontend/src/pages/device/Snapshots/index.vue index 09a14ff8bd..858e763b54 100644 --- a/frontend/src/pages/device/Snapshots/index.vue +++ b/frontend/src/pages/device/Snapshots/index.vue @@ -21,6 +21,7 @@ Create Snapshot @@ -52,6 +53,7 @@ + @@ -62,9 +64,11 @@ import { mapState } from 'vuex' import ApplicationApi from '../../../api/application.js' import DeviceApi from '../../../api/devices.js' +import SnapshotApi from '../../../api/snapshots.js' import EmptyState from '../../../components/EmptyState.vue' import SectionTopMenu from '../../../components/SectionTopMenu.vue' +import SnapshotViewerDialog from '../../../components/dialogs/SnapshotViewerDialog.vue' import UserCell from '../../../components/tables/cells/UserCell.vue' import permissionsMixin from '../../../mixins/Permissions.js' import Alerts from '../../../services/alerts.js' @@ -82,6 +86,7 @@ export default { SectionTopMenu, EmptyState, SnapshotCreateDialog, + SnapshotViewerDialog, PlusSmIcon }, mixins: [permissionsMixin], @@ -105,7 +110,7 @@ export default { computed: { ...mapState('account', ['teamMembership', 'features']), showContextMenu: function () { - return this.hasPermission('device:snapshot:delete') + return this.hasPermission('snapshot:delete') || this.hasPermission('snapshot:export') }, columns () { const cols = [ @@ -222,7 +227,7 @@ export default { kind: 'danger', confirmLabel: 'Delete' }, async () => { - await DeviceApi.deleteSnapshot(this.device.id, snapshot.id) + await SnapshotApi.deleteSnapshot(snapshot.id) const index = this.snapshots.indexOf(snapshot) this.snapshots.splice(index, 1) Alerts.emit('Successfully deleted snapshot.', 'confirmation') @@ -241,7 +246,7 @@ export default { }, onSnapshotFailed (err) { console.error(err) - Alerts.emit('Failed to create snapshot of device.', 'error') + Alerts.emit('Failed to create snapshot of device.', 'warning') this.busyMakingSnapshot = false }, onSnapshotCancel () { @@ -288,6 +293,14 @@ export default { Alerts.emit('Failed to apply snapshot: ' + err.toString(), 'warning', 7500) } }) + }, + showViewSnapshotDialog (snapshot) { + SnapshotApi.getFullSnapshot(snapshot.id).then((data) => { + this.$refs.snapshotViewerDialog.show(data) + }).catch(err => { + console.error(err) + Alerts.emit('Failed to get snapshot.', 'warning') + }) } } } From 3b4b38b5cd8b5448a1d1c1b046749fc88fe48fbe Mon Sep 17 00:00:00 2001 From: Steve-Mcl Date: Tue, 7 May 2024 17:09:02 +0100 Subject: [PATCH 6/8] add kebab menu with "view snapshot" entry for "application" view --- frontend/src/pages/application/Snapshots.vue | 26 +++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/frontend/src/pages/application/Snapshots.vue b/frontend/src/pages/application/Snapshots.vue index c99e6f64c4..1110e77c9c 100644 --- a/frontend/src/pages/application/Snapshots.vue +++ b/frontend/src/pages/application/Snapshots.vue @@ -11,7 +11,11 @@ +