@datalayer/core 1.2.12 → 1.2.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/lib/hooks/useCache.d.ts +23 -0
- package/lib/hooks/useCache.js +146 -9
- package/lib/hooks/useContents.js +3 -0
- package/lib/models/URN.d.ts +37 -0
- package/lib/models/URN.js +59 -1
- package/lib/state/substates/NavigationState.d.ts +11 -1
- package/lib/state/substates/NavigationState.js +55 -6
- package/lib/utils/Handles.js +1 -1
- package/lib/views/mcp/McpDashboard.js +15 -10
- package/lib/views/mcp/McpHome.js +12 -5
- package/lib/views/mcp/types.d.ts +4 -0
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
|
|
19
19
|
## Overview
|
|
20
20
|
|
|
21
|
-
Datalayer Core is the foundational package that powers the [Datalayer AI Platform](https://datalayer.
|
|
21
|
+
Datalayer Core is the foundational package that powers the [Datalayer AI Platform](https://datalayer.ai/). It provides a TypesScript and Python packages as a Command Line Interface (CLI) for AI engineers, data scientists, and researchers to seamlessly integrate scalable compute runtimes into their workflows.
|
|
22
22
|
|
|
23
23
|
This package serves as the base foundation used by many other Datalayer packages, containing core application classes, configuration, and unified APIs for authentication, runtime management, and code execution in cloud-based environments.
|
|
24
24
|
|
|
@@ -219,7 +219,7 @@ This project is licensed under the [BSD 3-Clause License](https://github.com/dat
|
|
|
219
219
|
|
|
220
220
|
- **Documentation**: [Datalayer Platform Documentation](https://datalayer.ai/docs/)
|
|
221
221
|
- **Issues**: [GitHub Issues](https://github.com/datalayer/core/issues)
|
|
222
|
-
- **Community**: [Datalayer Platform](https://datalayer.
|
|
222
|
+
- **Community**: [Datalayer Platform](https://datalayer.ai/)
|
|
223
223
|
|
|
224
224
|
---
|
|
225
225
|
|
|
@@ -229,5 +229,5 @@ This project is licensed under the [BSD 3-Clause License](https://github.com/dat
|
|
|
229
229
|
|
|
230
230
|
<p align="center">
|
|
231
231
|
<strong>🚀 AI Agents for Data Analysis</strong><br></br>
|
|
232
|
-
<a href="https://datalayer.
|
|
232
|
+
<a href="https://datalayer.ai/">Get started with Datalayer today!</a>
|
|
233
233
|
</p>
|
package/lib/hooks/useCache.d.ts
CHANGED
|
@@ -498,6 +498,29 @@ export declare const useCache: ({ loginRoute }?: CacheProps) => {
|
|
|
498
498
|
returnOrigin?: string;
|
|
499
499
|
}, unknown>;
|
|
500
500
|
useDisconnectBluesky: () => import("@tanstack/react-query").UseMutationResult<any, Error, void, unknown>;
|
|
501
|
+
useXConnection: (enabled?: boolean) => import("@tanstack/react-query").UseQueryResult<{
|
|
502
|
+
configured: boolean;
|
|
503
|
+
connected: boolean;
|
|
504
|
+
account?: {
|
|
505
|
+
id: string;
|
|
506
|
+
username: string;
|
|
507
|
+
name: string;
|
|
508
|
+
profile_image_url: string;
|
|
509
|
+
url: string;
|
|
510
|
+
} | null;
|
|
511
|
+
}, Error>;
|
|
512
|
+
useConnectX: () => import("@tanstack/react-query").UseMutationResult<{
|
|
513
|
+
authorization_url: string;
|
|
514
|
+
}, Error, string | undefined, unknown>;
|
|
515
|
+
useDisconnectX: () => import("@tanstack/react-query").UseMutationResult<any, Error, void, unknown>;
|
|
516
|
+
usePublishXShare: () => import("@tanstack/react-query").UseMutationResult<any, Error, {
|
|
517
|
+
itemId: string;
|
|
518
|
+
text: string;
|
|
519
|
+
idempotencyKey: string;
|
|
520
|
+
imageDataUrl?: string;
|
|
521
|
+
}, unknown>;
|
|
522
|
+
useUnpublishXShare: () => import("@tanstack/react-query").UseMutationResult<any, Error, string, unknown>;
|
|
523
|
+
useXShares: (itemId: string, enabled?: boolean) => import("@tanstack/react-query").UseQueryResult<any, Error>;
|
|
501
524
|
usePublishLinkedInShare: () => import("@tanstack/react-query").UseMutationResult<any, Error, {
|
|
502
525
|
itemId: string;
|
|
503
526
|
commentary: string;
|
package/lib/hooks/useCache.js
CHANGED
|
@@ -58,6 +58,19 @@ const DEFAULT_QUERY_OPTIONS = {
|
|
|
58
58
|
// Ensure queries prioritize cache over network when data is fresh
|
|
59
59
|
networkMode: 'online',
|
|
60
60
|
};
|
|
61
|
+
/**
|
|
62
|
+
* A list of what a space holds — all of it, or the items of one type. Every
|
|
63
|
+
* such list takes these options (`spaceListsRefetchOnMount.unit.test.ts`
|
|
64
|
+
* holds them to it). Refetched every time a page mounts it: an item
|
|
65
|
+
* created elsewhere — a cell has no create mutation here to clear this cache —
|
|
66
|
+
* would otherwise stay missing from the list for the five minutes the default
|
|
67
|
+
* options keep it fresh, and coming back to the list is exactly when somebody
|
|
68
|
+
* looks for it.
|
|
69
|
+
*/
|
|
70
|
+
const LIST_QUERY_OPTIONS = {
|
|
71
|
+
...DEFAULT_QUERY_OPTIONS,
|
|
72
|
+
refetchOnMount: 'always',
|
|
73
|
+
};
|
|
61
74
|
/**
|
|
62
75
|
* Refresh what a visitor sees, not just what the editor is looking at.
|
|
63
76
|
*
|
|
@@ -863,6 +876,32 @@ export const useCache = ({ loginRoute = '/login' } = {}) => {
|
|
|
863
876
|
owner: toItemOwner(raw),
|
|
864
877
|
};
|
|
865
878
|
};
|
|
879
|
+
/**
|
|
880
|
+
* A published agentic UI application: what it answers, and its definition
|
|
881
|
+
* as the library hands it over — `model_s`, the string the Studio reads
|
|
882
|
+
* the definition from, left unparsed because the Studio owns its shape.
|
|
883
|
+
*/
|
|
884
|
+
const toApp = (raw) => {
|
|
885
|
+
return {
|
|
886
|
+
id: raw.uid,
|
|
887
|
+
type: 'app',
|
|
888
|
+
name: raw.name_t,
|
|
889
|
+
description: raw.description_t,
|
|
890
|
+
tags: Array.isArray(raw.tags_ss) ? raw.tags_ss : [],
|
|
891
|
+
public: raw.is_public_b ?? false,
|
|
892
|
+
model_s: raw.model_s,
|
|
893
|
+
creationDate: raw.creation_ts_dt
|
|
894
|
+
? new Date(raw.creation_ts_dt)
|
|
895
|
+
: undefined,
|
|
896
|
+
lastUpdateDate: raw.last_update_ts_dt
|
|
897
|
+
? new Date(raw.last_update_ts_dt)
|
|
898
|
+
: undefined,
|
|
899
|
+
lastPublicationDate: raw.published_ts_dt
|
|
900
|
+
? new Date(raw.published_ts_dt)
|
|
901
|
+
: undefined,
|
|
902
|
+
owner: toItemOwner(raw),
|
|
903
|
+
};
|
|
904
|
+
};
|
|
866
905
|
/** An evaluator of the platform's catalogue (B5-01), published as an agent is. */
|
|
867
906
|
const toEvaluator = (raw) => {
|
|
868
907
|
return {
|
|
@@ -1375,6 +1414,10 @@ export const useCache = ({ loginRoute = '/login' } = {}) => {
|
|
|
1375
1414
|
return toInvestigation(item);
|
|
1376
1415
|
case 'evaluator':
|
|
1377
1416
|
return toEvaluator(item);
|
|
1417
|
+
// Without this a published app answered `{}`, as a deck once did: a
|
|
1418
|
+
// card with no type and no name.
|
|
1419
|
+
case 'app':
|
|
1420
|
+
return toApp(item);
|
|
1378
1421
|
case 'sitecard':
|
|
1379
1422
|
return toSiteCard(item);
|
|
1380
1423
|
default:
|
|
@@ -2345,7 +2388,7 @@ export const useCache = ({ loginRoute = '/login' } = {}) => {
|
|
|
2345
2388
|
}
|
|
2346
2389
|
return [];
|
|
2347
2390
|
},
|
|
2348
|
-
...
|
|
2391
|
+
...LIST_QUERY_OPTIONS,
|
|
2349
2392
|
enabled: !!spaceId,
|
|
2350
2393
|
});
|
|
2351
2394
|
};
|
|
@@ -2477,7 +2520,7 @@ export const useCache = ({ loginRoute = '/login' } = {}) => {
|
|
|
2477
2520
|
}
|
|
2478
2521
|
return [];
|
|
2479
2522
|
},
|
|
2480
|
-
...
|
|
2523
|
+
...LIST_QUERY_OPTIONS,
|
|
2481
2524
|
enabled: !!spaceId,
|
|
2482
2525
|
});
|
|
2483
2526
|
};
|
|
@@ -2652,7 +2695,7 @@ export const useCache = ({ loginRoute = '/login' } = {}) => {
|
|
|
2652
2695
|
}
|
|
2653
2696
|
return [];
|
|
2654
2697
|
},
|
|
2655
|
-
...
|
|
2698
|
+
...LIST_QUERY_OPTIONS,
|
|
2656
2699
|
enabled: !!spaceId,
|
|
2657
2700
|
});
|
|
2658
2701
|
};
|
|
@@ -4160,7 +4203,7 @@ export const useCache = ({ loginRoute = '/login' } = {}) => {
|
|
|
4160
4203
|
return [];
|
|
4161
4204
|
},
|
|
4162
4205
|
enabled: !!spaceId,
|
|
4163
|
-
...
|
|
4206
|
+
...LIST_QUERY_OPTIONS,
|
|
4164
4207
|
});
|
|
4165
4208
|
};
|
|
4166
4209
|
/**
|
|
@@ -4347,7 +4390,7 @@ export const useCache = ({ loginRoute = '/login' } = {}) => {
|
|
|
4347
4390
|
return [];
|
|
4348
4391
|
},
|
|
4349
4392
|
enabled: !!spaceId,
|
|
4350
|
-
...
|
|
4393
|
+
...LIST_QUERY_OPTIONS,
|
|
4351
4394
|
});
|
|
4352
4395
|
};
|
|
4353
4396
|
/**
|
|
@@ -4438,7 +4481,7 @@ export const useCache = ({ loginRoute = '/login' } = {}) => {
|
|
|
4438
4481
|
return [];
|
|
4439
4482
|
},
|
|
4440
4483
|
enabled: !!spaceId,
|
|
4441
|
-
...
|
|
4484
|
+
...LIST_QUERY_OPTIONS,
|
|
4442
4485
|
});
|
|
4443
4486
|
};
|
|
4444
4487
|
/**
|
|
@@ -4478,7 +4521,7 @@ export const useCache = ({ loginRoute = '/login' } = {}) => {
|
|
|
4478
4521
|
return [];
|
|
4479
4522
|
},
|
|
4480
4523
|
enabled: !!spaceId,
|
|
4481
|
-
...
|
|
4524
|
+
...LIST_QUERY_OPTIONS,
|
|
4482
4525
|
});
|
|
4483
4526
|
};
|
|
4484
4527
|
/**
|
|
@@ -4547,7 +4590,7 @@ export const useCache = ({ loginRoute = '/login' } = {}) => {
|
|
|
4547
4590
|
return [];
|
|
4548
4591
|
},
|
|
4549
4592
|
enabled: !!spaceId,
|
|
4550
|
-
...
|
|
4593
|
+
...LIST_QUERY_OPTIONS,
|
|
4551
4594
|
});
|
|
4552
4595
|
};
|
|
4553
4596
|
/**
|
|
@@ -4641,7 +4684,7 @@ export const useCache = ({ loginRoute = '/login' } = {}) => {
|
|
|
4641
4684
|
return [];
|
|
4642
4685
|
},
|
|
4643
4686
|
enabled: !!spaceId,
|
|
4644
|
-
...
|
|
4687
|
+
...LIST_QUERY_OPTIONS,
|
|
4645
4688
|
});
|
|
4646
4689
|
};
|
|
4647
4690
|
/**
|
|
@@ -6332,6 +6375,8 @@ export const useCache = ({ loginRoute = '/login' } = {}) => {
|
|
|
6332
6375
|
'evalset',
|
|
6333
6376
|
'dataset',
|
|
6334
6377
|
'agent',
|
|
6378
|
+
// An agentic UI application, published from the Studio.
|
|
6379
|
+
'app',
|
|
6335
6380
|
];
|
|
6336
6381
|
const librarySearchQueryString = ({ q, types, max = 20, offset = 0, sort = 'relevance', featured = false, owner, }) => {
|
|
6337
6382
|
const normalizedTypes = Array.from(new Set((types || [])
|
|
@@ -6906,6 +6951,59 @@ export const useCache = ({ loginRoute = '/login' } = {}) => {
|
|
|
6906
6951
|
enabled: Boolean(configuration.libraryUrl) && Boolean(itemId) && enabled,
|
|
6907
6952
|
});
|
|
6908
6953
|
};
|
|
6954
|
+
/**
|
|
6955
|
+
* Post a public artifact to X through the Library's saga: the author's
|
|
6956
|
+
* text, then the artifact's attributed share-card link (X draws the card),
|
|
6957
|
+
* and optionally one picked result as an image.
|
|
6958
|
+
*/
|
|
6959
|
+
const usePublishXShare = () => {
|
|
6960
|
+
return useMutation({
|
|
6961
|
+
mutationFn: async ({ itemId, text, idempotencyKey, imageDataUrl, }) => {
|
|
6962
|
+
const resp = await requestDatalayer({
|
|
6963
|
+
url: `${configuration.libraryUrl}/api/library/v1/items/${encodeURIComponent(itemId)}/shares/x`,
|
|
6964
|
+
method: 'POST',
|
|
6965
|
+
headers: { 'Idempotency-Key': idempotencyKey },
|
|
6966
|
+
body: { text, imageDataUrl },
|
|
6967
|
+
});
|
|
6968
|
+
if (!resp.success) {
|
|
6969
|
+
throw new Error(resp.message || 'Failed to post to X');
|
|
6970
|
+
}
|
|
6971
|
+
return resp.share;
|
|
6972
|
+
},
|
|
6973
|
+
});
|
|
6974
|
+
};
|
|
6975
|
+
const useUnpublishXShare = () => {
|
|
6976
|
+
return useMutation({
|
|
6977
|
+
mutationFn: async (idempotencyKey) => {
|
|
6978
|
+
const resp = await requestDatalayer({
|
|
6979
|
+
url: `${configuration.libraryUrl}/api/library/v1/shares/x/${encodeURIComponent(idempotencyKey)}`,
|
|
6980
|
+
method: 'DELETE',
|
|
6981
|
+
});
|
|
6982
|
+
if (!resp.success) {
|
|
6983
|
+
throw new Error(resp.message || 'Failed to remove the X post');
|
|
6984
|
+
}
|
|
6985
|
+
return resp.share;
|
|
6986
|
+
},
|
|
6987
|
+
});
|
|
6988
|
+
};
|
|
6989
|
+
const useXShares = (itemId, enabled = true) => {
|
|
6990
|
+
return useQuery({
|
|
6991
|
+
queryKey: ['library', 'social-shares', 'x', itemId],
|
|
6992
|
+
queryFn: async () => {
|
|
6993
|
+
const resp = await requestDatalayer({
|
|
6994
|
+
url: `${configuration.libraryUrl}/api/library/v1/items/${encodeURIComponent(itemId)}/shares/x`,
|
|
6995
|
+
method: 'GET',
|
|
6996
|
+
notifyOnError: false,
|
|
6997
|
+
});
|
|
6998
|
+
if (!resp.success) {
|
|
6999
|
+
throw new Error(resp.message || 'Failed to load X posts');
|
|
7000
|
+
}
|
|
7001
|
+
return Array.isArray(resp.shares) ? resp.shares : [];
|
|
7002
|
+
},
|
|
7003
|
+
...DEFAULT_QUERY_OPTIONS,
|
|
7004
|
+
enabled: Boolean(configuration.libraryUrl) && Boolean(itemId) && enabled,
|
|
7005
|
+
});
|
|
7006
|
+
};
|
|
6909
7007
|
/** Publish one selected public result through the durable Bluesky saga. */
|
|
6910
7008
|
const usePublishBlueskyShare = () => {
|
|
6911
7009
|
return useMutation({
|
|
@@ -7241,6 +7339,39 @@ export const useCache = ({ loginRoute = '/login' } = {}) => {
|
|
|
7241
7339
|
method: 'DELETE',
|
|
7242
7340
|
}),
|
|
7243
7341
|
});
|
|
7342
|
+
/**
|
|
7343
|
+
* The X connection, as IAM reports it: whether X is configured on this
|
|
7344
|
+
* deployment, whether the caller connected it, and the account (no token).
|
|
7345
|
+
*/
|
|
7346
|
+
const useXConnection = (enabled = true) => useQuery({
|
|
7347
|
+
queryKey: ['iam', 'social', 'x', 'status'],
|
|
7348
|
+
queryFn: async () => requestDatalayer({
|
|
7349
|
+
url: `${configuration.iamUrl}/api/iam/v1/social/x/status`,
|
|
7350
|
+
method: 'GET',
|
|
7351
|
+
notifyOnError: false,
|
|
7352
|
+
}),
|
|
7353
|
+
...DEFAULT_QUERY_OPTIONS,
|
|
7354
|
+
enabled: Boolean(configuration.iamUrl) && enabled,
|
|
7355
|
+
});
|
|
7356
|
+
/**
|
|
7357
|
+
* Begin connecting X. Answers the start link to open at top level;
|
|
7358
|
+
* `returnOrigin` is where to come back to (an origin only: IAM builds the
|
|
7359
|
+
* path, so this cannot ask to be sent anywhere).
|
|
7360
|
+
*/
|
|
7361
|
+
const useConnectX = () => useMutation({
|
|
7362
|
+
mutationFn: async (returnOrigin) => requestDatalayer({
|
|
7363
|
+
url: `${configuration.iamUrl}/api/iam/v1/social/x/connect`,
|
|
7364
|
+
method: 'POST',
|
|
7365
|
+
body: returnOrigin ? { return_origin: returnOrigin } : {},
|
|
7366
|
+
}),
|
|
7367
|
+
});
|
|
7368
|
+
const useDisconnectX = () => useMutation({
|
|
7369
|
+
mutationFn: async () => requestDatalayer({
|
|
7370
|
+
url: `${configuration.iamUrl}/api/iam/v1/social/x/connection`,
|
|
7371
|
+
method: 'DELETE',
|
|
7372
|
+
}),
|
|
7373
|
+
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['iam', 'social', 'x'] }),
|
|
7374
|
+
});
|
|
7244
7375
|
// ============================================================================
|
|
7245
7376
|
// Waiting List & Growth
|
|
7246
7377
|
// ============================================================================
|
|
@@ -8292,6 +8423,12 @@ export const useCache = ({ loginRoute = '/login' } = {}) => {
|
|
|
8292
8423
|
useGetBlueskyConnection,
|
|
8293
8424
|
useConnectBluesky,
|
|
8294
8425
|
useDisconnectBluesky,
|
|
8426
|
+
useXConnection,
|
|
8427
|
+
useConnectX,
|
|
8428
|
+
useDisconnectX,
|
|
8429
|
+
usePublishXShare,
|
|
8430
|
+
useUnpublishXShare,
|
|
8431
|
+
useXShares,
|
|
8295
8432
|
usePublishLinkedInShare,
|
|
8296
8433
|
useUnpublishLinkedInShare,
|
|
8297
8434
|
useLinkedInShares,
|
package/lib/hooks/useContents.js
CHANGED
|
@@ -156,6 +156,9 @@ export const useContentSources = (filters = {}) => {
|
|
|
156
156
|
queryFn: () => listSources(token ?? '', filters, contentsUrl),
|
|
157
157
|
enabled: Boolean(token && contentsUrl),
|
|
158
158
|
staleTime: 30_000,
|
|
159
|
+
// Coming back to a list is when somebody looks for what they just made:
|
|
160
|
+
// it is read again, whatever made it.
|
|
161
|
+
refetchOnMount: 'always',
|
|
159
162
|
refetchOnWindowFocus: true,
|
|
160
163
|
});
|
|
161
164
|
};
|
package/lib/models/URN.d.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import type { IIAMProviderName } from './IAMProvidersSpecs';
|
|
2
|
+
/** What an identity provider's account URN starts with, before its name. */
|
|
3
|
+
export declare const IAM_PROVIDER_URN_PREFIX = "urn:dla:iam:ext::";
|
|
1
4
|
export declare class URN implements IURN {
|
|
2
5
|
private _partition;
|
|
3
6
|
private _service;
|
|
@@ -12,7 +15,41 @@ export declare class URN implements IURN {
|
|
|
12
15
|
get account(): string;
|
|
13
16
|
get type(): string;
|
|
14
17
|
get uid(): string;
|
|
18
|
+
/** An identity provider's account (`urn:dla:iam:ext::github:…`). */
|
|
19
|
+
get isIAMProviderAccount(): boolean;
|
|
20
|
+
toString(): string;
|
|
15
21
|
}
|
|
22
|
+
/** A URN, or `undefined` when the value is not one — never a throw. */
|
|
23
|
+
export declare function parseURN(value?: string | null): URN | undefined;
|
|
24
|
+
/**
|
|
25
|
+
* Where an account came from, read from its `origin`.
|
|
26
|
+
*
|
|
27
|
+
* - `datalayer`: made on Datalayer, with a password.
|
|
28
|
+
* - `iam-provider`: made by signing in with an identity provider, which it
|
|
29
|
+
* still signs in through (`urn:dla:iam:ext::<provider>:<account id>`).
|
|
30
|
+
* - `urn`: any other URN — an AWS Marketplace or enterprise origin.
|
|
31
|
+
* - `unknown`: nothing recorded, or a value that is none of the above.
|
|
32
|
+
*/
|
|
33
|
+
export type IAccountOrigin = {
|
|
34
|
+
kind: 'datalayer';
|
|
35
|
+
} | {
|
|
36
|
+
kind: 'iam-provider';
|
|
37
|
+
provider: IIAMProviderName;
|
|
38
|
+
accountId: string;
|
|
39
|
+
urn: URN;
|
|
40
|
+
} | {
|
|
41
|
+
kind: 'urn';
|
|
42
|
+
urn: URN;
|
|
43
|
+
} | {
|
|
44
|
+
kind: 'unknown';
|
|
45
|
+
value: string;
|
|
46
|
+
};
|
|
47
|
+
export declare function accountOriginOf(origin?: string | null): IAccountOrigin;
|
|
48
|
+
/**
|
|
49
|
+
* Whether an account signs in through a provider: disconnecting that
|
|
50
|
+
* provider would leave it nothing to sign in with.
|
|
51
|
+
*/
|
|
52
|
+
export declare function signsInWith(origin: string | null | undefined, provider: IIAMProviderName): boolean;
|
|
16
53
|
/**
|
|
17
54
|
Datalayer Uniform Resource Name (URN)
|
|
18
55
|
|
package/lib/models/URN.js
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
* Copyright (c) 2023-2025 Datalayer, Inc.
|
|
3
3
|
* Distributed under the terms of the Modified BSD License.
|
|
4
4
|
*/
|
|
5
|
+
/** What an identity provider's account URN starts with, before its name. */
|
|
6
|
+
export const IAM_PROVIDER_URN_PREFIX = 'urn:dla:iam:ext::';
|
|
5
7
|
export class URN {
|
|
6
8
|
_partition;
|
|
7
9
|
_service;
|
|
@@ -17,7 +19,8 @@ export class URN {
|
|
|
17
19
|
this._region = parts[3];
|
|
18
20
|
this._account = parts[4];
|
|
19
21
|
this._type = parts[5];
|
|
20
|
-
|
|
22
|
+
// The rest, colons and all: a provider's account id may carry them.
|
|
23
|
+
this._uid = parts.slice(6).join(':');
|
|
21
24
|
}
|
|
22
25
|
get partition() {
|
|
23
26
|
return this._partition;
|
|
@@ -37,4 +40,59 @@ export class URN {
|
|
|
37
40
|
get uid() {
|
|
38
41
|
return this._uid;
|
|
39
42
|
}
|
|
43
|
+
/** An identity provider's account (`urn:dla:iam:ext::github:…`). */
|
|
44
|
+
get isIAMProviderAccount() {
|
|
45
|
+
return this._service === 'iam' && this._region === 'ext' && !!this._type;
|
|
46
|
+
}
|
|
47
|
+
toString() {
|
|
48
|
+
return [
|
|
49
|
+
'urn',
|
|
50
|
+
this._partition,
|
|
51
|
+
this._service,
|
|
52
|
+
this._region,
|
|
53
|
+
this._account,
|
|
54
|
+
this._type,
|
|
55
|
+
this._uid,
|
|
56
|
+
].join(':');
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/** A URN, or `undefined` when the value is not one — never a throw. */
|
|
60
|
+
export function parseURN(value) {
|
|
61
|
+
const text = (value ?? '').trim();
|
|
62
|
+
if (!text.toLowerCase().startsWith('urn:') || text.split(':').length < 7) {
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
return new URN(text);
|
|
66
|
+
}
|
|
67
|
+
const IAM_PROVIDER_NAMES = [
|
|
68
|
+
'bluesky',
|
|
69
|
+
'discord',
|
|
70
|
+
'github',
|
|
71
|
+
'google',
|
|
72
|
+
'linkedin',
|
|
73
|
+
'okta',
|
|
74
|
+
'x',
|
|
75
|
+
];
|
|
76
|
+
export function accountOriginOf(origin) {
|
|
77
|
+
const value = (origin ?? '').trim();
|
|
78
|
+
if (value === 'datalayer') {
|
|
79
|
+
return { kind: 'datalayer' };
|
|
80
|
+
}
|
|
81
|
+
const urn = parseURN(value);
|
|
82
|
+
if (!urn) {
|
|
83
|
+
return { kind: 'unknown', value };
|
|
84
|
+
}
|
|
85
|
+
const provider = urn.type.toLowerCase();
|
|
86
|
+
if (urn.isIAMProviderAccount && IAM_PROVIDER_NAMES.includes(provider)) {
|
|
87
|
+
return { kind: 'iam-provider', provider, accountId: urn.uid, urn };
|
|
88
|
+
}
|
|
89
|
+
return { kind: 'urn', urn };
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Whether an account signs in through a provider: disconnecting that
|
|
93
|
+
* provider would leave it nothing to sign in with.
|
|
94
|
+
*/
|
|
95
|
+
export function signsInWith(origin, provider) {
|
|
96
|
+
const parsed = accountOriginOf(origin);
|
|
97
|
+
return parsed.kind === 'iam-provider' && parsed.provider === provider;
|
|
40
98
|
}
|
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
/** The signed-in shell: the platform, the business cases, or the admin. */
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* The four shells of the signed-in application.
|
|
4
|
+
*
|
|
5
|
+
* `studio` is where an agentic UI application is composed, validated and
|
|
6
|
+
* shipped — the default for somebody who has not chosen, and what the root
|
|
7
|
+
* shows. `home` is the whole platform, shown as *Power*, at `/power`: the key
|
|
8
|
+
* is kept so a cookie written before the Studio existed still names the
|
|
9
|
+
* shell it meant. `agentify` is the business cases; `admin` is the
|
|
10
|
+
* platform's administration.
|
|
11
|
+
*/
|
|
12
|
+
export type NavigationView = 'studio' | 'home' | 'agentify' | 'admin';
|
|
3
13
|
/** The shells, and where each one opens when it has not been visited. */
|
|
4
14
|
export declare const NAVIGATION_VIEW_HOMES: Record<NavigationView, string>;
|
|
5
15
|
/** Well-known view identifiers for {@link NavigationState.tabsByView}. */
|
|
@@ -33,7 +33,10 @@ import { createStore } from 'zustand/vanilla';
|
|
|
33
33
|
import { registerSessionState } from '../sessionEnd.js';
|
|
34
34
|
/** The shells, and where each one opens when it has not been visited. */
|
|
35
35
|
export const NAVIGATION_VIEW_HOMES = {
|
|
36
|
-
|
|
36
|
+
studio: '/studio',
|
|
37
|
+
// Not `/`: the root is the Studio's, so the Power shell has an address of
|
|
38
|
+
// its own to be sent to.
|
|
39
|
+
home: '/power',
|
|
37
40
|
agentify: '/agentify',
|
|
38
41
|
admin: '/admin',
|
|
39
42
|
};
|
|
@@ -50,7 +53,10 @@ const SHELL_COOKIE = 'datalayer-signed-in-view';
|
|
|
50
53
|
const FORMER_TABS_KEY = 'datalayer_view_tabs';
|
|
51
54
|
/** Days a remembered shell lives in the cookie. */
|
|
52
55
|
const COOKIE_MAX_AGE_DAYS = 365;
|
|
53
|
-
const isView = (value) => value === '
|
|
56
|
+
const isView = (value) => value === 'studio' ||
|
|
57
|
+
value === 'home' ||
|
|
58
|
+
value === 'agentify' ||
|
|
59
|
+
value === 'admin';
|
|
54
60
|
function readCookie(name) {
|
|
55
61
|
if (typeof document === 'undefined') {
|
|
56
62
|
return undefined;
|
|
@@ -90,7 +96,8 @@ function restore() {
|
|
|
90
96
|
const parsed = JSON.parse(stored);
|
|
91
97
|
// The landing kept this under the same key through zustand's
|
|
92
98
|
// `persist`, which wraps what it writes in `{ state, version }`.
|
|
93
|
-
|
|
99
|
+
const kept = parsed?.state ?? parsed;
|
|
100
|
+
persisted = kept && typeof kept === 'object' ? kept : {};
|
|
94
101
|
}
|
|
95
102
|
catch {
|
|
96
103
|
persisted = {};
|
|
@@ -112,8 +119,32 @@ function restore() {
|
|
|
112
119
|
if (isView(shell)) {
|
|
113
120
|
persisted.view = shell;
|
|
114
121
|
}
|
|
122
|
+
persisted.lastRouteByView = restoredRoutes(persisted.lastRouteByView);
|
|
115
123
|
return persisted;
|
|
116
124
|
}
|
|
125
|
+
/**
|
|
126
|
+
* The shells' pages as they were written down, less the ones no shell
|
|
127
|
+
* returns to.
|
|
128
|
+
*
|
|
129
|
+
* What is in storage was written by whichever version ran last, under that
|
|
130
|
+
* version's rules. Before the Power shell had an address of its own, its
|
|
131
|
+
* page could be the root — which is now the Studio's, and would send Power
|
|
132
|
+
* to the Studio — and an earlier version filed pages under the shell the
|
|
133
|
+
* toggle named. Such a page is dropped here rather than carried, so the next
|
|
134
|
+
* write does not put it back.
|
|
135
|
+
*/
|
|
136
|
+
function restoredRoutes(stored) {
|
|
137
|
+
const routes = {};
|
|
138
|
+
if (!stored || typeof stored !== 'object') {
|
|
139
|
+
return routes;
|
|
140
|
+
}
|
|
141
|
+
for (const [view, route] of Object.entries(stored)) {
|
|
142
|
+
if (isView(view) && isRouteOfView(route, view)) {
|
|
143
|
+
routes[view] = route;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return routes;
|
|
147
|
+
}
|
|
117
148
|
function persist(state) {
|
|
118
149
|
const written = {
|
|
119
150
|
view: state.view,
|
|
@@ -162,6 +193,15 @@ export function isRememberableRoute(route) {
|
|
|
162
193
|
*/
|
|
163
194
|
export function viewForRoute(route) {
|
|
164
195
|
const path = route.split('?')[0];
|
|
196
|
+
// The root is the Studio: what a signed-in reader opens on. The settings
|
|
197
|
+
// are read from it too, with its sidebar beside them.
|
|
198
|
+
if (path === '/' ||
|
|
199
|
+
path === '/studio' ||
|
|
200
|
+
path.startsWith('/studio/') ||
|
|
201
|
+
path === '/settings' ||
|
|
202
|
+
path.startsWith('/settings/')) {
|
|
203
|
+
return 'studio';
|
|
204
|
+
}
|
|
165
205
|
if (path === '/agentify' || path.startsWith('/agentify/')) {
|
|
166
206
|
return 'agentify';
|
|
167
207
|
}
|
|
@@ -170,9 +210,17 @@ export function viewForRoute(route) {
|
|
|
170
210
|
}
|
|
171
211
|
return 'home';
|
|
172
212
|
}
|
|
213
|
+
/** Whether a page may be the one a shell returns to. */
|
|
214
|
+
function isRouteOfView(route, view) {
|
|
215
|
+
return (typeof route === 'string' &&
|
|
216
|
+
isRememberableRoute(route) &&
|
|
217
|
+
viewForRoute(route) === view);
|
|
218
|
+
}
|
|
173
219
|
const initial = restore();
|
|
174
220
|
export const navigationStore = createStore((set, get) => ({
|
|
175
|
-
|
|
221
|
+
// The Studio, for a reader who never chose: a cookie from before it
|
|
222
|
+
// existed says `home`, and is honoured.
|
|
223
|
+
view: initial.view ?? 'studio',
|
|
176
224
|
lastRouteByView: initial.lastRouteByView ?? {},
|
|
177
225
|
tabsByView: initial.tabsByView ?? {},
|
|
178
226
|
requestedRoute: undefined,
|
|
@@ -210,9 +258,10 @@ export const navigationStore = createStore((set, get) => ({
|
|
|
210
258
|
// Only a page of that shell: an earlier version filed pages under the
|
|
211
259
|
// shell the toggle named rather than the one the route belonged to, so a
|
|
212
260
|
// reader can still have `/items` written down as Agentify's page. Going
|
|
213
|
-
// "to Agentify" must never land on a Home page
|
|
261
|
+
// "to Agentify" must never land on a Home page — nor Power on the root,
|
|
262
|
+
// which was its page before it had `/power` and is now the Studio's.
|
|
214
263
|
const remembered = get().lastRouteByView[view];
|
|
215
|
-
return
|
|
264
|
+
return isRouteOfView(remembered, view)
|
|
216
265
|
? remembered
|
|
217
266
|
: NAVIGATION_VIEW_HOMES[view];
|
|
218
267
|
},
|
package/lib/utils/Handles.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Copyright (c) 2023-2025 Datalayer, Inc.
|
|
3
3
|
* Distributed under the terms of the Modified BSD License.
|
|
4
4
|
*/
|
|
5
|
-
|
|
5
|
+
import { IAM_PROVIDER_URN_PREFIX as EXT_URN_PREFIX } from '../models/URN.js';
|
|
6
6
|
export function isExternalUrnHandle(handle) {
|
|
7
7
|
const normalized = (handle || '').trim().toLowerCase();
|
|
8
8
|
return normalized.startsWith(EXT_URN_PREFIX);
|
|
@@ -3,7 +3,7 @@ import { useMemo, useRef, useState } from 'react';
|
|
|
3
3
|
import { ActionList, ActionMenu, Button, Heading, Label, Link, RelativeTime, Select, Spinner, Text, } from '@primer/react';
|
|
4
4
|
import { Blankslate, DataTable, Dialog, Table, } from '@primer/react/experimental';
|
|
5
5
|
import { Box } from '@datalayer/primer-addons';
|
|
6
|
-
import { ChecklistIcon, KebabHorizontalIcon, PlayIcon, PlugIcon, StackIcon,
|
|
6
|
+
import { ChecklistIcon, KebabHorizontalIcon, PlayIcon, PlugIcon, StackIcon, } from '@primer/octicons-react';
|
|
7
7
|
import { ShareAccessDialog, sandboxSharingUrl } from '../../components/sharing/index.js';
|
|
8
8
|
import { ClientBadge, McpErrorBlankslate } from '../../components/mcp/index.js';
|
|
9
9
|
import { useDisconnectAgent, useMcpActivity, useTerminateBinding, } from '../../hooks/useMcp.js';
|
|
@@ -54,7 +54,7 @@ const boundTo = (client) => {
|
|
|
54
54
|
return '';
|
|
55
55
|
};
|
|
56
56
|
const countLook = (tone) => tone === 'danger' ? 'danger.fg' : 'fg.default';
|
|
57
|
-
const Count = ({ label, value, tone = 'neutral', note, }) => (_jsxs(Box, { sx: {
|
|
57
|
+
const Count = ({ label, value, tone = 'neutral', note, to, onOpen, }) => (_jsxs(Box, { sx: {
|
|
58
58
|
p: 3,
|
|
59
59
|
border: '1px solid',
|
|
60
60
|
borderColor: 'border.default',
|
|
@@ -66,7 +66,14 @@ const Count = ({ label, value, tone = 'neutral', note, }) => (_jsxs(Box, { sx: {
|
|
|
66
66
|
fontSize: 4,
|
|
67
67
|
fontWeight: 'bold',
|
|
68
68
|
color: countLook(tone),
|
|
69
|
-
}, children: value }),
|
|
69
|
+
}, children: value }), to ? (_jsx(Link, { href: to, onClick: (event) => {
|
|
70
|
+
// A modified click asks for a new tab; `href` is real, so let it.
|
|
71
|
+
if (event.metaKey || event.ctrlKey || event.shiftKey) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
event.preventDefault();
|
|
75
|
+
onOpen?.(to);
|
|
76
|
+
}, sx: { display: 'block', fontSize: 0 }, children: label })) : (_jsx(Text, { sx: { display: 'block', fontSize: 0, color: 'fg.muted' }, children: label })), note && (_jsx(Text, { sx: { display: 'block', fontSize: 0, color: 'fg.subtle', mt: 1 }, children: note }))] }));
|
|
70
77
|
/** A panel that has nothing to show, and the step that would fill it. */
|
|
71
78
|
const PanelEmpty = ({ icon: Icon, heading, description, action, }) => (_jsxs(Blankslate, { border: true, spacious: true, children: [_jsx(Blankslate.Visual, { children: _jsx(Icon, { size: "medium" }) }), _jsx(Blankslate.Heading, { children: heading }), _jsx(Blankslate.Description, { children: _jsx(Text, { as: "p", sx: { textAlign: 'center', m: 0 }, children: description }) }), action && (_jsx(Button, { size: "small", onClick: action.onClick, children: action.label }))] }));
|
|
72
79
|
export const McpDashboard = ({ errorState, routes, org, showTitle = true, section, }) => {
|
|
@@ -379,7 +386,10 @@ export const McpDashboard = ({ errorState, routes, org, showTitle = true, sectio
|
|
|
379
386
|
'repeat(3, 1fr)',
|
|
380
387
|
'repeat(6, 1fr)',
|
|
381
388
|
],
|
|
382
|
-
}, children: [_jsx(Count, { label: "Clients connected", value: clients.length }), _jsx(Count, { label: "Sandboxes bound", value: sandboxes.filter(binding => (binding.state ?? 'active') === 'active').length }), _jsx(Count, { label: "Tasks running", value: data?.tasks.length ?? 0 }), _jsx(Count, { label: "Calls today", value: data?.today.calls ?? 0 }), _jsx(Count, { label: "Refusals today", value: data?.today.refusals ?? 0, tone: (data?.today.refusals ?? 0) > 0 ? 'danger' : 'neutral' }), _jsx(Count, { label: "Credits by agents", value: data?.today.credits ?? 0, note: "today"
|
|
389
|
+
}, children: [_jsx(Count, { label: "Clients connected", value: clients.length, to: routes.agents, onOpen: navigate }), _jsx(Count, { label: "Sandboxes bound", to: routes.sandboxes, onOpen: navigate, value: sandboxes.filter(binding => (binding.state ?? 'active') === 'active').length }), _jsx(Count, { label: "Tasks running", value: data?.tasks.length ?? 0, to: routes.runs, onOpen: navigate }), _jsx(Count, { label: "Calls today", value: data?.today.calls ?? 0, to: routes.calls, onOpen: navigate }), _jsx(Count, { label: "Refusals today", value: data?.today.refusals ?? 0, to: routes.audit, onOpen: navigate, tone: (data?.today.refusals ?? 0) > 0 ? 'danger' : 'neutral' }), _jsx(Count, { label: "Credits by agents", value: data?.today.credits ?? 0, note: "today",
|
|
390
|
+
// Credits are summed from the day's calls, which the Calls tab
|
|
391
|
+
// lists.
|
|
392
|
+
to: routes.calls, onOpen: navigate })] }))), draws('agents') &&
|
|
383
393
|
!loading &&
|
|
384
394
|
(clients.length > 0 ? (_jsxs(Table.Container, { children: [_jsx(Table.Title, { as: "h3", id: "mcp-clients", children: "Connected clients" }), _jsxs(Table.Subtitle, { as: "p", id: "mcp-clients-subtitle", children: [plural(clients.length, 'client'), " with a live grant on your workspace."] }), _jsx(DataTable, { "aria-labelledby": "mcp-clients", "aria-describedby": "mcp-clients-subtitle", data: clients, columns: clientColumns })] })) : (_jsx(PanelEmpty, { icon: PlugIcon, heading: "No client connected", description: "Connect Claude Code, Codex, Cursor, VS Code or any MCP client to your workspace, and it appears here on its first call.", action: {
|
|
385
395
|
label: 'Set up a client',
|
|
@@ -396,12 +406,7 @@ export const McpDashboard = ({ errorState, routes, org, showTitle = true, sectio
|
|
|
396
406
|
}, children: "No call matches these filters." }))] })) : (_jsx(PanelEmpty, { icon: ChecklistIcon, heading: "No call yet", description: "Ask your agent to list your notebooks. The call, its decision and its outcome land here and in the audit log.", action: {
|
|
397
407
|
label: 'Open the audit log',
|
|
398
408
|
onClick: () => navigate(routes.audit),
|
|
399
|
-
} }))),
|
|
400
|
-
display: 'flex',
|
|
401
|
-
gap: 3,
|
|
402
|
-
alignItems: 'center',
|
|
403
|
-
flexWrap: 'wrap',
|
|
404
|
-
}, children: [_jsx(Button, { size: "small", leadingVisual: TelescopeIcon, onClick: () => navigate(routes.observability), children: "Observability" }), _jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: ["Refreshed ", timeAgo(data?.at) || 'just now', ", and again every ten seconds."] })] })), disconnecting && (_jsx(Dialog, { title: "Disconnect this client?", onClose: () => setDisconnecting(null), returnFocusRef: returnFocusRef, footerButtons: [
|
|
409
|
+
} }))), disconnecting && (_jsx(Dialog, { title: "Disconnect this client?", onClose: () => setDisconnecting(null), returnFocusRef: returnFocusRef, footerButtons: [
|
|
405
410
|
{
|
|
406
411
|
buttonType: 'default',
|
|
407
412
|
content: 'Keep it',
|
package/lib/views/mcp/McpHome.js
CHANGED
|
@@ -63,7 +63,7 @@ export const Copyable = ({ text }) => {
|
|
|
63
63
|
} })] }));
|
|
64
64
|
};
|
|
65
65
|
/** One of the five summaries: a heading, what it holds, and the way in. */
|
|
66
|
-
const Summary = ({ icon: Icon, title, children, action, }) => (_jsxs(Box, { sx: {
|
|
66
|
+
const Summary = ({ icon: Icon, title, children, action, to, onOpen, }) => (_jsxs(Box, { sx: {
|
|
67
67
|
p: 3,
|
|
68
68
|
border: '1px solid',
|
|
69
69
|
borderColor: 'border.default',
|
|
@@ -72,7 +72,14 @@ const Summary = ({ icon: Icon, title, children, action, }) => (_jsxs(Box, { sx:
|
|
|
72
72
|
gap: 2,
|
|
73
73
|
alignContent: 'start',
|
|
74
74
|
minWidth: 0,
|
|
75
|
-
}, children: [_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsx(Icon, { size: 16 }),
|
|
75
|
+
}, children: [_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsx(Icon, { size: 16 }), to ? (_jsx(Link, { href: to, onClick: event => {
|
|
76
|
+
// A modified click asks for a new tab; `href` is real, so let it.
|
|
77
|
+
if (event.metaKey || event.ctrlKey || event.shiftKey) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
event.preventDefault();
|
|
81
|
+
onOpen?.(to);
|
|
82
|
+
}, sx: { fontSize: 1, fontWeight: 'semibold' }, children: title })) : (_jsx(Text, { sx: { fontSize: 1, fontWeight: 'semibold' }, children: title }))] }), _jsx(Box, { sx: { fontSize: 0, color: 'fg.muted', display: 'grid', gap: 1 }, children: children }), action && (_jsx(Box, { children: _jsx(Link, { as: "button", sx: { fontSize: 0, cursor: 'pointer' }, onClick: action.onClick, children: action.label }) }))] }));
|
|
76
83
|
export const McpHome = ({ routes, clientDocsBase = '/docs/mcp-clients', showTitle = true, showSummaries = true, showSetup = true, onOpenDocs, }) => {
|
|
77
84
|
const navigate = useNavigate();
|
|
78
85
|
const endpoint = useCoreStore(state => state.configuration.datalayerMcpServerUrl);
|
|
@@ -130,12 +137,12 @@ export const McpHome = ({ routes, clientDocsBase = '/docs/mcp-clients', showTitl
|
|
|
130
137
|
display: 'grid',
|
|
131
138
|
gap: 3,
|
|
132
139
|
gridTemplateColumns: ['1fr', 'repeat(2, 1fr)', 'repeat(3, 1fr)'],
|
|
133
|
-
}, children: [_jsx(Summary, { icon: PlugIcon, title: "Agents", action: {
|
|
140
|
+
}, children: [_jsx(Summary, { icon: PlugIcon, title: "Agents", to: routes.agents, onOpen: navigate, action: {
|
|
134
141
|
label: 'Connected agents',
|
|
135
142
|
onClick: () => navigate(routes.agents),
|
|
136
143
|
}, children: connected.length === 0 ? (_jsx(Text, { children: "No agent has been authorized yet. Set up a client above and approve the scopes it asks for." })) : (_jsxs(_Fragment, { children: [_jsxs(Text, { children: [plural(connected.length, 'agent'), " authorized."] }), connected.slice(0, 3).map(agent => (_jsxs(Text, { children: [agent.clientName || agent.clientId, " \u2014", ' ', agent.lastUsedAt
|
|
137
144
|
? `used ${timeAgo(agent.lastUsedAt)}`
|
|
138
|
-
: 'never used'] }, agent.uid)))] })) }), _jsx(Summary, { icon: PulseIcon, title: "Runs", action: { label: 'All runs', onClick: () => navigate(routes.runs) }, children: runs.length === 0 ? (_jsx(Text, { children: "Nothing has run yet. A tool call that outlives its request becomes a run you can watch and cancel." })) : (runs.map(task => (_jsxs(Text, { children: [task.tool, " \u2014 ", task.status, " ", timeAgo(task.lastUpdatedAt)] }, task.uid)))) }), _jsxs(Summary, { icon: TelescopeIcon, title: "Observability", action: {
|
|
145
|
+
: 'never used'] }, agent.uid)))] })) }), _jsx(Summary, { icon: PulseIcon, title: "Runs", to: routes.runs, onOpen: navigate, action: { label: 'All runs', onClick: () => navigate(routes.runs) }, children: runs.length === 0 ? (_jsx(Text, { children: "Nothing has run yet. A tool call that outlives its request becomes a run you can watch and cancel." })) : (runs.map(task => (_jsxs(Text, { children: [task.tool, " \u2014 ", task.status, " ", timeAgo(task.lastUpdatedAt)] }, task.uid)))) }), _jsxs(Summary, { icon: TelescopeIcon, title: "Observability", to: routes.observability, onOpen: navigate, action: {
|
|
139
146
|
label: 'Runs and metrics',
|
|
140
147
|
onClick: () => navigate(routes.observability),
|
|
141
148
|
}, children: [_jsx(Text, { children: metrics.data?.slis.samples.calls
|
|
@@ -145,7 +152,7 @@ export const McpHome = ({ routes, clientDocsBase = '/docs/mcp-clients', showTitl
|
|
|
145
152
|
: 'Latency not measured yet.' }), _jsx(Text, { children: metrics.data?.slis.availability === null ||
|
|
146
153
|
metrics.data?.slis.availability === undefined
|
|
147
154
|
? 'Error rate not measured yet.'
|
|
148
|
-
: `${((1 - metrics.data.slis.availability) * 100).toFixed(1)}% of calls failed.` })] }), _jsx(Summary, { icon: ToolsIcon, title: "Tools", children: _jsx(Text, { children: "The toolsets an agent may execute \u2014 the Contents sources you have enabled for it, their tools, their approval policy and their health \u2014 are managed here once toolset bindings ship." }) }), _jsx(Summary, { icon: ShareIcon, title: "Reach", children: _jsx(Text, { children: "Which notebooks and sources an agent can actually reach, as a list you can read at a glance, arrives with sharing to agents as principals." }) }), _jsx(Summary, { icon: KeyIcon, title: "Policies", action: {
|
|
155
|
+
: `${((1 - metrics.data.slis.availability) * 100).toFixed(1)}% of calls failed.` })] }), _jsx(Summary, { icon: ToolsIcon, title: "Tools", children: _jsx(Text, { children: "The toolsets an agent may execute \u2014 the Contents sources you have enabled for it, their tools, their approval policy and their health \u2014 are managed here once toolset bindings ship." }) }), _jsx(Summary, { icon: ShareIcon, title: "Reach", children: _jsx(Text, { children: "Which notebooks and sources an agent can actually reach, as a list you can read at a glance, arrives with sharing to agents as principals." }) }), _jsx(Summary, { icon: KeyIcon, title: "Policies", to: routes.policies, onOpen: navigate, action: {
|
|
149
156
|
label: 'What applies',
|
|
150
157
|
onClick: () => navigate(routes.policies),
|
|
151
158
|
}, children: _jsx(Text, { children: "What your agents are allowed to do, and which layer decided each rule." }) })] }))] }));
|
package/lib/views/mcp/types.d.ts
CHANGED
|
@@ -63,4 +63,8 @@ export interface McpRoutes {
|
|
|
63
63
|
agents: string;
|
|
64
64
|
/** The effective policy. */
|
|
65
65
|
policies: string;
|
|
66
|
+
/** The calls list, where an Overview count of calls or credits leads. */
|
|
67
|
+
calls?: string;
|
|
68
|
+
/** The bound code sandboxes, where the Overview's sandbox count leads. */
|
|
69
|
+
sandboxes?: string;
|
|
66
70
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datalayer/core",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.13",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"workspaces": [
|
|
6
6
|
".",
|
|
@@ -109,11 +109,11 @@
|
|
|
109
109
|
"rebuild:fresh": "npm run create:patches && npm install && npm run build && npm run clean:cache"
|
|
110
110
|
},
|
|
111
111
|
"dependencies": {
|
|
112
|
-
"@datalayer/design": "^1.0.
|
|
113
|
-
"@datalayer/icons-react": "^1.0.
|
|
114
|
-
"@datalayer/jupyter-lexical": "^
|
|
115
|
-
"@datalayer/jupyter-react": "^2.0.
|
|
116
|
-
"@datalayer/primer-addons": "^1.0.
|
|
112
|
+
"@datalayer/design": "^1.0.3",
|
|
113
|
+
"@datalayer/icons-react": "^1.0.14",
|
|
114
|
+
"@datalayer/jupyter-lexical": "^2.0.18",
|
|
115
|
+
"@datalayer/jupyter-react": "^2.0.18",
|
|
116
|
+
"@datalayer/primer-addons": "^1.0.23",
|
|
117
117
|
"@datalayer/primer-rjsf": "^1.0.3",
|
|
118
118
|
"@fluentui/react": "^8.125.3",
|
|
119
119
|
"@jupyter-widgets/base-manager": "^1.0.12",
|