feat: Update the design for macros design page (#9999)

This is the continuation of the design update for settings page. This PR updates the design for the macros page.

Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
This commit is contained in:
Pranav
2024-08-21 18:27:53 +05:30
committed by GitHub
parent 77b718c22c
commit 44227de97e
5 changed files with 177 additions and 185 deletions

View File

@@ -1,117 +1,112 @@
<script>
import { mapGetters } from 'vuex';
<script setup>
import { useAlert } from 'dashboard/composables';
import { useAccount } from 'dashboard/composables/useAccount';
import MacrosTableRow from './MacrosTableRow.vue';
export default {
components: {
MacrosTableRow,
},
setup() {
const { accountScopedUrl } = useAccount();
return {
accountScopedUrl,
};
},
data() {
return {
showDeleteConfirmationPopup: false,
selectedResponse: {},
loading: {},
};
},
computed: {
...mapGetters({
records: ['macros/getMacros'],
uiFlags: 'macros/getUIFlags',
}),
deleteMessage() {
return ` ${this.selectedResponse.name}?`;
},
},
mounted() {
this.$store.dispatch('macros/get');
},
methods: {
openDeletePopup(response) {
this.showDeleteConfirmationPopup = true;
this.selectedResponse = response;
},
closeDeletePopup() {
this.showDeleteConfirmationPopup = false;
},
confirmDeletion() {
this.loading[this.selectedResponse.id] = true;
this.closeDeletePopup();
this.deleteMacro(this.selectedResponse.id);
},
async deleteMacro(id) {
try {
await this.$store.dispatch('macros/delete', id);
useAlert(this.$t('MACROS.DELETE.API.SUCCESS_MESSAGE'));
this.loading[this.selectedResponse.id] = false;
} catch (error) {
useAlert(this.$t('MACROS.DELETE.API.ERROR_MESSAGE'));
}
},
},
import BaseSettingsHeader from '../components/BaseSettingsHeader.vue';
import SettingsLayout from '../SettingsLayout.vue';
import { computed, onMounted, ref } from 'vue';
import { useI18n } from 'dashboard/composables/useI18n';
import { useStoreGetters, useStore } from 'dashboard/composables/store';
const getters = useStoreGetters();
const store = useStore();
const { t } = useI18n();
const showDeleteConfirmationPopup = ref(false);
const selectedMacro = ref({});
const records = computed(() => getters['macros/getMacros'].value);
const uiFlags = computed(() => getters['macros/getUIFlags'].value);
const deleteMessage = computed(() => ` ${selectedMacro.value.name}?`);
onMounted(() => {
store.dispatch('macros/get');
});
const deleteMacro = async id => {
try {
await store.dispatch('macros/delete', id);
useAlert(t('MACROS.DELETE.API.SUCCESS_MESSAGE'));
} catch (error) {
useAlert(t('MACROS.DELETE.API.ERROR_MESSAGE'));
}
};
const openDeletePopup = response => {
showDeleteConfirmationPopup.value = true;
selectedMacro.value = response;
};
const closeDeletePopup = () => {
showDeleteConfirmationPopup.value = false;
};
const confirmDeletion = () => {
closeDeletePopup();
deleteMacro(selectedMacro.value.id);
};
</script>
<template>
<div class="flex-1 overflow-auto">
<router-link
:to="accountScopedUrl('settings/macros/new')"
class="button success button--fixed-top button success button--fixed-top px-3.5 py-1 rounded-[5px] flex gap-2"
>
<fluent-icon icon="add-circle" />
<span class="button__content">
{{ $t('MACROS.HEADER_BTN_TXT') }}
</span>
</router-link>
<div class="flex flex-row gap-4 p-8">
<div class="w-full lg:w-3/5">
<div v-if="!uiFlags.isFetching && !records.length" class="p-3">
<p class="flex flex-col items-center justify-center h-full">
{{ $t('MACROS.LIST.404') }}
</p>
</div>
<woot-loading-state
v-if="uiFlags.isFetching"
:message="$t('MACROS.LOADING')"
/>
<table v-if="!uiFlags.isFetching && records.length" class="woot-table">
<thead>
<th
v-for="thHeader in $t('MACROS.LIST.TABLE_HEADER')"
:key="thHeader"
>
{{ thHeader }}
</th>
</thead>
<tbody>
<MacrosTableRow
v-for="(macro, index) in records"
:key="index"
:macro="macro"
@delete="openDeletePopup(macro, index)"
/>
</tbody>
</table>
</div>
<div class="hidden w-1/3 lg:block">
<span v-dompurify-html="$t('MACROS.SIDEBAR_TXT')" />
</div>
</div>
<woot-delete-modal
:show.sync="showDeleteConfirmationPopup"
:on-close="closeDeletePopup"
:on-confirm="confirmDeletion"
:title="$t('LABEL_MGMT.DELETE.CONFIRM.TITLE')"
:message="$t('MACROS.DELETE.CONFIRM.MESSAGE')"
:message-value="deleteMessage"
:confirm-text="$t('MACROS.DELETE.CONFIRM.YES')"
:reject-text="$t('MACROS.DELETE.CONFIRM.NO')"
/>
</div>
<SettingsLayout
:no-records-message="$t('MACROS.LIST.404')"
:no-records-found="!records.length"
:is-loading="uiFlags.isFetching"
:loading-message="$t('MACROS.LOADING')"
feature-name="macros"
>
<template #header>
<BaseSettingsHeader
:title="$t('MACROS.HEADER')"
:description="$t('MACROS.DESCRIPTION')"
:link-text="$t('MACROS.LEARN_MORE')"
feature-name="macros"
>
<template #actions>
<router-link
:to="{ name: 'macros_new' }"
class="button rounded-md primary"
>
<fluent-icon icon="add-circle" />
<span class="button__content">
{{ $t('MACROS.HEADER_BTN_TXT') }}
</span>
</router-link>
</template>
</BaseSettingsHeader>
</template>
<template #body>
<table class="min-w-full divide-y divide-slate-75 dark:divide-slate-700">
<thead>
<th
v-for="thHeader in $t('MACROS.LIST.TABLE_HEADER')"
:key="thHeader"
class="py-4 ltr:pr-4 rtl:pl-4 text-left font-semibold text-slate-700 dark:text-slate-300"
>
{{ thHeader }}
</th>
</thead>
<tbody
class="divide-y divide-slate-50 dark:divide-slate-800 text-slate-700 dark:text-slate-300"
>
<MacrosTableRow
v-for="(macro, index) in records"
:key="index"
:macro="macro"
@delete="openDeletePopup(macro)"
/>
</tbody>
</table>
<woot-delete-modal
:show.sync="showDeleteConfirmationPopup"
:on-close="closeDeletePopup"
:on-confirm="confirmDeletion"
:title="$t('LABEL_MGMT.DELETE.CONFIRM.TITLE')"
:message="$t('MACROS.DELETE.CONFIRM.MESSAGE')"
:message-value="deleteMessage"
:confirm-text="$t('MACROS.DELETE.CONFIRM.YES')"
:reject-text="$t('MACROS.DELETE.CONFIRM.NO')"
/>
</template>
</SettingsLayout>
</template>

View File

@@ -1,59 +1,56 @@
<script>
import { useAccount } from 'dashboard/composables/useAccount';
<script setup>
import { computed } from 'vue';
import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue';
export default {
components: {
Thumbnail,
},
props: {
macro: {
type: Object,
required: true,
},
},
setup() {
const { accountScopedUrl } = useAccount();
import { useI18n } from 'dashboard/composables/useI18n';
return {
accountScopedUrl,
};
const props = defineProps({
macro: {
type: Object,
required: true,
},
computed: {
createdByName() {
const createdBy = this.macro.created_by;
return createdBy.available_name ?? createdBy.email ?? '';
},
updatedByName() {
const updatedBy = this.macro.updated_by;
return updatedBy.available_name ?? updatedBy.email ?? '';
},
visibilityLabel() {
return this.macro.visibility === 'global'
? this.$t('MACROS.EDITOR.VISIBILITY.GLOBAL.LABEL')
: this.$t('MACROS.EDITOR.VISIBILITY.PERSONAL.LABEL');
},
},
};
});
defineEmits(['delete']);
const { t } = useI18n();
const createdByName = computed(() => {
const createdBy = props.macro.created_by;
return createdBy.available_name ?? createdBy.email ?? '';
});
const updatedByName = computed(() => {
const updatedBy = props.macro.updated_by;
return updatedBy.available_name ?? updatedBy.email ?? '';
});
const visibilityLabel = computed(() => {
const i18nKey =
props.macro.visibility === 'global'
? 'MACROS.EDITOR.VISIBILITY.GLOBAL.LABEL'
: 'MACROS.EDITOR.VISIBILITY.PERSONAL.LABEL';
return t(i18nKey);
});
</script>
<template>
<tr>
<td>{{ macro.name }}</td>
<td>
<div v-if="macro.created_by" class="avatar-container">
<td class="py-4 ltr:pr-4 rtl:pl-4 truncate">{{ macro.name }}</td>
<td class="py-4 ltr:pr-4 rtl:pl-4">
<div v-if="macro.created_by" class="flex items-center">
<Thumbnail :username="createdByName" size="24px" />
<span>{{ createdByName }}</span>
<span class="mx-2">{{ createdByName }}</span>
</div>
<div v-else>--</div>
</td>
<td>
<div v-if="macro.updated_by" class="avatar-container">
<td class="py-4 ltr:pr-4 rtl:pl-4">
<div v-if="macro.updated_by" class="flex items-center">
<Thumbnail :username="updatedByName" size="24px" />
<span>{{ updatedByName }}</span>
<span class="mx-2">{{ updatedByName }}</span>
</div>
<div v-else>--</div>
</td>
<td>{{ visibilityLabel }}</td>
<td class="button-wrapper">
<router-link :to="accountScopedUrl(`settings/macros/${macro.id}/edit`)">
<td class="py-4 ltr:pr-4 rtl:pl-4">{{ visibilityLabel }}</td>
<td class="py-4 flex justify-end gap-1">
<router-link :to="{ name: 'macros_edit', params: { macroId: macro.id } }">
<woot-button
v-tooltip.top="$t('MACROS.EDIT.TOOLTIP')"
variant="smooth"
@@ -75,15 +72,3 @@ export default {
</td>
</tr>
</template>
<style scoped lang="scss">
.avatar-container {
display: flex;
align-items: center;
span {
margin-left: var(--space-small);
margin-right: var(--space-small);
}
}
</style>

View File

@@ -1,6 +1,7 @@
import { frontendURL } from 'dashboard/helper/URLHelper';
const SettingsContent = () => import('../Wrapper.vue');
const SettingsWrapper = () => import('../SettingsWrapper.vue');
const Macros = () => import('./Index.vue');
const MacroEditor = () => import('./MacroEditor.vue');
@@ -8,16 +9,7 @@ export default {
routes: [
{
path: frontendURL('accounts/:accountId/settings/macros'),
component: SettingsContent,
props: params => {
const showBackButton = params.name !== 'macros_wrapper';
return {
headerTitle: 'MACROS.HEADER',
headerButtonText: 'MACROS.HEADER_BTN_TXT',
icon: 'flash-settings',
showBackButton,
};
},
component: SettingsWrapper,
children: [
{
path: '',
@@ -27,6 +19,27 @@ export default {
permissions: ['administrator', 'agent'],
},
},
],
},
{
path: frontendURL('accounts/:accountId/settings/macros'),
component: SettingsContent,
props: () => {
return {
headerTitle: 'MACROS.HEADER',
icon: 'flash-settings',
showBackButton: true,
};
},
children: [
{
path: ':macroId/edit',
name: 'macros_edit',
component: MacroEditor,
meta: {
permissions: ['administrator', 'agent'],
},
},
{
path: 'new',
name: 'macros_new',
@@ -35,14 +48,6 @@ export default {
permissions: ['administrator', 'agent'],
},
},
{
path: ':macroId/edit',
name: 'macros_edit',
component: MacroEditor,
meta: {
permissions: ['administrator', 'agent'],
},
},
],
},
],