chore: Update buttons in dashboard (#11145)

# Pull Request Template

## Changes

* Remove unused component `MaskedText.vue`
* Remove unused component `ContactIntro.vue`
* Remove unused `AddCustomViews.vue` component
* Update buttons in help center upgrade page
<img width="741" alt="image"
src="https://github.com/user-attachments/assets/f46b8ffa-ef74-4b83-95c1-83842844c4b7"
/>

* Update SLA view details button in reports page
<img width="419" alt="image"
src="https://github.com/user-attachments/assets/7db6bff6-9ba5-4c13-850f-b9d4dbb55489"
/>

* Update assign to me conversation action button
<img width="152" alt="image"
src="https://github.com/user-attachments/assets/587ee1fe-93c9-48e0-910a-390dd4eac1f2"
/>

* Update button in participants action
<img width="365" alt="image"
src="https://github.com/user-attachments/assets/50eb386f-882b-4277-ad61-d557893ac490"
/>
<img width="365" alt="image"
src="https://github.com/user-attachments/assets/3c64ed42-0203-43c6-9a26-8ad9465aa394"
/>

* Update the show more attributes button
<img width="365" alt="image"
src="https://github.com/user-attachments/assets/f2105a2f-8441-4d8b-b355-dfe97ce2e362"
/>

* Update SLA empty state
<img width="376" alt="image"
src="https://github.com/user-attachments/assets/55fd4376-6183-45c9-acb2-6ad5a6a58730"
/>

* Update create new label button from dropdown
<img width="376" alt="image"
src="https://github.com/user-attachments/assets/bb8226d0-795f-431f-8fe4-15d15ee1d695"
/>

* Update add macro button
<img width="382" alt="image"
src="https://github.com/user-attachments/assets/b6375402-5213-4041-841b-09c2157ed56a"
/>

* Update copy button
<img width="382" alt="image"
src="https://github.com/user-attachments/assets/f1929d63-f7ca-4eab-bfa8-716be2aa4be8"
/>

* Update the buttons in banner component
<img width="849" alt="image"
src="https://github.com/user-attachments/assets/bb86b498-ab8e-4a92-8c6a-60edcef0fd7b"
/>
<img width="838" alt="image"
src="https://github.com/user-attachments/assets/4bde00de-907e-49ac-9128-f364a90cd3c1"
/>

* Update table pagination buttons
<img width="968" alt="image"
src="https://github.com/user-attachments/assets/8d439af6-8126-4fad-a3fe-89b26a56f880"
/>
<img width="968" alt="image"
src="https://github.com/user-attachments/assets/a178b3d7-3385-4a2b-a0d7-35be9a25fd93"
/>

* Update filter chip buttons and dropdown colors
<img width="541" alt="image"
src="https://github.com/user-attachments/assets/7be1f418-82df-4db6-b265-4c185fc79f4b"
/>
<img width="541" alt="image"
src="https://github.com/user-attachments/assets/69110d75-85e9-4974-8c2a-e195b23a335c"
/>
<img width="173" alt="image"
src="https://github.com/user-attachments/assets/c8f5bc82-15b4-4f25-b7d4-35a9280ec7c6"
/>
<img width="565" alt="image"
src="https://github.com/user-attachments/assets/7dad1d00-784b-46eb-b823-e6e55d5f9dc8"
/>
<img width="565" alt="image"
src="https://github.com/user-attachments/assets/384a86ed-f45f-488c-b9aa-1f02b16c813d"
/>

---------

Co-authored-by: Pranav <pranav@chatwoot.com>
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
Co-authored-by: Shivam Mishra <scm.mymail@gmail.com>
This commit is contained in:
Sivin Varghese
2025-04-01 05:51:32 +05:30
committed by GitHub
parent 9fb3053007
commit cc4d54becf
53 changed files with 515 additions and 1003 deletions

View File

@@ -1,3 +1,5 @@
<!-- DEPRECIATED -->
<!-- TODO: Replace this banner component with NextBanner "app/javascript/dashboard/components-next/banner/Banner.vue" -->
<script setup> <script setup>
import { computed } from 'vue'; import { computed } from 'vue';

View File

@@ -103,7 +103,7 @@ export default {
{{ $t('FILTER.CUSTOM_VIEWS.ADD.TITLE') }} {{ $t('FILTER.CUSTOM_VIEWS.ADD.TITLE') }}
</h3> </h3>
<form class="w-full grid gap-6" @submit.prevent="saveCustomViews"> <form class="w-full grid gap-6" @submit.prevent="saveCustomViews">
<div> <label :class="{ error: v$.name.$error }">
<input <input
v-model="name" v-model="name"
class="py-1.5 px-3 text-n-slate-12 bg-n-alpha-1 text-sm rounded-lg reset-base w-full" class="py-1.5 px-3 text-n-slate-12 bg-n-alpha-1 text-sm rounded-lg reset-base w-full"
@@ -116,14 +116,14 @@ export default {
> >
{{ $t('FILTER.CUSTOM_VIEWS.ADD.ERROR_MESSAGE') }} {{ $t('FILTER.CUSTOM_VIEWS.ADD.ERROR_MESSAGE') }}
</span> </span>
</div> </label>
<div class="flex flex-row justify-end w-full gap-2"> <div class="flex flex-row justify-end w-full gap-2">
<NextButton sm solid blue :disabled="isButtonDisabled">
{{ $t('FILTER.CUSTOM_VIEWS.ADD.SAVE_BUTTON') }}
</NextButton>
<NextButton faded slate sm @click.prevent="onClose"> <NextButton faded slate sm @click.prevent="onClose">
{{ $t('FILTER.CUSTOM_VIEWS.ADD.CANCEL_BUTTON') }} {{ $t('FILTER.CUSTOM_VIEWS.ADD.CANCEL_BUTTON') }}
</NextButton> </NextButton>
<NextButton solid blue sm :disabled="isButtonDisabled">
{{ $t('FILTER.CUSTOM_VIEWS.ADD.SAVE_BUTTON') }}
</NextButton>
</div> </div>
</form> </form>
</div> </div>

View File

@@ -1,64 +0,0 @@
<script>
import 'highlight.js/styles/default.css';
import { copyTextToClipboard } from 'shared/helpers/clipboard';
import { useAlert } from 'dashboard/composables';
export default {
props: {
value: {
type: String,
default: '',
},
},
data() {
return {
masked: true,
};
},
methods: {
async onCopy(e) {
e.preventDefault();
await copyTextToClipboard(this.value);
useAlert(this.$t('COMPONENTS.CODE.COPY_SUCCESSFUL'));
},
toggleMasked() {
this.masked = !this.masked;
},
},
};
</script>
<template>
<div class="text--container">
<woot-button size="small" class="button--text" @click="onCopy">
{{ $t('COMPONENTS.CODE.BUTTON_TEXT') }}
</woot-button>
<woot-button
variant="clear"
size="small"
class="button--visibility"
color-scheme="secondary"
:icon="masked ? 'eye-show' : 'eye-hide'"
@click.prevent="toggleMasked"
/>
<highlightjs v-if="value" :code="masked ? '•'.repeat(10) : value" />
</div>
</template>
<style lang="scss" scoped>
.text--container {
position: relative;
text-align: left;
.button--text,
.button--visibility {
margin-top: 0;
position: absolute;
right: 0;
}
.button--visibility {
right: 60px;
}
}
</style>

View File

@@ -3,12 +3,16 @@ import { FEATURE_FLAGS } from 'dashboard/featureFlags';
import { BUS_EVENTS } from 'shared/constants/busEvents'; import { BUS_EVENTS } from 'shared/constants/busEvents';
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import { emitter } from 'shared/helpers/mitt'; import { emitter } from 'shared/helpers/mitt';
import NextButton from 'dashboard/components-next/button/Button.vue';
export default { export default {
components: {
NextButton,
},
props: { props: {
size: { size: {
type: String, type: String,
default: 'small', default: 'sm',
}, },
}, },
computed: { computed: {
@@ -33,13 +37,13 @@ export default {
<!-- eslint-disable-next-line vue/no-root-v-if --> <!-- eslint-disable-next-line vue/no-root-v-if -->
<template> <template>
<woot-button <NextButton
v-if="!hasNextSidebar" v-if="!hasNextSidebar"
ghost
slate
:size="size" :size="size"
variant="clear" icon="i-lucide-menu"
color-scheme="secondary" class="-ml-3"
class="-ml-3 text-black-900 dark:text-slate-300"
icon="list"
@click="onMenuItemClick" @click="onMenuItemClick"
/> />
</template> </template>

View File

@@ -35,7 +35,7 @@ export default {
color-scheme="alert" color-scheme="alert"
:banner-message="bannerMessage" :banner-message="bannerMessage"
:action-button-label="actionButtonMessage" :action-button-label="actionButtonMessage"
action-button-icon="mail" action-button-icon="i-lucide-mail"
has-action-button has-action-button
@primary-action="resendVerificationEmail" @primary-action="resendVerificationEmail"
/> />

View File

@@ -1,7 +1,6 @@
// [NOTE][DEPRECATED] This method is to be deprecated, please do not add new components to this file. // [NOTE][DEPRECATED] This method is to be deprecated, please do not add new components to this file.
/* eslint no-plusplus: 0 */ /* eslint no-plusplus: 0 */
import AvatarUploader from './widgets/forms/AvatarUploader.vue'; import AvatarUploader from './widgets/forms/AvatarUploader.vue';
import Button from './ui/WootButton.vue';
import Code from './Code.vue'; import Code from './Code.vue';
import ColorPicker from './widgets/ColorPicker.vue'; import ColorPicker from './widgets/ColorPicker.vue';
import ConfirmDeleteModal from './widgets/modal/ConfirmDeleteModal.vue'; import ConfirmDeleteModal from './widgets/modal/ConfirmDeleteModal.vue';
@@ -26,7 +25,6 @@ import DatePicker from './ui/DatePicker/DatePicker.vue';
const WootUIKit = { const WootUIKit = {
AvatarUploader, AvatarUploader,
Button,
Code, Code,
ColorPicker, ColorPicker,
ConfirmDeleteModal, ConfirmDeleteModal,

View File

@@ -7,6 +7,7 @@ import WootDropdownHeader from 'shared/components/ui/dropdown/DropdownHeader.vue
import WootDropdownDivider from 'shared/components/ui/dropdown/DropdownDivider.vue'; import WootDropdownDivider from 'shared/components/ui/dropdown/DropdownDivider.vue';
import AvailabilityStatusBadge from '../widgets/conversation/AvailabilityStatusBadge.vue'; import AvailabilityStatusBadge from '../widgets/conversation/AvailabilityStatusBadge.vue';
import wootConstants from 'dashboard/constants/globals'; import wootConstants from 'dashboard/constants/globals';
import NextButton from 'dashboard/components-next/button/Button.vue';
const { AVAILABILITY_STATUS_KEYS } = wootConstants; const { AVAILABILITY_STATUS_KEYS } = wootConstants;
@@ -17,6 +18,7 @@ export default {
WootDropdownMenu, WootDropdownMenu,
WootDropdownItem, WootDropdownItem,
AvailabilityStatusBadge, AvailabilityStatusBadge,
NextButton,
}, },
data() { data() {
return { return {
@@ -101,19 +103,21 @@ export default {
:key="status.value" :key="status.value"
class="flex items-baseline" class="flex items-baseline"
> >
<woot-button <NextButton
size="small" sm
:color-scheme="status.disabled ? '' : 'secondary'" :color="status.disabled ? 'blue' : 'slate'"
:variant="status.disabled ? 'smooth' : 'clear'" :variant="status.disabled ? 'faded' : 'ghost'"
class="status-change--dropdown-button" class="status-change--dropdown-button !w-full !justify-start"
@click="changeAvailabilityStatus(status.value)" @click="changeAvailabilityStatus(status.value)"
> >
<AvailabilityStatusBadge :status="status.value" /> <AvailabilityStatusBadge :status="status.value" />
<span class="min-w-0 truncate font-medium text-xs">
{{ status.label }} {{ status.label }}
</woot-button> </span>
</NextButton>
</WootDropdownItem> </WootDropdownItem>
<WootDropdownDivider /> <WootDropdownDivider />
<WootDropdownItem class="flex items-center justify-between p-2 m-0"> <WootDropdownItem class="flex items-center justify-between px-3 py-2 m-0">
<div class="flex items-center"> <div class="flex items-center">
<fluent-icon <fluent-icon
v-tooltip.right-start="$t('SIDEBAR.SET_AUTO_OFFLINE.INFO_TEXT')" v-tooltip.right-start="$t('SIDEBAR.SET_AUTO_OFFLINE.INFO_TEXT')"
@@ -123,7 +127,7 @@ export default {
/> />
<span <span
class="mx-1 my-0 text-xs font-medium text-slate-600 dark:text-slate-100" class="mx-2 my-0 text-xs font-medium text-slate-600 dark:text-slate-100"
> >
{{ $t('SIDEBAR.SET_AUTO_OFFLINE.TEXT') }} {{ $t('SIDEBAR.SET_AUTO_OFFLINE.TEXT') }}
</span> </span>

View File

@@ -1,7 +1,11 @@
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import NextButton from 'dashboard/components-next/button/Button.vue';
export default { export default {
components: {
NextButton,
},
emits: ['toggleAccounts'], emits: ['toggleAccounts'],
data() { data() {
return { showSwitchButton: false }; return { showSwitchButton: false };
@@ -46,14 +50,13 @@ export default {
class="absolute top-0 right-0 flex items-center justify-end w-full h-full rounded-md ltr:overlay-shadow ltr:dark:overlay-shadow-dark rtl:rtl-overlay-shadow rtl:dark:rtl-overlay-shadow-dark" class="absolute top-0 right-0 flex items-center justify-end w-full h-full rounded-md ltr:overlay-shadow ltr:dark:overlay-shadow-dark rtl:rtl-overlay-shadow rtl:dark:rtl-overlay-shadow-dark"
> >
<div class="mx-2 my-0"> <div class="mx-2 my-0">
<woot-button <NextButton
variant="clear" ghost
size="tiny" xs
icon="arrow-swap" icon="i-lucide-arrow-right-left"
:label="$t('SIDEBAR.SWITCH')"
@click="$emit('toggleAccounts')" @click="$emit('toggleAccounts')"
> />
{{ $t('SIDEBAR.SWITCH') }}
</woot-button>
</div> </div>
</div> </div>
</transition> </transition>

View File

@@ -1,10 +1,12 @@
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import Thumbnail from '../../widgets/Thumbnail.vue'; import Thumbnail from '../../widgets/Thumbnail.vue';
import NextButton from 'dashboard/components-next/button/Button.vue';
export default { export default {
components: { components: {
Thumbnail, Thumbnail,
NextButton,
}, },
emits: ['toggleMenu'], emits: ['toggleMenu'],
computed: { computed: {
@@ -25,10 +27,10 @@ export default {
</script> </script>
<template> <template>
<woot-button <NextButton
v-tooltip.right="$t(`SIDEBAR.PROFILE_SETTINGS`)" v-tooltip.right="$t(`SIDEBAR.PROFILE_SETTINGS`)"
variant="link" link
class="flex items-center rounded-full" class="rounded-full"
@click="handleClick" @click="handleClick"
> >
<Thumbnail <Thumbnail
@@ -37,6 +39,7 @@ export default {
:status="statusOfAgent" :status="statusOfAgent"
should-show-status-always should-show-status-always
size="32px" size="32px"
class="flex-shrink-0"
/> />
</woot-button> </NextButton>
</template> </template>

View File

@@ -5,12 +5,14 @@ import WootDropdownItem from 'shared/components/ui/dropdown/DropdownItem.vue';
import WootDropdownMenu from 'shared/components/ui/dropdown/DropdownMenu.vue'; import WootDropdownMenu from 'shared/components/ui/dropdown/DropdownMenu.vue';
import AvailabilityStatus from 'dashboard/components/layout/AvailabilityStatus.vue'; import AvailabilityStatus from 'dashboard/components/layout/AvailabilityStatus.vue';
import { FEATURE_FLAGS } from '../../../featureFlags'; import { FEATURE_FLAGS } from '../../../featureFlags';
import NextButton from 'dashboard/components-next/button/Button.vue';
export default { export default {
components: { components: {
WootDropdownMenu, WootDropdownMenu,
WootDropdownItem, WootDropdownItem,
AvailabilityStatus, AvailabilityStatus,
NextButton,
}, },
props: { props: {
show: { show: {
@@ -82,37 +84,46 @@ export default {
<AvailabilityStatus /> <AvailabilityStatus />
<WootDropdownMenu> <WootDropdownMenu>
<WootDropdownItem v-if="showChangeAccountOption"> <WootDropdownItem v-if="showChangeAccountOption">
<woot-button <NextButton
variant="clear" ghost
color-scheme="secondary" sm
size="small" slate
icon="arrow-swap" icon="i-lucide-arrow-right-left"
class="!w-full !justify-start"
@click="$emit('toggleAccounts')" @click="$emit('toggleAccounts')"
> >
<span class="min-w-0 truncate font-medium text-xs">
{{ $t('SIDEBAR_ITEMS.CHANGE_ACCOUNTS') }} {{ $t('SIDEBAR_ITEMS.CHANGE_ACCOUNTS') }}
</woot-button> </span>
</NextButton>
</WootDropdownItem> </WootDropdownItem>
<WootDropdownItem v-if="showChatSupport"> <WootDropdownItem v-if="showChatSupport">
<woot-button <NextButton
variant="clear" ghost
color-scheme="secondary" sm
size="small" slate
icon="chat-help" icon="i-lucide-message-circle-question"
class="!w-full !justify-start"
@click="$emit('showSupportChatWindow')" @click="$emit('showSupportChatWindow')"
> >
<span class="min-w-0 truncate font-medium text-xs">
{{ $t('SIDEBAR_ITEMS.CONTACT_SUPPORT') }} {{ $t('SIDEBAR_ITEMS.CONTACT_SUPPORT') }}
</woot-button> </span>
</NextButton>
</WootDropdownItem> </WootDropdownItem>
<WootDropdownItem> <WootDropdownItem>
<woot-button <NextButton
variant="clear" ghost
color-scheme="secondary" sm
size="small" slate
icon="keyboard" icon="i-lucide-keyboard"
class="!w-full !justify-start"
@click="handleKeyboardHelpClick" @click="handleKeyboardHelpClick"
> >
<span class="min-w-0 truncate font-medium text-xs">
{{ $t('SIDEBAR_ITEMS.KEYBOARD_SHORTCUTS') }} {{ $t('SIDEBAR_ITEMS.KEYBOARD_SHORTCUTS') }}
</woot-button> </span>
</NextButton>
</WootDropdownItem> </WootDropdownItem>
<WootDropdownItem> <WootDropdownItem>
<router-link <router-link
@@ -122,56 +133,70 @@ export default {
> >
<a <a
:href="href" :href="href"
class="h-8 bg-white button small clear secondary dark:bg-slate-800"
:class="{ 'is-active': isActive }" :class="{ 'is-active': isActive }"
@click="e => handleProfileSettingClick(e, navigate)" @click="e => handleProfileSettingClick(e, navigate)"
> >
<fluent-icon icon="person" size="14" class="icon icon--font" /> <NextButton
<span class="button__content"> ghost
sm
slate
icon="i-lucide-circle-user"
class="!w-full !justify-start"
>
<span class="min-w-0 truncate font-medium text-xs">
{{ $t('SIDEBAR_ITEMS.PROFILE_SETTINGS') }} {{ $t('SIDEBAR_ITEMS.PROFILE_SETTINGS') }}
</span> </span>
</NextButton>
</a> </a>
</router-link> </router-link>
</WootDropdownItem> </WootDropdownItem>
<WootDropdownItem> <WootDropdownItem>
<woot-button <NextButton
variant="clear" ghost
color-scheme="secondary" sm
size="small" slate
icon="appearance" icon="i-lucide-sun-moon"
class="!w-full !justify-start"
@click="openAppearanceOptions" @click="openAppearanceOptions"
> >
<span class="min-w-0 truncate font-medium text-xs">
{{ $t('SIDEBAR_ITEMS.APPEARANCE') }} {{ $t('SIDEBAR_ITEMS.APPEARANCE') }}
</woot-button> </span>
</NextButton>
</WootDropdownItem> </WootDropdownItem>
<WootDropdownItem v-if="currentUser.type === 'SuperAdmin'"> <WootDropdownItem v-if="currentUser.type === 'SuperAdmin'">
<a <a
href="/super_admin" href="/super_admin"
class="h-8 bg-white button small clear secondary dark:bg-slate-800"
target="_blank" target="_blank"
rel="noopener nofollow noreferrer" rel="noopener nofollow noreferrer"
@click="$emit('close')" @click="$emit('close')"
> >
<fluent-icon <NextButton
icon="content-settings" ghost
size="14" sm
class="icon icon--font" slate
/> icon="i-lucide-layout-dashboard"
<span class="button__content"> class="!w-full !justify-start"
>
<span class="min-w-0 truncate font-medium text-xs">
{{ $t('SIDEBAR_ITEMS.SUPER_ADMIN_CONSOLE') }} {{ $t('SIDEBAR_ITEMS.SUPER_ADMIN_CONSOLE') }}
</span> </span>
</NextButton>
</a> </a>
</WootDropdownItem> </WootDropdownItem>
<WootDropdownItem> <WootDropdownItem>
<woot-button <NextButton
variant="clear" ghost
color-scheme="secondary" sm
size="small" slate
icon="power" icon="i-lucide-circle-power"
class="!w-full !justify-start"
@click="logout" @click="logout"
> >
<span class="min-w-0 truncate font-medium text-xs">
{{ $t('SIDEBAR_ITEMS.LOGOUT') }} {{ $t('SIDEBAR_ITEMS.LOGOUT') }}
</woot-button> </span>
</NextButton>
</WootDropdownItem> </WootDropdownItem>
</WootDropdownMenu> </WootDropdownMenu>
</div> </div>

View File

@@ -13,9 +13,10 @@ import {
isOnUnattendedView, isOnUnattendedView,
} from '../../../store/modules/conversations/helpers/actionHelpers'; } from '../../../store/modules/conversations/helpers/actionHelpers';
import Policy from '../../policy.vue'; import Policy from '../../policy.vue';
import NextButton from 'dashboard/components-next/button/Button.vue';
export default { export default {
components: { SecondaryChildNavItem, Policy }, components: { SecondaryChildNavItem, Policy, NextButton },
props: { props: {
menuItem: { menuItem: {
type: Object, type: Object,
@@ -205,14 +206,7 @@ export default {
{{ $t(`SIDEBAR.${menuItem.label}`) }} {{ $t(`SIDEBAR.${menuItem.label}`) }}
</span> </span>
<div v-if="menuItem.showNewButton" class="flex items-center"> <div v-if="menuItem.showNewButton" class="flex items-center">
<woot-button <NextButton ghost xs slate icon="i-lucide-plus" @click="onClickOpen" />
size="tiny"
variant="clear"
color-scheme="secondary"
icon="add"
class="p-0 ml-2"
@click="onClickOpen"
/>
</div> </div>
</div> </div>
<router-link <router-link
@@ -272,16 +266,15 @@ export default {
> >
<li class="pl-1"> <li class="pl-1">
<a :href="href"> <a :href="href">
<woot-button <NextButton
size="tiny" ghost
variant="clear" xs
color-scheme="secondary" slate
icon="add" icon="i-lucide-plus"
:label="$t(`SIDEBAR.${menuItem.newLinkTag}`)"
:data-testid="menuItem.dataTestid" :data-testid="menuItem.dataTestid"
@click="e => newLinkClick(e, navigate)" @click="e => newLinkClick(e, navigate)"
> />
{{ $t(`SIDEBAR.${menuItem.newLinkTag}`) }}
</woot-button>
</a> </a>
</li> </li>
</router-link> </router-link>

View File

@@ -41,7 +41,6 @@ describe('AccountSelector', () => {
'fluent-icon': FluentIcon, 'fluent-icon': FluentIcon,
}, },
stubs: { stubs: {
WootButton: { template: '<button />' },
// override global stub // override global stub
WootModalHeader: false, WootModalHeader: false,
}, },

View File

@@ -2,7 +2,7 @@ import { shallowMount } from '@vue/test-utils';
import { createStore } from 'vuex'; import { createStore } from 'vuex';
import AgentDetails from '../AgentDetails.vue'; import AgentDetails from '../AgentDetails.vue';
import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue'; import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue';
import WootButton from 'dashboard/components/ui/WootButton.vue'; import NextButton from 'dashboard/components-next/button/Button.vue';
describe('AgentDetails', () => { describe('AgentDetails', () => {
const currentUser = { const currentUser = {
@@ -40,12 +40,12 @@ describe('AgentDetails', () => {
plugins: [store], plugins: [store],
components: { components: {
Thumbnail, Thumbnail,
WootButton, NextButton,
}, },
directives: { directives: {
tooltip: mockTooltipDirective, // Mocking the tooltip directive tooltip: mockTooltipDirective, // Mocking the tooltip directive
}, },
stubs: { WootButton: { template: '<button><slot /></button>' } }, stubs: { NextButton: { template: '<button><slot /></button>' } },
}, },
}); });
}); });

View File

@@ -1,7 +1,7 @@
import { mount } from '@vue/test-utils'; import { mount } from '@vue/test-utils';
import { createStore } from 'vuex'; import { createStore } from 'vuex';
import AvailabilityStatus from '../AvailabilityStatus.vue'; import AvailabilityStatus from '../AvailabilityStatus.vue';
import WootButton from 'dashboard/components/ui/WootButton.vue'; import NextButton from 'dashboard/components-next/button/Button.vue';
import WootDropdownItem from 'shared/components/ui/dropdown/DropdownItem.vue'; import WootDropdownItem from 'shared/components/ui/dropdown/DropdownItem.vue';
import WootDropdownMenu from 'shared/components/ui/dropdown/DropdownMenu.vue'; import WootDropdownMenu from 'shared/components/ui/dropdown/DropdownMenu.vue';
import WootDropdownHeader from 'shared/components/ui/dropdown/DropdownHeader.vue'; import WootDropdownHeader from 'shared/components/ui/dropdown/DropdownHeader.vue';
@@ -40,7 +40,7 @@ describe('AvailabilityStatus', () => {
global: { global: {
plugins: [store], plugins: [store],
components: { components: {
WootButton, NextButton,
WootDropdownItem, WootDropdownItem,
WootDropdownMenu, WootDropdownMenu,
WootDropdownHeader, WootDropdownHeader,

View File

@@ -22,7 +22,7 @@ const store = createStore({
describe('SidemenuIcon', () => { describe('SidemenuIcon', () => {
test('matches snapshot', () => { test('matches snapshot', () => {
const wrapper = shallowMount(SidemenuIcon, { const wrapper = shallowMount(SidemenuIcon, {
stubs: { WootButton: { template: '<button><slot /></button>' } }, stubs: { NextButton: { template: '<button><slot /></button>' } },
global: { plugins: [store] }, global: { plugins: [store] },
}); });
expect(wrapper.vm).toBeTruthy(); expect(wrapper.vm).toBeTruthy();

View File

@@ -2,11 +2,11 @@
exports[`SidemenuIcon > matches snapshot 1`] = ` exports[`SidemenuIcon > matches snapshot 1`] = `
<button <button
class="-ml-3 text-black-900 dark:text-slate-300" class="-ml-3"
color-scheme="secondary" ghost=""
icon="list" icon="i-lucide-menu"
size="small" size="sm"
variant="clear" slate=""
> >

View File

@@ -1,5 +1,10 @@
<script> <script>
import NextButton from 'dashboard/components-next/button/Button.vue';
export default { export default {
components: {
NextButton,
},
props: { props: {
bannerMessage: { bannerMessage: {
type: String, type: String,
@@ -19,7 +24,7 @@ export default {
}, },
actionButtonVariant: { actionButtonVariant: {
type: String, type: String,
default: '', default: 'faded',
}, },
actionButtonLabel: { actionButtonLabel: {
type: String, type: String,
@@ -27,7 +32,7 @@ export default {
}, },
actionButtonIcon: { actionButtonIcon: {
type: String, type: String,
default: 'arrow-right', default: 'i-lucide-arrow-right',
}, },
colorScheme: { colorScheme: {
type: String, type: String,
@@ -48,6 +53,18 @@ export default {
} }
return classList; return classList;
}, },
// TODO - Remove this method when we standardize
// the button color and variant names
getButtonColor() {
const colorMap = {
primary: 'blue',
secondary: 'blue',
alert: 'ruby',
warning: 'amber',
};
return colorMap[this.colorScheme] || 'blue';
},
}, },
methods: { methods: {
onClick(e) { onClick(e) {
@@ -77,27 +94,23 @@ export default {
</a> </a>
</span> </span>
<div class="actions"> <div class="actions">
<woot-button <NextButton
v-if="hasActionButton" v-if="hasActionButton"
size="tiny" xs
:icon="actionButtonIcon" :icon="actionButtonIcon"
:variant="actionButtonVariant" :variant="actionButtonVariant"
color-scheme="primary" :color="getButtonColor"
class-names="banner-action__button" :label="actionButtonLabel"
@click="onClick" @click="onClick"
> />
{{ actionButtonLabel }} <NextButton
</woot-button>
<woot-button
v-if="hasCloseButton" v-if="hasCloseButton"
size="tiny" xs
:color-scheme="colorScheme" icon="i-lucide-circle-x"
icon="dismiss-circle" :color="getButtonColor"
class-names="banner-action__button" :label="$t('GENERAL_SETTINGS.DISMISS')"
@click="onClickClose" @click="onClickClose"
> />
{{ $t('GENERAL_SETTINGS.DISMISS') }}
</woot-button>
</div> </div>
</div> </div>
</template> </template>
@@ -106,13 +119,6 @@ export default {
.banner { .banner {
&.primary { &.primary {
@apply bg-woot-500 dark:bg-woot-500; @apply bg-woot-500 dark:bg-woot-500;
.banner-action__button {
@apply bg-woot-600 dark:bg-woot-600 border-none text-white;
&:hover {
@apply bg-woot-700 dark:bg-woot-700;
}
}
} }
&.secondary { &.secondary {
@@ -124,13 +130,6 @@ export default {
&.alert { &.alert {
@apply bg-n-ruby-3 text-n-ruby-12; @apply bg-n-ruby-3 text-n-ruby-12;
.banner-action__button {
@apply border-none text-n-ruby-12 bg-n-ruby-5;
&:hover {
@apply bg-n-ruby-4;
}
}
a { a {
@apply text-n-ruby-12; @apply text-n-ruby-12;
@@ -146,21 +145,12 @@ export default {
&.gray { &.gray {
@apply text-black-500 dark:text-black-500; @apply text-black-500 dark:text-black-500;
.banner-action__button {
@apply text-white dark:text-white;
}
} }
a { a {
@apply ml-1 underline text-white dark:text-white text-xs; @apply ml-1 underline text-white dark:text-white text-xs;
} }
.banner-action__button {
::v-deep .button__content {
@apply whitespace-nowrap;
}
}
.banner-message { .banner-message {
@apply flex items-center; @apply flex items-center;
} }

View File

@@ -1,14 +1,16 @@
<script setup> <script setup>
import Button from 'dashboard/components-next/button/Button.vue';
defineProps({ defineProps({
buttonText: { buttonText: {
type: String, type: String,
default: '', default: '',
}, },
rightIcon: { trailingIcon: {
type: String, type: Boolean,
default: '', default: false,
}, },
leftIcon: { icon: {
type: String, type: String,
default: '', default: '',
}, },
@@ -16,32 +18,15 @@ defineProps({
</script> </script>
<template> <template>
<button <Button
class="inline-flex relative items-center p-1.5 w-fit h-8 gap-1.5 rounded-lg hover:bg-slate-50 dark:hover:bg-slate-800 active:bg-slate-75 dark:active:bg-slate-800" ghost
slate
sm
class="relative"
:icon="icon"
:trailing-icon="trailingIcon"
> >
<slot name="leftIcon"> <span class="min-w-0 truncate">{{ buttonText }}</span>
<fluent-icon
v-if="leftIcon"
:icon="leftIcon"
size="18"
class="flex-shrink-0 text-slate-900 dark:text-slate-50"
/>
</slot>
<span
v-if="buttonText"
class="text-sm font-medium truncate text-slate-900 dark:text-slate-50"
>
{{ buttonText }}
</span>
<slot name="rightIcon">
<fluent-icon
v-if="rightIcon"
:icon="rightIcon"
size="18"
class="flex-shrink-0 text-slate-900 dark:text-slate-50"
/>
</slot>
<slot name="dropdown" /> <slot name="dropdown" />
</button> </Button>
</template> </template>

View File

@@ -8,9 +8,7 @@ defineProps({
</script> </script>
<template> <template>
<div <div class="flex items-center justify-center h-10 text-sm text-n-slate-11">
class="flex items-center justify-center h-10 text-sm text-slate-500 dark:text-slate-300"
>
{{ message }} {{ message }}
</div> </div>
</template> </template>

View File

@@ -78,7 +78,7 @@ const shouldShowEmptyState = computed(() => {
<template> <template>
<div <div
class="absolute z-20 w-40 bg-white border shadow dark:bg-slate-800 rounded-xl border-slate-50 dark:border-slate-700/50 max-h-[400px]" class="absolute z-20 w-40 bg-n-solid-2 border-0 outline outline-1 outline-n-weak shadow rounded-xl max-h-[400px]"
@click.stop @click.stop
> >
<slot name="search"> <slot name="search">

View File

@@ -21,7 +21,7 @@ defineProps({
<template> <template>
<button <button
class="relative inline-flex items-center justify-start w-full p-3 border-0 rounded-none first:rounded-t-xl last:rounded-b-xl h-11 hover:bg-slate-50 dark:hover:bg-slate-700 active:bg-slate-75 dark:active:bg-slate-800" class="relative inline-flex items-center justify-start w-full p-3 border-0 rounded-none first:rounded-t-xl last:rounded-b-xl h-11 hover:enabled:bg-n-alpha-2"
> >
<div class="inline-flex items-center gap-3 overflow-hidden"> <div class="inline-flex items-center gap-3 overflow-hidden">
<fluent-icon <fluent-icon
@@ -30,16 +30,14 @@ defineProps({
size="18" size="18"
:style="{ color: iconColor }" :style="{ color: iconColor }"
/> />
<span <span class="text-sm font-medium truncate text-n-slate-12">
class="text-sm font-medium truncate text-slate-900 dark:text-slate-50"
>
{{ buttonText }} {{ buttonText }}
</span> </span>
<fluent-icon <fluent-icon
v-if="isActive" v-if="isActive"
icon="checkmark" icon="checkmark"
size="18" size="18"
class="flex-shrink-0 text-slate-900 dark:text-slate-50" class="flex-shrink-0 text-n-slate-12"
/> />
</div> </div>
<slot name="dropdown" /> <slot name="dropdown" />

View File

@@ -8,9 +8,7 @@ defineProps({
</script> </script>
<template> <template>
<div <div class="flex items-center justify-center h-10 text-sm text-n-slate-11">
class="flex items-center justify-center h-10 text-sm text-slate-500 dark:text-slate-300"
>
{{ message }} {{ message }}
</div> </div>
</template> </template>

View File

@@ -1,5 +1,7 @@
<script setup> <script setup>
import { defineEmits, defineModel } from 'vue'; import { defineEmits, defineModel } from 'vue';
import NextButton from 'dashboard/components-next/button/Button.vue';
defineProps({ defineProps({
inputPlaceholder: { inputPlaceholder: {
type: String, type: String,
@@ -21,31 +23,29 @@ const value = defineModel({
<template> <template>
<div <div
class="flex items-center justify-between h-10 min-h-[40px] sticky top-0 bg-white z-10 dark:bg-slate-800 gap-2 px-3 border-b rounded-t-xl border-slate-50 dark:border-slate-700" class="flex items-center justify-between h-10 min-h-[40px] sticky top-0 bg-n-solid-2 dark:bg-n-solid-2 z-10 gap-2 px-3 border-b rounded-t-xl border-n-weak"
> >
<div class="flex items-center w-full gap-2" @keyup.space.prevent> <div class="flex items-center w-full gap-2" @keyup.space.prevent>
<fluent-icon <fluent-icon
icon="search" icon="search"
size="16" size="16"
class="text-slate-400 dark:text-slate-400 flex-shrink-0" class="text-n-slate-11 flex-shrink-0"
/> />
<input <input
v-model="value" v-model="value"
:placeholder="inputPlaceholder" :placeholder="inputPlaceholder"
type="text" type="text"
class="w-full mb-0 text-sm bg-white dark:bg-slate-800 text-slate-800 dark:text-slate-75 reset-base" class="w-full mb-0 text-sm !outline-0 bg-transparent text-n-slate-12 placeholder:text-n-slate-10 reset-base"
/> />
</div> </div>
<!-- Clear filter button --> <!-- Clear filter button -->
<woot-button <NextButton
v-if="!modelValue && showClearFilter" v-if="!modelValue && showClearFilter"
size="small" faded
variant="clear" xs
color-scheme="primary" class="flex-shrink-0"
class="!px-1 !py-1.5" :label="$t('REPORT.FILTER_ACTIONS.CLEAR_FILTER')"
@click="emit('remove')" @click="emit('remove')"
> />
{{ $t('REPORT.FILTER_ACTIONS.CLEAR_FILTER') }}
</woot-button>
</div> </div>
</template> </template>

View File

@@ -1,129 +0,0 @@
<script>
import Spinner from 'shared/components/Spinner.vue';
import EmojiOrIcon from 'shared/components/EmojiOrIcon.vue';
export default {
name: 'WootButton',
components: { EmojiOrIcon, Spinner },
props: {
type: {
type: String,
default: 'submit',
},
variant: {
type: String,
default: '',
},
size: {
type: String,
default: '',
},
icon: {
type: String,
default: '',
},
emoji: {
type: String,
default: '',
},
colorScheme: {
type: String,
default: 'primary',
},
classNames: {
type: [String, Object],
default: '',
},
isDisabled: {
type: Boolean,
default: false,
},
isLoading: {
type: Boolean,
default: false,
},
isExpanded: {
type: Boolean,
default: false,
},
},
computed: {
variantClasses() {
if (this.variant.includes('link')) {
return `clear ${this.variant}`;
}
return this.variant;
},
hasOnlyIcon() {
const hasEmojiOrIcon = this.emoji || this.icon;
return !this.$slots.default && hasEmojiOrIcon;
},
hasOnlyIconClasses() {
return this.hasOnlyIcon ? 'button--only-icon' : '';
},
buttonClasses() {
return [
this.variantClasses,
this.hasOnlyIconClasses,
this.size,
this.colorScheme,
this.classNames,
this.isDisabled ? 'disabled' : '',
this.isExpanded ? 'expanded' : '',
];
},
iconSize() {
switch (this.size) {
case 'tiny':
return 12;
case 'small':
return 14;
case 'medium':
return 16;
case 'large':
return 18;
default:
return 16;
}
},
showDarkSpinner() {
return (
this.colorScheme === 'secondary' ||
this.variant === 'clear' ||
this.variant === 'link' ||
this.variant === 'hollow'
);
},
},
};
</script>
<template>
<button
class="button"
:type="type"
:class="buttonClasses"
:disabled="isDisabled || isLoading"
>
<Spinner
v-if="isLoading"
size="small"
:color-scheme="showDarkSpinner ? 'dark' : ''"
/>
<EmojiOrIcon
v-else-if="icon || emoji"
class="icon"
:emoji="emoji"
:icon="icon"
:icon-size="iconSize"
/>
<span
v-if="$slots.default"
class="button__content"
:class="{ 'text-left rtl:text-right': size !== 'expanded' }"
>
<slot />
</span>
</button>
</template>

View File

@@ -1,7 +1,7 @@
<script setup> <script setup>
import { computed } from 'vue'; import { computed } from 'vue';
import NextButton from 'dashboard/components-next/button/Button.vue';
// Props
const props = defineProps({ const props = defineProps({
currentPage: { currentPage: {
type: Number, type: Number,
@@ -21,13 +21,6 @@ const hasFirstPage = computed(() => props.currentPage === 1);
const hasNextPage = computed(() => props.currentPage === props.totalPages); const hasNextPage = computed(() => props.currentPage === props.totalPages);
const hasPrevPage = computed(() => props.currentPage === 1); const hasPrevPage = computed(() => props.currentPage === 1);
function buttonClass(hasPage) {
if (hasPage) {
return 'hover:!bg-slate-50 dark:hover:!bg-slate-800';
}
return 'dark:hover:!bg-slate-700/50';
}
function onPageChange(newPage) { function onPageChange(newPage) {
emit('pageChange', newPage); emit('pageChange', newPage);
} }
@@ -55,84 +48,61 @@ const onLastPage = () => {
</script> </script>
<template> <template>
<div class="flex items-center h-8 rounded-lg bg-slate-50 dark:bg-slate-800">
<woot-button
size="small"
variant="smooth"
color-scheme="secondary"
:is-disabled="hasFirstPage"
class-names="dark:!bg-slate-800 !opacity-100 ltr:rounded-l-lg ltr:rounded-r-none rtl:rounded-r-lg rtl:rounded-l-none"
:class="buttonClass(hasFirstPage)"
@click="onFirstPage"
>
<fluent-icon
icon="chevrons-left"
size="20"
icon-lib="lucide"
:class="hasFirstPage && 'opacity-40'"
/>
</woot-button>
<div class="w-px h-4 rounded-sm bg-slate-75 dark:bg-slate-700/50" />
<woot-button
size="small"
variant="smooth"
color-scheme="secondary"
:is-disabled="hasPrevPage"
class-names="dark:!bg-slate-800 !opacity-100 rounded-none"
:class="buttonClass(hasPrevPage)"
@click="onPrevPage"
>
<fluent-icon
icon="chevron-left-single"
size="20"
icon-lib="lucide"
:class="hasPrevPage && 'opacity-40'"
/>
</woot-button>
<div <div
class="flex items-center gap-3 px-3 tabular-nums bg-slate-50 dark:bg-slate-800 text-slate-700 dark:text-slate-100" class="flex items-center h-8 outline outline-1 outline-n-weak rounded-lg"
> >
<span class="text-sm text-slate-800 dark:text-slate-75"> <NextButton
faded
sm
slate
icon="i-lucide-chevrons-left"
class="ltr:rounded-l-lg ltr:rounded-r-none rtl:rounded-r-lg rtl:rounded-l-none"
:disabled="hasFirstPage"
@click="onFirstPage"
/>
<div class="flex items-center justify-center bg-n-slate-9/10 h-full">
<div class="w-px h-4 rounded-sm bg-n-strong" />
</div>
<NextButton
faded
sm
slate
icon="i-lucide-chevron-left"
class="rounded-none"
:disabled="hasPrevPage"
@click="onPrevPage"
/>
<div
class="flex items-center gap-3 px-3 tabular-nums bg-n-slate-9/10 h-full"
>
<span class="text-sm text-n-slate-12">
{{ currentPage }} {{ currentPage }}
</span> </span>
<span class="text-slate-600 dark:text-slate-500">/</span> <span class="text-n-slate-11">/</span>
<span class="text-sm text-slate-600 dark:text-slate-500"> <span class="text-sm text-n-slate-11">
{{ totalPages }} {{ totalPages }}
</span> </span>
</div> </div>
<woot-button <NextButton
size="small" faded
variant="smooth" sm
color-scheme="secondary" slate
:is-disabled="hasNextPage" icon="i-lucide-chevron-right"
class-names="dark:!bg-slate-800 !opacity-100 rounded-none" class="rounded-none"
:class="buttonClass(hasNextPage)" :disabled="hasNextPage"
@click="onNextPage" @click="onNextPage"
>
<fluent-icon
icon="chevron-right-single"
size="20"
icon-lib="lucide"
:class="hasNextPage && 'opacity-40'"
/> />
</woot-button> <div class="flex items-center justify-center bg-n-slate-9/10 h-full">
<div class="w-px h-4 rounded-sm bg-slate-75 dark:bg-slate-700/50" /> <div class="w-px h-4 rounded-sm bg-n-strong" />
<woot-button </div>
size="small" <NextButton
variant="smooth" faded
color-scheme="secondary" sm
class-names="dark:!bg-slate-800 !opacity-100 ltr:rounded-r-lg ltr:rounded-l-none rtl:rounded-l-lg rtl:rounded-r-none" slate
:class="buttonClass(hasLastPage)" icon="i-lucide-chevrons-right"
:is-disabled="hasLastPage" class="ltr:rounded-r-lg ltr:rounded-l-none rtl:rounded-l-lg rtl:rounded-r-none"
:disabled="hasLastPage"
@click="onLastPage" @click="onLastPage"
>
<fluent-icon
icon="chevrons-right"
size="20"
icon-lib="lucide"
:class="hasLastPage && 'opacity-40'"
/> />
</woot-button>
</div> </div>
</template> </template>

View File

@@ -1074,7 +1074,7 @@ export default {
<template> <template>
<Banner <Banner
v-if="showSelfAssignBanner" v-if="showSelfAssignBanner"
action-button-variant="clear" action-button-variant="ghost"
color-scheme="secondary" color-scheme="secondary"
class="banner--self-assign mx-2 mb-2 rounded-lg" class="banner--self-assign mx-2 mb-2 rounded-lg"
:banner-message="$t('CONVERSATION.NOT_ASSIGNED_TO_YOU')" :banner-message="$t('CONVERSATION.NOT_ASSIGNED_TO_YOU')"

View File

@@ -4,8 +4,12 @@ import {
DuplicateContactException, DuplicateContactException,
ExceptionWithMessage, ExceptionWithMessage,
} from 'shared/helpers/CustomErrors'; } from 'shared/helpers/CustomErrors';
import NextButton from 'dashboard/components-next/button/Button.vue';
export default { export default {
components: {
NextButton,
},
props: { props: {
name: { name: {
type: String, type: String,
@@ -91,9 +95,12 @@ export default {
</p> </p>
</div> </div>
<div v-if="formattedPhoneNumber" class="link-wrap"> <div v-if="formattedPhoneNumber" class="link-wrap">
<woot-button variant="clear" size="small" @click.prevent="addContact"> <NextButton
{{ $t('CONVERSATION.SAVE_CONTACT') }} ghost
</woot-button> xs
:label="$t('CONVERSATION.SAVE_CONTACT')"
@click.prevent="addContact"
/>
</div> </div>
</div> </div>
</template> </template>

View File

@@ -2,8 +2,12 @@
import DyteAPI from 'dashboard/api/integrations/dyte'; import DyteAPI from 'dashboard/api/integrations/dyte';
import { buildDyteURL } from 'shared/helpers/IntegrationHelper'; import { buildDyteURL } from 'shared/helpers/IntegrationHelper';
import { useAlert } from 'dashboard/composables'; import { useAlert } from 'dashboard/composables';
import NextButton from 'dashboard/components-next/button/Button.vue';
export default { export default {
components: {
NextButton,
},
props: { props: {
messageId: { messageId: {
type: Number, type: Number,
@@ -41,31 +45,25 @@ export default {
<template> <template>
<div> <div>
<woot-button <NextButton
size="small" blue
variant="smooth" sm
color-scheme="secondary" icon="i-lucide-video"
icon="video-add" :label="$t('INTEGRATION_SETTINGS.DYTE.CLICK_HERE_TO_JOIN')"
class="join-call-button"
:is-loading="isLoading" :is-loading="isLoading"
@click="joinTheCall" @click="joinTheCall"
> />
{{ $t('INTEGRATION_SETTINGS.DYTE.CLICK_HERE_TO_JOIN') }}
</woot-button>
<div v-if="dyteAuthToken" class="video-call--container"> <div v-if="dyteAuthToken" class="video-call--container">
<iframe <iframe
:src="meetingLink" :src="meetingLink"
allow="camera;microphone;fullscreen;display-capture;picture-in-picture;clipboard-write;" allow="camera;microphone;fullscreen;display-capture;picture-in-picture;clipboard-write;"
/> />
<woot-button <NextButton
size="small" sm
variant="smooth" class="mt-2"
color-scheme="secondary" :label="$t('INTEGRATION_SETTINGS.DYTE.LEAVE_THE_ROOM')"
class="join-call-button"
@click="leaveTheRoom" @click="leaveTheRoom"
> />
{{ $t('INTEGRATION_SETTINGS.DYTE.LEAVE_THE_ROOM') }}
</woot-button>
</div> </div>
</div> </div>
</template> </template>

View File

@@ -1,6 +1,6 @@
<script> <script>
// components // components
import WootButton from '../../../ui/WootButton.vue'; import NextButton from 'dashboard/components-next/button/Button.vue';
import Avatar from '../../Avatar.vue'; import Avatar from '../../Avatar.vue';
// composables // composables
@@ -19,7 +19,7 @@ export default {
name: 'LabelSuggestion', name: 'LabelSuggestion',
components: { components: {
Avatar, Avatar,
WootButton, NextButton,
}, },
props: { props: {
suggestedLabels: { suggestedLabels: {
@@ -185,42 +185,44 @@ export default {
" "
/> />
</button> </button>
<WootButton <NextButton
v-if="preparedLabels.length === 1" v-if="preparedLabels.length === 1"
v-tooltip.top="{ v-tooltip.top="{
content: $t('LABEL_MGMT.SUGGESTIONS.TOOLTIP.DISMISS'), content: $t('LABEL_MGMT.SUGGESTIONS.TOOLTIP.DISMISS'),
delay: { show: 600, hide: 0 }, delay: { show: 600, hide: 0 },
hideOnClick: true, hideOnClick: true,
}" }"
variant="smooth" faded
:color-scheme="isHovered ? 'alert' : 'primary'" xs
class="label--add" icon="i-lucide-x"
icon="dismiss" class="flex-shrink-0"
size="tiny" :color="isHovered ? 'ruby' : 'blue'"
@click="dismissSuggestions" @click="dismissSuggestions"
/> />
</div> </div>
<div v-if="preparedLabels.length > 1"> <div
<WootButton v-if="preparedLabels.length > 1"
:variant="selectedLabels.length === 0 ? 'smooth' : ''" class="inline-flex items-center gap-1"
class="label--add"
icon="add"
size="tiny"
@click="addAllLabels"
> >
{{ addButtonText }} <NextButton
</WootButton> xs
<WootButton icon="i-lucide-plus"
class="flex-shrink-0"
:variant="selectedLabels.length === 0 ? 'faded' : 'solid'"
:label="addButtonText"
@click="addAllLabels"
/>
<NextButton
v-tooltip.top="{ v-tooltip.top="{
content: $t('LABEL_MGMT.SUGGESTIONS.TOOLTIP.DISMISS'), content: $t('LABEL_MGMT.SUGGESTIONS.TOOLTIP.DISMISS'),
delay: { show: 600, hide: 0 }, delay: { show: 600, hide: 0 },
hideOnClick: true, hideOnClick: true,
}" }"
:color-scheme="isHovered ? 'alert' : 'primary'" faded
variant="smooth" xs
class="label--add" icon="i-lucide-x"
icon="dismiss" class="flex-shrink-0"
size="tiny" :color="isHovered ? 'ruby' : 'blue'"
@click="dismissSuggestions" @click="dismissSuggestions"
/> />
</div> </div>

View File

@@ -107,9 +107,10 @@ const linkIssue = async () => {
:class="shouldShowDropdown ? 'h-[256px]' : 'gap-2'" :class="shouldShowDropdown ? 'h-[256px]' : 'gap-2'"
> >
<FilterButton <FilterButton
right-icon="chevron-down" trailing-icon
icon="i-lucide-chevron-down"
:button-text="linkIssueTitle" :button-text="linkIssueTitle"
class="justify-between w-full h-[2.5rem] py-1.5 px-3 rounded-xl border border-slate-50 bg-slate-25 dark:border-slate-600 dark:bg-slate-900 hover:bg-slate-50 dark:hover:bg-slate-900/50" class="justify-between w-full h-[2.5rem] py-1.5 px-3 rounded-xl bg-n-alpha-black2 outline outline-1 outline-n-weak dark:outline-n-weak hover:outline-n-slate-6 dark:hover:outline-n-slate-6"
@click="toggleDropdown" @click="toggleDropdown"
> >
<template v-if="shouldShowDropdown" #dropdown> <template v-if="shouldShowDropdown" #dropdown>

View File

@@ -50,9 +50,10 @@ const selectedItemId = computed(() => selectedItem.value?.id || null);
<label class="w-full" :class="{ error: hasError }"> <label class="w-full" :class="{ error: hasError }">
{{ label }} {{ label }}
<FilterButton <FilterButton
right-icon="chevron-down" trailing-icon
icon="i-lucide-chevron-down"
:button-text="selectedItemName" :button-text="selectedItemName"
class="justify-between w-full h-[2.5rem] py-1.5 px-3 rounded-xl border border-slate-50 bg-slate-25 dark:border-slate-600 dark:bg-slate-900 hover:bg-slate-50 dark:hover:bg-slate-900/50" class="justify-between w-full h-[2.5rem] py-1.5 px-3 rounded-xl bg-n-alpha-black2 outline outline-1 outline-n-weak dark:outline-n-weak hover:outline-n-slate-6 dark:hover:outline-n-slate-6"
@click="toggleDropdown" @click="toggleDropdown"
> >
<template v-if="shouldShowDropdown" #dropdown> <template v-if="shouldShowDropdown" #dropdown>

View File

@@ -1,5 +1,10 @@
<script> <script>
import NextButton from 'dashboard/components-next/button/Button.vue';
export default { export default {
components: {
NextButton,
},
props: { props: {
label: { label: {
type: String, type: String,
@@ -49,15 +54,13 @@ export default {
:username="usernameAvatar" :username="usernameAvatar"
/> />
<div v-if="src && deleteAvatar" class="avatar-delete-btn"> <div v-if="src && deleteAvatar" class="avatar-delete-btn">
<woot-button <NextButton
color-scheme="alert" outline
variant="hollow" xs
size="tiny" ruby
type="button" :label="$t('INBOX_MGMT.DELETE.AVATAR_DELETE_BUTTON_TEXT')"
@click="onAvatarDelete" @click="onAvatarDelete"
> />
{{ $t('INBOX_MGMT.DELETE.AVATAR_DELETE_BUTTON_TEXT') }}
</woot-button>
</div> </div>
<label> <label>
<input <input

View File

@@ -1,123 +0,0 @@
<script>
import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue';
import SocialIcons from 'dashboard/routes/dashboard/conversation/contact/SocialIcons.vue';
export default {
components: {
Thumbnail,
SocialIcons,
},
props: {
contact: {
type: Object,
default: () => ({}),
},
},
emits: ['edit', 'message'],
computed: {
additionalAttributes() {
return this.contact.additional_attributes || {};
},
socialProfiles() {
const {
social_profiles: socialProfiles,
screen_name: twitterScreenName,
} = this.additionalAttributes;
return { twitter: twitterScreenName, ...(socialProfiles || {}) };
},
company() {
const { company = {} } = this.contact;
return company;
},
},
methods: {
onEditClick() {
this.$emit('edit');
},
onNewMessageClick() {
this.$emit('message');
},
},
};
</script>
<template>
<div class="contact--intro">
<Thumbnail
:src="contact.thumbnail"
size="64px"
:username="contact.name"
:status="contact.availability_status"
/>
<div class="contact--details">
<h2 class="text-lg contact--name">
{{ contact.name }}
</h2>
<h3 class="text-base contact--work">
{{ contact.title }}
<i v-if="company.name" class="i-lucide-circle-minus" />
<span class="company-name">{{ company.name }}</span>
</h3>
<p v-if="additionalAttributes.description" class="contact--bio">
{{ additionalAttributes.description }}
</p>
<SocialIcons :social-profiles="socialProfiles" />
</div>
<div class="contact-actions">
<woot-button
class="new-message"
size="small expanded"
icon="ion-paper-airplane"
@click="onNewMessageClick"
>
{{ $t('CONTACT_PANEL.NEW_MESSAGE') }}
</woot-button>
<woot-button
variant="hollow"
size="small expanded"
icon="edit"
@click="onEditClick"
>
{{ $t('EDIT_CONTACT.BUTTON_LABEL') }}
</woot-button>
</div>
</div>
</template>
<style scoped lang="scss">
.contact--details {
margin-top: var(--space-small);
}
.contact--work {
color: var(--color-body);
.icon {
font-size: var(--font-size-nano);
vertical-align: middle;
}
}
.contact--name {
text-transform: capitalize;
font-weight: var(--font-weight-bold);
}
.contact--bio {
margin: var(--space-smaller) 0 0;
}
.button.new-message {
margin-right: var(--space-small);
}
.contact-actions {
display: flex;
align-items: center;
width: 100%;
margin-top: var(--space-small);
}
</style>

View File

@@ -13,12 +13,14 @@ import {
} from '../../../helper/AnalyticsHelper/events'; } from '../../../helper/AnalyticsHelper/events';
import MenuItem from '../../../components/widgets/conversation/contextMenu/menuItem.vue'; import MenuItem from '../../../components/widgets/conversation/contextMenu/menuItem.vue';
import { useTrack } from 'dashboard/composables'; import { useTrack } from 'dashboard/composables';
import NextButton from 'dashboard/components-next/button/Button.vue';
export default { export default {
components: { components: {
AddCannedModal, AddCannedModal,
MenuItem, MenuItem,
ContextMenu, ContextMenu,
NextButton,
}, },
props: { props: {
message: { message: {
@@ -175,12 +177,12 @@ export default {
:confirm-text="$t('CONVERSATION.CONTEXT_MENU.DELETE_CONFIRMATION.DELETE')" :confirm-text="$t('CONVERSATION.CONTEXT_MENU.DELETE_CONFIRMATION.DELETE')"
:reject-text="$t('CONVERSATION.CONTEXT_MENU.DELETE_CONFIRMATION.CANCEL')" :reject-text="$t('CONVERSATION.CONTEXT_MENU.DELETE_CONFIRMATION.CANCEL')"
/> />
<woot-button <NextButton
v-if="!hideButton" v-if="!hideButton"
icon="more-vertical" ghost
color-scheme="secondary" slate
variant="clear" sm
size="small" icon="i-lucide-ellipsis-vertical"
class="invisible group-hover/context-menu:visible" class="invisible group-hover/context-menu:visible"
@click="handleOpen" @click="handleOpen"
/> />

View File

@@ -9,12 +9,14 @@ import ConversationLabels from './labels/LabelBox.vue';
import { CONVERSATION_PRIORITY } from '../../../../shared/constants/messages'; import { CONVERSATION_PRIORITY } from '../../../../shared/constants/messages';
import { CONVERSATION_EVENTS } from '../../../helper/AnalyticsHelper/events'; import { CONVERSATION_EVENTS } from '../../../helper/AnalyticsHelper/events';
import { useTrack } from 'dashboard/composables'; import { useTrack } from 'dashboard/composables';
import NextButton from 'dashboard/components-next/button/Button.vue';
export default { export default {
components: { components: {
ContactDetailsItem, ContactDetailsItem,
MultiselectDropdown, MultiselectDropdown,
ConversationLabels, ConversationLabels,
NextButton,
}, },
props: { props: {
conversationId: { conversationId: {
@@ -212,15 +214,15 @@ export default {
:title="$t('CONVERSATION_SIDEBAR.ASSIGNEE_LABEL')" :title="$t('CONVERSATION_SIDEBAR.ASSIGNEE_LABEL')"
> >
<template #button> <template #button>
<woot-button <NextButton
v-if="showSelfAssign" v-if="showSelfAssign"
icon="arrow-right" link
variant="link" xs
size="small" icon="i-lucide-arrow-right"
class="!gap-1"
:label="$t('CONVERSATION_SIDEBAR.SELF_ASSIGN')"
@click="onSelfAssign" @click="onSelfAssign"
> />
{{ $t('CONVERSATION_SIDEBAR.SELF_ASSIGN') }}
</woot-button>
</template> </template>
</ContactDetailsItem> </ContactDetailsItem>
<MultiselectDropdown <MultiselectDropdown

View File

@@ -6,12 +6,14 @@ import { useAgentsList } from 'dashboard/composables/useAgentsList';
import ThumbnailGroup from 'dashboard/components/widgets/ThumbnailGroup.vue'; import ThumbnailGroup from 'dashboard/components/widgets/ThumbnailGroup.vue';
import MultiselectDropdownItems from 'shared/components/ui/MultiselectDropdownItems.vue'; import MultiselectDropdownItems from 'shared/components/ui/MultiselectDropdownItems.vue';
import NextButton from 'dashboard/components-next/button/Button.vue';
export default { export default {
components: { components: {
Spinner, Spinner,
ThumbnailGroup, ThumbnailGroup,
MultiselectDropdownItems, MultiselectDropdownItems,
NextButton,
}, },
props: { props: {
conversationId: { conversationId: {
@@ -165,13 +167,14 @@ export default {
{{ $t('CONVERSATION_PARTICIPANTS.NO_PARTICIPANTS_TEXT') }} {{ $t('CONVERSATION_PARTICIPANTS.NO_PARTICIPANTS_TEXT') }}
</p> </p>
</div> </div>
<woot-button <NextButton
v-tooltip.left="$t('CONVERSATION_PARTICIPANTS.ADD_PARTICIPANTS')" v-tooltip.left="$t('CONVERSATION_PARTICIPANTS.ADD_PARTICIPANTS')"
slate
ghost
sm
icon="i-lucide-settings"
class="relative -top-1"
:title="$t('CONVERSATION_PARTICIPANTS.ADD_PARTICIPANTS')" :title="$t('CONVERSATION_PARTICIPANTS.ADD_PARTICIPANTS')"
icon="settings"
size="tiny"
variant="smooth"
color-scheme="secondary"
@click="onOpenDropdown" @click="onOpenDropdown"
/> />
</div> </div>
@@ -188,15 +191,15 @@ export default {
> >
{{ $t('CONVERSATION_PARTICIPANTS.YOU_ARE_WATCHING') }} {{ $t('CONVERSATION_PARTICIPANTS.YOU_ARE_WATCHING') }}
</p> </p>
<woot-button <NextButton
v-else v-else
icon="arrow-right" link
variant="link" xs
size="small" icon="i-lucide-arrow-right"
class="!gap-1"
:label="$t('CONVERSATION_PARTICIPANTS.WATCH_CONVERSATION')"
@click="onSelfAssign" @click="onSelfAssign"
> />
{{ $t('CONVERSATION_PARTICIPANTS.WATCH_CONVERSATION') }}
</woot-button>
</div> </div>
<div <div
v-on-clickaway=" v-on-clickaway="
@@ -213,13 +216,7 @@ export default {
> >
{{ $t('CONVERSATION_PARTICIPANTS.ADD_PARTICIPANTS') }} {{ $t('CONVERSATION_PARTICIPANTS.ADD_PARTICIPANTS') }}
</h4> </h4>
<woot-button <NextButton ghost slate xs icon="i-lucide-x" @click="onCloseDropdown" />
icon="dismiss"
size="tiny"
color-scheme="secondary"
variant="clear"
@click="onCloseDropdown"
/>
</div> </div>
<MultiselectDropdownItems <MultiselectDropdownItems
:options="agentsList" :options="agentsList"

View File

@@ -7,6 +7,7 @@ import { useUISettings } from 'dashboard/composables/useUISettings';
import Draggable from 'vuedraggable'; import Draggable from 'vuedraggable';
import Spinner from 'dashboard/components-next/spinner/Spinner.vue'; import Spinner from 'dashboard/components-next/spinner/Spinner.vue';
import MacroItem from './MacroItem.vue'; import MacroItem from './MacroItem.vue';
import NextButton from 'dashboard/components-next/button/Button.vue';
defineProps({ defineProps({
conversationId: { conversationId: {
@@ -71,9 +72,13 @@ onMounted(() => {
{{ $t('MACROS.LIST.404') }} {{ $t('MACROS.LIST.404') }}
</p> </p>
<router-link :to="accountScopedUrl('settings/macros')"> <router-link :to="accountScopedUrl('settings/macros')">
<woot-button variant="smooth" icon="add" size="tiny" class="mt-1"> <NextButton
{{ $t('MACROS.HEADER_BTN_TXT') }} faded
</woot-button> xs
icon="i-lucide-plus"
class="mt-1"
:label="$t('MACROS.HEADER_BTN_TXT')"
/>
</router-link> </router-link>
</div> </div>
<div <div

View File

@@ -2,10 +2,12 @@
import { useAlert } from 'dashboard/composables'; import { useAlert } from 'dashboard/composables';
import EmojiOrIcon from 'shared/components/EmojiOrIcon.vue'; import EmojiOrIcon from 'shared/components/EmojiOrIcon.vue';
import { copyTextToClipboard } from 'shared/helpers/clipboard'; import { copyTextToClipboard } from 'shared/helpers/clipboard';
import NextButton from 'dashboard/components-next/button/Button.vue';
export default { export default {
components: { components: {
EmojiOrIcon, EmojiOrIcon,
NextButton,
}, },
props: { props: {
href: { href: {
@@ -62,15 +64,13 @@ export default {
<span v-else class="text-sm text-n-slate-11"> <span v-else class="text-sm text-n-slate-11">
{{ $t('CONTACT_PANEL.NOT_AVAILABLE') }} {{ $t('CONTACT_PANEL.NOT_AVAILABLE') }}
</span> </span>
<NextButton
<woot-button
v-if="showCopy" v-if="showCopy"
type="submit" ghost
variant="clear" xs
size="tiny" slate
color-scheme="secondary" class="ltr:-ml-1 rtl:-mr-1"
icon="clipboard" icon="i-lucide-clipboard"
class-names="p-0"
@click="onCopy" @click="onCopy"
/> />
</a> </a>

View File

@@ -9,6 +9,7 @@ import { useI18n } from 'vue-i18n';
import { useUISettings } from 'dashboard/composables/useUISettings'; import { useUISettings } from 'dashboard/composables/useUISettings';
import { copyTextToClipboard } from 'shared/helpers/clipboard'; import { copyTextToClipboard } from 'shared/helpers/clipboard';
import CustomAttribute from 'dashboard/components/CustomAttribute.vue'; import CustomAttribute from 'dashboard/components/CustomAttribute.vue';
import NextButton from 'dashboard/components-next/button/Button.vue';
const props = defineProps({ const props = defineProps({
attributeType: { attributeType: {
@@ -318,17 +319,16 @@ const evenClass = [
{{ emptyStateMessage }} {{ emptyStateMessage }}
</p> </p>
<!-- Show more and show less buttons show it if the combinedElements length is greater than 5 --> <!-- Show more and show less buttons show it if the combinedElements length is greater than 5 -->
<div v-if="combinedElements.length > 5" class="flex px-2 py-2"> <div v-if="combinedElements.length > 5" class="flex items-center px-2 py-2">
<woot-button <NextButton
size="small" ghost
:icon="showAllAttributes ? 'chevron-up' : 'chevron-down'" xs
variant="clear" :icon="
color-scheme="primary" showAllAttributes ? 'i-lucide-chevron-up' : 'i-lucide-chevron-down'
class="!px-2 hover:!bg-transparent dark:hover:!bg-transparent" "
:label="toggleButtonText"
@click="onClickToggle" @click="onClickToggle"
> />
{{ toggleButtonText }}
</woot-button>
</div> </div>
</div> </div>
</template> </template>

View File

@@ -2,6 +2,7 @@
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import SwitchLayout from './SwitchLayout.vue'; import SwitchLayout from './SwitchLayout.vue';
import { frontendURL } from 'dashboard/helper/URLHelper'; import { frontendURL } from 'dashboard/helper/URLHelper';
export default { export default {
components: { components: {
SwitchLayout, SwitchLayout,
@@ -37,7 +38,7 @@ export default {
class="flex px-4 pb-1 justify-between items-center flex-row gap-1 pt-2.5 border-b border-transparent" class="flex px-4 pb-1 justify-between items-center flex-row gap-1 pt-2.5 border-b border-transparent"
> >
<woot-sidemenu-icon <woot-sidemenu-icon
size="tiny" size="xs"
class="relative top-0 ltr:-ml-1.5 rtl:-mr-1.5 flex-shrink-0 focus:!bg-n-solid-3 dark:!hover:bg-n-solid-2 hover:!bg-n-alpha-2" class="relative top-0 ltr:-ml-1.5 rtl:-mr-1.5 flex-shrink-0 focus:!bg-n-solid-3 dark:!hover:bg-n-solid-2 hover:!bg-n-alpha-2"
/> />
<router-link <router-link

View File

@@ -1,114 +0,0 @@
<script>
import { useVuelidate } from '@vuelidate/core';
import { required, minLength } from '@vuelidate/validators';
import { useAlert } from 'dashboard/composables';
import { CONTACTS_EVENTS } from '../../../helper/AnalyticsHelper/events';
import { useTrack } from 'dashboard/composables';
export default {
props: {
filterType: {
type: Number,
default: 0,
},
customViewsQuery: {
type: Object,
default: () => {},
},
openLastSavedItem: {
type: Function,
default: () => {},
},
},
emits: ['close'],
setup() {
return { v$: useVuelidate() };
},
data() {
return {
show: true,
name: '',
};
},
computed: {
isButtonDisabled() {
return this.v$.name.$invalid;
},
},
validations: {
name: {
required,
minLength: minLength(1),
},
},
methods: {
onClose() {
this.$emit('close');
},
async saveCustomViews() {
this.v$.$touch();
if (this.v$.$invalid) {
return;
}
try {
await this.$store.dispatch('customViews/create', {
name: this.name,
filter_type: this.filterType,
query: this.customViewsQuery,
});
this.alertMessage =
this.filterType === 0
? this.$t('FILTER.CUSTOM_VIEWS.ADD.API_FOLDERS.SUCCESS_MESSAGE')
: this.$t('FILTER.CUSTOM_VIEWS.ADD.API_SEGMENTS.SUCCESS_MESSAGE');
this.onClose();
useTrack(CONTACTS_EVENTS.SAVE_FILTER, {
type: this.filterType === 0 ? 'folder' : 'segment',
});
} catch (error) {
const errorMessage = error?.message;
this.alertMessage =
errorMessage || this.filterType === 0
? errorMessage
: this.$t('FILTER.CUSTOM_VIEWS.ADD.API_SEGMENTS.ERROR_MESSAGE');
} finally {
useAlert(this.alertMessage);
}
this.openLastSavedItem();
},
},
};
</script>
<template>
<woot-modal v-model:show="show" :on-close="onClose">
<woot-modal-header :header-title="$t('FILTER.CUSTOM_VIEWS.ADD.TITLE')" />
<form class="w-full" @submit.prevent="saveCustomViews">
<div class="w-full">
<woot-input
v-model="name"
:label="$t('FILTER.CUSTOM_VIEWS.ADD.LABEL')"
type="text"
:error="
v$.name.$error ? $t('FILTER.CUSTOM_VIEWS.ADD.ERROR_MESSAGE') : ''
"
:class="{ error: v$.name.$error }"
:placeholder="$t('FILTER.CUSTOM_VIEWS.ADD.PLACEHOLDER')"
@blur="v$.name.$touch"
/>
<div class="flex flex-row justify-end w-full gap-2 px-0 py-2">
<woot-button :disabled="isButtonDisabled">
{{ $t('FILTER.CUSTOM_VIEWS.ADD.SAVE_BUTTON') }}
</woot-button>
<woot-button variant="clear" @click.prevent="onClose">
{{ $t('FILTER.CUSTOM_VIEWS.ADD.CANCEL_BUTTON') }}
</woot-button>
</div>
</div>
</form>
</woot-modal>
</template>

View File

@@ -1,7 +1,12 @@
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import wootConstants from 'dashboard/constants/globals'; import wootConstants from 'dashboard/constants/globals';
import NextButton from 'dashboard/components-next/button/Button.vue';
export default { export default {
components: {
NextButton,
},
data() { data() {
return { return {
helpCenterDocsURL: wootConstants.HELP_CENTER_DOCS_URL, helpCenterDocsURL: wootConstants.HELP_CENTER_DOCS_URL,
@@ -86,21 +91,15 @@ export default {
v-if="isOnChatwootCloud" v-if="isOnChatwootCloud"
class="flex flex-row gap-3 justify-start items-center sm:justify-center" class="flex flex-row gap-3 justify-start items-center sm:justify-center"
> >
<woot-button <NextButton
size="medium" outline
variant="hollow" :label="$t('HELP_CENTER.UPGRADE_PAGE.BUTTON.LEARN_MORE')"
color-scheme="primary"
@click="openHelpCenterDocs" @click="openHelpCenterDocs"
> />
{{ $t('HELP_CENTER.UPGRADE_PAGE.BUTTON.LEARN_MORE') }} <NextButton
</woot-button> :label="$t('HELP_CENTER.UPGRADE_PAGE.BUTTON.UPGRADE')"
<woot-button
size="medium"
color-scheme="primary"
@click="openBillingPage" @click="openBillingPage"
> />
{{ $t('HELP_CENTER.UPGRADE_PAGE.BUTTON.UPGRADE') }}
</woot-button>
</div> </div>
</div> </div>
<div <div

View File

@@ -3,10 +3,12 @@ import { mapGetters } from 'vuex';
import NotificationPanelList from './NotificationPanelList.vue'; import NotificationPanelList from './NotificationPanelList.vue';
import { useTrack } from 'dashboard/composables'; import { useTrack } from 'dashboard/composables';
import { ACCOUNT_EVENTS } from '../../../../helper/AnalyticsHelper/events'; import { ACCOUNT_EVENTS } from '../../../../helper/AnalyticsHelper/events';
import NextButton from 'dashboard/components-next/button/Button.vue';
export default { export default {
components: { components: {
NotificationPanelList, NotificationPanelList,
NextButton,
}, },
emits: ['close'], emits: ['close'],
data() { data() {
@@ -148,28 +150,27 @@ export default {
</span> </span>
</div> </div>
<div class="flex gap-2"> <div class="flex gap-2">
<woot-button <NextButton
v-if="!noUnreadNotificationAvailable" v-if="!noUnreadNotificationAvailable"
color-scheme="primary" faded
variant="smooth" xs
size="tiny" icon="i-lucide-list-check"
:is-loading="uiFlags.isUpdating" :is-loading="uiFlags.isUpdating"
:label="$t('NOTIFICATIONS_PAGE.MARK_ALL_DONE')"
@click="onMarkAllDoneClick" @click="onMarkAllDoneClick"
> />
{{ $t('NOTIFICATIONS_PAGE.MARK_ALL_DONE') }} <NextButton
</woot-button> faded
<woot-button xs
color-scheme="secondary" slate
variant="smooth" icon="i-lucide-settings"
size="tiny"
icon="settings"
@click="openAudioNotificationSettings" @click="openAudioNotificationSettings"
/> />
<woot-button <NextButton
color-scheme="secondary" ghost
variant="link" xs
size="tiny" slate
icon="dismiss" icon="i-lucide-x"
@click="closeNotificationPanel" @click="closeNotificationPanel"
/> />
</div> </div>
@@ -186,25 +187,18 @@ export default {
class="flex items-center justify-between px-5 py-1" class="flex items-center justify-between px-5 py-1"
> >
<div class="flex"> <div class="flex">
<woot-button <NextButton
size="medium" ghost
variant="clear" slate
color-scheme="secondary" icon="i-lucide-chevrons-left"
:is-disabled="inFirstPage" :disabled="inFirstPage"
@click="onClickFirstPage" @click="onClickFirstPage"
>
<fluent-icon icon="chevron-left" size="16" />
<fluent-icon
icon="chevron-left"
size="16"
class="rtl:-mr-3 ltr:-ml-3"
/> />
</woot-button> <NextButton
<woot-button ghost
color-scheme="secondary" slate
variant="clear" icon="i-lucide-chevron-left"
size="medium" class="ltr:-ml-3 rtl:-mr-3"
icon="chevron-left"
:disabled="inFirstPage" :disabled="inFirstPage"
@click="onClickPreviousPage" @click="onClickPreviousPage"
/> />
@@ -213,28 +207,21 @@ export default {
{{ currentPage }} - {{ lastPage }} {{ currentPage }} - {{ lastPage }}
</span> </span>
<div class="flex"> <div class="flex">
<woot-button <NextButton
color-scheme="secondary" ghost
variant="clear" slate
size="medium" icon="i-lucide-chevron-right"
icon="chevron-right" class="ltr:-mr-3 rtl:-ml-3"
:disabled="inLastPage" :disabled="inLastPage"
@click="onClickNextPage" @click="onClickNextPage"
/> />
<woot-button <NextButton
size="medium" ghost
variant="clear" slate
color-scheme="secondary" icon="i-lucide-chevrons-right"
:disabled="inLastPage" :disabled="inLastPage"
@click="onClickLastPage" @click="onClickLastPage"
>
<fluent-icon icon="chevron-right" size="16" />
<fluent-icon
icon="chevron-right"
size="16"
class="rtl:-mr-3 ltr:-ml-3"
/> />
</woot-button>
</div> </div>
</div> </div>
<div v-else /> <div v-else />

View File

@@ -1,10 +1,12 @@
<script> <script>
import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue'; import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue';
import { dynamicTime } from 'shared/helpers/timeHelper'; import { dynamicTime } from 'shared/helpers/timeHelper';
import NextButton from 'dashboard/components-next/button/Button.vue';
export default { export default {
components: { components: {
Thumbnail, Thumbnail,
NextButton,
}, },
props: { props: {
notificationItem: { notificationItem: {
@@ -39,11 +41,10 @@ export default {
<template> <template>
<div class="w-full"> <div class="w-full">
<woot-button <NextButton
size="expanded" link
color-scheme="secondary" slate
variant="link" class="!w-full !h-auto"
class="w-full"
@click="onClickOpenNotification()" @click="onClickOpenNotification()"
> >
<div <div
@@ -100,6 +101,6 @@ export default {
</span> </span>
</div> </div>
</div> </div>
</woot-button> </NextButton>
</div> </div>
</template> </template>

View File

@@ -2,12 +2,14 @@
import Spinner from 'shared/components/Spinner.vue'; import Spinner from 'shared/components/Spinner.vue';
import EmptyState from 'dashboard/components/widgets/EmptyState.vue'; import EmptyState from 'dashboard/components/widgets/EmptyState.vue';
import NotificationPanelItem from './NotificationPanelItem.vue'; import NotificationPanelItem from './NotificationPanelItem.vue';
import NextButton from 'dashboard/components-next/button/Button.vue';
export default { export default {
components: { components: {
NotificationPanelItem, NotificationPanelItem,
Spinner, Spinner,
EmptyState, EmptyState,
NextButton,
}, },
props: { props: {
notifications: { notifications: {
@@ -59,16 +61,13 @@ export default {
v-if="showEmptyResult" v-if="showEmptyResult"
:title="$t('NOTIFICATIONS_PAGE.UNREAD_NOTIFICATION.EMPTY_MESSAGE')" :title="$t('NOTIFICATIONS_PAGE.UNREAD_NOTIFICATION.EMPTY_MESSAGE')"
/> />
<woot-button <NextButton
v-if="!isLoading && inLastPage" v-if="!isLoading && inLastPage"
size="expanded" ghost
variant="clear" class="!w-full mt-3"
color-scheme="primary" :label="$t('NOTIFICATIONS_PAGE.UNREAD_NOTIFICATION.ALL_NOTIFICATIONS')"
class-names="mt-3"
@click="openNotificationPage" @click="openNotificationPage"
> />
{{ $t('NOTIFICATIONS_PAGE.UNREAD_NOTIFICATION.ALL_NOTIFICATIONS') }}
</woot-button>
<div <div
v-if="isLoading" v-if="isLoading"
class="flex items-center justify-center mx-2 my-12 text-sm font-medium" class="flex items-center justify-center mx-2 my-12 text-sm font-medium"

View File

@@ -51,7 +51,8 @@ const closeDropdown = () => emit('closeDropdown');
<template> <template>
<FilterButton <FilterButton
right-icon="chevron-down" trailing-icon
icon="i-lucide-chevron-down"
:button-text="name" :button-text="name"
@click="toggleDropdown" @click="toggleDropdown"
> >

View File

@@ -59,7 +59,11 @@ const closeDropdown = () => {
</script> </script>
<template> <template>
<FilterButton :button-text="name" left-icon="filter" @click="toggleDropdown"> <FilterButton
:button-text="name"
icon="i-lucide-filter"
@click="toggleDropdown"
>
<!-- Dropdown with search and sub-dropdown --> <!-- Dropdown with search and sub-dropdown -->
<template v-if="showMenu" #dropdown> <template v-if="showMenu" #dropdown>
<FilterListDropdown <FilterListDropdown

View File

@@ -1,8 +1,11 @@
<script> <script>
import SLAPopoverCard from 'dashboard/components/widgets/conversation/components/SLAPopoverCard.vue'; import SLAPopoverCard from 'dashboard/components/widgets/conversation/components/SLAPopoverCard.vue';
import NextButton from 'dashboard/components-next/button/Button.vue';
export default { export default {
components: { components: {
SLAPopoverCard, SLAPopoverCard,
NextButton,
}, },
props: { props: {
slaEvents: { slaEvents: {
@@ -34,13 +37,13 @@ export default {
class="flex items-center col-span-2 text-slate-11 justify-end" class="flex items-center col-span-2 text-slate-11 justify-end"
> >
<div class="relative"> <div class="relative">
<woot-button <NextButton
color-scheme="secondary" link
variant="link" slate
type="button"
:label="$t('SLA_REPORTS.TABLE.VIEW_DETAILS')"
@click="openSlaEvents" @click="openSlaEvents"
> />
{{ $t('SLA_REPORTS.TABLE.VIEW_DETAILS') }}
</woot-button>
<SLAPopoverCard <SLAPopoverCard
v-if="showSlaPopoverCard" v-if="showSlaPopoverCard"
:sla-missed-events="slaEvents" :sla-missed-events="slaEvents"

View File

@@ -1,5 +1,6 @@
<script setup> <script setup>
import BaseEmptyState from './BaseEmptyState.vue'; import BaseEmptyState from './BaseEmptyState.vue';
import NextButton from 'dashboard/components-next/button/Button.vue';
const emit = defineEmits(['primaryAction']); const emit = defineEmits(['primaryAction']);
const primaryAction = () => emit('primaryAction'); const primaryAction = () => emit('primaryAction');
@@ -10,13 +11,11 @@ const primaryAction = () => emit('primaryAction');
<p class="max-w-xs text-sm font-medium text-center"> <p class="max-w-xs text-sm font-medium text-center">
{{ $t('SLA.LIST.404') }} {{ $t('SLA.LIST.404') }}
</p> </p>
<woot-button <NextButton
color-scheme="primary" icon="i-lucide-plus"
icon="plus-sign" class="mt-4"
class="px-5 mt-4 rounded-xl" :label="$t('SLA.ADD_ACTION_LONG')"
@click="primaryAction" @click="primaryAction"
> />
{{ $t('SLA.ADD_ACTION_LONG') }}
</woot-button>
</BaseEmptyState> </BaseEmptyState>
</template> </template>

View File

@@ -1,11 +1,11 @@
<script> <script>
import emojis from './emojisGroup.json'; import emojis from './emojisGroup.json';
import FluentIcon from 'shared/components/FluentIcon/Index.vue'; import FluentIcon from 'shared/components/FluentIcon/Index.vue';
import WootButton from 'dashboard/components/ui/WootButton.vue'; import NextButton from 'dashboard/components-next/button/Button.vue';
const SEARCH_KEY = 'Search'; const SEARCH_KEY = 'Search';
export default { export default {
components: { FluentIcon, WootButton }, components: { FluentIcon, NextButton },
props: { props: {
onClick: { onClick: {
type: Function, type: Function,
@@ -87,30 +87,31 @@ export default {
<template> <template>
<div <div
role="dialog" role="dialog"
class="emoji-dialog bg-white shadow-lg dark:bg-slate-900 rounded-md border border-solid border-slate-75 dark:border-slate-800/50 box-content h-[18.75rem] absolute right-0 -top-[95px] w-80 z-20" class="emoji-dialog bg-n-background shadow-lg rounded-md outline outline-1 outline-n-weak box-content h-[18.75rem] absolute right-0 -top-[95px] w-80 z-20"
> >
<div class="flex flex-col"> <div class="flex flex-col">
<div class="flex gap-2 emoji-search--wrap"> <div class="flex gap-2 m-2 sticky top-2">
<input <input
ref="searchbar" ref="searchbar"
v-model="search" v-model="search"
type="text" type="text"
class="emoji-search--input focus:box-shadow-blue dark:focus:box-shadow-dark !mb-0 !h-8 !text-sm" class="focus:box-shadow-blue dark:focus:box-shadow-dark !mb-0 !h-8 !text-sm"
:placeholder="$t('EMOJI.PLACEHOLDER')" :placeholder="$t('EMOJI.PLACEHOLDER')"
/> />
<WootButton <NextButton
v-if="showRemoveButton" v-if="showRemoveButton"
size="small" faded
variant="smooth" sm
class="dark:!bg-slate-800 dark:!hover:bg-slate-700" slate
color-scheme="secondary" class="flex-shrink-0"
:label="$t('EMOJI.REMOVE')"
@click="onClick('')" @click="onClick('')"
> />
{{ $t('EMOJI.REMOVE') }}
</WootButton>
</div> </div>
<div v-if="hasNoSearch" ref="emojiItem" class="emoji-item"> <div v-if="hasNoSearch" ref="emojiItem" class="emoji-item">
<h5 class="emoji-category--title"> <h5
class="text-sm text-n-slate-12 font-medium leading-normal m-0 py-1 px-2 capitalize"
>
{{ selectedKey }} {{ selectedKey }}
</h5> </h5>
<div class="emoji--row"> <div class="emoji--row">
@@ -126,7 +127,10 @@ export default {
</div> </div>
<div v-else ref="emojiItem" class="emoji-item"> <div v-else ref="emojiItem" class="emoji-item">
<div v-for="category in filterAllEmojisBySearch" :key="category.slug"> <div v-for="category in filterAllEmojisBySearch" :key="category.slug">
<h5 v-if="category.emojis.length > 0" class="emoji-category--title"> <h5
v-if="category.emojis.length > 0"
class="text-sm text-n-slate-12 font-medium leading-normal m-0 py-1 px-2 capitalize"
>
{{ category.name }} {{ category.name }}
</h5> </h5>
<div v-if="category.emojis.length > 0" class="emoji--row"> <div v-if="category.emojis.length > 0" class="emoji--row">
@@ -140,29 +144,33 @@ export default {
/> />
</div> </div>
</div> </div>
<div v-if="hasEmptySearchResult" class="empty-message"> <div
<div class="emoji-icon"> v-if="hasEmptySearchResult"
class="items-center flex flex-col h-[13.25rem] justify-center"
>
<div class="text-n-slate-11 mb-2">
<FluentIcon icon="emoji" size="48" /> <FluentIcon icon="emoji" size="48" />
</div> </div>
<span class="empty-message--text"> <span class="text-n-slate-11 text-sm font-medium">
{{ $t('EMOJI.NOT_FOUND') }} {{ $t('EMOJI.NOT_FOUND') }}
</span> </span>
</div> </div>
</div> </div>
<div class="emoji-dialog--footer" role="menu"> <div
<ul> class="emoji-dialog--footer relative w-full py-0 rounded-b-[0.34rem] px-1 bg-n-slate-3"
role="menu"
>
<ul
class="flex relative left-[2px] rtl:left-[unset] rtl:right-[2px] list-none m-0 overflow-auto py-1 px-0"
>
<li> <li>
<button <button
class="emoji--item" class="emoji--item"
:class="{ active: selectedKey === 'Search' }" :class="{ active: selectedKey === 'Search' }"
@click="changeCategory('Search')" @click="changeCategory('Search')"
> >
<FluentIcon <FluentIcon icon="search" size="16" class="text-n-slate-11" />
icon="search"
size="16"
class="text-slate-700 dark:text-slate-100"
/>
</button> </button>
</li> </li>
<li <li
@@ -223,7 +231,7 @@ export default {
} }
.emoji--item { .emoji--item {
@apply bg-transparent border-0 rounded cursor-pointer text-lg h-6 m-0 py-0 px-1 hover:bg-slate-75 dark:hover:bg-slate-800; @apply bg-transparent border-0 rounded cursor-pointer text-lg h-6 m-0 py-0 px-1 hover:bg-n-slate-4;
} }
.emoji--row { .emoji--row {
@@ -234,53 +242,25 @@ export default {
} }
} }
.emoji-search--wrap {
@apply m-2 sticky top-2;
.emoji-search--input {
@apply text-sm focus-visible:border-transparent text-slate-800 dark:text-slate-100 h-8 m-0 p-2 w-full rounded-md bg-slate-50 dark:bg-slate-800 border border-solid border-transparent dark:border-slate-800/50;
}
}
.empty-message {
@apply items-center flex flex-col h-[13.25rem] justify-center;
.emoji-icon {
@apply text-slate-200 dark:text-slate-200 mb-2;
}
.empty-message--text {
@apply text-slate-200 dark:text-slate-200 text-sm font-medium;
}
}
.emoji-item { .emoji-item {
@apply h-[13.25rem] overflow-y-auto; @apply h-[13.25rem] overflow-y-auto;
} }
.emoji-category--title {
@apply text-slate-800 text-sm dark:text-slate-100 font-medium leading-normal m-0 py-1 px-2 capitalize;
}
.emoji-dialog--footer { .emoji-dialog--footer {
@apply relative w-full py-0 rounded-b-[0.34rem] px-1 bg-slate-75 dark:bg-slate-800;
ul { ul {
@apply flex relative left-[2px] rtl:left-[unset] rtl:right-[2px] list-none m-0 overflow-auto py-1 px-0;
> li { > li {
@apply items-center cursor-pointer flex justify-center p-1; @apply items-center cursor-pointer flex justify-center p-1;
} }
li .active { li .active {
@apply bg-white dark:bg-slate-900; @apply bg-n-background;
} }
.emoji--item { .emoji--item {
@apply items-center flex text-sm; @apply items-center flex text-sm;
&:hover { &:hover {
@apply bg-slate-75 dark:bg-slate-900; @apply bg-n-slate-2;
} }
} }
} }

View File

@@ -4,12 +4,14 @@ import Hotkey from 'dashboard/components/base/Hotkey.vue';
import AddLabelModal from 'dashboard/routes/dashboard/settings/labels/AddLabel.vue'; import AddLabelModal from 'dashboard/routes/dashboard/settings/labels/AddLabel.vue';
import { picoSearch } from '@scmmishra/pico-search'; import { picoSearch } from '@scmmishra/pico-search';
import { sanitizeLabel } from 'shared/helpers/sanitizeData'; import { sanitizeLabel } from 'shared/helpers/sanitizeData';
import NextButton from 'dashboard/components-next/button/Button.vue';
export default { export default {
components: { components: {
LabelDropdownItem, LabelDropdownItem,
AddLabelModal, AddLabelModal,
Hotkey, Hotkey,
NextButton,
}, },
props: { props: {
@@ -117,7 +119,7 @@ export default {
{{ $t('CONTACT_PANEL.LABELS.LABEL_SELECT.TITLE') }} {{ $t('CONTACT_PANEL.LABELS.LABEL_SELECT.TITLE') }}
</h4> </h4>
<Hotkey <Hotkey
custom-class="border border-solid text-slate-800 dark:text-slate-100 bg-slate-50 dark:bg-slate-600 text-xxs border-slate-75 dark:border-slate-600" custom-class="border border-solid text-slate-800 dark:text-slate-100 bg-slate-50 dark:bg-slate-600 text-xxs border-slate-75 dark:border-slate-600 flex-shrink-0"
> >
{{ 'L' }} {{ 'L' }}
</Hotkey> </Hotkey>
@@ -156,19 +158,15 @@ export default {
v-if="allowCreation && shouldShowCreate" v-if="allowCreation && shouldShowCreate"
class="flex pt-1 border-t border-solid border-slate-100 dark:border-slate-900" class="flex pt-1 border-t border-solid border-slate-100 dark:border-slate-900"
> >
<woot-button <NextButton
size="small" icon="i-lucide-plus"
variant="clear" slate
color-scheme="secondary" sm
icon="add" ghost
is-expanded :label="`${createLabelPlaceholder} ${parsedSearch}`"
class="button-new-label" :disabled="hasExactMatchInResults"
:is-disabled="hasExactMatchInResults"
@click="showCreateModal" @click="showCreateModal"
> />
{{ createLabelPlaceholder }}
{{ parsedSearch }}
</woot-button>
<woot-modal <woot-modal
v-model:show="createModalVisible" v-model:show="createModalVisible"
@@ -184,21 +182,3 @@ export default {
</div> </div>
</div> </div>
</template> </template>
<style lang="scss" scoped>
.hotkey {
@apply flex-shrink-0;
}
.search-input {
@apply m-0 w-full border border-solid border-transparent h-8 text-sm text-slate-700 dark:text-slate-100 rounded-md focus:border-woot-500 bg-slate-50 dark:bg-slate-900;
}
.button-new-label {
@apply whitespace-nowrap text-ellipsis overflow-hidden items-center;
.icon {
@apply min-w-0;
}
}
</style>

View File

@@ -6,7 +6,7 @@ import { nextTick } from 'vue';
const config = { const config = {
global: { global: {
stubs: { stubs: {
WootButton: { template: '<button />' }, NextButton: { template: '<button />' },
WootInput: { template: '<input />' }, WootInput: { template: '<input />' },
}, },
}, },

View File

@@ -13,5 +13,5 @@ config.global.plugins = [i18n, FloatingVue];
config.global.stubs = { config.global.stubs = {
WootModal: { template: '<div><slot/></div>' }, WootModal: { template: '<div><slot/></div>' },
WootModalHeader: { template: '<div><slot/></div>' }, WootModalHeader: { template: '<div><slot/></div>' },
WootButton: { template: '<button><slot/></button>' }, NextButton: { template: '<button><slot/></button>' },
}; };