Merge branch 'develop' into feature/enhanced-template-support

This commit is contained in:
Muhsin Keloth
2025-07-23 14:31:06 +04:00
committed by GitHub
28 changed files with 300 additions and 199 deletions
+4
View File
@@ -28,6 +28,10 @@ class Inboxes extends CacheEnabledApiClient {
agent_bot: botId,
});
}
syncTemplates(inboxId) {
return axios.post(`${this.url}/${inboxId}/sync_templates`);
}
}
export default new Inboxes();
@@ -12,6 +12,7 @@ describe('#InboxesAPI', () => {
expect(inboxesAPI).toHaveProperty('getCampaigns');
expect(inboxesAPI).toHaveProperty('getAgentBot');
expect(inboxesAPI).toHaveProperty('setAgentBot');
expect(inboxesAPI).toHaveProperty('syncTemplates');
});
describe('API calls', () => {
@@ -40,5 +41,12 @@ describe('#InboxesAPI', () => {
inboxesAPI.deleteInboxAvatar(2);
expect(axiosMock.delete).toHaveBeenCalledWith('/api/v1/inboxes/2/avatar');
});
it('#syncTemplates', () => {
inboxesAPI.syncTemplates(2);
expect(axiosMock.post).toHaveBeenCalledWith(
'/api/v1/inboxes/2/sync_templates'
);
});
});
});
@@ -6,7 +6,7 @@ import DropdownBody from './base/DropdownBody.vue';
import DropdownSection from './base/DropdownSection.vue';
import DropdownItem from './base/DropdownItem.vue';
import DropdownSeparator from './base/DropdownSeparator.vue';
import WootSwitch from 'components/ui/Switch.vue';
import ToggleSwitch from 'dashboard/components-next/switch/Switch.vue';
const currentUserAutoOffline = ref(false);
@@ -61,7 +61,7 @@ const menuItems = ref([
<DropdownItem label="Contact Support" class="justify-between">
<span>{{ $t('SIDEBAR.SET_AUTO_OFFLINE.TEXT') }}</span>
<div class="flex-shrink-0">
<WootSwitch v-model="currentUserAutoOffline" />
<ToggleSwitch v-model="currentUserAutoOffline" />
</div>
</DropdownItem>
</DropdownSection>
@@ -14,6 +14,7 @@ import {
} from 'next/dropdown-menu/base';
import Icon from 'next/icon/Icon.vue';
import Button from 'next/button/Button.vue';
import ToggleSwitch from 'dashboard/components-next/switch/Switch.vue';
const { t } = useI18n();
const store = useStore();
@@ -48,6 +49,16 @@ const activeStatus = computed(() => {
return availabilityStatuses.value.find(status => status.active);
});
const autoOfflineToggle = computed({
get: () => currentUserAutoOffline.value,
set: autoOffline => {
store.dispatch('updateAutoOffline', {
accountId: currentAccountId.value,
autoOffline,
});
},
});
function changeAvailabilityStatus(availability) {
if (isImpersonating.value) {
useAlert(t('PROFILE_SETTINGS.FORM.AVAILABILITY.IMPERSONATING_ERROR'));
@@ -62,13 +73,6 @@ function changeAvailabilityStatus(availability) {
useAlert(t('PROFILE_SETTINGS.FORM.AVAILABILITY.SET_AVAILABILITY_ERROR'));
}
}
function updateAutoOffline(autoOffline) {
store.dispatch('updateAutoOffline', {
accountId: currentAccountId.value,
autoOffline,
});
}
</script>
<template>
@@ -118,11 +122,7 @@ function updateAutoOffline(autoOffline) {
class="size-4 text-n-slate-10"
/>
</div>
<woot-switch
class="flex-shrink-0"
:model-value="currentUserAutoOffline"
@input="updateAutoOffline"
/>
<ToggleSwitch v-model="autoOfflineToggle" />
</DropdownItem>
</div>
</DropdownSection>
@@ -19,8 +19,8 @@ const updateValue = () => {
<template>
<button
type="button"
class="relative h-4 transition-colors duration-200 ease-in-out rounded-full w-7 focus:outline-none focus:ring-1 focus:ring-n-brand focus:ring-offset-n-slate-2 focus:ring-offset-2"
:class="modelValue ? 'bg-n-brand' : 'bg-n-alpha-1 dark:bg-n-alpha-2'"
class="relative h-4 transition-colors duration-200 ease-in-out rounded-full w-7 focus:outline-none focus:ring-1 focus:ring-n-brand focus:ring-offset-n-slate-2 focus:ring-offset-2 flex-shrink-0"
:class="modelValue ? 'bg-n-brand' : 'bg-n-slate-6 disabled:bg-n-slate-6/60'"
role="switch"
:aria-checked="modelValue"
@click="updateValue"
+9 -2
View File
@@ -61,7 +61,9 @@ const onCopy = async e => {
<template>
<div class="relative text-left">
<div class="top-1.5 absolute right-1.5 flex items-center gap-1">
<div
class="top-1.5 absolute ltr:right-1.5 rtl:left-1.5 flex backdrop-blur-sm rounded-lg items-center gap-1"
>
<form
v-if="enableCodePen"
class="flex items-center"
@@ -86,6 +88,11 @@ const onCopy = async e => {
@click="onCopy"
/>
</div>
<highlightjs v-if="script" :language="lang" :code="scrubbedScript" />
<highlightjs
v-if="script"
:language="lang"
:code="scrubbedScript"
class="[&_code]:text-start"
/>
</div>
</template>
@@ -1,83 +0,0 @@
<script>
export default {
props: {
modelValue: { type: Boolean, default: false },
size: { type: String, default: '' },
},
emits: ['update:modelValue', 'input'],
methods: {
onClick() {
this.$emit('update:modelValue', !this.modelValue);
this.$emit('input', !this.modelValue);
},
},
};
</script>
<template>
<button
type="button"
class="toggle-button p-0"
:class="{ active: modelValue, small: size === 'small' }"
role="switch"
:aria-checked="modelValue.toString()"
@click="onClick"
>
<span aria-hidden="true" :class="{ active: modelValue }" />
</button>
</template>
<style lang="scss" scoped>
.toggle-button {
@apply bg-n-slate-5;
--toggle-button-box-shadow: rgb(255, 255, 255) 0px 0px 0px 0px,
rgba(59, 130, 246, 0.5) 0px 0px 0px 0px, rgba(0, 0, 0, 0.1) 0px 1px 3px 0px,
rgba(0, 0, 0, 0.06) 0px 1px 2px 0px;
border-radius: 0.5625rem;
border: 2px solid transparent;
cursor: pointer;
display: flex;
flex-shrink: 0;
height: 1.188rem;
position: relative;
transition-duration: 200ms;
transition-property: background-color;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
width: 2.125rem;
&.active {
@apply bg-n-brand;
}
&.small {
width: 1.375rem;
height: 0.875rem;
span {
@apply size-2.5;
&.active {
@apply ltr:translate-x-[0.5rem] ltr:translate-y-0 rtl:translate-x-[-0.5rem] rtl:translate-y-0;
}
}
}
span {
@apply bg-n-background;
border-radius: 100%;
box-shadow: var(--toggle-button-box-shadow);
display: inline-block;
height: 0.9375rem;
transform: translate(0, 0);
transition-duration: 200ms;
transition-property: transform;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
width: 0.9375rem;
&.active {
@apply ltr:translate-x-[0.9375rem] ltr:translate-y-0 rtl:translate-x-[-0.9375rem] rtl:translate-y-0;
}
}
}
</style>
@@ -94,7 +94,7 @@ export default {
type: Boolean,
default: true,
},
hasWhatsappTemplates: {
enableWhatsAppTemplates: {
type: Boolean,
default: false,
},
@@ -333,7 +333,7 @@ export default {
@click="toggleMessageSignature"
/>
<NextButton
v-if="hasWhatsappTemplates"
v-if="enableWhatsAppTemplates"
v-tooltip.top-end="$t('CONVERSATION.FOOTER.WHATSAPP_TEMPLATES')"
icon="i-ph-whatsapp-logo"
slate
@@ -184,9 +184,8 @@ export default {
return false;
},
hasWhatsappTemplates() {
return !!this.$store.getters['inboxes/getWhatsAppTemplates'](this.inboxId)
.length;
showWhatsappTemplates() {
return this.isAWhatsAppCloudChannel && !this.isPrivate;
},
isPrivate() {
if (this.currentChat.can_reply || this.isAWhatsAppChannel) {
@@ -1212,7 +1211,7 @@ export default {
<ReplyBottomPanel
:conversation-id="conversationId"
:enable-multiple-file-upload="enableMultipleFileUpload"
:has-whatsapp-templates="hasWhatsappTemplates"
:enable-whats-app-templates="showWhatsappTemplates"
:inbox="inbox"
:is-on-private-note="isOnPrivateNote"
:is-recording-audio="isRecordingAudio"
@@ -1,7 +1,11 @@
<script>
// Support all template formats including media headers
import { useAlert } from 'dashboard/composables';
import Icon from 'dashboard/components-next/icon/Icon.vue';
export default {
components: {
Icon,
},
props: {
inboxId: {
type: Number,
@@ -12,6 +16,7 @@ export default {
data() {
return {
query: '',
isRefreshing: false,
};
},
computed: {
@@ -82,22 +87,47 @@ export default {
header.format === 'DOCUMENT')
);
},
async refreshTemplates() {
this.isRefreshing = true;
try {
await this.$store.dispatch('inboxes/syncTemplates', this.inboxId);
useAlert(this.$t('WHATSAPP_TEMPLATES.PICKER.REFRESH_SUCCESS'));
} catch (error) {
useAlert(this.$t('WHATSAPP_TEMPLATES.PICKER.REFRESH_ERROR'));
} finally {
this.isRefreshing = false;
}
},
},
};
</script>
<template>
<div class="w-full">
<div
class="flex gap-1 items-center px-2.5 py-0 mb-2.5 rounded-lg bg-n-alpha-black2 outline outline-1 outline-n-weak hover:outline-n-slate-6 dark:hover:outline-n-slate-6 focus-within:outline-n-brand dark:focus-within:outline-n-brand"
>
<fluent-icon icon="search" class="text-n-slate-12" size="16" />
<input
v-model="query"
type="search"
:placeholder="$t('WHATSAPP_TEMPLATES.PICKER.SEARCH_PLACEHOLDER')"
class="reset-base w-full h-9 bg-transparent text-n-slate-12 !text-sm !outline-0"
/>
<div class="flex gap-2 mb-2.5">
<div
class="flex flex-1 gap-1 items-center px-2.5 py-0 rounded-lg bg-n-alpha-black2 outline outline-1 outline-n-weak hover:outline-n-slate-6 dark:hover:outline-n-slate-6 focus-within:outline-n-brand dark:focus-within:outline-n-brand"
>
<fluent-icon icon="search" class="text-n-slate-12" size="16" />
<input
v-model="query"
type="search"
:placeholder="$t('WHATSAPP_TEMPLATES.PICKER.SEARCH_PLACEHOLDER')"
class="reset-base w-full h-9 bg-transparent text-n-slate-12 !text-sm !outline-0"
/>
</div>
<button
:disabled="isRefreshing"
class="flex justify-center items-center w-9 h-9 rounded-lg bg-n-alpha-black2 outline outline-1 outline-n-weak hover:outline-n-slate-6 dark:hover:outline-n-slate-6 hover:bg-n-alpha-2 dark:hover:bg-n-solid-2 disabled:opacity-50 disabled:cursor-not-allowed"
:title="$t('WHATSAPP_TEMPLATES.PICKER.REFRESH_BUTTON')"
@click="refreshTemplates"
>
<Icon
icon="i-lucide-refresh-ccw"
class="text-n-slate-12 size-4"
:class="{ 'animate-spin': isRefreshing }"
/>
</button>
</div>
<div
class="bg-n-background outline-n-container outline outline-1 rounded-lg max-h-[18.75rem] overflow-y-auto p-2.5"
@@ -190,11 +220,18 @@ export default {
class="border-b border-solid border-n-weak my-2.5 mx-auto max-w-[95%]"
/>
</div>
<div v-if="!filteredTemplateMessages.length">
<p>
{{ $t('WHATSAPP_TEMPLATES.PICKER.NO_TEMPLATES_FOUND') }}
<strong>{{ query }}</strong>
</p>
<div v-if="!filteredTemplateMessages.length" class="py-8 text-center">
<div v-if="query && whatsAppTemplateMessages.length">
<p>
{{ $t('WHATSAPP_TEMPLATES.PICKER.NO_TEMPLATES_FOUND') }}
<strong>{{ query }}</strong>
</p>
</div>
<div v-else-if="!whatsAppTemplateMessages.length" class="space-y-4">
<p class="text-n-slate-11">
{{ $t('WHATSAPP_TEMPLATES.PICKER.NO_TEMPLATES_AVAILABLE') }}
</p>
</div>
</div>
</div>
</div>
@@ -600,6 +600,10 @@
"WHATSAPP_SECTION_UPDATE_BUTTON": "Update",
"WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token",
"WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.",
"WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates",
"WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.",
"WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates",
"WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.",
"UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings"
},
"HELP_CENTER": {
@@ -14,6 +14,10 @@
"BUTTONS": "Buttons",
"CATEGORY": "Category",
"MEDIA_CONTENT": "Media Content",
"NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.",
"REFRESH_BUTTON": "Refresh templates",
"REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.",
"REFRESH_ERROR": "Failed to refresh templates. Please try again.",
"LABELS": {
"LANGUAGE": "Language",
"TEMPLATE_BODY": "Template Body",
@@ -1,6 +1,8 @@
<script setup>
import { computed } from 'vue';
import { messageStamp } from 'shared/helpers/timeHelper';
import Button from 'dashboard/components-next/button/Button.vue';
import ToggleSwitch from 'dashboard/components-next/switch/Switch.vue';
const props = defineProps({
automation: {
@@ -19,14 +21,17 @@ const readableDate = date => messageStamp(new Date(date), 'LLL d, yyyy');
const readableDateWithTime = date =>
messageStamp(new Date(date), 'LLL d, yyyy hh:mm a');
const toggle = () => {
const { id, name, active } = props.automation;
emit('toggle', {
id,
name,
status: active,
});
};
const automationActive = computed({
get: () => props.automation.active,
set: active => {
const { id, name } = props.automation;
emit('toggle', {
id,
name,
status: !active,
});
},
});
</script>
<template>
@@ -34,7 +39,7 @@ const toggle = () => {
<td class="py-4 ltr:pr-4 rtl:pl-4 min-w-[200px]">{{ automation.name }}</td>
<td class="py-4 ltr:pr-4 rtl:pl-4">{{ automation.description }}</td>
<td class="py-4 ltr:pr-4 rtl:pl-4">
<woot-switch :model-value="automation.active" @input="toggle" />
<ToggleSwitch v-model="automationActive" />
</td>
<td
class="py-4 ltr:pr-4 rtl:pl-4 min-w-[12px]"
@@ -1,8 +1,9 @@
<script>
import Draggable from 'vuedraggable';
import ToggleSwitch from 'dashboard/components-next/switch/Switch.vue';
export default {
components: { Draggable },
components: { Draggable, ToggleSwitch },
props: {
preChatFields: {
type: Array,
@@ -45,9 +46,9 @@ export default {
<tr class="border-b border-n-weak">
<td class="pre-chat-field"><fluent-icon icon="drag" /></td>
<td class="pre-chat-field">
<woot-switch
<ToggleSwitch
:model-value="item['enabled']"
@input="handlePreChatFieldOptions($event, 'enabled', item)"
@change="handlePreChatFieldOptions($event, 'enabled', item)"
/>
</td>
<td
@@ -29,6 +29,7 @@ export default {
return {
hmacMandatory: false,
whatsAppInboxAPIKey: '',
isSyncingTemplates: false,
};
},
validations: {
@@ -83,6 +84,19 @@ export default {
useAlert(this.$t('INBOX_MGMT.EDIT.API.ERROR_MESSAGE'));
}
},
async syncTemplates() {
this.isSyncingTemplates = true;
try {
await this.$store.dispatch('inboxes/syncTemplates', this.inbox.id);
useAlert(
this.$t('INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_TEMPLATES_SYNC_SUCCESS')
);
} catch (error) {
useAlert(this.$t('INBOX_MGMT.EDIT.API.ERROR_MESSAGE'));
} finally {
this.isSyncingTemplates = false;
}
},
},
};
</script>
@@ -137,7 +151,7 @@ export default {
:title="$t('INBOX_MGMT.SETTINGS_POPUP.HMAC_MANDATORY_VERIFICATION')"
:sub-title="$t('INBOX_MGMT.SETTINGS_POPUP.HMAC_MANDATORY_DESCRIPTION')"
>
<div class="flex items-center gap-2">
<div class="flex gap-2 items-center">
<input
id="hmacMandatory"
v-model="hmacMandatory"
@@ -169,7 +183,7 @@ export default {
:title="$t('INBOX_MGMT.SETTINGS_POPUP.HMAC_MANDATORY_VERIFICATION')"
:sub-title="$t('INBOX_MGMT.SETTINGS_POPUP.HMAC_MANDATORY_DESCRIPTION')"
>
<div class="flex items-center gap-2">
<div class="flex gap-2 items-center">
<input
id="hmacMandatory"
v-model="hmacMandatory"
@@ -215,12 +229,12 @@ export default {
"
>
<div
class="flex items-center justify-between flex-1 mt-2 whatsapp-settings--content"
class="flex flex-1 justify-between items-center mt-2 whatsapp-settings--content"
>
<woot-input
v-model="whatsAppInboxAPIKey"
type="text"
class="flex-1 mr-2"
class="flex-1 mr-2 [&>input]:!mb-0"
:placeholder="
$t(
'INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_SECTION_UPDATE_PLACEHOLDER'
@@ -235,6 +249,18 @@ export default {
</NextButton>
</div>
</SettingsSection>
<SettingsSection
:title="$t('INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_TEMPLATES_SYNC_TITLE')"
:sub-title="
$t('INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_TEMPLATES_SYNC_SUBHEADER')
"
>
<div class="flex justify-start items-center mt-2">
<NextButton :disabled="isSyncingTemplates" @click="syncTemplates">
{{ $t('INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_TEMPLATES_SYNC_BUTTON') }}
</NextButton>
</div>
</SettingsSection>
</div>
</div>
</template>
@@ -9,13 +9,13 @@ import {
verifyServiceWorkerExistence,
} from 'dashboard/helper/pushHelper.js';
import { FEATURE_FLAGS } from 'dashboard/featureFlags';
import FormSwitch from 'v3/components/Form/Switch.vue';
import ToggleSwitch from 'dashboard/components-next/switch/Switch.vue';
import { NOTIFICATION_TYPES } from './constants';
export default {
components: {
TableHeaderCell,
FormSwitch,
ToggleSwitch,
CheckBox,
},
data() {
@@ -284,9 +284,9 @@ export default {
{{ $t('PROFILE_SETTINGS.FORM.NOTIFICATIONS.BROWSER_PERMISSION') }}
</span>
</div>
<FormSwitch
:model-value="hasEnabledPushPermissions"
@update:model-value="onRequestPermissions"
<ToggleSwitch
v-model="hasEnabledPushPermissions"
@change="onRequestPermissions"
/>
</div>
</div>
@@ -10,6 +10,7 @@ import ReportsFiltersRatings from './Filters/Ratings.vue';
import subDays from 'date-fns/subDays';
import { DATE_RANGE_OPTIONS } from '../constants';
import { getUnixStartOfDay, getUnixEndOfDay } from 'helpers/DateHelper';
import ToggleSwitch from 'dashboard/components-next/switch/Switch.vue';
export default {
components: {
@@ -21,6 +22,7 @@ export default {
ReportsFiltersInboxes,
ReportsFiltersTeams,
ReportsFiltersRatings,
ToggleSwitch,
},
props: {
showGroupByFilter: {
@@ -106,11 +108,6 @@ export default {
return this.validGroupOptions[0];
},
},
watch: {
businessHoursSelected() {
this.emitChange();
},
},
mounted() {
this.emitChange();
},
@@ -224,7 +221,7 @@ export default {
{{ $t('REPORT.BUSINESS_HOURS') }}
</span>
<span>
<woot-switch v-model="businessHoursSelected" />
<ToggleSwitch v-model="businessHoursSelected" @change="emitChange" />
</span>
</div>
</div>
@@ -5,6 +5,7 @@ import startOfDay from 'date-fns/startOfDay';
import subDays from 'date-fns/subDays';
import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue';
import WootDateRangePicker from 'dashboard/components/ui/DateRangePicker.vue';
import ToggleSwitch from 'dashboard/components-next/switch/Switch.vue';
import { GROUP_BY_FILTER } from '../constants';
const CUSTOM_DATE_RANGE_ID = 5;
@@ -13,6 +14,7 @@ export default {
components: {
WootDateRangePicker,
Thumbnail,
ToggleSwitch,
},
props: {
currentFilter: {
@@ -125,9 +127,6 @@ export default {
groupByFilterItemsList() {
this.currentSelectedGroupByFilter = this.selectedGroupByFilter;
},
businessHoursSelected() {
this.$emit('businessHoursToggle', this.businessHoursSelected);
},
},
mounted() {
this.onDateRangeChange();
@@ -140,6 +139,9 @@ export default {
groupBy: this.groupBy,
});
},
onBusinessHoursToggle() {
this.$emit('businessHoursToggle', this.businessHoursSelected);
},
fromCustomDate(date) {
return getUnixTime(startOfDay(date));
},
@@ -303,7 +305,10 @@ export default {
{{ $t('REPORT.BUSINESS_HOURS') }}
</span>
<span>
<woot-switch v-model="businessHoursSelected" />
<ToggleSwitch
v-model="businessHoursSelected"
@change="onBusinessHoursToggle"
/>
</span>
</div>
@@ -5,11 +5,13 @@ import validations from './validations';
import SlaTimeInput from './SlaTimeInput.vue';
import NextButton from 'dashboard/components-next/button/Button.vue';
import { useVuelidate } from '@vuelidate/core';
import ToggleSwitch from 'dashboard/components-next/switch/Switch.vue';
export default {
components: {
SlaTimeInput,
NextButton,
ToggleSwitch,
},
props: {
selectedResponse: {
@@ -203,7 +205,7 @@ export default {
<span for="sla_bh" class="text-n-slate-11">
{{ $t('SLA.FORM.BUSINESS_HOURS.PLACEHOLDER') }}
</span>
<woot-switch id="sla_bh" v-model="onlyDuringBusinessHours" />
<ToggleSwitch id="sla_bh" v-model="onlyDuringBusinessHours" />
</div>
<div class="flex items-center justify-end w-full gap-2 mt-8">
@@ -281,6 +281,13 @@ export const actions = {
throw new Error(error);
}
},
syncTemplates: async (_, inboxId) => {
try {
await InboxesAPI.syncTemplates(inboxId);
} catch (error) {
throw new Error(error);
}
},
};
export const mutations = {
@@ -231,4 +231,28 @@ describe('#actions', () => {
).rejects.toThrow(Error);
});
});
describe('#syncTemplates', () => {
it('sends correct API call when sync is successful', async () => {
axios.post.mockResolvedValue({
data: { message: 'Template sync initiated successfully' },
});
await actions.syncTemplates({ commit }, 123);
expect(axios.post).toHaveBeenCalledWith(
'/api/v1/inboxes/123/sync_templates'
);
});
it('throws error when API call fails', async () => {
const errorMessage =
'Template sync is only available for WhatsApp channels';
axios.post.mockRejectedValue(new Error(errorMessage));
await expect(actions.syncTemplates({ commit }, 123)).rejects.toThrow(
errorMessage
);
});
});
});
-2
View File
@@ -7,7 +7,6 @@ import hljsVuePlugin from '@highlightjs/vue-plugin';
import Multiselect from 'vue-multiselect';
import { plugin, defaultConfig } from '@formkit/vue';
import WootSwitch from 'components/ui/Switch.vue';
import WootWizard from 'components/ui/Wizard.vue';
import FloatingVue from 'floating-vue';
import WootUiKit from 'dashboard/components';
@@ -90,7 +89,6 @@ app.use(FloatingVue, {
app.use(hljsVuePlugin);
app.component('multiselect', Multiselect);
app.component('woot-switch', WootSwitch);
app.component('woot-wizard', WootWizard);
app.component('fluent-icon', FluentIcon);
@@ -1,36 +0,0 @@
<script>
export default {
props: {
modelValue: { type: Boolean, default: false },
},
emits: ['update:modelValue'],
methods: {
onClick() {
this.$emit('update:modelValue', !this.modelValue);
},
},
};
</script>
<template>
<button
type="button"
class="relative flex-shrink-0 h-4 p-0 border-none shadow-inner w-7 rounded-3xl"
:class="
modelValue ? 'bg-n-brand shadow-n-brand' : 'shadow-n-slate-6 bg-n-slate-5'
"
role="switch"
:aria-checked="modelValue.toString()"
@click="onClick"
>
<span
aria-hidden="true"
class="rounded-full bg-n-background top-0.5 absolute w-3 h-3 translate-y-0 duration-200 transition-transform ease-in-out"
:class="
modelValue
? 'ltr:translate-x-0 rtl:translate-x-[0.75rem]'
: 'ltr:-translate-x-[0.75rem] rtl:translate-x-0'
"
/>
</button>
</template>