Add updating dashboard

This commit is contained in:
rijkvanzanten
2021-05-28 17:21:35 -04:00
parent 1084436d35
commit 6ce069eb03
5 changed files with 141 additions and 24 deletions

View File

@@ -548,6 +548,9 @@ dashboard: Dashboard
panel: Panel
panel_header: Panel Header
panel_delete_confirm: Are you sure you want to delete this panel? This action can not be undone.
dashboard_delete_confirm: Are you sure you want to delete this dashboard? This action can not be undone.
edit_dashboard: Edit Dashboard
delete_dashboard: Delete Dashboard
visible: Visible
no_dashboards: No Dashboards
no_dashboards_copy: You dont have any Dashboards yet.

View File

@@ -5,12 +5,14 @@
</template>
<v-card>
<v-card-title>{{ $t('create_dashboard') }}</v-card-title>
<v-card-title v-if="!dashboard">{{ $t('create_dashboard') }}</v-card-title>
<v-card-title v-else>{{ $t('edit_dashboard') }}</v-card-title>
<v-card-text>
<div class="fields">
<v-input @keyup.enter="save" autofocus v-model="dashboardName" :placeholder="$t('dashboard_name')" />
<interface-select-icon v-model="dashboardIcon" />
<v-input autofocus v-model="values.name" :placeholder="$t('dashboard_name')" />
<interface-select-icon v-model="values.icon" />
<v-input class="full" v-model="values.note" :placeholder="$t('note')" />
</div>
</v-card-text>
@@ -18,7 +20,7 @@
<v-button @click="cancel" secondary>
{{ $t('cancel') }}
</v-button>
<v-button :disabled="dashboardName === null || dashboardName.length === 0" @click="save" :loading="saving">
<v-button :disabled="!values.name" @click="save" :loading="saving">
{{ $t('save') }}
</v-button>
</v-card-actions>
@@ -29,11 +31,13 @@
<script lang="ts">
import api from '@/api';
import { unexpectedError } from '@/utils/unexpected-error';
import { defineComponent, ref } from '@vue/composition-api';
import { defineComponent, ref, reactive, PropType } from '@vue/composition-api';
import { useInsightsStore } from '@/stores';
import router from '@/router';
import { Dashboard } from '@/types';
export default defineComponent({
name: 'DashboardDialog',
model: {
prop: 'active',
event: 'toggle',
@@ -43,18 +47,25 @@ export default defineComponent({
type: Boolean,
default: false,
},
dashboard: {
type: Object as PropType<Dashboard>,
default: null,
},
},
setup(props, { emit }) {
const insightsStore = useInsightsStore();
const dashboardName = ref(null);
const dashboardIcon = ref(null);
const values = reactive({
name: props.dashboard?.name ?? null,
icon: props.dashboard?.icon ?? null,
note: props.dashboard?.note ?? null,
});
const saving = ref(false);
return { dashboardName, cancel, saving, save, dashboardIcon };
return { values, cancel, saving, save };
function cancel() {
dashboardName.value = null;
emit('toggle', false);
}
@@ -62,13 +73,14 @@ export default defineComponent({
saving.value = true;
try {
const response = await api.post(
'/dashboards',
{ name: dashboardName.value, icon: dashboardIcon.value },
{ params: { fields: ['id'] } }
);
await insightsStore.hydrate();
router.push(`/insights/${response.data.data.id}`);
if (props.dashboard) {
await api.patch(`/dashboards/${props.dashboard.id}`, values, { params: { fields: ['id'] } });
await insightsStore.hydrate();
} else {
const response = await api.post('/dashboards', values, { params: { fields: ['id'] } });
await insightsStore.hydrate();
router.push(`/insights/${response.data.data.id}`);
}
emit('toggle', false);
} catch (err) {
unexpectedError(err);
@@ -86,4 +98,8 @@ export default defineComponent({
grid-template-columns: 1fr 1fr;
gap: 12px;
}
.full {
grid-column: 1 / span 2;
}
</style>

View File

@@ -11,7 +11,7 @@
</template>
<template #actions>
<create-dashboard-dialog v-model="createDialogActive">
<dashboard-dialog v-model="createDialogActive">
<template #activator="{ on }">
<v-button
@click="on"
@@ -23,7 +23,7 @@
<v-icon name="add" />
</v-button>
</template>
</create-dashboard-dialog>
</dashboard-dialog>
</template>
<v-table
@@ -37,11 +37,56 @@
<template #item.icon="{ item }">
<v-icon class="icon" :name="item.icon" />
</template>
<template #item-append="{ item }">
<v-menu placement="left-start" show-arrow>
<template #activator="{ toggle }">
<v-icon name="more_vert" @click="toggle" class="ctx-toggle" />
</template>
<v-list>
<v-list-item @click="editDashboard = item" class="warning">
<v-list-item-icon>
<v-icon name="edit" outline />
</v-list-item-icon>
<v-list-item-content>
{{ $t('edit_dashboard') }}
</v-list-item-content>
</v-list-item>
<v-list-item @click="confirmDelete = item.id" class="danger">
<v-list-item-icon>
<v-icon name="delete" outline />
</v-list-item-icon>
<v-list-item-content>
{{ $t('delete_dashboard') }}
</v-list-item-content>
</v-list-item>
</v-list>
</v-menu>
</template>
</v-table>
<v-info icon="dashboard" :title="$t('no_dashboards')" v-else center>
{{ $t('no_dashboards_copy') }}
</v-info>
<v-dialog :active="!!confirmDelete" @esc="confirmDelete = null">
<v-card>
<v-card-title>{{ $t('dashboard_delete_confirm') }}</v-card-title>
<v-card-actions>
<v-button @click="confirmDelete = null" secondary>
{{ $t('cancel') }}
</v-button>
<v-button class="action-delete" @click="deleteDashboard" :loading="deletingDashboard">
{{ $t('delete') }}
</v-button>
</v-card-actions>
</v-card>
</v-dialog>
<dashboard-dialog v-if="editDashboard" active @toggle="editDashboard = null" :dashboard="editDashboard" />
</private-view>
</template>
@@ -52,15 +97,21 @@ import i18n from '@/lang';
import { Dashboard } from '@/types';
import router from '@/router';
import InsightsNavigation from '../components/navigation.vue';
import CreateDashboardDialog from '../components/create-dashboard-dialog.vue';
import DashboardDialog from '../components/dashboard-dialog.vue';
import api from '@/api';
import { unexpectedError } from '@/utils/unexpected-error';
export default defineComponent({
name: 'InsightsOverview',
components: { InsightsNavigation, CreateDashboardDialog },
components: { InsightsNavigation, DashboardDialog },
setup() {
const insightsStore = useInsightsStore();
const permissionsStore = usePermissionsStore();
const confirmDelete = ref<string | null>(null);
const deletingDashboard = ref(false);
const editDashboard = ref<Dashboard | null>(null);
const createDialogActive = ref(false);
const createAllowed = computed<boolean>(() => {
@@ -86,17 +137,39 @@ export default defineComponent({
},
];
const dashboards = computed(() => insightsStore.state.dashboards);
return {
dashboards: insightsStore.state.dashboards,
dashboards,
createAllowed,
tableHeaders,
navigateToDashboard,
createDialogActive,
confirmDelete,
deletingDashboard,
deleteDashboard,
editDashboard,
};
function navigateToDashboard(dashboard: Dashboard) {
router.push(`/insights/${dashboard.id}`);
}
async function deleteDashboard() {
if (!confirmDelete.value) return;
deletingDashboard.value = true;
try {
await api.delete(`/dashboards/${confirmDelete.value}`);
await insightsStore.hydrate();
confirmDelete.value = null;
} catch (err) {
unexpectedError(err);
} finally {
deletingDashboard.value = false;
}
}
},
});
</script>
@@ -106,4 +179,28 @@ export default defineComponent({
padding: var(--content-padding);
padding-top: 0;
}
.action-delete {
--v-button-background-color: var(--danger-10);
--v-button-color: var(--danger);
--v-button-background-color-hover: var(--danger-25);
--v-button-color-hover: var(--danger);
}
.ctx-toggle {
--v-icon-color: var(--foreground-subdued);
--v-icon-color-hover: var(--foreground-normal);
}
.v-list-item.danger {
--v-list-item-color: var(--danger);
--v-list-item-color-hover: var(--danger);
--v-list-item-icon-color: var(--danger);
}
.v-list-item.warning {
--v-list-item-color: var(--warning);
--v-list-item-color-hover: var(--warning);
--v-list-item-icon-color: var(--warning);
}
</style>

View File

@@ -1,6 +1,7 @@
export type Dashboard = {
id: string;
name: string;
note: string;
icon: string;
panels: Panel[];
date_created: string;

View File

@@ -1,9 +1,9 @@
<template functional>
<template>
<span class="null">--</span>
</template>
<style lang="scss" scoped>
<style scoped>
.null {
color: var(--border-normal); // Don't confuse NULL with subdued value
color: var(--border-normal); /* Don't confuse NULL with subdued value */
}
</style>