Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .github/pr-assets/org-billing-plans.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/pr-assets/org-general.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/pr-assets/org-team-members.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions messages/en.context.json
Original file line number Diff line number Diff line change
Expand Up @@ -2590,6 +2590,7 @@
"support-usernames-prompt-save": "Used in Capgo web console areas: components/dashboard. Role: short UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"support-usernames-prompt-title": "Used in Capgo web console areas: components/dashboard. Role: section or dialog title. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"switch-to-billing-period": "Used in Capgo web console areas: components/dashboard. Role: UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"team": "Used in Capgo web console areas: constants. Role: short UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"terms-of-service": "Used in Capgo web console areas: pages. Role: UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"test": "Used in Capgo web console areas: pages/settings/organization. Role: short UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"test-bundle": "Used in Capgo web console areas: pages. Role: UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
Expand Down
1 change: 1 addition & 0 deletions messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1543,6 +1543,7 @@
"member-added": "Member added",
"member-deleted": "Successfully deleted member",
"members": "Members",
"team": "Team",
"metadata": "Metadata",
"metadata-min-ver-not-set": "Minimal update version for current bundle is undefined",
"metadata-not-found": "metadata not found",
Expand Down
3 changes: 3 additions & 0 deletions playwright/visual-diff.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ export const visualDiffRoutes: VisualDiffRoute[] = [
{ slug: 'app-overview', path: '/app/com.demo.app', auth: true },
{ slug: 'app-settings', path: '/app/com.demo.app/settings', auth: true },
{ slug: 'app-settings-access', path: '/app/com.demo.app/settings/access', auth: true },
{ slug: 'org-settings', path: '/settings/organization', auth: true },
{ slug: 'org-settings-team', path: '/settings/organization/members', auth: true },
{ slug: 'org-settings-billing', path: '/settings/organization/plans', auth: true },
Comment thread
coderabbitai[bot] marked this conversation as resolved.
{ slug: 'channels', path: '/app/com.demo.app/channels', auth: true },
{
slug: 'devices',
Expand Down
41 changes: 34 additions & 7 deletions src/components/Tabs.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,34 +7,46 @@
activeTab: string
secondaryTabs?: Tab[]
secondaryActiveTab?: string
tertiaryTabs?: Tab[]
tertiaryActiveTab?: string
noWrap?: boolean
}>()

const emit = defineEmits(['update:activeTab', 'update:secondaryActiveTab'])
const emit = defineEmits(['update:activeTab', 'update:secondaryActiveTab', 'update:tertiaryActiveTab'])

const { t } = useI18n()

function activeTabColor(tab: string, isSecondary = false) {
const isActive = (isSecondary ? props.secondaryActiveTab : props.activeTab) === tab
function activeTabColor(tab: string, row: 'primary' | 'secondary' | 'tertiary' = 'primary') {
const isActive = row === 'tertiary'
? props.tertiaryActiveTab === tab
: row === 'secondary'
? props.secondaryActiveTab === tab
: props.activeTab === tab

Check warning on line 24 in src/components/Tabs.vue

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Extract this nested ternary operation into an independent statement.

See more on https://sonarcloud.io/project/issues?id=Cap-go_capgo&issues=AZ_20aDAXgDmGUzTX8hL&open=AZ_20aDAXgDmGUzTX8hL&pullRequest=3019

// Secondary row tabs
if (isSecondary) {
if (row === 'tertiary') {
return isActive
? 'border-b-2 border-blue-600 text-blue-600 dark:border-blue-400 dark:text-blue-400'
: 'border-b-2 border-transparent text-slate-500/75 dark:text-slate-400/75 hover:text-slate-700 dark:hover:text-slate-200'
}

if (row === 'secondary') {
return isActive
? 'text-blue-600 dark:text-blue-400 bg-white dark:bg-slate-800 border border-blue-200/70 dark:border-blue-800 shadow-sm hover:ring-1 hover:ring-blue-200 dark:hover:ring-blue-700 hover:bg-blue-50 dark:hover:bg-slate-900 transition-colors'
: 'border border-transparent text-slate-500/75 dark:text-slate-400/75 hover:bg-white dark:hover:bg-slate-900 hover:text-slate-700 dark:hover:text-slate-200 transition-colors'
}

// Primary row tabs - open tab style
return isActive
? 'text-blue-500 dark:text-blue-300 bg-blue-50 dark:bg-slate-800/40 border-t border-l border-r border-blue-200/60 dark:border-blue-800/70 border-b-0 before:content-[\'\'] before:absolute before:bottom-[-1px] before:left-0 before:right-0 before:h-[3px] before:bg-blue-50 dark:before:bg-[#141e33] before:z-[11] hover:bg-blue-100 dark:hover:bg-[#1e3050] transition-colors'
: 'border border-transparent text-slate-500/75 dark:text-slate-400/75 hover:bg-blue-100/70 dark:hover:bg-[#1a2744cc] hover:text-slate-700 dark:hover:text-slate-200 transition-colors'
}

const ulPrimaryClass = 'flex text-xs md:text-sm font-medium text-center text-gray-500 dark:text-gray-300 gap-1 pt-1 px-1'
const ulSecondaryClass = 'flex text-sm font-medium text-center text-gray-600 dark:text-gray-200 gap-2 py-2'
const ulTertiaryClass = 'flex text-sm font-medium text-center text-gray-600 dark:text-gray-200 gap-1 px-1'
const noWrapClass = 'flex-nowrap max-w-full overflow-x-auto overflow-y-hidden overscroll-x-contain touch-pan-x no-scrollbar px-1 pb-px'
const buttonPrimaryClass = 'inline-flex items-center gap-2 px-3 py-2 min-w-[42px] min-h-[38px] rounded-t-md cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2 focus-visible:ring-offset-slate-50 dark:focus-visible:ring-offset-slate-900 transition-all group relative'
const buttonSecondaryClass = 'inline-flex items-center gap-2 px-3 py-1.5 rounded-md cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2 focus-visible:ring-offset-slate-50 dark:focus-visible:ring-offset-slate-900 transition-colors group'
const buttonTertiaryClass = 'inline-flex items-center gap-2 px-3 py-2 cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2 focus-visible:ring-offset-slate-50 dark:focus-visible:ring-offset-slate-900 transition-colors group'
Comment thread
coderabbitai[bot] marked this conversation as resolved.
const iconClass = 'w-5 h-5 transition-colors'
const labelClass = 'hidden md:block text-xs md:text-sm font-medium transition-colors first-letter:uppercase'
</script>
Expand Down Expand Up @@ -65,7 +77,7 @@
type="button"
:aria-current="secondaryActiveTab === tab.key ? 'page' : undefined"
:aria-label="t(tab.label)"
:class="[buttonSecondaryClass, activeTabColor(tab.key, true)]"
:class="[buttonSecondaryClass, activeTabColor(tab.key, 'secondary')]"
@click="emit('update:secondaryActiveTab', tab.key)"
>
<component :is="tab.icon" :class="iconClass" />
Expand All @@ -74,6 +86,21 @@
</button>
</li>
</ul>
<ul v-if="tertiaryTabs?.length" :class="[ulTertiaryClass, noWrap ? noWrapClass : 'flex-wrap']">
<li v-for="(tab, i) in tertiaryTabs" :key="i" class="mr-1">
<button
type="button"
:aria-current="tertiaryActiveTab === tab.key ? 'page' : undefined"
:aria-label="t(tab.label)"
:class="[buttonTertiaryClass, activeTabColor(tab.key, 'tertiary')]"
@click="emit('update:tertiaryActiveTab', tab.key)"
>
<component :is="tab.icon" :class="iconClass" />
<span :class="labelClass">{{ t(tab.label) }}</span>
<span v-if="tab.badge" class="hidden px-1.5 py-0.5 text-[10px] font-semibold uppercase rounded border md:inline border-azure-500/40 bg-azure-500/10 text-azure-700 dark:text-azure-200">{{ t(tab.badge) }}</span>
</button>
</li>
</ul>
</div>
</div>
</template>
1 change: 1 addition & 0 deletions src/components/comp_def.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,5 @@ export interface Tab<T = TableRow> {
badge?: string
onClick?: (elem: T | undefined) => void
redirect?: boolean
children?: Tab<T>[]
}
25 changes: 20 additions & 5 deletions src/constants/organizationTabs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,29 @@ import IconWebhook from '~icons/heroicons/globe-alt'
import IconInfo from '~icons/heroicons/information-circle'
import IconSecurity from '~icons/heroicons/shield-check'
import IconUsers from '~icons/heroicons/users'
import { BILLING_TAB_KEY, TEAM_TAB_KEY } from '~/utils/organizationTabs'

export const organizationTabs: Tab[] = [
{ label: 'general', key: '/settings/organization', icon: IconInfo },
{ label: 'members', key: '/settings/organization/members', icon: IconUsers },
{ label: 'groups', key: '/settings/organization/groups', icon: IconUsers },
{ label: 'plans', key: '/settings/organization/plans', icon: IconPlan },
{ label: 'credits', key: '/settings/organization/credits', icon: IconCredits },
{ label: 'security', key: '/settings/organization/security', icon: IconSecurity },
{
label: 'team',
key: TEAM_TAB_KEY,
icon: IconUsers,
children: [
{ label: 'members', key: '/settings/organization/members', icon: IconUsers },
{ label: 'groups', key: '/settings/organization/groups', icon: IconUsers },
{ label: 'security', key: '/settings/organization/security', icon: IconSecurity },
],
},
{
label: 'billing',
key: BILLING_TAB_KEY,
icon: IconPlan,
children: [
{ label: 'plans', key: '/settings/organization/plans', icon: IconPlan },
{ label: 'credits', key: '/settings/organization/credits', icon: IconCredits },
],
},
{ label: 'usage', key: '/settings/organization/usage', icon: IconChart },
{ label: 'notifications', key: '/settings/organization/notifications', icon: IconBell },
{ label: 'audit-logs', key: '/settings/organization/auditlogs', icon: IconAudit },
Expand Down
Loading
Loading