-
Notifications
You must be signed in to change notification settings - Fork 4
Add Claude Console plugin #73
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
378c783
initial Claude console plugin work
andrewmumblebee 3ec56ef
Add ability to filter by default workspace
andrewmumblebee 07de045
Update Claude dashboards
andrewmumblebee bea096b
Claude plugin review tweaks
andrewmumblebee ea96f71
Update Claude readme
andrewmumblebee d08d0f7
account_id is not grouped by so drop from script
andrewmumblebee b310d63
Remove Claude prefix from readme
andrewmumblebee 63b5200
Remove duplicate tile and vis tiles on dashboard
andrewmumblebee 679085d
use dynamic currency column for Claude cost
andrewmumblebee 597a743
remove default workspace null note
andrewmumblebee File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| { | ||
| "steps": [ | ||
| { | ||
| "displayName": "Authenticate", | ||
| "dataStream": { | ||
| "name": "organization" | ||
| }, | ||
| "required": true, | ||
| "success": "Connected to your Claude Console organization.", | ||
| "error": "Could not authenticate. Check that your Admin API key (sk-ant-admin...) is valid and belongs to an organization, not an individual account." | ||
| } | ||
| ] | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| [ | ||
| { | ||
| "name": "Workspace", | ||
| "sourceType": "Workspace", | ||
| "icon": "layer-group", | ||
| "singular": "Workspace", | ||
| "plural": "Workspaces" | ||
| }, | ||
| { | ||
| "name": "API Key", | ||
| "sourceType": "API Key", | ||
| "icon": "key", | ||
| "singular": "API Key", | ||
| "plural": "API Keys" | ||
| }, | ||
| { | ||
| "name": "Member", | ||
| "sourceType": "Member", | ||
| "icon": "user", | ||
| "singular": "Member", | ||
| "plural": "Members" | ||
| } | ||
| ] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,100 @@ | ||
| { | ||
| "name": "apiKeys", | ||
| "displayName": "API Keys", | ||
| "description": "API keys in your Claude Console organization", | ||
| "tags": ["API Keys"], | ||
| "baseDataSourceName": "httpRequestUnscoped", | ||
| "config": { | ||
| "httpMethod": "get", | ||
| "endpointPath": "v1/organizations/api_keys", | ||
| "getArgs": [ | ||
| { | ||
| "key": "limit", | ||
| "value": "1000" | ||
| }, | ||
| { | ||
| "key": "created_by_user_id", | ||
| "value": "{{ (createdBy && createdBy.length) ? (Array.isArray(createdBy[0].rawId) ? createdBy[0].rawId[0] : createdBy[0].rawId) : null }}" | ||
| } | ||
| ], | ||
| "paging": { | ||
| "mode": "none" | ||
| }, | ||
| "expandInnerObjects": true, | ||
| "postRequestScript": "apiKeys.js" | ||
| }, | ||
| "matches": "none", | ||
| "ui": [ | ||
| { | ||
| "type": "objects", | ||
| "name": "workspace", | ||
| "label": "Workspace (optional)", | ||
| "matches": { | ||
| "sourceType": { | ||
| "type": "oneOf", | ||
| "values": ["Workspace"] | ||
| } | ||
| } | ||
| }, | ||
| { | ||
| "type": "objects", | ||
| "name": "createdBy", | ||
| "label": "Created by (optional)", | ||
| "matches": { | ||
| "sourceType": { "type": "oneOf", "values": ["Member"] } | ||
| } | ||
| } | ||
| ], | ||
| "metadata": [ | ||
| { | ||
| "name": "id", | ||
| "displayName": "API Key ID", | ||
| "shape": "string" | ||
| }, | ||
| { | ||
| "name": "name", | ||
| "displayName": "Name", | ||
| "shape": "string", | ||
| "role": "label" | ||
| }, | ||
| { | ||
| "name": "status", | ||
| "displayName": "Status", | ||
| "shape": [ | ||
| "state", | ||
| { | ||
| "map": { | ||
| "success": ["active"], | ||
| "unknown": ["expired", "archived", "inactive"] | ||
| } | ||
| } | ||
| ] | ||
| }, | ||
| { | ||
| "name": "workspace_id", | ||
| "displayName": "Workspace ID", | ||
| "shape": "string" | ||
| }, | ||
| { | ||
| "name": "partial_key_hint", | ||
| "displayName": "Key Hint", | ||
| "shape": "string" | ||
| }, | ||
| { | ||
| "name": "created_at", | ||
| "displayName": "Created", | ||
| "shape": "date" | ||
| }, | ||
| { | ||
| "name": "expires_at", | ||
| "displayName": "Expires", | ||
| "shape": "date" | ||
| }, | ||
| { | ||
| "name": "created_by.id", | ||
| "displayName": "Created By", | ||
| "shape": "string" | ||
| } | ||
| ], | ||
| "timeframes": false | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,103 @@ | ||
| { | ||
| "name": "cost", | ||
| "displayName": "Cost", | ||
| "description": "Organization spend in USD over time, one row per workspace/model/token-type bucket per day", | ||
| "tags": ["Cost", "Billing"], | ||
| "baseDataSourceName": "httpRequestUnscoped", | ||
| "config": { | ||
| "httpMethod": "get", | ||
| "endpointPath": "v1/organizations/cost_report", | ||
| "getArgs": [ | ||
| { | ||
| "key": "starting_at", | ||
| "value": "{{timeframe.start}}" | ||
| }, | ||
| { | ||
| "key": "ending_at", | ||
| "value": "{{timeframe.end}}" | ||
| }, | ||
| { | ||
| "key": "bucket_width", | ||
| "value": "1d" | ||
| }, | ||
| { | ||
| "key": "group_by[]", | ||
| "value": "workspace_id" | ||
| }, | ||
| { | ||
| "key": "group_by[]", | ||
| "value": "description" | ||
| }, | ||
| { | ||
| "key": "limit", | ||
| "value": "31" | ||
| } | ||
| ], | ||
| "paging": { | ||
| "mode": "none" | ||
| }, | ||
| "postRequestScript": "cost.js" | ||
| }, | ||
| "matches": "none", | ||
| "ui": [ | ||
| { | ||
| "type": "objects", | ||
| "name": "workspace", | ||
| "label": "Workspace (optional)", | ||
| "matches": { | ||
| "sourceType": { | ||
| "type": "oneOf", | ||
| "values": ["Workspace"] | ||
| } | ||
| } | ||
| } | ||
| ], | ||
| "metadata": [ | ||
| { | ||
| "name": "date", | ||
| "displayName": "Date", | ||
| "shape": "date", | ||
| "role": "timestamp" | ||
| }, | ||
| { | ||
| "name": "amount", | ||
| "displayName": "Cost ($)", | ||
| "shape": [ | ||
| "currency", | ||
| { | ||
| "code": "{{column.currency}}", | ||
| "decimalPlaces": 2, | ||
| "thousandsSeparator": true | ||
| } | ||
| ], | ||
| "role": "value" | ||
| }, | ||
| { | ||
| "name": "workspace_id", | ||
| "displayName": "Workspace ID", | ||
| "shape": "string" | ||
| }, | ||
| { | ||
| "name": "workspaceName", | ||
| "displayName": "Workspace", | ||
| "sourceId": "workspace_id", | ||
| "sourceType": "Workspace", | ||
| "objectPropertyPath": "name" | ||
| }, | ||
| { | ||
| "name": "description", | ||
| "displayName": "Description", | ||
| "shape": "string" | ||
| }, | ||
| { | ||
| "name": "currency", | ||
| "displayName": "Currency", | ||
| "shape": "string", | ||
| "visible": false | ||
| }, | ||
| { | ||
| "pattern": ".*" | ||
| } | ||
| ], | ||
| "timeframes": ["last7days", "last30days", "thisMonth", "lastMonth"] | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| { | ||
| "name": "members", | ||
| "displayName": "Members", | ||
| "description": "Organization members in your Claude Console organization, with email and role", | ||
| "tags": [ | ||
| "Members" | ||
| ], | ||
| "baseDataSourceName": "httpRequestUnscoped", | ||
| "config": { | ||
| "httpMethod": "get", | ||
| "endpointPath": "v1/organizations/users", | ||
| "getArgs": [ | ||
| { | ||
| "key": "limit", | ||
| "value": "1000" | ||
| } | ||
| ], | ||
| "paging": { | ||
| "mode": "none" | ||
| }, | ||
| "pathToData": "data" | ||
| }, | ||
| "matches": "none", | ||
| "metadata": [ | ||
| { | ||
| "name": "id", | ||
| "displayName": "User ID", | ||
| "shape": "string" | ||
| }, | ||
| { | ||
| "name": "name", | ||
| "displayName": "Name", | ||
| "shape": "string" | ||
| }, | ||
| { | ||
| "name": "email", | ||
| "displayName": "Email", | ||
| "shape": "string" | ||
| }, | ||
| { | ||
| "name": "role", | ||
| "displayName": "Role", | ||
| "shape": "string" | ||
| }, | ||
| { | ||
| "name": "added_at", | ||
| "displayName": "Added", | ||
| "shape": "date" | ||
| }, | ||
| { | ||
| "name": "memberName", | ||
| "displayName": "Member", | ||
| "computed": true, | ||
| "valueExpression": "{{ $['name']?.__isNone ? $['email'] : $['name'] }}", | ||
| "shape": "string", | ||
| "role": "label" | ||
| } | ||
| ], | ||
| "timeframes": false | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| { | ||
| "name": "organization", | ||
| "displayName": "Organization", | ||
| "description": "Your Claude Console organization id, name, and type", | ||
| "tags": [ | ||
| "Organization" | ||
| ], | ||
| "baseDataSourceName": "httpRequestUnscoped", | ||
| "config": { | ||
| "httpMethod": "get", | ||
| "endpointPath": "v1/organizations/me", | ||
| "paging": { | ||
| "mode": "none" | ||
| }, | ||
| "getArgs": [], | ||
| "headers": [] | ||
| }, | ||
| "matches": "none", | ||
| "metadata": [ | ||
| { | ||
| "name": "id", | ||
| "displayName": "Organization ID", | ||
| "shape": "string" | ||
| }, | ||
| { | ||
| "name": "name", | ||
| "displayName": "Name", | ||
| "shape": "string", | ||
| "role": "label" | ||
| }, | ||
| { | ||
| "name": "type", | ||
| "displayName": "Type", | ||
| "shape": "string" | ||
| } | ||
| ], | ||
| "timeframes": false, | ||
| "visibility": { | ||
| "type": "hidden" | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| const unwrap = (v) => (Array.isArray(v) ? v[0] : v); | ||
|
|
||
| // Build set of selected workspace rawIds (empty → account-wide, no filter) | ||
| const selected = (context.config && context.config.workspace) || []; | ||
| const workspaceIds = new Set( | ||
| selected.map((o) => unwrap(o.rawId)).filter(Boolean), | ||
| ); | ||
|
|
||
| let rows = data.data.map((a) => ({ | ||
| ...a, | ||
| // Claude does not let us filter by the default workspace on their api. | ||
| workspace_id: a.workspace_id || "default", | ||
| })); | ||
|
|
||
| // Apply optional workspace scope filter | ||
| if (workspaceIds.size) { | ||
| rows = rows.filter((r) => workspaceIds.has(r.workspace_id)); | ||
| } | ||
|
|
||
| result = rows; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| // cost.js — flatten nested time-bucket/results structure, coerce amount string→number, | ||
| // and optionally scope to selected workspace(s) via the `workspace` objects param. | ||
|
|
||
| const unwrap = (v) => (Array.isArray(v) ? v[0] : v); | ||
|
clarkd marked this conversation as resolved.
|
||
|
|
||
| // Build set of selected workspace rawIds (empty → account-wide, no filter) | ||
| const selected = (context.config && context.config.workspace) || []; | ||
| const workspaceIds = new Set( | ||
| selected.map((o) => unwrap(o.rawId)).filter(Boolean), | ||
| ); | ||
|
|
||
| // Flatten buckets × results into one row per combination | ||
| let rows = (data.data || []).flatMap((bucket) => | ||
| (bucket.results || []).map((r) => ({ | ||
| ...r, | ||
| date: bucket.starting_at, | ||
| // API returns `amount` in lowest currency units (cents) as a decimal string, | ||
| // e.g. "300" cents = $3.00 — divide by 100 to get USD. Verified empirically: | ||
| // cost/token matches Claude's published per-model list prices exactly only in cents. | ||
| amount: Number(r.amount) / 100, | ||
| workspace_id: r.workspace_id ?? "default", | ||
| description: r.description, | ||
| })), | ||
| ); | ||
|
|
||
| // Apply optional workspace scope filter | ||
| if (workspaceIds.size) { | ||
| rows = rows.filter((r) => workspaceIds.has(r.workspace_id)); | ||
| } | ||
|
|
||
| result = rows; | ||
|
|
||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.