diff --git a/app/components/MainComponent.vue b/app/components/MainComponent.vue index 5f40741c..343b3d2b 100644 --- a/app/components/MainComponent.vue +++ b/app/components/MainComponent.vue @@ -70,7 +70,8 @@ - + + @@ -108,6 +109,7 @@ import MetricsViewer from './MetricsViewer.vue' import BreakdownComponent from './BreakdownComponent.vue' import CopilotChatViewer from './CopilotChatViewer.vue' import SeatsAnalysisViewer from './SeatsAnalysisViewer.vue' +import TeamsComponent from './TeamsComponent.vue' import ApiResponse from './ApiResponse.vue' import AgentModeViewer from './AgentModeViewer.vue' import DateRangeSelector from './DateRangeSelector.vue' @@ -121,6 +123,7 @@ export default defineNuxtComponent({ BreakdownComponent, CopilotChatViewer, SeatsAnalysisViewer, + TeamsComponent, ApiResponse, AgentModeViewer, DateRangeSelector @@ -132,6 +135,19 @@ export default defineNuxtComponent({ this.seats = []; clear(); }, + getDisplayTabName(itemName: string): string { + // Transform scope names to display names for tabs + switch (itemName) { + case 'team-organization': + case 'team-enterprise': + return 'team'; + case 'organization': + case 'enterprise': + return itemName; + default: + return itemName; + } + }, async handleDateRangeChange(newDateRange: { since?: string; until?: string; @@ -232,7 +248,13 @@ export default defineNuxtComponent({ } }, created() { - this.tabItems.unshift(this.itemName); + this.tabItems.unshift(this.getDisplayTabName(this.itemName)); + + // Add teams tab for organization and enterprise scopes to allow team comparison + if (this.itemName === 'organization' || this.itemName === 'enterprise') { + this.tabItems.splice(1, 0, 'teams'); // Insert after the first tab + } + this.config = useRuntimeConfig(); }, async mounted() { diff --git a/app/components/SeatsAnalysisViewer.vue b/app/components/SeatsAnalysisViewer.vue index 8e34943e..cc6bb00d 100644 --- a/app/components/SeatsAnalysisViewer.vue +++ b/app/components/SeatsAnalysisViewer.vue @@ -11,11 +11,11 @@ elevation="4" color="white" variant="elevated" class="mx-auto my-4"
Total Assigned
- This metric represents the total number of Copilot seats assigned within the current organization/enterprise. + This metric represents the total number of Copilot seats assigned {{ isTeamView ? `to team "${currentTeam}"` : 'within the current organization/enterprise' }}.
- Currently assigned seats + {{ isTeamView ? `Seats assigned to team "${currentTeam}"` : 'Currently assigned seats' }}

{{ totalSeats.length }}

@@ -33,7 +33,7 @@ elevation="4" color="white" variant="elevated" class="mx-auto my-3"
Assigned But Never Used
- This metric shows seats that were assigned but never used within the current organization/enterprise. The assigned timestamp is also displayed in the chart. + This metric shows seats that were assigned but never used {{ isTeamView ? `within team "${currentTeam}"` : 'within the current organization/enterprise' }}. The assigned timestamp is also displayed in the chart.
@@ -108,7 +108,7 @@ elevation="4" color="white" variant="elevated" class="mx-auto my-3" + + \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index ae1639b4..eca5ac67 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,7 +17,7 @@ "nuxt-auth-utils": "^0.5.7", "roboto-fontface": "^0.10.0", "undici": ">=7.5.0", - "vue": "*", + "vue": "latest", "vue-chartjs": "^5.3.2", "vuetify": "^3.7.3", "webfontloader": "^1.6.28" diff --git a/tests/MainComponent.teams.spec.ts b/tests/MainComponent.teams.spec.ts new file mode 100644 index 00000000..8db4cc16 --- /dev/null +++ b/tests/MainComponent.teams.spec.ts @@ -0,0 +1,61 @@ +import { describe, test, expect } from 'vitest' + +describe('MainComponent tab name transformation', () => { + test('should transform team-organization scope to team display name', () => { + // Mock the MainComponent method logic + function getDisplayTabName(itemName: string): string { + switch (itemName) { + case 'team-organization': + case 'team-enterprise': + return 'team'; + case 'organization': + case 'enterprise': + return itemName; + default: + return itemName; + } + } + + expect(getDisplayTabName('team-organization')).toBe('team') + expect(getDisplayTabName('team-enterprise')).toBe('team') + expect(getDisplayTabName('organization')).toBe('organization') + expect(getDisplayTabName('enterprise')).toBe('enterprise') + }) + + test('should add teams tab for organization and enterprise scopes', () => { + // Mock the logic for adding teams tab + function getTabItems(scope: string): string[] { + const baseItems = ['languages', 'editors', 'copilot chat', 'seat analysis', 'api response'] + const items = [...baseItems] + + // Add main scope tab first + const displayName = scope === 'team-organization' || scope === 'team-enterprise' ? 'team' : scope + items.unshift(displayName) + + // Add teams tab for organization and enterprise scopes + if (scope === 'organization' || scope === 'enterprise') { + items.splice(1, 0, 'teams') + } + + return items + } + + const orgTabs = getTabItems('organization') + expect(orgTabs[0]).toBe('organization') + expect(orgTabs[1]).toBe('teams') + expect(orgTabs).toContain('languages') + expect(orgTabs).toContain('editors') + + const entTabs = getTabItems('enterprise') + expect(entTabs[0]).toBe('enterprise') + expect(entTabs[1]).toBe('teams') + + const teamOrgTabs = getTabItems('team-organization') + expect(teamOrgTabs[0]).toBe('team') + expect(teamOrgTabs).not.toContain('teams') // No teams tab for team scope + + const teamEntTabs = getTabItems('team-enterprise') + expect(teamEntTabs[0]).toBe('team') + expect(teamEntTabs).not.toContain('teams') // No teams tab for team scope + }) +}) \ No newline at end of file