duoops 0.1.9 → 0.2.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.
Files changed (55) hide show
  1. package/README.md +151 -63
  2. package/data/aws_machine_power_profiles.json +54 -0
  3. package/data/cpu_physical_specs.json +105 -0
  4. package/data/cpu_power_profiles.json +275 -0
  5. package/data/gcp_machine_power_profiles.json +1802 -0
  6. package/data/runtime-pue-mappings.json +183 -0
  7. package/dist/commands/autofix-ci.d.ts +13 -0
  8. package/dist/commands/autofix-ci.js +114 -0
  9. package/dist/commands/autofix.d.ts +5 -0
  10. package/dist/commands/autofix.js +11 -0
  11. package/dist/commands/init.js +50 -27
  12. package/dist/commands/mcp/deploy.d.ts +13 -0
  13. package/dist/commands/mcp/deploy.js +139 -0
  14. package/dist/commands/measure/calculate.js +2 -2
  15. package/dist/commands/portal.js +421 -6
  16. package/dist/lib/ai/agent.js +1 -0
  17. package/dist/lib/ai/tools/editing.js +28 -13
  18. package/dist/lib/ai/tools/gitlab.js +8 -4
  19. package/dist/lib/config.d.ts +10 -0
  20. package/dist/lib/gcloud.d.ts +7 -0
  21. package/dist/lib/gcloud.js +105 -0
  22. package/dist/lib/gitlab/pipelines-service.d.ts +23 -0
  23. package/dist/lib/gitlab/pipelines-service.js +146 -0
  24. package/dist/lib/gitlab/runner-service.d.ts +11 -0
  25. package/dist/lib/gitlab/runner-service.js +15 -0
  26. package/dist/lib/portal/settings.d.ts +3 -0
  27. package/dist/lib/portal/settings.js +48 -0
  28. package/dist/lib/scaffold.d.ts +5 -0
  29. package/dist/lib/scaffold.js +32 -0
  30. package/dist/portal/assets/HomeDashboard-DlkwSyKx.js +1 -0
  31. package/dist/portal/assets/JobDetailsDrawer-7kXXMSH8.js +1 -0
  32. package/dist/portal/assets/JobsDashboard-D4pNc9TM.js +1 -0
  33. package/dist/portal/assets/MetricsDashboard-BcgzvzBz.js +1 -0
  34. package/dist/portal/assets/PipelinesDashboard-BNrSM9GB.js +1 -0
  35. package/dist/portal/assets/allPaths-CXDKahbk.js +1 -0
  36. package/dist/portal/assets/allPathsLoader-BF5PAx2c.js +2 -0
  37. package/dist/portal/assets/cache-YerT0Slh.js +6 -0
  38. package/dist/portal/assets/core-Cz8f3oSB.js +19 -0
  39. package/dist/portal/assets/{index-C54ZhVUo.js → index-B9sNUqEC.js} +1 -1
  40. package/dist/portal/assets/index-BWa_E8Y7.css +1 -0
  41. package/dist/portal/assets/index-Bp4RqK05.js +1 -0
  42. package/dist/portal/assets/index-DW6Qp0d6.js +64 -0
  43. package/dist/portal/assets/index-Uc4Xhv31.js +1 -0
  44. package/dist/portal/assets/progressBar-C4SmnGeZ.js +1 -0
  45. package/dist/portal/assets/splitPathsBySizeLoader-C-T9_API.js +1 -0
  46. package/dist/portal/index.html +2 -2
  47. package/oclif.manifest.json +237 -92
  48. package/package.json +2 -1
  49. package/templates/.gitlab/duo/flows/duoops.yaml +114 -0
  50. package/templates/agents/agent.yml +45 -0
  51. package/templates/duoops-autofix-component.yml +52 -0
  52. package/templates/flows/flow.yml +283 -0
  53. package/dist/portal/assets/MetricsDashboard-Bnj-jtu6.js +0 -27
  54. package/dist/portal/assets/index-B1SGDQNX.css +0 -1
  55. package/dist/portal/assets/index-Bk8OVV7a.js +0 -106
@@ -0,0 +1,105 @@
1
+ import { execSync } from 'node:child_process';
2
+ export function requireGcloud() {
3
+ try {
4
+ execSync('gcloud --version', { stdio: 'ignore' });
5
+ }
6
+ catch {
7
+ throw new Error('gcloud CLI is not installed or not found in PATH. Install it from https://cloud.google.com/sdk');
8
+ }
9
+ }
10
+ export function getActiveAccount() {
11
+ try {
12
+ return execSync('gcloud config get-value account', { encoding: 'utf8', stdio: ['pipe', 'pipe', 'ignore'] }).trim();
13
+ }
14
+ catch {
15
+ return 'unknown';
16
+ }
17
+ }
18
+ export function detectGcpProject() {
19
+ try {
20
+ const value = execSync('gcloud config get-value project', { encoding: 'utf8', stdio: ['pipe', 'pipe', 'ignore'] }).trim();
21
+ return value && value !== '(unset)' ? value : undefined;
22
+ }
23
+ catch { }
24
+ }
25
+ export function validateProjectAccess(project) {
26
+ const account = getActiveAccount();
27
+ try {
28
+ execSync(`gcloud projects describe ${project} --format="value(projectId)"`, {
29
+ encoding: 'utf8',
30
+ stdio: ['pipe', 'pipe', 'pipe'],
31
+ });
32
+ }
33
+ catch (error) {
34
+ const stderr = error.stderr || '';
35
+ if (stderr.includes('does not have permission') || stderr.includes('PERMISSION_DENIED')) {
36
+ throw new Error(`Account "${account}" does not have access to project "${project}".\n\n` +
37
+ `Either:\n` +
38
+ ` 1. Switch account: gcloud config set account <account-with-access>\n` +
39
+ ` 2. Grant access: Grant Owner/Editor role to ${account} on project ${project}\n` +
40
+ ` 3. Use another project: --gcp-project <project-id>`);
41
+ }
42
+ if (stderr.includes('not exist')) {
43
+ throw new Error(`GCP project "${project}" does not exist. Check the project ID.`);
44
+ }
45
+ throw new Error(`Cannot access GCP project "${project}": ${stderr.trim()}`);
46
+ }
47
+ }
48
+ export function enableApis(project, apis, log) {
49
+ for (const api of apis) {
50
+ try {
51
+ execSync(`gcloud services enable ${api} --project=${project} --quiet`, {
52
+ encoding: 'utf8',
53
+ stdio: ['pipe', 'pipe', 'pipe'],
54
+ });
55
+ log(` ✓ ${api}`);
56
+ }
57
+ catch (error) {
58
+ const stderr = error.stderr || '';
59
+ if (stderr.includes('PERMISSION_DENIED') || stderr.includes('AUTH_PERMISSION_DENIED')) {
60
+ log(` ? ${api} — no permission to enable, will attempt to proceed`);
61
+ }
62
+ else {
63
+ throw new Error(`Failed to enable ${api}. Enable it manually:\n` +
64
+ ` https://console.developers.google.com/apis/api/${api}/overview?project=${project}\n\n` +
65
+ `Then retry.`);
66
+ }
67
+ }
68
+ }
69
+ }
70
+ export function getProjectNumber(project) {
71
+ try {
72
+ return execSync(`gcloud projects describe ${project} --format="value(projectNumber)"`, { encoding: 'utf8', stdio: ['pipe', 'pipe', 'ignore'] }).trim() || undefined;
73
+ }
74
+ catch {
75
+ return undefined;
76
+ }
77
+ }
78
+ export function ensureCloudBuildServiceAccount(project, log) {
79
+ const projectNumber = getProjectNumber(project);
80
+ if (!projectNumber) {
81
+ log(' ? Could not determine project number, skipping service account setup');
82
+ return;
83
+ }
84
+ const computeSa = `${projectNumber}-compute@developer.gserviceaccount.com`;
85
+ const roles = [
86
+ 'roles/cloudbuild.builds.builder',
87
+ 'roles/storage.admin',
88
+ ];
89
+ log(` Granting Cloud Build permissions to ${computeSa}...`);
90
+ for (const role of roles) {
91
+ try {
92
+ execSync(`gcloud projects add-iam-policy-binding ${project} --member="serviceAccount:${computeSa}" --role="${role}" --quiet`, { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] });
93
+ log(` ✓ ${role}`);
94
+ }
95
+ catch (error) {
96
+ const stderr = error.stderr || '';
97
+ if (stderr.includes('PERMISSION_DENIED')) {
98
+ log(` ? ${role} — no permission to grant, will attempt deploy anyway`);
99
+ }
100
+ else {
101
+ log(` ? ${role} — failed: ${stderr.trim().split('\n')[0]}`);
102
+ }
103
+ }
104
+ }
105
+ }
@@ -0,0 +1,23 @@
1
+ export interface PortalPipeline {
2
+ branch: string;
3
+ commit_message?: string;
4
+ created_at: string;
5
+ duration_seconds?: number;
6
+ id: number;
7
+ sha: string;
8
+ status: string;
9
+ triggered_by?: string;
10
+ updated_at?: string;
11
+ web_url?: string;
12
+ }
13
+ export interface PortalPipelinePage {
14
+ hasNextPage: boolean;
15
+ hasPrevPage: boolean;
16
+ page: number;
17
+ perPage: number;
18
+ pipelines: PortalPipeline[];
19
+ }
20
+ export declare function fetchPortalPipelines(projectId: string, options?: {
21
+ limit?: number;
22
+ page?: number;
23
+ }): Promise<PortalPipelinePage>;
@@ -0,0 +1,146 @@
1
+ /* eslint-disable camelcase */
2
+ import { createGitlabClient } from './client.js';
3
+ const DEFAULT_LIMIT = 20;
4
+ const MAX_LIMIT = 100;
5
+ export async function fetchPortalPipelines(projectId, options) {
6
+ if (!projectId) {
7
+ throw new Error('Project ID is required to fetch pipelines');
8
+ }
9
+ const client = createGitlabClient();
10
+ const perPage = clampLimit(options?.limit);
11
+ const page = normalizePage(options?.page);
12
+ const requestLimit = Math.min(perPage + 1, MAX_LIMIT);
13
+ const raw = await client.Pipelines.all(projectId, {
14
+ maxPages: 1,
15
+ orderBy: 'id',
16
+ page,
17
+ perPage: requestLimit,
18
+ sort: 'desc',
19
+ });
20
+ const normalized = normalizePipelines(raw);
21
+ const hasNextPage = normalized.length > perPage;
22
+ const visiblePipelines = hasNextPage ? normalized.slice(0, perPage) : normalized;
23
+ const commitMessages = await fetchCommitMessages(client, projectId, visiblePipelines);
24
+ const pipelines = visiblePipelines.map((pipeline) => ({
25
+ ...pipeline,
26
+ commit_message: pipeline.sha ? commitMessages.get(pipeline.sha) ?? undefined : undefined,
27
+ }));
28
+ return {
29
+ hasNextPage,
30
+ hasPrevPage: page > 1,
31
+ page,
32
+ perPage,
33
+ pipelines,
34
+ };
35
+ }
36
+ function normalizePipelines(raw) {
37
+ const data = Array.isArray(raw)
38
+ ? raw
39
+ : Array.isArray(raw?.data)
40
+ ? raw.data
41
+ : raw === undefined || raw === null
42
+ ? []
43
+ : [raw];
44
+ const arrayData = Array.isArray(data) ? data : [];
45
+ return arrayData
46
+ .map((item) => normalizePipeline(item))
47
+ .filter((pipeline) => pipeline !== null);
48
+ }
49
+ function normalizePipeline(raw) {
50
+ if (raw.id === undefined || raw.id === null) {
51
+ return null;
52
+ }
53
+ const branch = typeof raw.ref === 'string' ? raw.ref : String(raw.ref ?? '');
54
+ const sha = typeof raw.sha === 'string' ? raw.sha : String(raw.sha ?? '');
55
+ const status = typeof raw.status === 'string' && raw.status.length > 0
56
+ ? raw.status
57
+ : 'unknown';
58
+ const duration = typeof raw.duration === 'number'
59
+ ? raw.duration
60
+ : typeof raw.duration === 'string'
61
+ ? Number.parseFloat(raw.duration)
62
+ : undefined;
63
+ return {
64
+ branch,
65
+ created_at: typeof raw.created_at === 'string'
66
+ ? raw.created_at
67
+ : raw.created_at
68
+ ? String(raw.created_at)
69
+ : '',
70
+ duration_seconds: Number.isFinite(duration) ? duration : undefined,
71
+ id: Number(raw.id),
72
+ sha,
73
+ status,
74
+ triggered_by: extractUser(raw.user),
75
+ updated_at: typeof raw.updated_at === 'string'
76
+ ? raw.updated_at
77
+ : raw.updated_at
78
+ ? String(raw.updated_at)
79
+ : undefined,
80
+ web_url: typeof raw.web_url === 'string'
81
+ ? raw.web_url
82
+ : raw.web_url
83
+ ? String(raw.web_url)
84
+ : undefined,
85
+ };
86
+ }
87
+ function extractUser(user) {
88
+ if (!user || typeof user !== 'object') {
89
+ return undefined;
90
+ }
91
+ if (typeof user.name === 'string' && user.name.trim().length > 0) {
92
+ return user.name;
93
+ }
94
+ if (typeof user.username === 'string' && user.username.trim().length > 0) {
95
+ return user.username;
96
+ }
97
+ return undefined;
98
+ }
99
+ async function fetchCommitMessages(client, projectId, pipelines) {
100
+ const map = new Map();
101
+ const shas = [...new Set(pipelines
102
+ .map((pipeline) => pipeline.sha)
103
+ .filter(Boolean))];
104
+ await Promise.all(shas.map(async (sha) => {
105
+ try {
106
+ const commit = await client.Commits.show(projectId, sha);
107
+ const message = extractCommitMessage(commit);
108
+ if (message) {
109
+ map.set(sha, message);
110
+ }
111
+ }
112
+ catch {
113
+ map.set(sha, '');
114
+ }
115
+ }));
116
+ return map;
117
+ }
118
+ function extractCommitMessage(raw) {
119
+ if (!raw || typeof raw !== 'object') {
120
+ return undefined;
121
+ }
122
+ const data = raw;
123
+ const { title } = data;
124
+ const { message } = data;
125
+ if (typeof title === 'string' && title.trim().length > 0) {
126
+ return title;
127
+ }
128
+ if (typeof message === 'string' && message.trim().length > 0) {
129
+ return message;
130
+ }
131
+ return undefined;
132
+ }
133
+ function clampLimit(limit) {
134
+ if (!Number.isFinite(limit ?? Number.NaN)) {
135
+ return DEFAULT_LIMIT;
136
+ }
137
+ const value = Math.floor(limit ?? DEFAULT_LIMIT);
138
+ return Math.min(Math.max(value, 1), MAX_LIMIT - 1);
139
+ }
140
+ function normalizePage(page) {
141
+ if (!Number.isFinite(page ?? Number.NaN)) {
142
+ return 1;
143
+ }
144
+ const parsed = Math.floor(page ?? 1);
145
+ return parsed > 0 ? parsed : 1;
146
+ }
@@ -0,0 +1,11 @@
1
+ export interface RunnerStatus {
2
+ architecture?: string;
3
+ contactedAt?: string;
4
+ description: string;
5
+ id: number;
6
+ ipAddress?: string;
7
+ online: boolean;
8
+ status: string;
9
+ version?: string;
10
+ }
11
+ export declare function fetchProjectRunners(projectId: string): Promise<RunnerStatus[]>;
@@ -0,0 +1,15 @@
1
+ import { createGitlabClient } from './client.js';
2
+ export async function fetchProjectRunners(projectId) {
3
+ const client = createGitlabClient();
4
+ const runners = await client.Runners.all({ perPage: 50, projectId });
5
+ return runners.map((runner) => ({
6
+ architecture: typeof runner.architecture === 'string' ? runner.architecture : undefined,
7
+ contactedAt: typeof runner.contacted_at === 'string' ? runner.contacted_at : undefined,
8
+ description: typeof runner.description === 'string' ? runner.description : 'Runner',
9
+ id: Number(runner.id),
10
+ ipAddress: typeof runner.ip_address === 'string' ? runner.ip_address : undefined,
11
+ online: Boolean(runner.status === 'online'),
12
+ status: typeof runner.status === 'string' ? runner.status : 'unknown',
13
+ version: typeof runner.version === 'string' ? runner.version : undefined,
14
+ }));
15
+ }
@@ -0,0 +1,3 @@
1
+ import { type PortalBudgetConfig } from '../config.js';
2
+ export declare function getPortalBudgets(): PortalBudgetConfig[];
3
+ export declare function savePortalBudgets(budgets: PortalBudgetConfig[]): void;
@@ -0,0 +1,48 @@
1
+ import { configManager } from '../config.js';
2
+ const DEFAULT_BUDGETS = [
3
+ {
4
+ id: 'carbon',
5
+ limit: 5000,
6
+ name: 'Monthly Carbon Budget',
7
+ period: 'This month',
8
+ unit: 'gCO2e',
9
+ },
10
+ {
11
+ id: 'runtime',
12
+ limit: 7200,
13
+ name: 'Pipeline Runtime Budget',
14
+ period: 'Rolling 7 days',
15
+ unit: 'seconds',
16
+ },
17
+ ];
18
+ export function getPortalBudgets() {
19
+ const config = configManager.get();
20
+ const budgets = config.portal?.budgets;
21
+ if (!budgets || budgets.length === 0) {
22
+ return DEFAULT_BUDGETS;
23
+ }
24
+ return mergeBudgets(budgets);
25
+ }
26
+ export function savePortalBudgets(budgets) {
27
+ const normalized = mergeBudgets(budgets);
28
+ const config = configManager.get();
29
+ configManager.set({
30
+ ...config,
31
+ portal: {
32
+ ...config.portal,
33
+ budgets: normalized,
34
+ },
35
+ });
36
+ }
37
+ function mergeBudgets(budgets) {
38
+ return DEFAULT_BUDGETS.map((defaultBudget) => {
39
+ const match = budgets.find((budget) => budget.id === defaultBudget.id);
40
+ if (!match)
41
+ return defaultBudget;
42
+ return {
43
+ ...defaultBudget,
44
+ ...match,
45
+ limit: Number(match.limit) || defaultBudget.limit,
46
+ };
47
+ });
48
+ }
@@ -0,0 +1,5 @@
1
+ export interface ScaffoldResult {
2
+ created: string[];
3
+ skipped: string[];
4
+ }
5
+ export declare function scaffoldProject(targetDir: string): ScaffoldResult;
@@ -0,0 +1,32 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ const TEMPLATES_DIR = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../templates');
5
+ const SCAFFOLD_FILES = [
6
+ 'agents/agent.yml',
7
+ 'flows/flow.yml',
8
+ '.gitlab/duo/flows/duoops.yaml',
9
+ ];
10
+ export function scaffoldProject(targetDir) {
11
+ const created = [];
12
+ const skipped = [];
13
+ for (const relPath of SCAFFOLD_FILES) {
14
+ const src = path.join(TEMPLATES_DIR, relPath);
15
+ const dest = path.join(targetDir, relPath);
16
+ if (!fs.existsSync(src)) {
17
+ skipped.push(relPath);
18
+ continue;
19
+ }
20
+ if (fs.existsSync(dest)) {
21
+ skipped.push(relPath);
22
+ continue;
23
+ }
24
+ const destDir = path.dirname(dest);
25
+ if (!fs.existsSync(destDir)) {
26
+ fs.mkdirSync(destDir, { recursive: true });
27
+ }
28
+ fs.copyFileSync(src, dest);
29
+ created.push(relPath);
30
+ }
31
+ return { created, skipped };
32
+ }
@@ -0,0 +1 @@
1
+ import{r as a,j as e,D as q,a as J,c as K,b as U,d as X,e as Y,S as D,I as c,B as l,T as u,f as E,g as N}from"./index-DW6Qp0d6.js";import{h as Q,g as Z,u as ee,C as r,a as j,s as te}from"./cache-YerT0Slh.js";import{P as re}from"./progressBar-C4SmnGeZ.js";const W=a.forwardRef((n,m)=>{const{actions:d,children:y,className:s,minimal:x=!1,...p}=n;return e.jsxs("div",{...p,className:K(U,s,{[X]:!x}),ref:m,children:[e.jsx("div",{className:q,children:y}),d!=null&&e.jsx("div",{className:J,children:d})]})});W.displayName=`${Y}.DialogFooter`;const R=n=>{switch(n){case"breached":return"danger";case"warning":return"warning";default:return"success"}};function ne({activeProjectId:n}){const m=a.useMemo(()=>n?{projectId:n}:{},[n]),d=a.useMemo(()=>Q(["dashboard",m]),[m]),y=a.useMemo(()=>Z(d)??void 0,[d]),{data:s,isLoading:x,error:p,isFetching:M,refetch:f}=ee({queryKey:["dashboard",n],queryFn:async()=>{const t=await j.get("/api/dashboard",{params:m});return te(d,t.data,{ttlMs:6e4}),t.data},initialData:y,staleTime:6e4,refetchInterval:1e3*60*2}),i=s?.summary,b=s?.budgets??[],S=s?.alerts??[],z=s?.recommendations??[],B=s?.runnerHealth??[],[L,g]=a.useState(!1),[I,C]=a.useState(s?.budgetSettings??[]),[_,k]=a.useState(!1),[G,F]=a.useState(!1),[o,w]=a.useState(null),[O,T]=a.useState(null);a.useEffect(()=>{s?.budgetSettings&&C(s.budgetSettings)},[s?.budgetSettings]);const H=a.useMemo(()=>i?i.totalEmissions>0&&i.avgEmissions>0?`Average job emits ${i.avgEmissions.toFixed(1)} gCO₂e`:"Measurements will appear after your first pipeline run.":null,[i]),A=async()=>{try{T(null),w(null),F(!0),k(!0);const t=await j.post("/api/autofix",{projectId:n});w(t.data)}catch(t){T(String(t))}finally{F(!1)}},P=(t,h)=>{C($=>$.map(v=>v.id===t?{...v,limit:h}:v))},V=async()=>{try{await j.put("/api/budgets",{budgets:I}),g(!1),f()}catch(t){alert(`Failed to save budgets: ${String(t)}`)}};return!s&&x?e.jsx("div",{style:{flex:1,display:"flex",alignItems:"center",justifyContent:"center"},children:e.jsx(D,{size:40,intent:"success"})}):e.jsxs("div",{style:{flex:1,overflowY:"auto",padding:24,maxWidth:1100,margin:"0 auto"},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:24},children:[e.jsxs("div",{children:[e.jsxs("h1",{style:{fontSize:22,fontWeight:600,color:"var(--text-primary)",margin:0,display:"flex",alignItems:"center",gap:10},children:[e.jsx(c,{icon:"clean",size:20,style:{color:"var(--green-primary)"}}),"Sustainability Overview"]}),s?.projectId&&e.jsxs("p",{style:{fontSize:12,color:"var(--text-muted)",marginTop:4},children:["Project ID: ",s.projectId]}),i?.lastIngestedAt&&e.jsxs("p",{style:{fontSize:12,color:"var(--text-muted)"},children:["Last update: ",new Date(i.lastIngestedAt).toLocaleString()]})]}),e.jsxs("div",{style:{display:"flex",gap:8},children:[e.jsx(l,{icon:"build",text:"Inspect Latest Failure",intent:"primary",outlined:!0,small:!0,onClick:A}),e.jsx(l,{icon:"cog",text:"Manage Budgets",outlined:!0,small:!0,onClick:()=>g(!0)}),e.jsx(l,{icon:"refresh",small:!0,outlined:!0,loading:M,onClick:()=>f()})]})]}),p&&e.jsx(r,{style:{background:"rgba(219, 55, 55, 0.1)",border:"1px solid rgba(219, 55, 55, 0.3)",marginBottom:16},children:e.jsxs("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between"},children:[e.jsxs("span",{style:{color:"#f97171",fontSize:13},children:["Failed to load dashboard: ",String(p)]}),e.jsx(l,{small:!0,minimal:!0,text:"Retry",onClick:()=>f()})]})}),i&&e.jsxs("div",{style:{display:"grid",gridTemplateColumns:"repeat(4, 1fr)",gap:16,marginBottom:24},children:[e.jsxs(r,{style:{background:"var(--bg-card)",border:"1px solid var(--border-default)",padding:16},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:6,fontSize:10,textTransform:"uppercase",letterSpacing:1.5,color:"var(--text-muted)",marginBottom:6},children:[e.jsx(c,{icon:"clean",size:14,style:{color:"var(--green-primary)"}}),"Total Emissions"]}),e.jsxs("div",{style:{fontSize:24,fontFamily:"monospace",fontWeight:500,color:"var(--text-primary)"},children:[i.totalEmissions.toFixed(1)," g"]})]}),e.jsxs(r,{style:{background:"var(--bg-card)",border:"1px solid var(--border-default)",padding:16},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:6,fontSize:10,textTransform:"uppercase",letterSpacing:1.5,color:"var(--text-muted)",marginBottom:6},children:[e.jsx(c,{icon:"flame",size:14,style:{color:"#d29922"}}),"Avg per Job"]}),e.jsxs("div",{style:{fontSize:24,fontFamily:"monospace",fontWeight:500,color:"var(--text-primary)"},children:[i.avgEmissions.toFixed(1)," g"]})]}),e.jsxs(r,{style:{background:"var(--bg-card)",border:"1px solid var(--border-default)",padding:16},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:6,fontSize:10,textTransform:"uppercase",letterSpacing:1.5,color:"var(--text-muted)",marginBottom:6},children:[e.jsx(c,{icon:"tick-circle",size:14,style:{color:"#58a6ff"}}),"Jobs Tracked"]}),e.jsx("div",{style:{fontSize:24,fontFamily:"monospace",fontWeight:500,color:"var(--text-primary)"},children:i.jobCount})]}),e.jsxs(r,{style:{background:"var(--bg-card)",border:"1px solid var(--border-default)",padding:16},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:6,fontSize:10,textTransform:"uppercase",letterSpacing:1.5,color:"var(--text-muted)",marginBottom:6},children:[e.jsx(c,{icon:"time",size:14,style:{color:"var(--green-primary)"}}),"Avg Runtime"]}),e.jsxs("div",{style:{fontSize:24,fontFamily:"monospace",fontWeight:500,color:"var(--text-primary)"},children:[i.avgRuntime.toFixed(0)," s"]})]})]}),i&&e.jsxs(r,{style:{background:"linear-gradient(135deg, rgba(45, 164, 78, 0.12), var(--bg-card))",border:"1px solid var(--border-default)",padding:20,marginBottom:24},children:[e.jsx(u,{intent:"success",minimal:!0,style:{marginBottom:8,fontSize:10,letterSpacing:1},children:"INSIGHT"}),e.jsx("p",{style:{fontSize:16,fontWeight:500,color:"var(--text-primary)",margin:0},children:H})]}),B.length>0&&e.jsxs(r,{style:{background:"var(--bg-card)",border:"1px solid var(--border-default)",padding:16,marginBottom:24},children:[e.jsx("h2",{style:{fontSize:14,fontWeight:600,color:"var(--text-primary)",margin:"0 0 4px"},children:"Runner Health"}),e.jsx("p",{style:{fontSize:12,color:"var(--text-muted)",margin:"0 0 12px"},children:"Current fleet status"}),e.jsx("div",{style:{display:"grid",gridTemplateColumns:"repeat(2, 1fr)",gap:12},children:B.map(t=>e.jsxs(r,{style:{background:"var(--bg-primary)",border:"1px solid var(--border-muted)",padding:12},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:4},children:[e.jsx("span",{style:{fontSize:13,color:"var(--text-primary)"},children:t.description}),e.jsx(u,{intent:t.online?"success":"danger",minimal:!0,round:!0,style:{fontSize:11},children:t.online?"Online":"Offline"})]}),e.jsxs("p",{style:{fontSize:11,color:"var(--text-muted)",margin:0},children:["Status: ",t.status]}),t.version&&e.jsxs("p",{style:{fontSize:11,color:"var(--text-muted)",margin:0},children:["Version: ",t.version]})]},t.id))})]}),b.length>0&&e.jsxs(r,{style:{background:"var(--bg-card)",border:"1px solid var(--border-default)",padding:16,marginBottom:24},children:[e.jsx("h2",{style:{fontSize:14,fontWeight:600,color:"var(--text-primary)",margin:"0 0 4px"},children:"Budgets"}),e.jsx("p",{style:{fontSize:12,color:"var(--text-muted)",margin:"0 0 12px"},children:"Track sustainability guardrails in real time."}),e.jsx("div",{style:{display:"grid",gridTemplateColumns:"repeat(2, 1fr)",gap:12},children:b.map(t=>e.jsxs(r,{style:{background:"var(--bg-primary)",border:"1px solid var(--border-muted)",padding:14},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:6},children:[e.jsxs("div",{children:[e.jsx("p",{style:{fontSize:13,color:"var(--text-primary)",margin:0},children:t.name}),e.jsx("p",{style:{fontSize:11,color:"var(--text-muted)",margin:0},children:t.period})]}),e.jsx(u,{intent:R(t.status),minimal:!0,style:{fontSize:11},children:t.status==="breached"?"Breached":t.status==="warning"?"Warning":"On Track"})]}),e.jsxs("div",{style:{fontSize:18,fontFamily:"monospace",color:"var(--text-primary)",marginBottom:10},children:[t.used.toFixed(1)," / ",t.limit.toFixed(0)," ",t.unit]}),e.jsx(re,{intent:R(t.status),value:Math.min(1,Math.max(0,t.percent/100)),stripes:!1,animate:!1})]},t.id))})]}),S.length>0&&e.jsxs(r,{style:{background:"var(--bg-card)",border:"1px solid var(--border-default)",padding:16,marginBottom:24},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8,marginBottom:12},children:[e.jsx(c,{icon:"warning-sign",size:14,style:{color:"#d29922"}}),e.jsx("span",{style:{fontSize:10,textTransform:"uppercase",letterSpacing:1.5,color:"var(--text-muted)",fontWeight:600},children:"Alerts"})]}),S.map(t=>e.jsx(r,{style:{background:"var(--bg-primary)",border:"1px solid var(--border-muted)",padding:12,marginBottom:8},children:e.jsx("span",{style:{fontSize:13,color:"var(--text-primary)"},children:t.message})},t.id))]}),z.length>0&&e.jsxs(r,{style:{background:"var(--bg-card)",border:"1px solid var(--border-default)",padding:16,marginBottom:24},children:[e.jsx("h2",{style:{fontSize:14,fontWeight:600,color:"var(--text-primary)",margin:"0 0 4px"},children:"Recommendations"}),e.jsx("p",{style:{fontSize:12,color:"var(--text-muted)",margin:"0 0 12px"},children:"Generated by DuoOps agent"}),e.jsx("div",{style:{display:"grid",gridTemplateColumns:"repeat(2, 1fr)",gap:12},children:z.map(t=>e.jsxs(r,{style:{background:"var(--bg-primary)",border:"1px solid var(--border-muted)",padding:14},children:[e.jsx("p",{style:{fontSize:13,fontWeight:600,color:"var(--text-primary)",margin:"0 0 4px"},children:t.title}),e.jsx("p",{style:{fontSize:12,color:"var(--text-secondary)",lineHeight:1.5,margin:"0 0 6px"},children:t.description}),e.jsx(u,{minimal:!0,style:{fontSize:10,textTransform:"uppercase",letterSpacing:.5},children:t.source==="agent"?"Agent":"Heuristic"})]},t.id))})]}),!x&&!p&&!i&&e.jsx("div",{style:{textAlign:"center",color:"var(--text-muted)",padding:"48px 0"},children:"No sustainability data yet. Run the measurement component in your CI and refresh this page."}),e.jsxs(E,{isOpen:L,onClose:()=>g(!1),title:"Manage Budgets",icon:"cog",className:"bp5-dark",children:[e.jsxs(N,{children:[e.jsx("p",{style:{fontSize:12,color:"var(--text-muted)",marginBottom:16},children:"Adjust sustainability budgets to fit your targets."}),I.map(t=>e.jsxs("div",{style:{marginBottom:16},children:[e.jsxs("div",{style:{display:"flex",justifyContent:"space-between",marginBottom:4},children:[e.jsx("span",{style:{fontSize:13,color:"var(--text-primary)"},children:t.name}),e.jsx("span",{style:{fontSize:11,color:"var(--text-muted)"},children:t.period})]}),e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8},children:[e.jsx("input",{className:"bp5-input bp5-fill",type:"number",min:1,value:t.limit,onChange:h=>P(t.id,Number(h.target.value))}),e.jsx("span",{style:{fontSize:12,color:"var(--text-muted)",whiteSpace:"nowrap"},children:t.unit})]})]},t.id))]}),e.jsx(W,{actions:e.jsxs(e.Fragment,{children:[e.jsx(l,{text:"Cancel",onClick:()=>g(!1)}),e.jsx(l,{text:"Save Budgets",intent:"success",onClick:V})]})})]}),e.jsx(E,{isOpen:_,onClose:()=>k(!1),title:"Latest Pipeline Diagnosis",icon:"build",className:"bp5-dark",style:{width:640},children:e.jsx(N,{children:G?e.jsx("div",{style:{display:"flex",justifyContent:"center",padding:48},children:e.jsx(D,{size:40,intent:"success"})}):O?e.jsxs("div",{children:[e.jsx("p",{style:{color:"#f97171",fontSize:13},children:O}),e.jsx(l,{small:!0,text:"Retry",onClick:A,style:{marginTop:8}})]}):o?e.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:16},children:[e.jsxs(r,{style:{background:"var(--bg-primary)",border:"1px solid var(--border-muted)",padding:12},children:[e.jsxs("p",{style:{fontSize:13,color:"var(--text-secondary)",margin:0},children:["Pipeline #",o.pipeline.id," on ",e.jsx("strong",{style:{color:"var(--text-primary)"},children:o.pipeline.ref})]}),e.jsxs("p",{style:{fontSize:11,color:"var(--text-muted)",margin:"2px 0"},children:["Status: ",o.pipeline.status]}),o.pipeline.webUrl&&e.jsx("a",{href:o.pipeline.webUrl,target:"_blank",rel:"noreferrer",style:{fontSize:12,color:"var(--green-light)"},children:"View in GitLab"})]}),e.jsxs("div",{children:[e.jsx("h3",{style:{fontSize:13,fontWeight:600,color:"var(--text-primary)",marginBottom:8},children:"Jobs"}),o.jobs.length===0?e.jsx("p",{style:{fontSize:12,color:"var(--text-muted)"},children:"No job information returned."}):o.jobs.map(t=>e.jsxs("p",{style:{fontSize:12,color:"var(--text-secondary)",margin:"2px 0",fontFamily:"monospace"},children:["#",t.id," ",t.name," • ",t.stage," • ",t.status,t.duration?` (${t.duration}s)`:""]},t.id))]}),e.jsxs("div",{children:[e.jsx("h3",{style:{fontSize:13,fontWeight:600,color:"var(--text-primary)",marginBottom:8},children:"Agent Recommendation"}),e.jsx(r,{style:{background:"var(--bg-primary)",border:"1px solid var(--border-muted)",padding:14},children:e.jsx("pre",{style:{fontSize:12,color:"var(--text-primary)",whiteSpace:"pre-wrap",margin:0,fontFamily:"monospace"},children:o.analysis})})]})]}):e.jsx("p",{style:{color:"var(--text-muted)",fontSize:13},children:"No analysis to display."})})})]})}export{ne as HomeDashboard};
@@ -0,0 +1 @@
1
+ import{A as _,e as O,c as p,m as j,p as E,j as e,O as b,n as R,o as I,q as B,s as L,B as y,t as S,u as z,v as m,w as A,I as r,H as P,G as C}from"./index-DW6Qp0d6.js";import{C as o}from"./cache-YerT0Slh.js";import{P as x}from"./progressBar-C4SmnGeZ.js";const s={BOTTOM:"bottom",BOTTOM_LEFT:"bottom-left",BOTTOM_RIGHT:"bottom-right",LEFT:"left",LEFT_BOTTOM:"left-bottom",LEFT_TOP:"left-top",RIGHT:"right",TOP:"top",TOP_LEFT:"top-left",TOP_RIGHT:"top-right"};function F(t){return t===s.TOP||t===s.TOP_LEFT||t===s.TOP_RIGHT||t===s.BOTTOM||t===s.BOTTOM_LEFT||t===s.BOTTOM_RIGHT}function g(t){return t===s.TOP||t===s.TOP_LEFT||t===s.TOP_RIGHT?s.TOP:t===s.BOTTOM||t===s.BOTTOM_LEFT||t===s.BOTTOM_RIGHT?s.BOTTOM:t===s.LEFT||t===s.LEFT_TOP||t===s.LEFT_BOTTOM?s.LEFT:s.RIGHT}var c;(function(t){t.SMALL="360px",t.STANDARD="50%",t.LARGE="90%"})(c||(c={}));class D extends _{static displayName=`${O}.Drawer`;static defaultProps={canOutsideClickClose:!0,isOpen:!1,position:"right",style:{}};render(){const{hasBackdrop:i,size:a,style:n,position:l}=this.props,{className:u,children:f,...h}=this.props,d=g(l),T=p(j,{[E(d)??""]:!0},u),v=a==null?n:{...n,[F(d)?"height":"width"]:a};return e.jsx(b,{...h,className:p({[R]:i}),children:e.jsxs("div",{className:T,style:v,children:[this.maybeRenderHeader(),f]})})}validateProps(i){i.title==null&&(i.icon!=null&&console.warn(I),i.isCloseButtonShown!=null&&console.warn(B)),i.position!=null&&i.position!==g(i.position)&&console.warn(L)}maybeRenderCloseButton(){return this.props.isCloseButtonShown!==!1?e.jsx(y,{"aria-label":"Close",className:S,icon:e.jsx(z,{size:m.LARGE}),onClick:this.props.onClose,variant:"minimal"}):null}maybeRenderHeader(){const{icon:i,title:a}=this.props;return a==null?null:e.jsxs("div",{className:A,children:[e.jsx(r,{icon:i,size:m.LARGE}),e.jsx(P,{children:a}),this.maybeRenderCloseButton()]})}}function M({job:t,onClose:i}){return t?e.jsx(D,{isOpen:!!t,onClose:i,size:c.SMALL,position:"right",title:e.jsxs("span",{style:{display:"flex",alignItems:"center",gap:8},children:[e.jsx(r,{icon:"console",style:{color:"var(--green-primary)"}}),"Job Details"]}),className:"bp5-dark",children:e.jsxs("div",{style:{padding:20,display:"flex",flexDirection:"column",gap:24,overflowY:"auto"},children:[e.jsxs("div",{children:[e.jsx("h2",{style:{fontSize:20,fontWeight:700,color:"var(--text-primary)",margin:0},children:t.gitlab_job_name||`Job ${t.gitlab_job_id}`}),e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8,fontSize:12,fontFamily:"monospace",color:"var(--text-muted)",marginTop:4},children:[e.jsxs("span",{children:["ID: ",t.gitlab_job_id]}),e.jsx("span",{children:"•"}),e.jsxs("span",{style:{display:"flex",alignItems:"center",gap:4},children:[e.jsx(r,{icon:"time",size:10}),new Date(t.ingested_at.value).toLocaleString()]})]})]}),e.jsxs("div",{style:{display:"grid",gridTemplateColumns:"1fr 1fr",gap:12},children:[e.jsxs(o,{style:{background:"var(--bg-primary)",border:"1px solid var(--border-default)",padding:14},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:6,fontSize:10,textTransform:"uppercase",letterSpacing:1,color:"var(--text-muted)",marginBottom:4},children:[e.jsx(r,{icon:"clean",size:12,style:{color:"var(--green-primary)"}}),"Emissions"]}),e.jsxs("div",{style:{fontSize:20,fontFamily:"monospace",fontWeight:500,color:"var(--text-primary)"},children:[t.total_emissions_g.toFixed(2)," ",e.jsx("span",{style:{fontSize:12,color:"var(--text-muted)"},children:"gCO₂e"})]})]}),e.jsxs(o,{style:{background:"var(--bg-primary)",border:"1px solid var(--border-default)",padding:14},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:6,fontSize:10,textTransform:"uppercase",letterSpacing:1,color:"var(--text-muted)",marginBottom:4},children:[e.jsx(r,{icon:"flash",size:12,style:{color:"#d29922"}}),"Energy"]}),e.jsxs("div",{style:{fontSize:20,fontFamily:"monospace",fontWeight:500,color:"var(--text-primary)"},children:[(t.energy_kwh*1e3).toFixed(2)," ",e.jsx("span",{style:{fontSize:12,color:"var(--text-muted)"},children:"Wh"})]})]})]}),e.jsxs("div",{children:[e.jsx("h3",{style:{fontSize:12,fontWeight:600,textTransform:"uppercase",letterSpacing:1,color:"var(--text-muted)",marginBottom:12},children:"Resource Utilization"}),e.jsxs(o,{style:{background:"var(--bg-primary)",border:"1px solid var(--border-default)",padding:14},children:[e.jsxs("div",{style:{marginBottom:14},children:[e.jsxs("div",{style:{display:"flex",justifyContent:"space-between",fontSize:13,marginBottom:6},children:[e.jsxs("span",{style:{display:"flex",alignItems:"center",gap:6,color:"var(--text-secondary)"},children:[e.jsx(r,{icon:"dashboard",size:14,style:{color:"var(--text-muted)"}})," CPU Usage"]}),e.jsxs("span",{style:{fontFamily:"monospace",color:"var(--text-primary)"},children:[(t.cpu_utilization_avg*100).toFixed(1),"%"]})]}),e.jsx(x,{value:t.cpu_utilization_avg,intent:"primary",stripes:!1,animate:!1})]}),e.jsxs("div",{children:[e.jsxs("div",{style:{display:"flex",justifyContent:"space-between",fontSize:13,marginBottom:6},children:[e.jsxs("span",{style:{display:"flex",alignItems:"center",gap:6,color:"var(--text-secondary)"},children:[e.jsx(r,{icon:"pulse",size:14,style:{color:"var(--text-muted)"}})," RAM Usage"]}),e.jsxs("span",{style:{fontFamily:"monospace",color:"var(--text-primary)"},children:[(t.ram_utilization_avg*100).toFixed(1),"%"]})]}),e.jsx(x,{value:t.ram_utilization_avg,intent:"success",stripes:!1,animate:!1})]})]})]}),e.jsxs("div",{children:[e.jsx("h3",{style:{fontSize:12,fontWeight:600,textTransform:"uppercase",letterSpacing:1,color:"var(--text-muted)",marginBottom:12},children:"Environment Details"}),e.jsx("div",{style:{display:"flex",flexDirection:"column",gap:0},children:[{icon:"cog",label:"Machine Type",value:e.jsx("code",{style:{background:"var(--bg-tertiary)",padding:"2px 8px",borderRadius:4,fontSize:12},children:t.machine_type})},{icon:"map-marker",label:"Region",value:t.region||"us-central1"},{icon:"person",label:"Triggered By",value:t.gitlab_user_name||"Unknown"},{icon:"time",label:"Duration",value:e.jsxs("span",{style:{fontFamily:"monospace"},children:[t.runtime_seconds?.toFixed(1),"s"]})}].map(({icon:a,label:n,value:l})=>e.jsxs("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center",padding:"10px 0",borderBottom:"1px solid var(--border-muted)",fontSize:13},children:[e.jsxs("span",{style:{display:"flex",alignItems:"center",gap:8,color:"var(--text-muted)"},children:[e.jsx(r,{icon:a,size:14})," ",n]}),e.jsx("span",{style:{color:"var(--text-primary)"},children:l})]},n))})]}),e.jsx(y,{fill:!0,intent:"success",icon:e.jsx(C,{style:{width:16,height:16}}),text:"View Job on GitLab",onClick:()=>window.open(`https://gitlab.com/projects/${t.gitlab_project_id}/jobs/${t.gitlab_job_id}`,"_blank")})]})}):null}export{M as J};
@@ -0,0 +1 @@
1
+ import{r as i,j as e,S as M,G as D,I as g,l as R,B as E,T as K}from"./index-DW6Qp0d6.js";import{h as L,g as $,u as N,C as n,a as O,s as U}from"./cache-YerT0Slh.js";import{J as V}from"./JobDetailsDrawer-7kXXMSH8.js";import"./progressBar-C4SmnGeZ.js";function Q({activeProjectId:d}){const[x,k]=i.useState("emissions"),[h,F]=i.useState("desc"),[c,w]=i.useState("all"),[m,C]=i.useState(""),[J,v]=i.useState(null),u=i.useMemo(()=>d?{projectId:d}:{},[d]),p=i.useMemo(()=>L(["jobs-dashboard",u]),[u]),T=i.useMemo(()=>$(p)??void 0,[p]),{data:r,isLoading:b,error:y,isFetching:A}=N({queryKey:["jobs-dashboard",d],queryFn:async()=>{const t=await O.get("/api/metrics",{params:u});return U(p,t.data,{ttlMs:45e3}),t.data},initialData:T,staleTime:45e3}),I=i.useMemo(()=>{if(!r)return[];const t=new Set(r.map(s=>s.machine_type).filter(Boolean));return Array.from(t)},[r]),j=i.useMemo(()=>r?r.filter(t=>{if(c!=="all"&&t.machine_type!==c)return!1;if(!m.trim())return!0;const s=m.toLowerCase();return String(t.gitlab_job_id).includes(s)||t.gitlab_job_name?.toLowerCase().includes(s)||t.gitlab_user_name?.toLowerCase().includes(s)}):[],[r,c,m]),W=i.useMemo(()=>{const t=s=>{switch(x){case"runtime":return s.runtime_seconds??0;case"energy":return s.energy_kwh??0;case"intensity":return s.energy_kwh>0?s.total_emissions_g/(s.energy_kwh*1e3):s.total_emissions_g;default:return s.total_emissions_g}};return[...j].sort((s,l)=>{const S=t(s),z=t(l);return h==="desc"?z-S:S-z})},[j,h,x]),a=i.useMemo(()=>!r||r.length===0?null:[...r].sort((t,s)=>s.total_emissions_g-t.total_emissions_g)[0],[r]),o=i.useMemo(()=>!r||r.length===0?null:[...r].sort((t,s)=>(s.runtime_seconds??0)-(t.runtime_seconds??0))[0],[r]),B=r&&r.length>0?r.reduce((t,s)=>t+s.total_emissions_g,0)/r.length:0,f=r&&r.length>0?r.reduce((t,s)=>t+(s.runtime_seconds??0),0)/r.length:0,_=i.useMemo(()=>{if(!r||r.length===0)return[];const t=r.find(l=>typeof l.cpu_utilization_avg=="number"&&l.cpu_utilization_avg<.4&&(l.runtime_seconds??0)>300),s=[];return a&&s.push({title:`Job ${a.gitlab_job_id} emits ${a.total_emissions_g.toFixed(1)} gCO₂e`,description:"Consider caching dependencies or breaking the workload into smaller stages to limit repeated compute."}),o&&(o.runtime_seconds??0)>f*1.5&&s.push({title:`Job ${o.gitlab_job_id} runs for ${(o.runtime_seconds??0).toFixed(0)} seconds`,description:"Investigate parallelizing the work or using a larger machine type temporarily to shorten the critical path."}),t&&s.push({title:`Job ${t.gitlab_job_id} averages ${(t.cpu_utilization_avg*100).toFixed(0)}% CPU`,description:"This workload looks underutilized—downsize the runner or combine tasks to improve efficiency."}),s.slice(0,3)},[f,o,r,a]);return(!r||r.length===0)&&b?e.jsx("div",{style:{flex:1,display:"flex",alignItems:"center",justifyContent:"center"},children:e.jsx(M,{size:40,intent:"success"})}):e.jsxs("div",{style:{flex:1,overflowY:"auto",padding:24,maxWidth:1100,margin:"0 auto"},children:[e.jsx(V,{job:J,onClose:()=>v(null)}),r&&r.length>0&&A&&e.jsx("div",{style:{fontSize:11,color:"var(--text-muted)",textAlign:"right",marginBottom:8},children:"Refreshing jobs…"}),y&&e.jsx(n,{style:{background:"rgba(219,55,55,0.1)",border:"1px solid rgba(219,55,55,0.3)",marginBottom:16,padding:14},children:e.jsxs("span",{style:{color:"#f97171",fontSize:13},children:["Failed to load jobs: ",String(y)]})}),r&&r.length>0?e.jsxs(e.Fragment,{children:[e.jsxs("div",{style:{display:"grid",gridTemplateColumns:"repeat(4, 1fr)",gap:16,marginBottom:24},children:[e.jsxs(n,{style:{background:"var(--bg-card)",border:"1px solid var(--border-default)",padding:16},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:6,fontSize:10,textTransform:"uppercase",letterSpacing:1.5,color:"var(--text-muted)",marginBottom:6},children:[e.jsx(D,{style:{width:14,height:14}}),"Jobs Tracked"]}),e.jsx("div",{style:{fontSize:24,fontFamily:"monospace",fontWeight:500,color:"var(--text-primary)"},children:r.length})]}),e.jsxs(n,{style:{background:"var(--bg-card)",border:"1px solid var(--border-default)",padding:16},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:6,fontSize:10,textTransform:"uppercase",letterSpacing:1.5,color:"var(--text-muted)",marginBottom:6},children:[e.jsx(g,{icon:"flame",size:14,style:{color:"#d29922"}}),"Avg Emissions"]}),e.jsxs("div",{style:{fontSize:24,fontFamily:"monospace",fontWeight:500,color:"var(--text-primary)"},children:[B.toFixed(1)," ",e.jsx("span",{style:{fontSize:12,color:"var(--text-muted)"},children:"gCO₂e"})]}),a&&e.jsxs("p",{style:{fontSize:11,color:"var(--text-muted)",margin:"4px 0 0"},children:["Top: Job ",a.gitlab_job_id," (",a.total_emissions_g.toFixed(0)," g)"]})]}),e.jsxs(n,{style:{background:"var(--bg-card)",border:"1px solid var(--border-default)",padding:16},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:6,fontSize:10,textTransform:"uppercase",letterSpacing:1.5,color:"var(--text-muted)",marginBottom:6},children:[e.jsx(g,{icon:"time",size:14,style:{color:"#58a6ff"}}),"Avg Runtime"]}),e.jsxs("div",{style:{fontSize:24,fontFamily:"monospace",fontWeight:500,color:"var(--text-primary)"},children:[f.toFixed(0)," ",e.jsx("span",{style:{fontSize:12,color:"var(--text-muted)"},children:"s"})]}),o&&e.jsxs("p",{style:{fontSize:11,color:"var(--text-muted)",margin:"4px 0 0"},children:["Longest: Job ",o.gitlab_job_id," (",(o.runtime_seconds??0).toFixed(0)," s)"]})]}),e.jsxs(n,{style:{background:"var(--bg-card)",border:"1px solid var(--border-default)",padding:16},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:6,fontSize:10,textTransform:"uppercase",letterSpacing:1.5,color:"var(--text-muted)",marginBottom:6},children:[e.jsx(g,{icon:"flash",size:14,style:{color:"var(--green-primary)"}}),"Energy / Job"]}),e.jsxs("div",{style:{fontSize:24,fontFamily:"monospace",fontWeight:500,color:"var(--text-primary)"},children:[(r.reduce((t,s)=>t+s.energy_kwh,0)/r.length).toFixed(2),e.jsx("span",{style:{fontSize:12,color:"var(--text-muted)"},children:" kWh"})]})]})]}),e.jsx(n,{style:{background:"var(--bg-card)",border:"1px solid var(--border-default)",padding:16,marginBottom:24},children:e.jsxs("div",{style:{display:"flex",gap:12,alignItems:"center",flexWrap:"wrap"},children:[e.jsx("div",{style:{flex:1,minWidth:200},children:e.jsx(R,{leftIcon:"search",placeholder:"Search by job ID, name, or user",value:m,onChange:t=>C(t.target.value)})}),e.jsx("div",{className:"bp5-html-select",style:{minWidth:160},children:e.jsxs("select",{value:c,onChange:t=>w(t.target.value),style:{background:"var(--bg-primary)",border:"1px solid var(--border-default)",color:"var(--text-primary)",borderRadius:6,padding:"6px 8px",fontSize:12},children:[e.jsx("option",{value:"all",children:"All machine types"}),I.map(t=>e.jsx("option",{value:t,children:t},t))]})}),e.jsx("div",{className:"bp5-html-select",style:{minWidth:140},children:e.jsxs("select",{value:x,onChange:t=>k(t.target.value),style:{background:"var(--bg-primary)",border:"1px solid var(--border-default)",color:"var(--text-primary)",borderRadius:6,padding:"6px 8px",fontSize:12},children:[e.jsx("option",{value:"emissions",children:"Sort by emissions"}),e.jsx("option",{value:"runtime",children:"Sort by runtime"}),e.jsx("option",{value:"energy",children:"Sort by energy"}),e.jsx("option",{value:"intensity",children:"Sort by intensity"})]})}),e.jsx(E,{small:!0,icon:"sort",text:h==="desc"?"Desc":"Asc",onClick:()=>F(t=>t==="desc"?"asc":"desc")})]})}),e.jsxs("div",{style:{display:"grid",gridTemplateColumns:"2fr 1fr",gap:16},children:[e.jsx(n,{style:{background:"var(--bg-card)",border:"1px solid var(--border-default)",padding:0,overflow:"hidden"},children:e.jsx("div",{style:{maxHeight:520,overflowY:"auto"},children:e.jsxs("table",{className:"bp5-html-table bp5-html-table-condensed",style:{width:"100%"},children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Job"}),e.jsx("th",{children:"Machine"}),e.jsx("th",{style:{textAlign:"right"},children:"Runtime (s)"}),e.jsx("th",{style:{textAlign:"right"},children:"Energy (Wh)"}),e.jsx("th",{style:{textAlign:"right"},children:"Emissions (g)"}),e.jsx("th",{style:{textAlign:"right"},children:"Intensity"}),e.jsx("th",{children:"User"})]})}),e.jsx("tbody",{children:W.map(t=>{const s=t.energy_kwh>0?t.total_emissions_g/(t.energy_kwh*1e3):0;return e.jsxs("tr",{style:{cursor:"pointer"},onClick:()=>v(t),children:[e.jsx("td",{children:e.jsxs("div",{children:[e.jsxs("span",{style:{fontFamily:"monospace",fontSize:12,color:"var(--text-primary)"},children:["Job ",t.gitlab_job_id]}),e.jsx("br",{}),e.jsx("span",{style:{fontSize:11,color:"var(--text-muted)"},children:t.gitlab_job_name||"Unnamed job"})]})}),e.jsx("td",{children:e.jsx(K,{minimal:!0,style:{fontSize:11,fontFamily:"monospace"},children:t.machine_type})}),e.jsx("td",{style:{textAlign:"right",fontFamily:"monospace",fontSize:12,color:"var(--text-primary)"},children:(t.runtime_seconds??0).toFixed(0)}),e.jsx("td",{style:{textAlign:"right",fontFamily:"monospace",fontSize:12,color:"var(--text-primary)"},children:(t.energy_kwh*1e3).toFixed(0)}),e.jsx("td",{style:{textAlign:"right",fontFamily:"monospace",fontSize:12,color:"var(--text-primary)"},children:t.total_emissions_g.toFixed(1)}),e.jsx("td",{style:{textAlign:"right",fontFamily:"monospace",fontSize:12,color:"var(--text-primary)"},children:s.toFixed(2)}),e.jsx("td",{style:{fontSize:12,color:"var(--text-secondary)"},children:t.gitlab_user_name||"Unknown"})]},t.gitlab_job_id)})})]})})}),e.jsxs(n,{style:{background:"var(--bg-card)",border:"1px solid var(--border-default)",padding:16},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8,marginBottom:12},children:[e.jsx(g,{icon:"warning-sign",size:14,style:{color:"#d29922"}}),e.jsx("span",{style:{fontSize:10,textTransform:"uppercase",letterSpacing:1.5,color:"var(--text-muted)",fontWeight:600},children:"Optimization Opportunities"})]}),_.length===0?e.jsx("p",{style:{fontSize:12,color:"var(--text-muted)"},children:"No obvious issues detected. Keep collecting data to surface new opportunities."}):e.jsx("div",{style:{display:"flex",flexDirection:"column",gap:10},children:_.map(t=>e.jsxs(n,{style:{background:"var(--bg-primary)",border:"1px solid var(--border-muted)",padding:12},children:[e.jsx("p",{style:{fontSize:13,fontWeight:500,color:"var(--text-primary)",margin:"0 0 4px"},children:t.title}),e.jsx("p",{style:{fontSize:11,color:"var(--text-muted)",lineHeight:1.5,margin:0},children:t.description})]},t.title))})]})]})]}):!b&&!y&&e.jsx("div",{style:{textAlign:"center",color:"var(--text-muted)",padding:32},children:"No job data available. Run the measurement component to populate this view."})]})}export{Q as JobsDashboard};
@@ -0,0 +1 @@
1
+ import{r as D,j as l,S as q,I as Q}from"./index-DW6Qp0d6.js";import{h as ee,g as te,u as re,C as I,a as ie,s as oe}from"./cache-YerT0Slh.js";import{_ as w,c as $,r as ae,e as se,l as ne,u as J,s as le,i as ce,g as G,n as he,Z as de,a as F,b as ue,t as pe,d as Z,f as B,h as me,G as P,j as ye,k as ge,m as fe,o as ve,p as V,q as be,v as Se,w as xe,x as _e,S as Ie,B as Ce,P as De,C as je,y as H,z as we,R as ze,A as T,D as Ae,E as Te,F as Le,H as Me,I as Pe,J as Re}from"./core-Cz8f3oSB.js";import{J as Oe}from"./JobDetailsDrawer-7kXXMSH8.js";import"./progressBar-C4SmnGeZ.js";var ke=(function(n){w(t,n);function t(e,r,a,i){var o=n.call(this)||this;return o.updateData(e,r,a,i),o}return t.prototype._createSymbol=function(e,r,a,i,o,s){this.removeAll();var c=$(e,-1,-1,2,2,null,s);c.attr({z2:ae(o,100),culling:!0,scaleX:i[0]/2,scaleY:i[1]/2}),c.drift=Ee,this._symbolType=e,this.add(c)},t.prototype.stopSymbolAnimation=function(e){this.childAt(0).stopAnimation(null,e)},t.prototype.getSymbolType=function(){return this._symbolType},t.prototype.getSymbolPath=function(){return this.childAt(0)},t.prototype.highlight=function(){se(this.childAt(0))},t.prototype.downplay=function(){ne(this.childAt(0))},t.prototype.setZ=function(e,r){var a=this.childAt(0);a.zlevel=e,a.z=r},t.prototype.setDraggable=function(e,r){var a=this.childAt(0);a.draggable=e,a.cursor=!r&&e?"move":a.cursor},t.prototype.updateData=function(e,r,a,i){this.silent=!1;var o=e.getItemVisual(r,"symbol")||"circle",s=e.hostModel,c=t.getSymbolSize(e,r),p=t.getSymbolZ2(e,r),y=o!==this._symbolType,d=i&&i.disableAnimation;if(y){var m=e.getItemVisual(r,"symbolKeepAspect");this._createSymbol(o,e,r,c,p,m)}else{var h=this.childAt(0);h.silent=!1;var v={scaleX:c[0]/2,scaleY:c[1]/2};d?h.attr(v):J(h,v,s,r),le(h)}if(this._updateCommon(e,r,c,a,i),y){var h=this.childAt(0);if(!d){var v={scaleX:this._sizeX,scaleY:this._sizeY,style:{opacity:h.style.opacity}};h.scaleX=h.scaleY=0,h.style.opacity=0,ce(h,v,s,r)}}d&&this.childAt(0).stopAnimation("leave")},t.prototype._updateCommon=function(e,r,a,i,o){var s=this.childAt(0),c=e.hostModel,p,y,d,m,h,v,x,b,u;if(i&&(p=i.emphasisItemStyle,y=i.blurItemStyle,d=i.selectItemStyle,m=i.focus,h=i.blurScope,x=i.labelStatesModels,b=i.hoverScale,u=i.cursorStyle,v=i.emphasisDisabled),!i||e.hasItemOption){var f=i&&i.itemModel?i.itemModel:e.getItemModel(r),g=f.getModel("emphasis");p=g.getModel("itemStyle").getItemStyle(),d=f.getModel(["select","itemStyle"]).getItemStyle(),y=f.getModel(["blur","itemStyle"]).getItemStyle(),m=g.get("focus"),h=g.get("blurScope"),v=g.get("disabled"),x=G(f),b=g.getShallow("scale"),u=f.getShallow("cursor")}var _=e.getItemVisual(r,"symbolRotate");s.attr("rotation",(_||0)*Math.PI/180||0);var S=he(e.getItemVisual(r,"symbolOffset"),a);S&&(s.x=S[0],s.y=S[1]),u&&s.attr("cursor",u);var C=e.getItemVisual(r,"style"),R=C.fill;if(s instanceof de){var j=s.style;s.useStyle(F({image:j.image,x:j.x,y:j.y,width:j.width,height:j.height},C))}else s.__isEmptyBrush?s.useStyle(F({},C)):s.useStyle(C),s.style.decal=null,s.setColor(R,o&&o.symbolInnerColor),s.style.strokeNoScale=!0;var O=e.getItemVisual(r,"liftZ"),z=this._z2;O!=null?z==null&&(this._z2=s.z2,s.z2+=O):z!=null&&(s.z2=z,this._z2=null);var X=o&&o.useNameLabel;ue(s,x,{labelFetcher:c,labelDataIndex:r,defaultText:K,inheritColor:R,defaultOpacity:C.opacity});function K(E){return X?e.getName(E):ye(e,E)}this._sizeX=a[0]/2,this._sizeY=a[1]/2;var A=s.ensureState("emphasis");A.style=p,s.ensureState("select").style=d,s.ensureState("blur").style=y;var k=b==null||b===!0?Math.max(1.1,3/this._sizeY):isFinite(b)&&b>0?+b:1;A.scaleX=this._sizeX*k,A.scaleY=this._sizeY*k,this.setSymbolScale(1),pe(this,m,h,v)},t.prototype.setSymbolScale=function(e){this.scaleX=this.scaleY=e},t.prototype.fadeOut=function(e,r,a){var i=this.childAt(0),o=Z(this).dataIndex,s=a&&a.animation;if(this.silent=i.silent=!0,a&&a.fadeLabel){var c=i.getTextContent();c&&B(c,{style:{opacity:0}},r,{dataIndex:o,removeOpt:s,cb:function(){i.removeTextContent()}})}else i.removeTextContent();B(i,{style:{opacity:0},scaleX:0,scaleY:0},r,{dataIndex:o,cb:e,removeOpt:s})},t.getSymbolSize=function(e,r){return me(e.getItemVisual(r,"symbolSize"))},t.getSymbolZ2=function(e,r){return e.getItemVisual(r,"z2")},t})(P);function Ee(n,t){this.parent.drift(n,t)}function L(n,t,e,r){return t&&!isNaN(t[0])&&!isNaN(t[1])&&!(r.isIgnore&&r.isIgnore(e))&&!(r.clipShape&&!r.clipShape.contain(t[0],t[1]))&&n.getItemVisual(e,"symbol")!=="none"}function N(n){return n!=null&&!fe(n)&&(n={isIgnore:n}),n||{}}function W(n){var t=n.hostModel,e=t.getModel("emphasis");return{emphasisItemStyle:e.getModel("itemStyle").getItemStyle(),blurItemStyle:t.getModel(["blur","itemStyle"]).getItemStyle(),selectItemStyle:t.getModel(["select","itemStyle"]).getItemStyle(),focus:e.get("focus"),blurScope:e.get("blurScope"),emphasisDisabled:e.get("disabled"),hoverScale:e.get("scale"),labelStatesModels:G(t),cursorStyle:t.get("cursor")}}var Fe=(function(){function n(t){this.group=new P,this._SymbolCtor=t||ke}return n.prototype.updateData=function(t,e){this._progressiveEls=null,e=N(e);var r=this.group,a=t.hostModel,i=this._data,o=this._SymbolCtor,s=e.disableAnimation,c=W(t),p={disableAnimation:s},y=e.getSymbolPoint||function(d){return t.getItemLayout(d)};i||r.removeAll(),t.diff(i).add(function(d){var m=y(d);if(L(t,m,d,e)){var h=new o(t,d,c,p);h.setPosition(m),t.setItemGraphicEl(d,h),r.add(h)}}).update(function(d,m){var h=i.getItemGraphicEl(m),v=y(d);if(!L(t,v,d,e)){r.remove(h);return}var x=t.getItemVisual(d,"symbol")||"circle",b=h&&h.getSymbolType&&h.getSymbolType();if(!h||b&&b!==x)r.remove(h),h=new o(t,d,c,p),h.setPosition(v);else{h.updateData(t,d,c,p);var u={x:v[0],y:v[1]};s?h.attr(u):J(h,u,a)}r.add(h),t.setItemGraphicEl(d,h)}).remove(function(d){var m=i.getItemGraphicEl(d);m&&m.fadeOut(function(){r.remove(m)},a)}).execute(),this._getSymbolPoint=y,this._data=t},n.prototype.updateLayout=function(){var t=this,e=this._data;e&&e.eachItemGraphicEl(function(r,a){var i=t._getSymbolPoint(a);r.setPosition(i),r.markRedraw()})},n.prototype.incrementalPrepareUpdate=function(t){this._seriesScope=W(t),this._data=null,this.group.removeAll()},n.prototype.incrementalUpdate=function(t,e,r){this._progressiveEls=[],r=N(r);function a(c){c.isGroup||(c.incremental=!0,c.ensureState("emphasis").hoverLayer=!0)}for(var i=t.start;i<t.end;i++){var o=e.getItemLayout(i);if(L(e,o,i,r)){var s=new this._SymbolCtor(e,i,this._seriesScope);s.traverse(a),s.setPosition(o),this.group.add(s),e.setItemGraphicEl(i,s),this._progressiveEls.push(s)}}},n.prototype.eachRendered=function(t){ge(this._progressiveEls||this.group,t)},n.prototype.remove=function(t){var e=this.group,r=this._data;r&&t?r.eachItemGraphicEl(function(a){a.fadeOut(function(){e.remove(a)},r.hostModel)}):e.removeAll()},n})();function U(n,t){return{seriesType:n,plan:Se(),reset:function(e){var r=e.getData(),a=e.coordinateSystem,i=e.pipelineContext,o=i.large;if(a){var s=ve(a.dimensions,function(h){return r.mapDimension(h)}).slice(0,2),c=s.length,p=r.getCalculationInfo("stackResultDimension");V(r,s[0])&&(s[0]=p),V(r,s[1])&&(s[1]=p);var y=r.getStore(),d=r.getDimensionIndex(s[0]),m=r.getDimensionIndex(s[1]);return c&&{progress:function(h,v){for(var x=h.end-h.start,b=o&&be(x*c),u=[],f=[],g=h.start,_=0;g<h.end;g++){var S=void 0;if(c===1){var C=y.get(d,g);S=a.dataToPoint(C,null,f)}else u[0]=y.get(d,g),u[1]=y.get(m,g),S=a.dataToPoint(u,null,f);o?(b[_++]=S[0],b[_++]=S[1]):v.setItemLayout(g,S.slice())}o&&v.setLayout("points",b)}}}}}}var Be=(function(n){w(t,n);function t(){var e=n!==null&&n.apply(this,arguments)||this;return e.type=t.type,e.hasSymbolVisual=!0,e}return t.prototype.getInitialData=function(e,r){return xe(null,this,{useEncodeDefaulter:!0})},t.prototype.getProgressive=function(){var e=this.option.progressive;return e??(this.option.large?5e3:this.get("progressive"))},t.prototype.getProgressiveThreshold=function(){var e=this.option.progressiveThreshold;return e??(this.option.large?1e4:this.get("progressiveThreshold"))},t.prototype.brushSelector=function(e,r,a){return a.point(r.getItemLayout(e))},t.prototype.getZLevelKey=function(){return this.getData().count()>this.getProgressiveThreshold()?this.id:""},t.type="series.scatter",t.dependencies=["grid","polar","geo","singleAxis","calendar","matrix"],t.defaultOption={coordinateSystem:"cartesian2d",z:2,legendHoverLink:!0,symbolSize:10,large:!1,largeThreshold:2e3,itemStyle:{opacity:.8},emphasis:{scale:!0},clip:!0,select:{itemStyle:{borderColor:_e.color.primary}},universalTransition:{divideShape:"clone"}},t})(Ie),Y=4,Ve=(function(){function n(){}return n})(),Ne=(function(n){w(t,n);function t(e){var r=n.call(this,e)||this;return r._off=0,r.hoverDataIdx=-1,r}return t.prototype.getDefaultShape=function(){return new Ve},t.prototype.reset=function(){this.notClear=!1,this._off=0},t.prototype.buildPath=function(e,r){var a=r.points,i=r.size,o=this.symbolProxy,s=o.shape,c=e.getContext?e.getContext():e,p=c&&i[0]<Y,y=this.softClipShape,d;if(p){this._ctx=c;return}for(this._ctx=null,d=this._off;d<a.length;){var m=a[d++],h=a[d++];isNaN(m)||isNaN(h)||y&&!y.contain(m,h)||(s.x=m-i[0]/2,s.y=h-i[1]/2,s.width=i[0],s.height=i[1],o.buildPath(e,s,!0))}this.incremental&&(this._off=d,this.notClear=!0)},t.prototype.afterBrush=function(){var e=this.shape,r=e.points,a=e.size,i=this._ctx,o=this.softClipShape,s;if(i){for(s=this._off;s<r.length;){var c=r[s++],p=r[s++];isNaN(c)||isNaN(p)||o&&!o.contain(c,p)||i.fillRect(c-a[0]/2,p-a[1]/2,a[0],a[1])}this.incremental&&(this._off=s,this.notClear=!0)}},t.prototype.findDataIndex=function(e,r){for(var a=this.shape,i=a.points,o=a.size,s=Math.max(o[0],4),c=Math.max(o[1],4),p=i.length/2-1;p>=0;p--){var y=p*2,d=i[y]-s/2,m=i[y+1]-c/2;if(e>=d&&r>=m&&e<=d+s&&r<=m+c)return p}return-1},t.prototype.contain=function(e,r){var a=this.transformCoordToLocal(e,r),i=this.getBoundingRect();if(e=a[0],r=a[1],i.contain(e,r)){var o=this.hoverDataIdx=this.findDataIndex(e,r);return o>=0}return this.hoverDataIdx=-1,!1},t.prototype.getBoundingRect=function(){var e=this._rect;if(!e){for(var r=this.shape,a=r.points,i=r.size,o=i[0],s=i[1],c=1/0,p=1/0,y=-1/0,d=-1/0,m=0;m<a.length;){var h=a[m++],v=a[m++];c=Math.min(h,c),y=Math.max(h,y),p=Math.min(v,p),d=Math.max(v,d)}e=this._rect=new Ce(c-o/2,p-s/2,y-c+o,d-p+s)}return e},t})(De),We=(function(){function n(){this.group=new P}return n.prototype.updateData=function(t,e){this._clear();var r=this._create();r.setShape({points:t.getLayout("points")}),this._setCommon(r,t,e)},n.prototype.updateLayout=function(t){var e=t.getLayout("points");this.group.eachChild(function(r){if(r.startIndex!=null){var a=(r.endIndex-r.startIndex)*2,i=r.startIndex*4*2;e=new Float32Array(e.buffer,i,a)}r.setShape("points",e),r.reset()})},n.prototype.incrementalPrepareUpdate=function(t){this._clear()},n.prototype.incrementalUpdate=function(t,e,r){var a=this._newAdded[0],i=e.getLayout("points"),o=a&&a.shape.points;if(o&&o.length<2e4){var s=o.length,c=new Float32Array(s+i.length);c.set(o),c.set(i,s),a.endIndex=t.end,a.setShape({points:c})}else{this._newAdded=[];var p=this._create();p.startIndex=t.start,p.endIndex=t.end,p.incremental=!0,p.setShape({points:i}),this._setCommon(p,e,r)}},n.prototype.eachRendered=function(t){this._newAdded[0]&&t(this._newAdded[0])},n.prototype._create=function(){var t=new Ne({cursor:"default"});return t.ignoreCoarsePointer=!0,this.group.add(t),this._newAdded.push(t),t},n.prototype._setCommon=function(t,e,r){var a=e.hostModel;r=r||{};var i=e.getVisual("symbolSize");t.setShape("size",i instanceof Array?i:[i,i]),t.softClipShape=r.clipShape||null,t.symbolProxy=$(e.getVisual("symbol"),0,0,0,0),t.setColor=t.symbolProxy.setColor;var o=t.shape.size[0]<Y;t.useStyle(a.getModel("itemStyle").getItemStyle(o?["color","shadowBlur","shadowColor"]:["color"]));var s=e.getVisual("style"),c=s&&s.fill;c&&t.setColor(c);var p=Z(t);p.seriesIndex=a.seriesIndex,t.on("mousemove",function(y){p.dataIndex=null;var d=t.hoverDataIdx;d>=0&&(p.dataIndex=d+(t.startIndex||0))})},n.prototype.remove=function(){this._clear()},n.prototype._clear=function(){this._newAdded=[],this.group.removeAll()},n})(),$e=(function(n){w(t,n);function t(){var e=n!==null&&n.apply(this,arguments)||this;return e.type=t.type,e}return t.prototype.render=function(e,r,a){var i=e.getData(),o=this._updateSymbolDraw(i,e);o.updateData(i,{clipShape:this._getClipShape(e)}),this._finished=!0},t.prototype.incrementalPrepareRender=function(e,r,a){var i=e.getData(),o=this._updateSymbolDraw(i,e);o.incrementalPrepareUpdate(i),this._finished=!1},t.prototype.incrementalRender=function(e,r,a){this._symbolDraw.incrementalUpdate(e,r.getData(),{clipShape:this._getClipShape(r)}),this._finished=e.end===r.getData().count()},t.prototype.updateTransform=function(e,r,a){var i=e.getData();if(this.group.dirty(),!this._finished||i.count()>1e4)return{update:!0};var o=U("").reset(e,r,a);o.progress&&o.progress({start:0,end:i.count(),count:i.count()},i),this._symbolDraw.updateLayout(i)},t.prototype.eachRendered=function(e){this._symbolDraw&&this._symbolDraw.eachRendered(e)},t.prototype._getClipShape=function(e){if(e.get("clip",!0)){var r=e.coordinateSystem;return r&&r.getArea&&r.getArea(.1)}},t.prototype._updateSymbolDraw=function(e,r){var a=this._symbolDraw,i=r.pipelineContext,o=i.large;return(!a||o!==this._isLargeDraw)&&(a&&a.remove(),a=this._symbolDraw=o?new We:new Fe,this._isLargeDraw=o,this.group.removeAll()),this.group.add(a.group),a},t.prototype.remove=function(e,r){this._symbolDraw&&this._symbolDraw.remove(!0),this._symbolDraw=null},t.prototype.dispose=function(){},t.type="scatter",t})(je);function Je(n){H(we),n.registerSeriesModel(Be),n.registerChartView($e),n.registerLayout(U("scatter"))}H([Ae,Te,Je,Le,Me,Pe,Re]);const M=ze;function Xe({activeProjectId:n}){const[t,e]=D.useState(null),r=D.useMemo(()=>n?{projectId:n}:{},[n]),a=D.useMemo(()=>ee(["metrics",r]),[r]),i=D.useMemo(()=>te(a)??void 0,[a]),{data:o,isLoading:s,error:c,isFetching:p}=re({queryKey:["metrics",n],queryFn:async()=>{const u=await ie.get("/api/metrics",{params:r});return oe(a,u.data,{ttlMs:45e3}),u.data},initialData:i,staleTime:45e3}),d={click:u=>{if(!o)return;let f;if(u.seriesType==="scatter")f=u.data[2];else if(u.seriesType==="bar"){const g=u.name.match(/Job (\d+)/);g&&(f=parseInt(g[1]))}if(f){const g=o.find(_=>_.gitlab_job_id===f);g&&e(g)}}},m=D.useMemo(()=>{if(!o||o.length===0)return{};const u=[...o].reverse();return{tooltip:{trigger:"axis",backgroundColor:"#161b22",borderColor:"#30363d",textStyle:{color:"#e6edf3"}},grid:{left:"3%",right:"4%",bottom:"3%",containLabel:!0},xAxis:{type:"category",data:u.map(f=>`Job ${f.gitlab_job_id}`),axisLine:{show:!1},axisTick:{show:!1},axisLabel:{color:"#6e7681"}},yAxis:{type:"value",splitLine:{lineStyle:{color:"#21262d"}},axisLabel:{color:"#6e7681",formatter:"{value} g"}},series:[{name:"Emissions",type:"bar",data:u.map(f=>f.total_emissions_g),itemStyle:{color:"#2da44e",borderRadius:[4,4,0,0]},barMaxWidth:50,cursor:"pointer"}]}},[o]),h=D.useMemo(()=>{if(!o||o.length===0)return{};const u={};o.forEach(g=>{u[g.machine_type]=(u[g.machine_type]||0)+g.total_emissions_g});const f=Object.entries(u).map(([g,_])=>({name:g,value:parseFloat(_.toFixed(2))}));return{tooltip:{trigger:"item",backgroundColor:"#161b22",borderColor:"#30363d",textStyle:{color:"#e6edf3"},formatter:"{b}: {c}g ({d}%)"},legend:{top:"5%",left:"center",textStyle:{color:"#8b949e"}},series:[{name:"Emissions by Machine Type",type:"pie",radius:["40%","70%"],avoidLabelOverlap:!1,itemStyle:{borderRadius:10,borderColor:"#0d1117",borderWidth:2},label:{show:!1},emphasis:{label:{show:!0,fontSize:18,fontWeight:"bold",color:"#e6edf3"}},labelLine:{show:!1},data:f}]}},[o]),v=D.useMemo(()=>!o||o.length===0?{}:{tooltip:{backgroundColor:"#161b22",borderColor:"#30363d",textStyle:{color:"#e6edf3"},formatter:u=>{const[f,g,_,S]=u.data;return`Job ${_}<br/>Runtime: ${f}s<br/>Emissions: ${g}g<br/>Type: ${S}`}},grid:{left:"8%",right:"8%",bottom:"8%",containLabel:!0},xAxis:{name:"Runtime (s)",nameTextStyle:{color:"#6e7681"},splitLine:{lineStyle:{color:"#21262d"}},axisLabel:{color:"#6e7681"}},yAxis:{name:"Emissions (g)",nameTextStyle:{color:"#6e7681"},splitLine:{lineStyle:{color:"#21262d"}},axisLabel:{color:"#6e7681"}},series:[{symbolSize:10,data:o.map(u=>[u.runtime_seconds||0,u.total_emissions_g,u.gitlab_job_id,u.machine_type]),type:"scatter",itemStyle:{color:"#2da44e"},cursor:"pointer"}]},[o]),x=o?.reduce((u,f)=>u+f.total_emissions_g,0)||0,b=o?.length?x/o.length:0;return(!o||o.length===0)&&s?l.jsx("div",{style:{flex:1,display:"flex",alignItems:"center",justifyContent:"center"},children:l.jsx(q,{size:40,intent:"success"})}):l.jsxs("div",{style:{flex:1,overflowY:"auto",padding:24,maxWidth:1100,margin:"0 auto"},children:[l.jsx(Oe,{job:t,onClose:()=>e(null)}),o&&o.length>0&&p&&l.jsx("div",{style:{fontSize:11,color:"var(--text-muted)",textAlign:"right",marginBottom:8},children:"Refreshing data…"}),c&&l.jsx(I,{style:{background:"rgba(219,55,55,0.1)",border:"1px solid rgba(219,55,55,0.3)",marginBottom:16,padding:14},children:l.jsxs("span",{style:{color:"#f97171",fontSize:13},children:["Failed to load metrics: ",String(c)]})}),o&&o.length>0&&l.jsxs(l.Fragment,{children:[l.jsxs("div",{style:{display:"grid",gridTemplateColumns:"repeat(3, 1fr)",gap:16,marginBottom:24},children:[l.jsxs(I,{style:{background:"var(--bg-card)",border:"1px solid var(--border-default)",padding:16},children:[l.jsxs("div",{style:{display:"flex",alignItems:"center",gap:6,fontSize:10,textTransform:"uppercase",letterSpacing:1.5,color:"var(--text-muted)",marginBottom:6},children:[l.jsx(Q,{icon:"clean",size:12,style:{color:"var(--green-primary)"}}),"Total Emissions"]}),l.jsxs("div",{style:{fontSize:24,fontFamily:"monospace",fontWeight:500,color:"var(--text-primary)"},children:[x.toFixed(2)," gCO₂e"]})]}),l.jsxs(I,{style:{background:"var(--bg-card)",border:"1px solid var(--border-default)",padding:16},children:[l.jsx("div",{style:{display:"flex",alignItems:"center",gap:6,fontSize:10,textTransform:"uppercase",letterSpacing:1.5,color:"var(--text-muted)",marginBottom:6},children:"Avg per Job"}),l.jsxs("div",{style:{fontSize:24,fontFamily:"monospace",fontWeight:500,color:"var(--text-primary)"},children:[b.toFixed(2)," gCO₂e"]})]}),l.jsxs(I,{style:{background:"var(--bg-card)",border:"1px solid var(--border-default)",padding:16},children:[l.jsx("div",{style:{display:"flex",alignItems:"center",gap:6,fontSize:10,textTransform:"uppercase",letterSpacing:1.5,color:"var(--text-muted)",marginBottom:6},children:"Jobs Analyzed"}),l.jsx("div",{style:{fontSize:24,fontFamily:"monospace",fontWeight:500,color:"var(--text-primary)"},children:o.length})]})]}),l.jsxs("div",{style:{marginBottom:24},children:[l.jsx("h3",{style:{fontSize:13,fontWeight:500,color:"var(--text-secondary)",marginBottom:8},children:"Emissions History"}),l.jsx(I,{style:{background:"var(--bg-card)",border:"1px solid var(--border-default)",padding:16,height:320},children:l.jsx(M,{echarts:T,option:m,style:{height:"100%",width:"100%"},theme:"dark",onEvents:d})})]}),l.jsxs("div",{style:{display:"grid",gridTemplateColumns:"1fr 1fr",gap:16,marginBottom:24},children:[l.jsxs("div",{children:[l.jsx("h3",{style:{fontSize:13,fontWeight:500,color:"var(--text-secondary)",marginBottom:8},children:"Emissions by Machine Type"}),l.jsx(I,{style:{background:"var(--bg-card)",border:"1px solid var(--border-default)",padding:16,height:320},children:l.jsx(M,{echarts:T,option:h,style:{height:"100%",width:"100%"},theme:"dark",onEvents:d})})]}),l.jsxs("div",{children:[l.jsx("h3",{style:{fontSize:13,fontWeight:500,color:"var(--text-secondary)",marginBottom:8},children:"Runtime vs Emissions"}),l.jsx(I,{style:{background:"var(--bg-card)",border:"1px solid var(--border-default)",padding:16,height:320},children:l.jsx(M,{echarts:T,option:v,style:{height:"100%",width:"100%"},theme:"dark",onEvents:d})})]})]}),l.jsxs("div",{children:[l.jsx("h3",{style:{fontSize:13,fontWeight:500,color:"var(--text-secondary)",marginBottom:8},children:"Top Carbon-Intensive Jobs"}),l.jsx(I,{style:{background:"var(--bg-card)",border:"1px solid var(--border-default)",padding:0,overflow:"hidden"},children:l.jsx("div",{style:{overflowX:"auto"},children:l.jsxs("table",{className:"bp5-html-table bp5-html-table-condensed",style:{width:"100%"},children:[l.jsx("thead",{children:l.jsxs("tr",{children:[l.jsx("th",{children:"Job ID"}),l.jsx("th",{children:"Machine Type"}),l.jsx("th",{style:{textAlign:"right"},children:"Runtime (s)"}),l.jsx("th",{style:{textAlign:"right"},children:"Energy (Wh)"}),l.jsx("th",{style:{textAlign:"right"},children:"Emissions (gCO₂e)"})]})}),l.jsx("tbody",{children:o.sort((u,f)=>f.total_emissions_g-u.total_emissions_g).slice(0,10).map(u=>l.jsxs("tr",{style:{cursor:"pointer"},onClick:()=>e(u),children:[l.jsx("td",{style:{fontFamily:"monospace",fontSize:12,color:"var(--text-primary)"},children:u.gitlab_job_id}),l.jsx("td",{children:l.jsx("code",{style:{background:"var(--bg-tertiary)",padding:"2px 6px",borderRadius:4,fontSize:11},children:u.machine_type})}),l.jsx("td",{style:{textAlign:"right",fontFamily:"monospace",fontSize:12,color:"var(--text-secondary)"},children:u.runtime_seconds?.toFixed(1)||"-"}),l.jsx("td",{style:{textAlign:"right",fontFamily:"monospace",fontSize:12,color:"var(--text-secondary)"},children:(u.energy_kwh*1e3).toFixed(2)}),l.jsx("td",{style:{textAlign:"right",fontFamily:"monospace",fontSize:12,color:"var(--green-light)",fontWeight:500},children:u.total_emissions_g.toFixed(2)})]},u.gitlab_job_id))})]})})})]})]}),o&&o.length===0&&!s&&l.jsx("div",{style:{textAlign:"center",padding:48,color:"var(--text-muted)"},children:"No metrics found for this project. Have you run a pipeline with the measurement component?"})]})}export{Xe as MetricsDashboard};
@@ -0,0 +1 @@
1
+ import{r as o,j as e,S,T as w,I as x,B as z}from"./index-DW6Qp0d6.js";import{R,A as C,y as A,D as F,E as M,F as W,H as $,I as N,J as O}from"./core-Cz8f3oSB.js";import{h as K,g as q,u as G,a as H,s as V,C as g}from"./cache-YerT0Slh.js";function J({activeProjectId:a,page:u,limit:d}){const n=o.useMemo(()=>{const l={page:u};return l.limit=d,a&&(l.projectId=a),l},[a,u,d]),c=o.useMemo(()=>K(["pipelines",n]),[n]),h=o.useMemo(()=>q(c)??void 0,[c]);return G({queryKey:["pipelines",a,u,d],queryFn:async()=>{const{data:l}=await H.get("/api/pipelines",{params:n});return V(c,l,{ttlMs:45e3}),l},initialData:h,staleTime:45e3})}A([F,M,W,$,N,O]);const k=R,Q=20;function Z({activeProjectId:a}){const[u,d]=o.useState(1);o.useEffect(()=>{d(1)},[a]);const{data:n,isLoading:c,error:h,isFetching:l}=J({activeProjectId:a,page:u,limit:Q}),s=(n&&"pipelines"in n?n.pipelines:[])??[],y=a??(n&&"projectId"in n?n.projectId:void 0),f=n&&"pagination"in n?n.pagination:void 0,p=s.length===0?null:s.filter(t=>t.status==="success").length/s.length*100,b=s.length===0?null:s.reduce((t,r)=>t+(r.duration_seconds??0),0)/s.length,_=!!f?.hasPrevPage,P=!!f?.hasNextPage,m=l&&!c,j=o.useMemo(()=>{const t={};return s.forEach(r=>{t[r.status]=(t[r.status]||0)+1}),Object.entries(t).map(([r,i])=>({name:r,value:i}))},[s]),I=o.useMemo(()=>({tooltip:{trigger:"item",backgroundColor:"#161b22",borderColor:"#30363d",textStyle:{color:"#e6edf3"}},legend:{top:"5%",left:"center",textStyle:{color:"#8b949e"}},series:[{name:"Pipeline Status",type:"pie",radius:["40%","70%"],avoidLabelOverlap:!1,itemStyle:{borderRadius:10,borderColor:"#0d1117",borderWidth:2},label:{show:!1},emphasis:{label:{show:!0,fontSize:18,fontWeight:"bold",color:"#e6edf3"}},labelLine:{show:!1},data:j.map(t=>({...t,itemStyle:{color:t.name==="success"?"#2da44e":t.name==="failed"?"#f85149":t.name==="running"?"#58a6ff":"#6e7681"}}))}]}),[j]),B=o.useMemo(()=>{if(s.length===0)return{};const t=[...s].reverse().slice(-20);return{tooltip:{trigger:"axis",backgroundColor:"#161b22",borderColor:"#30363d",textStyle:{color:"#e6edf3"}},grid:{left:"3%",right:"4%",bottom:"3%",containLabel:!0},xAxis:{type:"category",data:t.map(r=>`#${r.id}`),axisLine:{show:!1},axisTick:{show:!1},axisLabel:{color:"#6e7681"}},yAxis:{type:"value",splitLine:{lineStyle:{color:"#21262d"}},axisLabel:{color:"#6e7681",formatter:"{value} s"}},series:[{name:"Duration",type:"bar",data:t.map(r=>({value:r.duration_seconds??0,itemStyle:{color:r.status==="success"?"#2da44e":r.status==="failed"?"#f85149":r.status==="running"?"#58a6ff":"#6e7681"}})),barMaxWidth:30}]}},[s]),D=t=>{switch(t){case"success":return e.jsx(x,{icon:"tick-circle",size:14,style:{color:"#2da44e"}});case"failed":return e.jsx(x,{icon:"error",size:14,style:{color:"#f85149"}});case"running":return e.jsx(S,{size:14,intent:"primary"});default:return e.jsx(x,{icon:"time",size:14,style:{color:"#6e7681"}})}},v=t=>{!t.web_url||typeof window>"u"||window.open(t.web_url,"_blank","noopener,noreferrer")},T=(t,r)=>{t.web_url&&(r.target instanceof HTMLElement&&r.target.closest("a")||v(t))},E=(t,r)=>{t.web_url&&(r.key==="Enter"||r.key===" ")&&(r.preventDefault(),v(t))};return s.length===0&&c?e.jsx("div",{style:{flex:1,display:"flex",alignItems:"center",justifyContent:"center"},children:e.jsx(S,{size:40,intent:"success"})}):e.jsxs("div",{style:{flex:1,overflowY:"auto",padding:24,maxWidth:1100,margin:"0 auto"},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:24},children:[e.jsx("h2",{style:{fontSize:18,fontWeight:600,color:"var(--text-primary)",margin:0},children:"Pipelines Overview"}),e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:10},children:[m&&s.length>0&&e.jsx("span",{style:{fontSize:11,color:"var(--text-muted)"},children:"Refreshing…"}),y&&e.jsxs(w,{minimal:!0,style:{fontSize:11},children:["Project ID: ",y]})]})]}),h&&e.jsx(g,{style:{background:"rgba(219,55,55,0.1)",border:"1px solid rgba(219,55,55,0.3)",marginBottom:16,padding:14},children:e.jsxs("span",{style:{color:"#f97171",fontSize:13},children:["Failed to load pipelines: ",String(h)]})}),s.length>0&&e.jsxs(e.Fragment,{children:[e.jsx("div",{style:{display:"grid",gridTemplateColumns:"repeat(4, 1fr)",gap:16,marginBottom:24},children:[{icon:"play",label:"Total Pipelines",value:String(s.length),color:"var(--text-muted)"},{icon:"tick-circle",label:"Success Rate",value:p===null?"--":`${p.toFixed(1)}%`,color:"#2da44e"},{icon:"time",label:"Avg Duration",value:b===null?"--":`${b.toFixed(0)}s`,color:"var(--text-muted)"},{icon:"refresh",label:"Running",value:String(s.filter(t=>t.status==="running").length),color:"#58a6ff"}].map(({icon:t,label:r,value:i,color:L})=>e.jsxs(g,{style:{background:"var(--bg-card)",border:"1px solid var(--border-default)",padding:16},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:6,fontSize:10,textTransform:"uppercase",letterSpacing:1.5,color:"var(--text-muted)",marginBottom:6},children:[e.jsx(x,{icon:t,size:14,style:{color:L}}),r]}),e.jsx("div",{style:{fontSize:24,fontFamily:"monospace",fontWeight:500,color:"var(--text-primary)"},children:i})]},r))}),e.jsxs("div",{style:{display:"grid",gridTemplateColumns:"1fr 1fr",gap:16,marginBottom:24},children:[e.jsxs("div",{children:[e.jsx("h3",{style:{fontSize:13,fontWeight:500,color:"var(--text-secondary)",marginBottom:8},children:"Status Distribution"}),e.jsx(g,{style:{background:"var(--bg-card)",border:"1px solid var(--border-default)",padding:16,height:320},children:e.jsx(k,{echarts:C,option:I,style:{height:"100%",width:"100%"},theme:"dark"})})]}),e.jsxs("div",{children:[e.jsx("h3",{style:{fontSize:13,fontWeight:500,color:"var(--text-secondary)",marginBottom:8},children:"Duration Trend (Last 20)"}),e.jsx(g,{style:{background:"var(--bg-card)",border:"1px solid var(--border-default)",padding:16,height:320},children:e.jsx(k,{echarts:C,option:B,style:{height:"100%",width:"100%"},theme:"dark"})})]})]}),e.jsxs("div",{children:[e.jsx("h3",{style:{fontSize:13,fontWeight:500,color:"var(--text-secondary)",marginBottom:8},children:"Recent Pipelines"}),e.jsxs(g,{style:{background:"var(--bg-card)",border:"1px solid var(--border-default)",padding:0,overflow:"hidden"},children:[e.jsx("div",{style:{overflowX:"auto"},children:e.jsxs("table",{className:"bp5-html-table bp5-html-table-condensed",style:{width:"100%"},children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Status"}),e.jsx("th",{children:"Pipeline ID"}),e.jsx("th",{children:"Branch"}),e.jsx("th",{children:"Commit"}),e.jsx("th",{children:"Triggered By"}),e.jsx("th",{style:{textAlign:"right"},children:"Duration"}),e.jsx("th",{style:{textAlign:"right"},children:"Created At"})]})}),e.jsx("tbody",{children:s.map(t=>{const r=t.triggered_by||"--";return e.jsxs("tr",{onClick:i=>T(t,i),onKeyDown:i=>E(t,i),role:t.web_url?"button":void 0,tabIndex:t.web_url?0:-1,style:{cursor:t.web_url?"pointer":"default"},children:[e.jsx("td",{children:e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:6},children:[D(t.status),e.jsx("span",{style:{textTransform:"capitalize",color:"var(--text-primary)",fontSize:12},children:t.status})]})}),e.jsx("td",{style:{fontFamily:"monospace",fontSize:12},children:t.web_url?e.jsxs("a",{href:t.web_url,target:"_blank",rel:"noreferrer",style:{color:"var(--green-light)"},onClick:i=>i.stopPropagation(),children:["#",t.id]}):`#${t.id}`}),e.jsx("td",{children:e.jsx(w,{minimal:!0,round:!0,style:{fontSize:11,fontFamily:"monospace"},children:t.branch||"-"})}),e.jsx("td",{style:{color:"var(--text-secondary)",fontSize:12,maxWidth:200,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:t.commit_message||t.sha||"—"}),e.jsx("td",{children:e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:6,fontSize:12,color:"var(--text-secondary)"},children:[e.jsx("div",{style:{width:20,height:20,borderRadius:"50%",background:"var(--bg-tertiary)",display:"flex",alignItems:"center",justifyContent:"center",fontSize:10,color:"var(--text-muted)",textTransform:"uppercase"},children:r.substring(0,2)}),r]})}),e.jsx("td",{style:{textAlign:"right",fontFamily:"monospace",fontSize:12,color:"var(--text-secondary)"},children:t.duration_seconds!==void 0?`${t.duration_seconds}s`:"--"}),e.jsx("td",{style:{textAlign:"right",fontSize:11,color:"var(--text-muted)"},children:t.created_at?new Date(t.created_at).toLocaleString():"--"})]},t.id)})})]})}),e.jsxs("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between",borderTop:"1px solid var(--border-default)",padding:"10px 16px",background:"var(--bg-tertiary)"},children:[e.jsxs("span",{style:{fontSize:12,color:"var(--text-muted)"},children:["Page ",f?.page??u]}),e.jsxs("div",{style:{display:"flex",gap:8},children:[e.jsx(z,{small:!0,text:"Previous",disabled:!_||m,onClick:()=>d(t=>Math.max(1,t-1))}),e.jsx(z,{small:!0,text:"Next",disabled:!P||m,onClick:()=>d(t=>t+1)})]})]})]})]})]}),s.length===0&&!c&&!h&&e.jsx("div",{style:{textAlign:"center",color:"var(--text-muted)",padding:32},children:"No pipelines found for this project."})]})}export{Z as PipelinesDashboard};
@@ -0,0 +1 @@
1
+ import{I as s}from"./index-Bp4RqK05.js";import{I as r}from"./index-Uc4Xhv31.js";import{a6 as n,v as c}from"./index-DW6Qp0d6.js";function i(a,t){const o=n(a);return t===c.STANDARD?s[o]:r[o]}export{s as IconSvgPaths16,r as IconSvgPaths20,i as getIconPaths};
@@ -0,0 +1,2 @@
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/allPaths-CXDKahbk.js","assets/index-Bp4RqK05.js","assets/index-Uc4Xhv31.js","assets/index-DW6Qp0d6.js","assets/index-BWa_E8Y7.css"])))=>i.map(i=>d[i]);
2
+ import{a5 as e}from"./index-DW6Qp0d6.js";const s=async(t,a)=>{const{getIconPaths:o}=await e(async()=>{const{getIconPaths:r}=await import("./allPaths-CXDKahbk.js");return{getIconPaths:r}},__vite__mapDeps([0,1,2,3,4]));return o(t,a)};export{s as allPathsLoader};