Files
chatwoot/app/javascript/dashboard/components-next/sidebar/SidebarSubGroup.vue
Shivam Mishra ef7bf66476 feat: Add frontend changes for Captain limits (#10749)
This PR introduces several improvements to the Captain AI dashboard
section:

- New billing page, with new colors, layout and meters for Captain usage
- Updated the base paywall component to use new colors
- Updated PageLayout.vue, it's more generic and can be used for other
pages as well
   - Use flags to toggle empty state and loading state
- Add prop for `featureFlag` to show the paywall slot based on feature
enabled on account
- Update `useAccount` to add a `isCloudFeatureEnabled`
- **Removed feature flag checks from captain route definitions**, so the
captain entry will always be visible on the sidebar
- Add banner to Captain pages for the following cases
   - Responses usage is over 80%
   - Documents limit is fully exhausted


### Screenshots

<details><summary>Free plan</summary>
<p>

![CleanShot 2025-01-22 at 18 37
11@2x](https://github.com/user-attachments/assets/17d3ddba-9095-4e81-9b6f-45b5f69e6a3f)
![CleanShot 2025-01-22 at 18 37
04@2x](https://github.com/user-attachments/assets/df9bb0a6-085f-45da-97d4-74cbcc33fc7e)


</p>
</details> 

<details><summary>Paid plan</summary>
<p>

![CleanShot 2025-01-22 at 18 36
45@2x](https://github.com/user-attachments/assets/a7ccf9d4-143b-49e4-8149-83c7a7985023)

![CleanShot 2025-01-22 at 20 23
57@2x](https://github.com/user-attachments/assets/c6ce35ba-e537-486d-85c8-4cc2d4e76438)


</p>
</details>

---------

Co-authored-by: Sojan Jose <sojan@pepalo.com>
Co-authored-by: Pranav <pranav@chatwoot.com>
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2025-01-24 09:21:09 -08:00

118 lines
3.5 KiB
Vue

<script setup>
import { computed, ref } from 'vue';
import SidebarGroupLeaf from './SidebarGroupLeaf.vue';
import SidebarGroupSeparator from './SidebarGroupSeparator.vue';
import SidebarGroupEmptyLeaf from './SidebarGroupEmptyLeaf.vue';
import { useSidebarContext } from './provider';
import { useEventListener } from '@vueuse/core';
const props = defineProps({
isExpanded: { type: Boolean, default: false },
label: { type: String, required: true },
icon: { type: [Object, String], required: true },
children: { type: Array, default: undefined },
activeChild: { type: Object, default: undefined },
});
const { isAllowed, isOnChatwootCloud } = useSidebarContext();
const scrollableContainer = ref(null);
const accessibleItems = computed(() =>
props.children.filter(child => {
if (child.showOnlyOnCloud && !isOnChatwootCloud.value) return false;
return child.to && isAllowed(child.to);
})
);
const hasAccessibleItems = computed(() => {
if (props.children.length === 0) {
// cases like segment, folder and labels where users can create new items
return true;
}
return accessibleItems.value.length > 0;
});
const isScrollable = computed(() => {
return accessibleItems.value.length > 7;
});
const scrollEnd = ref(false);
// set scrollEnd to true when the scroll reaches the end
useEventListener(scrollableContainer, 'scroll', () => {
const { scrollHeight, scrollTop, clientHeight } = scrollableContainer.value;
scrollEnd.value = scrollHeight - scrollTop === clientHeight;
});
</script>
<template>
<SidebarGroupSeparator
v-if="hasAccessibleItems"
v-show="isExpanded"
:label
:icon
class="my-1"
/>
<ul class="m-0 list-none reset-base relative group">
<!-- Each element has h-8, which is 32px, we will show 7 items with one hidden at the end,
which is 14rem. Then we add 16px so that we have some text visible from the next item -->
<div
ref="scrollableContainer"
:class="{
'max-h-[calc(14rem+16px)] overflow-y-scroll no-scrollbar': isScrollable,
}"
>
<template v-if="children.length">
<SidebarGroupLeaf
v-for="child in children"
v-show="isExpanded || activeChild?.name === child.name"
v-bind="child"
:key="child.name"
:active="activeChild?.name === child.name"
/>
</template>
<SidebarGroupEmptyLeaf v-else v-show="isExpanded" class="ml-3 rtl:mr-3" />
</div>
<div
v-if="isScrollable && isExpanded"
v-show="!scrollEnd"
class="absolute bg-gradient-to-t from-n-solid-2 w-full h-12 to-transparent -bottom-1 pointer-events-none flex items-end justify-end px-2 animate-fade-in-up"
>
<svg
width="16"
height="24"
viewBox="0 0 16 24"
fill="none"
class="text-n-slate-9 opacity-50 group-hover:opacity-100"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M4 4L8 8L12 4"
stroke="currentColor"
opacity="0.5"
stroke-width="1.33333"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M4 10L8 14L12 10"
stroke="currentColor"
opacity="0.75"
stroke-width="1.33333"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M4 16L8 20L12 16"
stroke="currentColor"
stroke-width="1.33333"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</div>
</ul>
</template>