session-wrap-dashboard 3.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +6 -0
- package/coverage/base.css +224 -0
- package/coverage/block-navigation.js +87 -0
- package/coverage/coverage-final.json +6 -0
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +146 -0
- package/coverage/prettify.css +1 -0
- package/coverage/prettify.js +2 -0
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +210 -0
- package/coverage/src/auth.ts.html +307 -0
- package/coverage/src/components/Header.tsx.html +262 -0
- package/coverage/src/components/Sidebar.tsx.html +262 -0
- package/coverage/src/components/index.html +131 -0
- package/coverage/src/hooks/index.html +131 -0
- package/coverage/src/hooks/useAuth.ts.html +292 -0
- package/coverage/src/hooks/useWorkspace.ts.html +475 -0
- package/coverage/src/index.html +116 -0
- package/index.html +13 -0
- package/package.json +49 -0
- package/playwright.config.ts +38 -0
- package/postcss.config.js +6 -0
- package/src/App.tsx +67 -0
- package/src/api.ts +130 -0
- package/src/auth.ts +74 -0
- package/src/components/AgentLeaderboard.tsx +84 -0
- package/src/components/AnalyticsDashboard.tsx +223 -0
- package/src/components/Header.tsx +62 -0
- package/src/components/IntegrationManager.tsx +292 -0
- package/src/components/RoleManager.tsx +230 -0
- package/src/components/Sidebar.tsx +62 -0
- package/src/components/TrendChart.tsx +92 -0
- package/src/components/WorkspaceSelector.tsx +157 -0
- package/src/components/__tests__/Header.test.tsx +64 -0
- package/src/components/__tests__/Sidebar.test.tsx +39 -0
- package/src/components/index.ts +8 -0
- package/src/hooks/__tests__/useAuth.test.ts +88 -0
- package/src/hooks/__tests__/useWorkspace.test.ts +101 -0
- package/src/hooks/index.ts +4 -0
- package/src/hooks/useAnalytics.ts +76 -0
- package/src/hooks/useApi.ts +62 -0
- package/src/hooks/useAuth.ts +69 -0
- package/src/hooks/useWorkspace.ts +130 -0
- package/src/index.css +57 -0
- package/src/main.tsx +13 -0
- package/src/pages/DashboardPage.tsx +13 -0
- package/src/pages/HomePage.tsx +156 -0
- package/src/pages/IntegrationsPage.tsx +9 -0
- package/src/pages/RolesPage.tsx +9 -0
- package/src/pages/SettingsPage.tsx +118 -0
- package/src/pages/WorkspacesPage.tsx +9 -0
- package/src/pages/index.ts +6 -0
- package/src/test/setup.ts +31 -0
- package/src/test/utils.tsx +15 -0
- package/src/types.ts +132 -0
- package/tailwind.config.js +11 -0
- package/tests/e2e/auth.spec.ts +42 -0
- package/tests/e2e/dashboard.spec.ts +52 -0
- package/tests/e2e/integrations.spec.ts +91 -0
- package/tests/e2e/workspaces.spec.ts +78 -0
- package/tsconfig.json +26 -0
- package/tsconfig.node.json +10 -0
- package/vite.config.ts +26 -0
- package/vitest.config.ts +31 -0
package/src/types.ts
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript 類型定義 - 與後端 API 對應
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// 認證
|
|
6
|
+
export interface User {
|
|
7
|
+
id: string
|
|
8
|
+
github_login: string
|
|
9
|
+
email?: string
|
|
10
|
+
created_at: string
|
|
11
|
+
subscription?: {
|
|
12
|
+
subscription_status: 'active' | 'expired'
|
|
13
|
+
verified_at: string
|
|
14
|
+
expires_at: string
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// 工作區
|
|
19
|
+
export interface Workspace {
|
|
20
|
+
id: string
|
|
21
|
+
name: string
|
|
22
|
+
owner_id: string
|
|
23
|
+
is_public: boolean
|
|
24
|
+
created_at: string
|
|
25
|
+
updated_at: string
|
|
26
|
+
roles?: string[]
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface WorkspaceMember {
|
|
30
|
+
id: string
|
|
31
|
+
github_login: string
|
|
32
|
+
email: string
|
|
33
|
+
avatar_url: string | null
|
|
34
|
+
roles: string[]
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// 分析
|
|
38
|
+
export interface AnalyticsDashboard {
|
|
39
|
+
snapshot: {
|
|
40
|
+
id: string
|
|
41
|
+
workspace_id: string
|
|
42
|
+
snapshot_date: string
|
|
43
|
+
total_tasks: number
|
|
44
|
+
completed_tasks: number
|
|
45
|
+
pending_tasks: number
|
|
46
|
+
in_progress_tasks: number
|
|
47
|
+
total_decisions: number
|
|
48
|
+
avg_decision_quality: number
|
|
49
|
+
active_agents: number
|
|
50
|
+
agent_participation: Record<string, number>
|
|
51
|
+
}
|
|
52
|
+
completion_rate: number
|
|
53
|
+
trends: AnalyticsTrend[]
|
|
54
|
+
top_agents: AgentPerformance[]
|
|
55
|
+
period_days: number
|
|
56
|
+
timestamp: string
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface AnalyticsTrend {
|
|
60
|
+
snapshot_date: string
|
|
61
|
+
total_tasks: number
|
|
62
|
+
completed_tasks: number
|
|
63
|
+
pending_tasks: number
|
|
64
|
+
in_progress_tasks: number
|
|
65
|
+
total_decisions: number
|
|
66
|
+
avg_decision_quality: number
|
|
67
|
+
active_agents: number
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface AgentPerformance {
|
|
71
|
+
agent_name: string
|
|
72
|
+
tasks_created: number
|
|
73
|
+
tasks_completed: number
|
|
74
|
+
comments_added: number
|
|
75
|
+
decisions_logged: number
|
|
76
|
+
avg_response_time: number
|
|
77
|
+
error_count: number
|
|
78
|
+
efficiency_score?: number
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export interface Insight {
|
|
82
|
+
type: 'positive' | 'warning' | 'info'
|
|
83
|
+
message: string
|
|
84
|
+
recommendation: string
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// 集成
|
|
88
|
+
export interface Integration {
|
|
89
|
+
id: string
|
|
90
|
+
service_name: 'slack' | 'github' | 'jira'
|
|
91
|
+
is_active: boolean
|
|
92
|
+
created_at: string
|
|
93
|
+
updated_at: string
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export interface IntegrationEvent {
|
|
97
|
+
id: string
|
|
98
|
+
event_type: string
|
|
99
|
+
status: 'success' | 'failed'
|
|
100
|
+
error_message: string | null
|
|
101
|
+
payload: Record<string, any>
|
|
102
|
+
created_at: string
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// 角色
|
|
106
|
+
export interface Role {
|
|
107
|
+
id: string
|
|
108
|
+
name: string
|
|
109
|
+
description: string
|
|
110
|
+
permissions: Record<string, string[]>
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export interface UserRole {
|
|
114
|
+
id: string
|
|
115
|
+
user_id: string
|
|
116
|
+
role_id: string
|
|
117
|
+
workspace_id: string
|
|
118
|
+
granted_by: string
|
|
119
|
+
granted_at: string
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Session Wraps
|
|
123
|
+
export interface SessionWrap {
|
|
124
|
+
id: string
|
|
125
|
+
workspace_name: string
|
|
126
|
+
wrap_date: string
|
|
127
|
+
summary: string
|
|
128
|
+
memory_size: number
|
|
129
|
+
obsidian_files_count: number
|
|
130
|
+
created_at: string
|
|
131
|
+
updated_at: string
|
|
132
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { test, expect } from '@playwright/test'
|
|
2
|
+
|
|
3
|
+
test.describe('Authentication Flow', () => {
|
|
4
|
+
test('should display login page', async ({ page }) => {
|
|
5
|
+
await page.goto('/')
|
|
6
|
+
|
|
7
|
+
// Check if we're on the home page or redirected to login
|
|
8
|
+
const heading = page.locator('h1, h2').first()
|
|
9
|
+
await expect(heading).toBeVisible()
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
test('should navigate through protected routes', async ({ page }) => {
|
|
13
|
+
await page.goto('/dashboard')
|
|
14
|
+
|
|
15
|
+
// Should see dashboard or be redirected to login
|
|
16
|
+
const dashboardContent = page.locator('[data-testid="dashboard"]')
|
|
17
|
+
const loginForm = page.locator('form, [data-testid="login"]')
|
|
18
|
+
|
|
19
|
+
const isDashboard = await dashboardContent.isVisible().catch(() => false)
|
|
20
|
+
const isLogin = await loginForm.isVisible().catch(() => false)
|
|
21
|
+
|
|
22
|
+
expect(isDashboard || isLogin).toBeTruthy()
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
test('should display sidebar navigation', async ({ page }) => {
|
|
26
|
+
await page.goto('/')
|
|
27
|
+
|
|
28
|
+
const sidebar = page.locator('[data-testid="sidebar"], nav').first()
|
|
29
|
+
await expect(sidebar).toBeVisible()
|
|
30
|
+
|
|
31
|
+
// Check navigation items exist
|
|
32
|
+
const navItems = page.locator('nav a, [data-testid="nav-item"]')
|
|
33
|
+
await expect(navItems.first()).toBeVisible()
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
test('should display header with workspace selector', async ({ page }) => {
|
|
37
|
+
await page.goto('/')
|
|
38
|
+
|
|
39
|
+
const header = page.locator('header, [data-testid="header"]').first()
|
|
40
|
+
await expect(header).toBeVisible()
|
|
41
|
+
})
|
|
42
|
+
})
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { test, expect } from '@playwright/test'
|
|
2
|
+
|
|
3
|
+
test.describe('Analytics Dashboard', () => {
|
|
4
|
+
test.beforeEach(async ({ page }) => {
|
|
5
|
+
await page.goto('/dashboard')
|
|
6
|
+
})
|
|
7
|
+
|
|
8
|
+
test('should display dashboard heading', async ({ page }) => {
|
|
9
|
+
const heading = page.locator('h1, h2').first()
|
|
10
|
+
const title = page.locator('title')
|
|
11
|
+
|
|
12
|
+
const content = await heading.textContent().catch(() => '')
|
|
13
|
+
const pageTitle = await title.textContent().catch(() => '')
|
|
14
|
+
|
|
15
|
+
expect(content || pageTitle).toBeTruthy()
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
test('should display KPI cards', async ({ page }) => {
|
|
19
|
+
const cards = page.locator('[data-testid="kpi-card"], .card, [class*="Card"]')
|
|
20
|
+
|
|
21
|
+
// Expect at least some cards to be visible
|
|
22
|
+
const count = await cards.count().catch(() => 0)
|
|
23
|
+
expect(count).toBeGreaterThanOrEqual(0)
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
test('should display charts', async ({ page }) => {
|
|
27
|
+
const charts = page.locator('[data-testid="chart"], svg, canvas')
|
|
28
|
+
|
|
29
|
+
// Expect some chart elements
|
|
30
|
+
const count = await charts.count().catch(() => 0)
|
|
31
|
+
// At least SVG or canvas elements should exist for charts
|
|
32
|
+
expect(count).toBeGreaterThanOrEqual(0)
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
test('should have responsive layout', async ({ page }) => {
|
|
36
|
+
// Test mobile view
|
|
37
|
+
await page.setViewportSize({ width: 375, height: 667 })
|
|
38
|
+
|
|
39
|
+
const sidebar = page.locator('[data-testid="sidebar"], nav').first()
|
|
40
|
+
// Sidebar might be hidden on mobile, that's okay
|
|
41
|
+
const isSidebarVisible = await sidebar.isVisible().catch(() => false)
|
|
42
|
+
expect(typeof isSidebarVisible).toBe('boolean')
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
test('should display navigation tabs', async ({ page }) => {
|
|
46
|
+
const tabs = page.locator('[role="tab"], [data-testid="nav-tab"], button[class*="tab"]')
|
|
47
|
+
const count = await tabs.count().catch(() => 0)
|
|
48
|
+
|
|
49
|
+
// Tab navigation should exist
|
|
50
|
+
expect(typeof count).toBe('number')
|
|
51
|
+
})
|
|
52
|
+
})
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { test, expect } from '@playwright/test'
|
|
2
|
+
|
|
3
|
+
test.describe('Integrations Setup', () => {
|
|
4
|
+
test.beforeEach(async ({ page }) => {
|
|
5
|
+
await page.goto('/integrations')
|
|
6
|
+
})
|
|
7
|
+
|
|
8
|
+
test('should display integrations page', async ({ page }) => {
|
|
9
|
+
const heading = page.locator('h1, h2').first()
|
|
10
|
+
const content = await heading.textContent().catch(() => '')
|
|
11
|
+
|
|
12
|
+
expect(content).toBeTruthy()
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
test('should display integration cards', async ({ page }) => {
|
|
16
|
+
const integrationCards = page.locator('[data-testid="integration-card"], [class*="integration"]')
|
|
17
|
+
|
|
18
|
+
const count = await integrationCards.count().catch(() => 0)
|
|
19
|
+
// Should have at least some integration options
|
|
20
|
+
expect(count).toBeGreaterThanOrEqual(0)
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
test('should display Slack integration option', async ({ page }) => {
|
|
24
|
+
const slack = page.locator('text=Slack, [data-testid="slack-integration"], [class*="slack"]')
|
|
25
|
+
|
|
26
|
+
const count = await slack.count().catch(() => 0)
|
|
27
|
+
expect(typeof count).toBe('number')
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
test('should display GitHub integration option', async ({ page }) => {
|
|
31
|
+
const github = page.locator('text=GitHub, [data-testid="github-integration"], [class*="github"]')
|
|
32
|
+
|
|
33
|
+
const count = await github.count().catch(() => 0)
|
|
34
|
+
expect(typeof count).toBe('number')
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
test('should display Jira integration option', async ({ page }) => {
|
|
38
|
+
const jira = page.locator('text=Jira, [data-testid="jira-integration"], [class*="jira"]')
|
|
39
|
+
|
|
40
|
+
const count = await jira.count().catch(() => 0)
|
|
41
|
+
expect(typeof count).toBe('number')
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
test('should have setup/connect buttons', async ({ page }) => {
|
|
45
|
+
const buttons = page.locator('button:has-text("Connect"), button:has-text("Setup"), button[data-testid*="connect"]')
|
|
46
|
+
|
|
47
|
+
const count = await buttons.count().catch(() => 0)
|
|
48
|
+
expect(typeof count).toBe('number')
|
|
49
|
+
})
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
test.describe('Settings Page', () => {
|
|
53
|
+
test.beforeEach(async ({ page }) => {
|
|
54
|
+
await page.goto('/settings')
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
test('should display settings page', async ({ page }) => {
|
|
58
|
+
const heading = page.locator('h1, h2').first()
|
|
59
|
+
const content = await heading.textContent().catch(() => '')
|
|
60
|
+
|
|
61
|
+
expect(content).toBeTruthy()
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
test('should display account section', async ({ page }) => {
|
|
65
|
+
const accountSection = page.locator('text=Account, [data-testid="account-section"]')
|
|
66
|
+
|
|
67
|
+
const count = await accountSection.count().catch(() => 0)
|
|
68
|
+
expect(typeof count).toBe('number')
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
test('should display preferences section', async ({ page }) => {
|
|
72
|
+
const prefsSection = page.locator('text=Preferences, text=Settings, [data-testid="preferences-section"]')
|
|
73
|
+
|
|
74
|
+
const count = await prefsSection.count().catch(() => 0)
|
|
75
|
+
expect(typeof count).toBe('number')
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
test('should have toggles for options', async ({ page }) => {
|
|
79
|
+
const toggles = page.locator('[role="switch"], input[type="checkbox"], [class*="toggle"]')
|
|
80
|
+
|
|
81
|
+
const count = await toggles.count().catch(() => 0)
|
|
82
|
+
expect(typeof count).toBe('number')
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
test('should have theme selector', async ({ page }) => {
|
|
86
|
+
const theme = page.locator('[data-testid="theme-selector"], select[name*="theme"]')
|
|
87
|
+
|
|
88
|
+
const count = await theme.count().catch(() => 0)
|
|
89
|
+
expect(typeof count).toBe('number')
|
|
90
|
+
})
|
|
91
|
+
})
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { test, expect } from '@playwright/test'
|
|
2
|
+
|
|
3
|
+
test.describe('Workspaces Management', () => {
|
|
4
|
+
test.beforeEach(async ({ page }) => {
|
|
5
|
+
await page.goto('/workspaces')
|
|
6
|
+
})
|
|
7
|
+
|
|
8
|
+
test('should display workspaces page', async ({ page }) => {
|
|
9
|
+
const heading = page.locator('h1, h2').first()
|
|
10
|
+
const content = await heading.textContent().catch(() => '')
|
|
11
|
+
|
|
12
|
+
expect(content).toBeTruthy()
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
test('should display workspace list or grid', async ({ page }) => {
|
|
16
|
+
const workspaceCards = page.locator('[data-testid="workspace-card"], [class*="workspace"], [class*="Workspace"]')
|
|
17
|
+
|
|
18
|
+
// Expect workspace container to exist
|
|
19
|
+
const count = await workspaceCards.count().catch(() => 0)
|
|
20
|
+
expect(typeof count).toBe('number')
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
test('should have create workspace button', async ({ page }) => {
|
|
24
|
+
const createBtn = page.locator('button:has-text("Create"), button[data-testid="create-workspace"]')
|
|
25
|
+
|
|
26
|
+
// At least one create button should exist
|
|
27
|
+
const count = await createBtn.count().catch(() => 0)
|
|
28
|
+
expect(count).toBeGreaterThanOrEqual(0)
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
test('should display workspace details', async ({ page }) => {
|
|
32
|
+
const workspaceInfo = page.locator('[data-testid="workspace-info"], [class*="info"], .details')
|
|
33
|
+
|
|
34
|
+
const count = await workspaceInfo.count().catch(() => 0)
|
|
35
|
+
expect(typeof count).toBe('number')
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
test('should have workspace actions', async ({ page }) => {
|
|
39
|
+
const actions = page.locator('button[data-testid*="action"], button[class*="action"]')
|
|
40
|
+
|
|
41
|
+
const count = await actions.count().catch(() => 0)
|
|
42
|
+
expect(typeof count).toBe('number')
|
|
43
|
+
})
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
test.describe('Roles & Members Management', () => {
|
|
47
|
+
test.beforeEach(async ({ page }) => {
|
|
48
|
+
await page.goto('/roles')
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
test('should display roles page', async ({ page }) => {
|
|
52
|
+
const heading = page.locator('h1, h2').first()
|
|
53
|
+
const content = await heading.textContent().catch(() => '')
|
|
54
|
+
|
|
55
|
+
expect(content).toBeTruthy()
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
test('should display members list', async ({ page }) => {
|
|
59
|
+
const members = page.locator('[data-testid="member"], [class*="member"], table tbody tr')
|
|
60
|
+
|
|
61
|
+
const count = await members.count().catch(() => 0)
|
|
62
|
+
expect(typeof count).toBe('number')
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
test('should have role assignment UI', async ({ page }) => {
|
|
66
|
+
const roleSelects = page.locator('select[data-testid*="role"], [data-testid*="role-select"]')
|
|
67
|
+
|
|
68
|
+
const count = await roleSelects.count().catch(() => 0)
|
|
69
|
+
expect(typeof count).toBe('number')
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
test('should have add member button', async ({ page }) => {
|
|
73
|
+
const addBtn = page.locator('button:has-text("Add"), button[data-testid="add-member"]')
|
|
74
|
+
|
|
75
|
+
const count = await addBtn.count().catch(() => 0)
|
|
76
|
+
expect(typeof count).toBe('number')
|
|
77
|
+
})
|
|
78
|
+
})
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"useDefineForClassFields": true,
|
|
5
|
+
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
|
6
|
+
"module": "ESNext",
|
|
7
|
+
"skipLibCheck": true,
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
"allowSyntheticDefaultImports": true,
|
|
10
|
+
"types": ["vite/client"],
|
|
11
|
+
|
|
12
|
+
"strict": true,
|
|
13
|
+
"noUnusedLocals": true,
|
|
14
|
+
"noUnusedParameters": true,
|
|
15
|
+
"noFallthroughCasesInSwitch": true,
|
|
16
|
+
|
|
17
|
+
"moduleResolution": "bundler",
|
|
18
|
+
"allowImportingTsExtensions": true,
|
|
19
|
+
"resolveJsonModule": true,
|
|
20
|
+
"isolatedModules": true,
|
|
21
|
+
"noEmit": true,
|
|
22
|
+
"jsx": "react-jsx"
|
|
23
|
+
},
|
|
24
|
+
"include": ["src"],
|
|
25
|
+
"references": [{ "path": "./tsconfig.node.json" }]
|
|
26
|
+
}
|
package/vite.config.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { defineConfig } from 'vite'
|
|
2
|
+
import react from '@vitejs/plugin-react'
|
|
3
|
+
|
|
4
|
+
export default defineConfig({
|
|
5
|
+
plugins: [react()],
|
|
6
|
+
server: {
|
|
7
|
+
port: 3001,
|
|
8
|
+
proxy: {
|
|
9
|
+
'/api': {
|
|
10
|
+
target: 'http://localhost:3000',
|
|
11
|
+
changeOrigin: true,
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
build: {
|
|
16
|
+
outDir: 'dist',
|
|
17
|
+
sourcemap: false,
|
|
18
|
+
rollupOptions: {
|
|
19
|
+
output: {
|
|
20
|
+
manualChunks: {
|
|
21
|
+
recharts: ['recharts']
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
})
|
package/vitest.config.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { defineConfig } from 'vitest/config'
|
|
2
|
+
import react from '@vitejs/plugin-react'
|
|
3
|
+
import path from 'path'
|
|
4
|
+
|
|
5
|
+
export default defineConfig({
|
|
6
|
+
plugins: [react()],
|
|
7
|
+
test: {
|
|
8
|
+
environment: 'happy-dom',
|
|
9
|
+
globals: true,
|
|
10
|
+
setupFiles: ['./src/test/setup.ts'],
|
|
11
|
+
coverage: {
|
|
12
|
+
provider: 'v8',
|
|
13
|
+
reporter: ['text', 'json', 'html'],
|
|
14
|
+
exclude: [
|
|
15
|
+
'node_modules/',
|
|
16
|
+
'src/test/',
|
|
17
|
+
'**/*.d.ts',
|
|
18
|
+
'**/index.ts'
|
|
19
|
+
],
|
|
20
|
+
lines: 70,
|
|
21
|
+
functions: 70,
|
|
22
|
+
branches: 65,
|
|
23
|
+
statements: 70
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
resolve: {
|
|
27
|
+
alias: {
|
|
28
|
+
'@': path.resolve(__dirname, './src')
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
})
|