diff --git a/frontend/src/account/useAccountDashboard.js b/frontend/src/account/useAccountDashboard.js index a5ca904..d7b11da 100644 --- a/frontend/src/account/useAccountDashboard.js +++ b/frontend/src/account/useAccountDashboard.js @@ -1,6 +1,5 @@ import { computed, onMounted, reactive, ref, watch } from "vue"; import { auth, authFetch, login } from "@/auth"; - /** * Build the Account page dashboard and admin action state. * diff --git a/frontend/src/styles/onboarding-guides.css b/frontend/src/styles/onboarding-guides.css new file mode 100644 index 0000000..5b301bc --- /dev/null +++ b/frontend/src/styles/onboarding-guides.css @@ -0,0 +1,146 @@ +.guide-details { + margin-top: 10px; +} + +.guide-summary { + cursor: pointer; + display: inline-flex; + align-items: center; + gap: 10px; + padding: 6px 12px; + border-radius: 999px; + border: 1px solid rgba(92, 214, 167, 0.5); + background: rgba(92, 214, 167, 0.15); + color: var(--text-strong); + font-weight: 600; +} + +.guide-summary::after { + content: "Tap to open"; + font-size: 12px; + color: var(--text-muted); +} + +.guide-details[open] .guide-summary::after { + content: "Tap to close"; +} + +.guide-summary::-webkit-details-marker { + display: none; +} + +.guide-groups { + display: grid; + gap: 12px; + margin-top: 8px; +} + +.guide-title { + margin: 0 0 6px; +} + +.guide-images { + display: grid; + gap: 10px; +} + +.guide-shot { + border-radius: 10px; + overflow: hidden; + border: 1px solid rgba(255, 255, 255, 0.1); + background: rgba(0, 0, 0, 0.2); + padding: 0; + cursor: zoom-in; + display: flex; + flex-direction: column; + gap: 6px; +} + +.guide-shot figcaption { + margin: 0; + padding: 10px 12px 6px; + font-size: 18px; + font-weight: 600; + color: var(--text-strong); +} + +.guide-shot img { + display: block; + border-radius: 10px; + max-width: 100%; + width: auto; + height: auto; + max-height: min(60vh, 520px); + margin: 0 auto 10px; +} + +.guide-pagination { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; + flex-wrap: wrap; +} + +.guide-dots { + display: flex; + gap: 6px; + flex-wrap: wrap; +} + +.guide-dot { + border: 1px solid rgba(255, 255, 255, 0.18); + background: rgba(0, 0, 0, 0.3); + color: var(--text-muted); + border-radius: 999px; + padding: 4px 8px; + cursor: pointer; + font-size: 12px; +} + +.guide-dot.active { + border-color: rgba(120, 180, 255, 0.5); + color: var(--text-strong); +} + +.lightbox { + position: fixed; + inset: 0; + background: rgba(6, 8, 12, 0.82); + display: flex; + align-items: center; + justify-content: center; + padding: 28px; + z-index: 2000; +} + +.lightbox-card { + width: min(1400px, 96vw); + max-height: 94vh; + background: rgba(10, 14, 24, 0.96); + border: 1px solid rgba(255, 255, 255, 0.12); + border-radius: 16px; + padding: 16px; + display: flex; + flex-direction: column; + gap: 12px; +} + +.lightbox-head { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; +} + +.lightbox-label { + color: var(--text-muted); +} + +.lightbox-card img { + width: 100%; + max-height: 82vh; + object-fit: contain; + border-radius: 12px; + background: rgba(0, 0, 0, 0.35); +} diff --git a/frontend/src/styles/onboarding.css b/frontend/src/styles/onboarding.css index d410d69..3fb4a6a 100644 --- a/frontend/src/styles/onboarding.css +++ b/frontend/src/styles/onboarding.css @@ -3,12 +3,10 @@ margin: 0 auto; padding: 32px 22px 72px; } - .hero { margin-bottom: 12px; padding: 18px; } - .eyebrow { text-transform: uppercase; letter-spacing: 0.08em; @@ -16,7 +14,6 @@ margin: 0 0 6px; font-size: 13px; } - h1 { margin: 0 0 6px; font-size: 32px; @@ -416,111 +413,6 @@ button.copy:disabled { flex: 1; } -.guide-details { - margin-top: 10px; -} - -.guide-summary { - cursor: pointer; - display: inline-flex; - align-items: center; - gap: 10px; - padding: 6px 12px; - border-radius: 999px; - border: 1px solid rgba(92, 214, 167, 0.5); - background: rgba(92, 214, 167, 0.15); - color: var(--text-strong); - font-weight: 600; -} - -.guide-summary::after { - content: "Tap to open"; - font-size: 12px; - color: var(--text-muted); -} - -.guide-details[open] .guide-summary::after { - content: "Tap to close"; -} - -.guide-summary::-webkit-details-marker { - display: none; -} - -.guide-groups { - display: grid; - gap: 12px; - margin-top: 8px; -} - -.guide-title { - margin: 0 0 6px; -} - -.guide-images { - display: grid; - gap: 10px; -} - -.guide-shot { - border-radius: 10px; - overflow: hidden; - border: 1px solid rgba(255, 255, 255, 0.1); - background: rgba(0, 0, 0, 0.2); - padding: 0; - cursor: zoom-in; - display: flex; - flex-direction: column; - gap: 6px; -} - -.guide-shot figcaption { - margin: 0; - padding: 10px 12px 6px; - font-size: 18px; - font-weight: 600; - color: var(--text-strong); -} - -.guide-shot img { - display: block; - border-radius: 10px; - max-width: 100%; - width: auto; - height: auto; - max-height: min(60vh, 520px); - margin: 0 auto 10px; -} - -.guide-pagination { - display: flex; - align-items: center; - justify-content: space-between; - gap: 8px; - flex-wrap: wrap; -} - -.guide-dots { - display: flex; - gap: 6px; - flex-wrap: wrap; -} - -.guide-dot { - border: 1px solid rgba(255, 255, 255, 0.18); - background: rgba(0, 0, 0, 0.3); - color: var(--text-muted); - border-radius: 999px; - padding: 4px 8px; - cursor: pointer; - font-size: 12px; -} - -.guide-dot.active { - border-color: rgba(120, 180, 255, 0.5); - color: var(--text-strong); -} - .ready-box { margin-top: 18px; padding: 14px; @@ -563,48 +455,6 @@ button.copy:disabled { display: inline-flex; } -.lightbox { - position: fixed; - inset: 0; - background: rgba(6, 8, 12, 0.82); - display: flex; - align-items: center; - justify-content: center; - padding: 28px; - z-index: 2000; -} - -.lightbox-card { - width: min(1400px, 96vw); - max-height: 94vh; - background: rgba(10, 14, 24, 0.96); - border: 1px solid rgba(255, 255, 255, 0.12); - border-radius: 16px; - padding: 16px; - display: flex; - flex-direction: column; - gap: 12px; -} - -.lightbox-head { - display: flex; - align-items: center; - justify-content: space-between; - gap: 12px; -} - -.lightbox-label { - color: var(--text-muted); -} - -.lightbox-card img { - width: 100%; - max-height: 82vh; - object-fit: contain; - border-radius: 12px; - background: rgba(0, 0, 0, 0.35); -} - @media (max-width: 720px) { .page { padding: 24px 16px 56px; @@ -635,14 +485,11 @@ button.copy:disabled { .section-actions { flex-direction: column; align-items: stretch; - } - - .step-actions { + width: 100%; justify-content: flex-start; } - .section-actions { - width: 100%; + .step-actions { justify-content: flex-start; } diff --git a/frontend/src/views/OnboardingView.vue b/frontend/src/views/OnboardingView.vue index 7ed25d9..a5f117c 100644 --- a/frontend/src/views/OnboardingView.vue +++ b/frontend/src/views/OnboardingView.vue @@ -382,3 +382,4 @@ const { + diff --git a/testing/ci/quality_gate.py b/testing/ci/quality_gate.py index 2067d9a..91e7a83 100644 --- a/testing/ci/quality_gate.py +++ b/testing/ci/quality_gate.py @@ -16,7 +16,7 @@ DEFAULT_CONTRACT = ROOT / "testing" / "quality_contract.json" DEFAULT_BACKEND_COVERAGE = ROOT / "build" / "backend-coverage.xml" DEFAULT_FRONTEND_COVERAGE = ROOT / "frontend" / "coverage" / "coverage-summary.json" -TEXT_EXTENSIONS = {".py", ".js", ".mjs", ".ts", ".vue", ".json", ".yaml", ".yml"} +TEXT_EXTENSIONS = {".py", ".js", ".mjs", ".ts", ".vue", ".css", ".json", ".yaml", ".yml"} DOCSTRING_MIN_LINES = 10 diff --git a/testing/quality_contract.json b/testing/quality_contract.json index f0da421..61ac26e 100644 --- a/testing/quality_contract.json +++ b/testing/quality_contract.json @@ -2,47 +2,197 @@ "max_lines": 500, "coverage_threshold_pct": 95, "managed_files": [ + "backend/atlas_portal/__init__.py", "backend/atlas_portal/app_factory.py", + "backend/atlas_portal/ariadne_client.py", + "backend/atlas_portal/db.py", + "backend/atlas_portal/firefly_user_sync.py", + "backend/atlas_portal/k8s.py", + "backend/atlas_portal/keycloak.py", + "backend/atlas_portal/mailer.py", + "backend/atlas_portal/migrate.py", + "backend/atlas_portal/nextcloud_mail_sync.py", + "backend/atlas_portal/provisioning.py", + "backend/atlas_portal/provisioning_tasks.py", "backend/atlas_portal/rate_limit.py", + "backend/atlas_portal/routes/__init__.py", + "backend/atlas_portal/routes/access_request_onboarding.py", + "backend/atlas_portal/routes/access_request_onboarding_policy.py", + "backend/atlas_portal/routes/access_request_state.py", + "backend/atlas_portal/routes/access_request_status.py", + "backend/atlas_portal/routes/access_request_submission.py", + "backend/atlas_portal/routes/access_requests.py", + "backend/atlas_portal/routes/account.py", + "backend/atlas_portal/routes/account_actions.py", + "backend/atlas_portal/routes/account_overview.py", + "backend/atlas_portal/routes/admin_access.py", + "backend/atlas_portal/routes/ai.py", "backend/atlas_portal/routes/auth_config.py", "backend/atlas_portal/routes/health.py", + "backend/atlas_portal/routes/lab.py", "backend/atlas_portal/routes/monero.py", "backend/atlas_portal/settings.py", "backend/atlas_portal/utils.py", + "backend/atlas_portal/vaultwarden.py", + "backend/atlas_portal/wger_user_sync.py", + "frontend/src/App.vue", + "frontend/src/account/useAccountDashboard.js", + "frontend/src/assets/base.css", + "frontend/src/assets/theme.css", "frontend/src/auth.js", - "frontend/src/components/MetricRow.vue", + "frontend/src/components/HeroSection.vue", "frontend/src/components/MermaidCard.vue", + "frontend/src/components/MetricRow.vue", + "frontend/src/components/MetricsPanel.vue", "frontend/src/components/ServiceGrid.vue", "frontend/src/components/StatsGrid.vue", + "frontend/src/components/TopBar.vue", "frontend/src/data/sample.js", - "frontend/src/views/HomeView.vue" + "frontend/src/main.js", + "frontend/src/onboarding/onboardingGuides.js", + "frontend/src/onboarding/onboardingLabels.js", + "frontend/src/onboarding/onboardingSections.js", + "frontend/src/onboarding/useOnboardingFlow.js", + "frontend/src/onboarding/useOnboardingGuides.js", + "frontend/src/onboarding/useOnboardingNavigation.js", + "frontend/src/request-access/useRequestAccessFlow.js", + "frontend/src/router.js", + "frontend/src/styles/account.css", + "frontend/src/styles/onboarding-guides.css", + "frontend/src/styles/onboarding.css", + "frontend/src/styles/request-access.css", + "frontend/src/views/AboutView.vue", + "frontend/src/views/AccountView.vue", + "frontend/src/views/AiPlanView.vue", + "frontend/src/views/AiView.vue", + "frontend/src/views/AppsView.vue", + "frontend/src/views/HomeView.vue", + "frontend/src/views/MoneroView.vue", + "frontend/src/views/OnboardingView.vue", + "frontend/src/views/RequestAccessView.vue" ], "docstring_files": [ "backend/atlas_portal/app_factory.py", + "backend/atlas_portal/ariadne_client.py", + "backend/atlas_portal/db.py", + "backend/atlas_portal/firefly_user_sync.py", + "backend/atlas_portal/k8s.py", + "backend/atlas_portal/keycloak.py", + "backend/atlas_portal/mailer.py", + "backend/atlas_portal/migrate.py", + "backend/atlas_portal/nextcloud_mail_sync.py", + "backend/atlas_portal/provisioning.py", + "backend/atlas_portal/provisioning_tasks.py", "backend/atlas_portal/rate_limit.py", + "backend/atlas_portal/routes/access_request_onboarding.py", + "backend/atlas_portal/routes/access_request_onboarding_policy.py", + "backend/atlas_portal/routes/access_request_state.py", + "backend/atlas_portal/routes/access_request_status.py", + "backend/atlas_portal/routes/access_request_submission.py", + "backend/atlas_portal/routes/access_requests.py", + "backend/atlas_portal/routes/account.py", + "backend/atlas_portal/routes/account_actions.py", + "backend/atlas_portal/routes/account_overview.py", + "backend/atlas_portal/routes/admin_access.py", + "backend/atlas_portal/routes/ai.py", "backend/atlas_portal/routes/auth_config.py", "backend/atlas_portal/routes/health.py", + "backend/atlas_portal/routes/lab.py", "backend/atlas_portal/routes/monero.py", "backend/atlas_portal/settings.py", "backend/atlas_portal/utils.py", + "backend/atlas_portal/vaultwarden.py", + "backend/atlas_portal/wger_user_sync.py", + "frontend/src/App.vue", + "frontend/src/account/useAccountDashboard.js", "frontend/src/auth.js", + "frontend/src/components/HeroSection.vue", + "frontend/src/components/MermaidCard.vue", + "frontend/src/components/MetricRow.vue", + "frontend/src/components/MetricsPanel.vue", + "frontend/src/components/ServiceGrid.vue", + "frontend/src/components/StatsGrid.vue", + "frontend/src/components/TopBar.vue", "frontend/src/data/sample.js", - "frontend/src/views/HomeView.vue" + "frontend/src/main.js", + "frontend/src/onboarding/onboardingGuides.js", + "frontend/src/onboarding/onboardingLabels.js", + "frontend/src/onboarding/onboardingSections.js", + "frontend/src/onboarding/useOnboardingFlow.js", + "frontend/src/onboarding/useOnboardingGuides.js", + "frontend/src/onboarding/useOnboardingNavigation.js", + "frontend/src/request-access/useRequestAccessFlow.js", + "frontend/src/router.js", + "frontend/src/views/AboutView.vue", + "frontend/src/views/AccountView.vue", + "frontend/src/views/AiPlanView.vue", + "frontend/src/views/AiView.vue", + "frontend/src/views/AppsView.vue", + "frontend/src/views/HomeView.vue", + "frontend/src/views/MoneroView.vue", + "frontend/src/views/OnboardingView.vue", + "frontend/src/views/RequestAccessView.vue" ], "coverage_files": [ "backend/atlas_portal/app_factory.py", + "backend/atlas_portal/ariadne_client.py", + "backend/atlas_portal/db.py", + "backend/atlas_portal/firefly_user_sync.py", + "backend/atlas_portal/k8s.py", + "backend/atlas_portal/keycloak.py", + "backend/atlas_portal/mailer.py", + "backend/atlas_portal/migrate.py", + "backend/atlas_portal/nextcloud_mail_sync.py", + "backend/atlas_portal/provisioning.py", + "backend/atlas_portal/provisioning_tasks.py", "backend/atlas_portal/rate_limit.py", + "backend/atlas_portal/routes/access_request_onboarding.py", + "backend/atlas_portal/routes/access_request_onboarding_policy.py", + "backend/atlas_portal/routes/access_request_state.py", + "backend/atlas_portal/routes/access_request_status.py", + "backend/atlas_portal/routes/access_request_submission.py", + "backend/atlas_portal/routes/access_requests.py", + "backend/atlas_portal/routes/account.py", + "backend/atlas_portal/routes/account_actions.py", + "backend/atlas_portal/routes/account_overview.py", + "backend/atlas_portal/routes/admin_access.py", + "backend/atlas_portal/routes/ai.py", "backend/atlas_portal/routes/auth_config.py", "backend/atlas_portal/routes/health.py", + "backend/atlas_portal/routes/lab.py", "backend/atlas_portal/routes/monero.py", "backend/atlas_portal/settings.py", "backend/atlas_portal/utils.py", + "backend/atlas_portal/vaultwarden.py", + "backend/atlas_portal/wger_user_sync.py", + "frontend/src/App.vue", + "frontend/src/account/useAccountDashboard.js", "frontend/src/auth.js", - "frontend/src/components/MetricRow.vue", + "frontend/src/components/HeroSection.vue", "frontend/src/components/MermaidCard.vue", + "frontend/src/components/MetricRow.vue", + "frontend/src/components/MetricsPanel.vue", "frontend/src/components/ServiceGrid.vue", "frontend/src/components/StatsGrid.vue", + "frontend/src/components/TopBar.vue", "frontend/src/data/sample.js", - "frontend/src/views/HomeView.vue" + "frontend/src/main.js", + "frontend/src/onboarding/onboardingGuides.js", + "frontend/src/onboarding/onboardingLabels.js", + "frontend/src/onboarding/onboardingSections.js", + "frontend/src/onboarding/useOnboardingFlow.js", + "frontend/src/onboarding/useOnboardingGuides.js", + "frontend/src/onboarding/useOnboardingNavigation.js", + "frontend/src/request-access/useRequestAccessFlow.js", + "frontend/src/router.js", + "frontend/src/views/AboutView.vue", + "frontend/src/views/AccountView.vue", + "frontend/src/views/AiPlanView.vue", + "frontend/src/views/AiView.vue", + "frontend/src/views/AppsView.vue", + "frontend/src/views/HomeView.vue", + "frontend/src/views/MoneroView.vue", + "frontend/src/views/OnboardingView.vue", + "frontend/src/views/RequestAccessView.vue" ] }