@agent-native/core 0.107.2 → 0.108.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +6 -0
- package/corpus/core/docs/content/actions.mdx +48 -0
- package/corpus/core/docs/content/locales/ar-SA/actions.mdx +38 -0
- package/corpus/core/docs/content/locales/de-DE/actions.mdx +38 -0
- package/corpus/core/docs/content/locales/es-ES/actions.mdx +38 -0
- package/corpus/core/docs/content/locales/fr-FR/actions.mdx +38 -0
- package/corpus/core/docs/content/locales/hi-IN/actions.mdx +38 -0
- package/corpus/core/docs/content/locales/ja-JP/actions.mdx +38 -0
- package/corpus/core/docs/content/locales/ko-KR/actions.mdx +38 -0
- package/corpus/core/docs/content/locales/pt-BR/actions.mdx +38 -0
- package/corpus/core/docs/content/locales/zh-CN/actions.mdx +38 -0
- package/corpus/core/docs/content/locales/zh-TW/actions.mdx +38 -0
- package/corpus/core/package.json +5 -1
- package/corpus/core/src/a2a-claims.ts +52 -0
- package/corpus/core/src/action.ts +6 -2
- package/corpus/core/src/audit/record.ts +6 -0
- package/corpus/core/src/client/feature-flags/FeatureFlagsPanel.tsx +519 -0
- package/corpus/core/src/client/feature-flags/helpers.ts +77 -0
- package/corpus/core/src/client/feature-flags/index.ts +13 -0
- package/corpus/core/src/client/feature-flags/types.ts +29 -0
- package/corpus/core/src/client/feature-flags/use-feature-flag.ts +26 -0
- package/corpus/core/src/client/index.ts +11 -0
- package/corpus/core/src/extensions/routes.ts +1 -1
- package/corpus/core/src/feature-flags/a2a-action-route.ts +56 -0
- package/corpus/core/src/feature-flags/actions/get-feature-flags.ts +24 -0
- package/corpus/core/src/feature-flags/actions/list-feature-flags.ts +69 -0
- package/corpus/core/src/feature-flags/actions/set-feature-flag.ts +89 -0
- package/corpus/core/src/feature-flags/index.ts +21 -0
- package/corpus/core/src/feature-flags/permissions.ts +53 -0
- package/corpus/core/src/feature-flags/plugin.ts +44 -0
- package/corpus/core/src/feature-flags/registry.ts +96 -0
- package/corpus/core/src/feature-flags/store.ts +176 -0
- package/corpus/core/src/index.ts +15 -0
- package/corpus/core/src/localization/default-messages.ts +47 -0
- package/corpus/core/src/server/action-discovery.ts +12 -0
- package/corpus/core/src/server/action-routes.ts +47 -5
- package/corpus/core/src/server/index.ts +1 -0
- package/corpus/core/src/settings/org-settings.ts +13 -0
- package/corpus/core/src/settings/store.ts +57 -0
- package/corpus/core/src/templates/default/.agents/skills/feature-flags/SKILL.md +169 -0
- package/corpus/core/src/templates/default/AGENTS.md +1 -0
- package/corpus/core/src/templates/headless/.agents/skills/feature-flags/SKILL.md +169 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/feature-flags/SKILL.md +169 -0
- package/corpus/core/src/templates/workspace-core/AGENTS.md +1 -1
- package/corpus/core/src/templates/workspace-root/AGENTS.md +1 -1
- package/corpus/core/src/vite/action-types-plugin.ts +12 -0
- package/corpus/templates/analytics/.agents/skills/feature-flags/SKILL.md +169 -0
- package/corpus/templates/analytics/AGENTS.md +15 -3
- package/corpus/templates/analytics/actions/list-workspace-feature-flags.ts +15 -0
- package/corpus/templates/analytics/actions/navigate.ts +2 -2
- package/corpus/templates/analytics/actions/set-workspace-feature-flag.ts +45 -0
- package/corpus/templates/analytics/actions/view-screen.ts +13 -0
- package/corpus/templates/analytics/app/components/agents/FeatureFlagsFleetPanel.tsx +243 -0
- package/corpus/templates/analytics/app/components/layout/CommandPalette.tsx +11 -3
- package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +3 -1
- package/corpus/templates/analytics/app/i18n/zh-TW.ts +17 -0
- package/corpus/templates/analytics/app/i18n-data.ts +251 -0
- package/corpus/templates/analytics/app/pages/Agents.tsx +22 -2
- package/corpus/templates/analytics/changelog/2026-07-17-manage-feature-flag-rollouts-across-your-organization-s-apps.md +6 -0
- package/corpus/templates/analytics/server/lib/db-admin-connections.ts +13 -5
- package/corpus/templates/analytics/server/lib/workspace-feature-flags.ts +347 -0
- package/corpus/templates/assets/.agents/skills/feature-flags/SKILL.md +169 -0
- package/corpus/templates/brain/.agents/skills/feature-flags/SKILL.md +169 -0
- package/corpus/templates/calendar/.agents/skills/feature-flags/SKILL.md +169 -0
- package/corpus/templates/chat/.agents/skills/feature-flags/SKILL.md +169 -0
- package/corpus/templates/clips/.agents/skills/feature-flags/SKILL.md +169 -0
- package/corpus/templates/clips/server/plugins/feature-flags.ts +11 -0
- package/corpus/templates/clips/shared/feature-flags.ts +30 -37
- package/corpus/templates/content/.agents/skills/feature-flags/SKILL.md +169 -0
- package/corpus/templates/design/.agents/skills/feature-flags/SKILL.md +169 -0
- package/corpus/templates/design/AGENTS.md +5 -3
- package/corpus/templates/design/actions/add-fusion-screens.ts +4 -6
- package/corpus/templates/design/actions/apply-fusion-edits.ts +4 -6
- package/corpus/templates/design/actions/create-fusion-app.ts +5 -4
- package/corpus/templates/design/actions/deploy-fusion-app.ts +4 -3
- package/corpus/templates/design/actions/get-fusion-deploy-status.ts +4 -6
- package/corpus/templates/design/actions/list-fusion-edits.ts +4 -3
- package/corpus/templates/design/actions/push-fusion-app.ts +4 -6
- package/corpus/templates/design/actions/queue-fusion-edit.ts +4 -3
- package/corpus/templates/design/actions/send-fusion-message.ts +4 -6
- package/corpus/templates/design/actions/sync-fusion-app.ts +4 -3
- package/corpus/templates/design/app/components/editor/PromptDialog.tsx +1 -1
- package/corpus/templates/design/app/pages/Index.tsx +8 -6
- package/corpus/templates/design/server/plugins/feature-flags.ts +5 -0
- package/corpus/templates/design/shared/full-app.ts +10 -7
- package/corpus/templates/dispatch/.agents/skills/feature-flags/SKILL.md +169 -0
- package/corpus/templates/forms/.agents/skills/feature-flags/SKILL.md +169 -0
- package/corpus/templates/macros/.agents/skills/feature-flags/SKILL.md +169 -0
- package/corpus/templates/mail/.agents/skills/feature-flags/SKILL.md +169 -0
- package/corpus/templates/plan/.agents/skills/feature-flags/SKILL.md +169 -0
- package/corpus/templates/slides/.agents/skills/feature-flags/SKILL.md +169 -0
- package/corpus/templates/tasks/.agents/skills/feature-flags/SKILL.md +169 -0
- package/dist/a2a-claims.d.ts +10 -0
- package/dist/a2a-claims.d.ts.map +1 -0
- package/dist/a2a-claims.js +41 -0
- package/dist/a2a-claims.js.map +1 -0
- package/dist/action.d.ts +6 -2
- package/dist/action.d.ts.map +1 -1
- package/dist/action.js.map +1 -1
- package/dist/audit/record.d.ts +3 -0
- package/dist/audit/record.d.ts.map +1 -1
- package/dist/audit/record.js +3 -0
- package/dist/audit/record.js.map +1 -1
- package/dist/client/feature-flags/FeatureFlagsPanel.d.ts +10 -0
- package/dist/client/feature-flags/FeatureFlagsPanel.d.ts.map +1 -0
- package/dist/client/feature-flags/FeatureFlagsPanel.js +143 -0
- package/dist/client/feature-flags/FeatureFlagsPanel.js.map +1 -0
- package/dist/client/feature-flags/helpers.d.ts +16 -0
- package/dist/client/feature-flags/helpers.d.ts.map +1 -0
- package/dist/client/feature-flags/helpers.js +50 -0
- package/dist/client/feature-flags/helpers.js.map +1 -0
- package/dist/client/feature-flags/index.d.ts +5 -0
- package/dist/client/feature-flags/index.d.ts.map +1 -0
- package/dist/client/feature-flags/index.js +4 -0
- package/dist/client/feature-flags/index.js.map +1 -0
- package/dist/client/feature-flags/types.d.ts +27 -0
- package/dist/client/feature-flags/types.d.ts.map +1 -0
- package/dist/client/feature-flags/types.js +2 -0
- package/dist/client/feature-flags/types.js.map +1 -0
- package/dist/client/feature-flags/use-feature-flag.d.ts +8 -0
- package/dist/client/feature-flags/use-feature-flag.d.ts.map +1 -0
- package/dist/client/feature-flags/use-feature-flag.js +15 -0
- package/dist/client/feature-flags/use-feature-flag.js.map +1 -0
- package/dist/client/index.d.ts +1 -0
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +1 -0
- package/dist/client/index.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/extensions/routes.d.ts.map +1 -1
- package/dist/extensions/routes.js +1 -1
- package/dist/extensions/routes.js.map +1 -1
- package/dist/feature-flags/a2a-action-route.d.ts +14 -0
- package/dist/feature-flags/a2a-action-route.d.ts.map +1 -0
- package/dist/feature-flags/a2a-action-route.js +50 -0
- package/dist/feature-flags/a2a-action-route.js.map +1 -0
- package/dist/feature-flags/actions/get-feature-flags.d.ts +3 -0
- package/dist/feature-flags/actions/get-feature-flags.d.ts.map +1 -0
- package/dist/feature-flags/actions/get-feature-flags.js +18 -0
- package/dist/feature-flags/actions/get-feature-flags.js.map +1 -0
- package/dist/feature-flags/actions/list-feature-flags.d.ts +28 -0
- package/dist/feature-flags/actions/list-feature-flags.d.ts.map +1 -0
- package/dist/feature-flags/actions/list-feature-flags.js +60 -0
- package/dist/feature-flags/actions/list-feature-flags.js.map +1 -0
- package/dist/feature-flags/actions/set-feature-flag.d.ts +26 -0
- package/dist/feature-flags/actions/set-feature-flag.d.ts.map +1 -0
- package/dist/feature-flags/actions/set-feature-flag.js +78 -0
- package/dist/feature-flags/actions/set-feature-flag.js.map +1 -0
- package/dist/feature-flags/index.d.ts +5 -0
- package/dist/feature-flags/index.d.ts.map +1 -0
- package/dist/feature-flags/index.js +5 -0
- package/dist/feature-flags/index.js.map +1 -0
- package/dist/feature-flags/permissions.d.ts +13 -0
- package/dist/feature-flags/permissions.d.ts.map +1 -0
- package/dist/feature-flags/permissions.js +37 -0
- package/dist/feature-flags/permissions.js.map +1 -0
- package/dist/feature-flags/plugin.d.ts +17 -0
- package/dist/feature-flags/plugin.d.ts.map +1 -0
- package/dist/feature-flags/plugin.js +29 -0
- package/dist/feature-flags/plugin.js.map +1 -0
- package/dist/feature-flags/registry.d.ts +23 -0
- package/dist/feature-flags/registry.d.ts.map +1 -0
- package/dist/feature-flags/registry.js +59 -0
- package/dist/feature-flags/registry.js.map +1 -0
- package/dist/feature-flags/store.d.ts +31 -0
- package/dist/feature-flags/store.d.ts.map +1 -0
- package/dist/feature-flags/store.js +124 -0
- package/dist/feature-flags/store.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/localization/default-messages.d.ts +42 -0
- package/dist/localization/default-messages.d.ts.map +1 -1
- package/dist/localization/default-messages.js +42 -0
- package/dist/localization/default-messages.js.map +1 -1
- package/dist/observability/routes.d.ts +1 -1
- package/dist/progress/routes.d.ts +1 -1
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/server/action-discovery.d.ts.map +1 -1
- package/dist/server/action-discovery.js +12 -0
- package/dist/server/action-discovery.js.map +1 -1
- package/dist/server/action-routes.d.ts +3 -0
- package/dist/server/action-routes.d.ts.map +1 -1
- package/dist/server/action-routes.js +45 -5
- package/dist/server/action-routes.js.map +1 -1
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -0
- package/dist/server/index.js.map +1 -1
- package/dist/settings/org-settings.d.ts +2 -0
- package/dist/settings/org-settings.d.ts.map +1 -1
- package/dist/settings/org-settings.js +5 -1
- package/dist/settings/org-settings.js.map +1 -1
- package/dist/settings/store.d.ts +8 -0
- package/dist/settings/store.d.ts.map +1 -1
- package/dist/settings/store.js +48 -0
- package/dist/settings/store.js.map +1 -1
- package/dist/templates/chat/.agents/skills/feature-flags/SKILL.md +169 -0
- package/dist/templates/default/.agents/skills/feature-flags/SKILL.md +169 -0
- package/dist/templates/default/AGENTS.md +1 -0
- package/dist/templates/headless/.agents/skills/feature-flags/SKILL.md +169 -0
- package/dist/templates/workspace-core/.agents/skills/feature-flags/SKILL.md +169 -0
- package/dist/templates/workspace-core/AGENTS.md +1 -1
- package/dist/templates/workspace-root/AGENTS.md +1 -1
- package/dist/vite/action-types-plugin.d.ts.map +1 -1
- package/dist/vite/action-types-plugin.js +12 -0
- package/dist/vite/action-types-plugin.js.map +1 -1
- package/docs/content/actions.mdx +48 -0
- package/docs/content/locales/ar-SA/actions.mdx +38 -0
- package/docs/content/locales/de-DE/actions.mdx +38 -0
- package/docs/content/locales/es-ES/actions.mdx +38 -0
- package/docs/content/locales/fr-FR/actions.mdx +38 -0
- package/docs/content/locales/hi-IN/actions.mdx +38 -0
- package/docs/content/locales/ja-JP/actions.mdx +38 -0
- package/docs/content/locales/ko-KR/actions.mdx +38 -0
- package/docs/content/locales/pt-BR/actions.mdx +38 -0
- package/docs/content/locales/zh-CN/actions.mdx +38 -0
- package/docs/content/locales/zh-TW/actions.mdx +38 -0
- package/package.json +5 -1
- package/src/templates/chat/.agents/skills/feature-flags/SKILL.md +169 -0
- package/src/templates/default/.agents/skills/feature-flags/SKILL.md +169 -0
- package/src/templates/default/AGENTS.md +1 -0
- package/src/templates/headless/.agents/skills/feature-flags/SKILL.md +169 -0
- package/src/templates/workspace-core/.agents/skills/feature-flags/SKILL.md +169 -0
- package/src/templates/workspace-core/AGENTS.md +1 -1
- package/src/templates/workspace-root/AGENTS.md +1 -1
- package/corpus/templates/clips/actions/get-feature-flags.ts +0 -30
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import {
|
|
2
|
+
FeatureFlagsEditor,
|
|
3
|
+
useActionMutation,
|
|
4
|
+
useActionQuery,
|
|
5
|
+
useT,
|
|
6
|
+
type FeatureFlagMetadata,
|
|
7
|
+
type SetFeatureFlagInput,
|
|
8
|
+
} from "@agent-native/core/client";
|
|
9
|
+
import { IconRefresh } from "@tabler/icons-react";
|
|
10
|
+
import { useQueryClient } from "@tanstack/react-query";
|
|
11
|
+
|
|
12
|
+
import { Badge } from "@/components/ui/badge";
|
|
13
|
+
import { Button } from "@/components/ui/button";
|
|
14
|
+
|
|
15
|
+
export interface FeatureFlag {
|
|
16
|
+
key: string;
|
|
17
|
+
displayName?: string | null;
|
|
18
|
+
description?: string | null;
|
|
19
|
+
defaultValue?: boolean;
|
|
20
|
+
rules?: FeatureFlagMetadata["rules"];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface FlagApp {
|
|
24
|
+
appId?: string;
|
|
25
|
+
appName?: string;
|
|
26
|
+
appOrigin?: string;
|
|
27
|
+
state?: string;
|
|
28
|
+
id?: string;
|
|
29
|
+
name?: string;
|
|
30
|
+
url?: string;
|
|
31
|
+
status?: string;
|
|
32
|
+
reason?: string;
|
|
33
|
+
flags?: FeatureFlag[];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface FlagDirectory {
|
|
37
|
+
directoryStatus?: string;
|
|
38
|
+
apps?: FlagApp[];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function asDirectory(value: unknown): FlagDirectory {
|
|
42
|
+
return value && typeof value === "object" ? (value as FlagDirectory) : {};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function isReady(app: FlagApp) {
|
|
46
|
+
return app.state === "ready" || app.status === "ready";
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function statusLabel(app: FlagApp) {
|
|
50
|
+
return app.state || app.status || "unknown-legacy";
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function appId(app: FlagApp) {
|
|
54
|
+
return app.appId || app.id || "";
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function appName(app: FlagApp) {
|
|
58
|
+
return app.appName || app.name || appId(app);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function qualifyFleetMutation(
|
|
62
|
+
appId: string,
|
|
63
|
+
input: SetFeatureFlagInput,
|
|
64
|
+
) {
|
|
65
|
+
return { appId, ...input };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function FeatureFlagsFleetPanel() {
|
|
69
|
+
const t = useT();
|
|
70
|
+
const client = useQueryClient();
|
|
71
|
+
const flags = useActionQuery<unknown>(
|
|
72
|
+
"list-workspace-feature-flags",
|
|
73
|
+
undefined,
|
|
74
|
+
{ retry: false },
|
|
75
|
+
);
|
|
76
|
+
const mutation = useActionMutation<
|
|
77
|
+
unknown,
|
|
78
|
+
{ appId: string } & SetFeatureFlagInput
|
|
79
|
+
>("set-workspace-feature-flag", {
|
|
80
|
+
onMutate: async (input) => {
|
|
81
|
+
await client.cancelQueries({
|
|
82
|
+
queryKey: ["action", "list-workspace-feature-flags"],
|
|
83
|
+
});
|
|
84
|
+
const key = ["action", "list-workspace-feature-flags", undefined];
|
|
85
|
+
const previous = client.getQueryData(key);
|
|
86
|
+
client.setQueryData(key, (old: unknown) => {
|
|
87
|
+
const data = asDirectory(old);
|
|
88
|
+
return {
|
|
89
|
+
...data,
|
|
90
|
+
apps: data.apps?.map((app) =>
|
|
91
|
+
appId(app) !== input.appId
|
|
92
|
+
? app
|
|
93
|
+
: {
|
|
94
|
+
...app,
|
|
95
|
+
flags: app.flags?.map((flag) =>
|
|
96
|
+
flag.key !== input.key
|
|
97
|
+
? flag
|
|
98
|
+
: {
|
|
99
|
+
...flag,
|
|
100
|
+
rules:
|
|
101
|
+
input.operation === "replace-rules" && input.rules
|
|
102
|
+
? input.rules
|
|
103
|
+
: input.operation === "off"
|
|
104
|
+
? {
|
|
105
|
+
...flag.rules!,
|
|
106
|
+
mode: "off",
|
|
107
|
+
emails: [],
|
|
108
|
+
orgIds: [],
|
|
109
|
+
percentage: 0,
|
|
110
|
+
}
|
|
111
|
+
: flag.rules,
|
|
112
|
+
},
|
|
113
|
+
),
|
|
114
|
+
},
|
|
115
|
+
),
|
|
116
|
+
};
|
|
117
|
+
});
|
|
118
|
+
return { previous, key };
|
|
119
|
+
},
|
|
120
|
+
onError: (_error, _input, context: any) => {
|
|
121
|
+
if (context) client.setQueryData(context.key, context.previous);
|
|
122
|
+
},
|
|
123
|
+
onSettled: () =>
|
|
124
|
+
void client.invalidateQueries({
|
|
125
|
+
queryKey: ["action", "list-workspace-feature-flags"],
|
|
126
|
+
}),
|
|
127
|
+
});
|
|
128
|
+
const directory = asDirectory(flags.data);
|
|
129
|
+
const apps = directory.apps ?? [];
|
|
130
|
+
if (flags.isLoading) return <PanelLoading />;
|
|
131
|
+
if (flags.error || directory.directoryStatus === "unavailable")
|
|
132
|
+
return (
|
|
133
|
+
<StatusState
|
|
134
|
+
title={t("agents.flagsUnavailable")}
|
|
135
|
+
detail={flags.error?.message || t("agents.flagsUnreachable")}
|
|
136
|
+
onRetry={() => void flags.refetch()}
|
|
137
|
+
/>
|
|
138
|
+
);
|
|
139
|
+
if (apps.length === 0)
|
|
140
|
+
return (
|
|
141
|
+
<StatusState
|
|
142
|
+
title={t("agents.flagsEmpty")}
|
|
143
|
+
detail={t("agents.flagsEmptyDetail")}
|
|
144
|
+
onRetry={() => void flags.refetch()}
|
|
145
|
+
/>
|
|
146
|
+
);
|
|
147
|
+
return (
|
|
148
|
+
<div className="flex flex-col gap-4">
|
|
149
|
+
<div className="flex items-start justify-between gap-3">
|
|
150
|
+
<div>
|
|
151
|
+
<h2 className="text-sm font-semibold">{t("agents.featureFlags")}</h2>
|
|
152
|
+
<p className="mt-1 text-sm text-muted-foreground">
|
|
153
|
+
{t("agents.featureFlagsDescription")}
|
|
154
|
+
</p>
|
|
155
|
+
</div>
|
|
156
|
+
<Button
|
|
157
|
+
variant="outline"
|
|
158
|
+
size="sm"
|
|
159
|
+
onClick={() => void flags.refetch()}
|
|
160
|
+
>
|
|
161
|
+
<IconRefresh className="me-2 size-4" />
|
|
162
|
+
{t("agents.reloadFlags")}
|
|
163
|
+
</Button>
|
|
164
|
+
</div>
|
|
165
|
+
{apps.map((app) => (
|
|
166
|
+
<section key={appId(app)} className="overflow-hidden rounded-lg border">
|
|
167
|
+
<div className="flex items-center justify-between gap-3 border-b bg-muted/30 px-4 py-3">
|
|
168
|
+
<div>
|
|
169
|
+
<h3 className="text-sm font-medium">{appName(app)}</h3>
|
|
170
|
+
{app.reason ? (
|
|
171
|
+
<p className="text-xs text-muted-foreground">{app.reason}</p>
|
|
172
|
+
) : null}
|
|
173
|
+
</div>
|
|
174
|
+
{!isReady(app) ? (
|
|
175
|
+
<Badge variant="outline">{statusLabel(app)}</Badge>
|
|
176
|
+
) : null}
|
|
177
|
+
</div>
|
|
178
|
+
{isReady(app) ? (
|
|
179
|
+
<div className="p-4">
|
|
180
|
+
<FeatureFlagsEditor
|
|
181
|
+
flags={(app.flags ?? []).filter(
|
|
182
|
+
(flag): flag is FeatureFlagMetadata =>
|
|
183
|
+
!!flag.rules && typeof flag.defaultValue === "boolean",
|
|
184
|
+
)}
|
|
185
|
+
isPending={mutation.isPending}
|
|
186
|
+
error={
|
|
187
|
+
mutation.variables?.appId === appId(app)
|
|
188
|
+
? mutation.error
|
|
189
|
+
: null
|
|
190
|
+
}
|
|
191
|
+
errorFlagKey={
|
|
192
|
+
mutation.variables?.appId === appId(app)
|
|
193
|
+
? mutation.variables.key
|
|
194
|
+
: null
|
|
195
|
+
}
|
|
196
|
+
showHeader={false}
|
|
197
|
+
onMutate={(input) =>
|
|
198
|
+
mutation.mutate(qualifyFleetMutation(appId(app), input))
|
|
199
|
+
}
|
|
200
|
+
/>
|
|
201
|
+
</div>
|
|
202
|
+
) : (
|
|
203
|
+
<div className="p-4 text-sm text-muted-foreground">
|
|
204
|
+
{statusLabel(app) === "no-definitions"
|
|
205
|
+
? t("agents.noFlagDefinitions")
|
|
206
|
+
: t("agents.flagsNotReady", { status: statusLabel(app) })}
|
|
207
|
+
</div>
|
|
208
|
+
)}
|
|
209
|
+
</section>
|
|
210
|
+
))}
|
|
211
|
+
</div>
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function PanelLoading() {
|
|
216
|
+
const t = useT();
|
|
217
|
+
return (
|
|
218
|
+
<div className="flex min-h-52 items-center justify-center rounded-lg border text-sm text-muted-foreground">
|
|
219
|
+
{t("agents.loading")}
|
|
220
|
+
</div>
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function StatusState({
|
|
225
|
+
title,
|
|
226
|
+
detail,
|
|
227
|
+
onRetry,
|
|
228
|
+
}: {
|
|
229
|
+
title: string;
|
|
230
|
+
detail: string;
|
|
231
|
+
onRetry: () => void;
|
|
232
|
+
}) {
|
|
233
|
+
const t = useT();
|
|
234
|
+
return (
|
|
235
|
+
<div className="rounded-lg border p-6">
|
|
236
|
+
<h2 className="text-sm font-semibold">{title}</h2>
|
|
237
|
+
<p className="mt-1 text-sm text-muted-foreground">{detail}</p>
|
|
238
|
+
<Button className="mt-4" size="sm" variant="outline" onClick={onRetry}>
|
|
239
|
+
{t("sidebar.retry")}
|
|
240
|
+
</Button>
|
|
241
|
+
</div>
|
|
242
|
+
);
|
|
243
|
+
}
|
|
@@ -95,16 +95,20 @@ const defaultTools = [
|
|
|
95
95
|
"agent monitoring",
|
|
96
96
|
"observability",
|
|
97
97
|
"evals",
|
|
98
|
-
"experiments",
|
|
99
98
|
"feedback",
|
|
100
99
|
"database",
|
|
101
100
|
"db admin",
|
|
102
101
|
"dashboard usage",
|
|
103
102
|
"dashboard audit",
|
|
104
|
-
"ab testing",
|
|
105
103
|
"llm",
|
|
106
104
|
],
|
|
107
105
|
},
|
|
106
|
+
{
|
|
107
|
+
id: "feature-flags",
|
|
108
|
+
nameKey: "agents.featureFlags",
|
|
109
|
+
href: "/agents?view=flags",
|
|
110
|
+
keywords: ["flags", "rollout", "release", "targeting"],
|
|
111
|
+
},
|
|
108
112
|
{
|
|
109
113
|
id: "explorer",
|
|
110
114
|
nameKey: "commandPalette.toolExplorer",
|
|
@@ -565,7 +569,11 @@ export function CommandPalette() {
|
|
|
565
569
|
|
|
566
570
|
<CommandGroup key="tools" heading={t("commandPalette.groupTools")}>
|
|
567
571
|
{defaultTools
|
|
568
|
-
.filter((tool) =>
|
|
572
|
+
.filter((tool) =>
|
|
573
|
+
["agents", "feature-flags"].includes(tool.id)
|
|
574
|
+
? canManageOrg
|
|
575
|
+
: true,
|
|
576
|
+
)
|
|
569
577
|
.map((tool) => (
|
|
570
578
|
<CommandItem
|
|
571
579
|
key={`tool-${tool.id}`}
|
|
@@ -129,7 +129,9 @@ export function useNavigationState() {
|
|
|
129
129
|
if (cmd.view === "sessions") return "/sessions";
|
|
130
130
|
if (
|
|
131
131
|
cmd.view === "agents" &&
|
|
132
|
-
(cmd.agentsView === "database" ||
|
|
132
|
+
(cmd.agentsView === "database" ||
|
|
133
|
+
cmd.agentsView === "dashboards" ||
|
|
134
|
+
cmd.agentsView === "flags")
|
|
133
135
|
) {
|
|
134
136
|
const params = new URLSearchParams({ view: cmd.agentsView });
|
|
135
137
|
if (cmd.agentsView === "database" && cmd.dbAdminConnectionId) {
|
|
@@ -698,6 +698,23 @@ const messages = {
|
|
|
698
698
|
deleteConnectionTitle: "刪除資料庫連線?",
|
|
699
699
|
deleteConnectionDescription:
|
|
700
700
|
"這會從 Analytics 移除 {{name}} 並刪除儲存的連線密鑰。目標應用程式資料庫不會被修改。",
|
|
701
|
+
featureFlags: "功能旗標",
|
|
702
|
+
featureFlagsDescription: "檢視已註冊應用程式旗標,並進行可回復的發布調整。",
|
|
703
|
+
reloadFlags: "重新載入功能旗標",
|
|
704
|
+
loading: "載入中",
|
|
705
|
+
flagsUnavailable: "功能旗標無法使用",
|
|
706
|
+
flagsUnreachable: "無法連線到工作區目錄。連線可用後請重試。",
|
|
707
|
+
flagsEmpty: "沒有應用程式回報功能旗標",
|
|
708
|
+
flagsEmptyDetail: "連線的應用程式準備就緒後,已註冊旗標會顯示在這裡。",
|
|
709
|
+
flagsNotReady: "此應用程式為 {{status}},不會假定旗標已關閉。",
|
|
710
|
+
noFlagDefinitions: "此應用程式沒有已註冊的旗標定義。",
|
|
711
|
+
noFlagDescription: "未提供說明。",
|
|
712
|
+
selected: "已選取",
|
|
713
|
+
openFlag: "開啟功能旗標",
|
|
714
|
+
confirm: "確認",
|
|
715
|
+
name: "名稱",
|
|
716
|
+
appId: "應用程式 ID",
|
|
717
|
+
flagKey: "功能旗標",
|
|
701
718
|
},
|
|
702
719
|
providerCorpusNotifier: {
|
|
703
720
|
completed: "提供者語料庫作業已完成",
|
|
@@ -459,6 +459,27 @@ const enUS = {
|
|
|
459
459
|
deleteConnectionTitle: "Delete database connection?",
|
|
460
460
|
deleteConnectionDescription:
|
|
461
461
|
"This removes {{name}} from Analytics and deletes its stored connection secrets. The target app database is not modified.",
|
|
462
|
+
featureFlags: "Feature flags",
|
|
463
|
+
featureFlagsDescription:
|
|
464
|
+
"Review registered app flags and make deliberate, reversible rollout changes.",
|
|
465
|
+
reloadFlags: "Reload flags",
|
|
466
|
+
loading: "Loading",
|
|
467
|
+
flagsUnavailable: "Feature flags are unavailable",
|
|
468
|
+
flagsUnreachable:
|
|
469
|
+
"The workspace directory could not be reached. Retry when its connection is available.",
|
|
470
|
+
flagsEmpty: "No workspace apps reported flags",
|
|
471
|
+
flagsEmptyDetail:
|
|
472
|
+
"Registered flags will appear here when connected apps are ready.",
|
|
473
|
+
flagsNotReady:
|
|
474
|
+
"This app is {{status}}. Its flag state is not assumed to be off.",
|
|
475
|
+
noFlagDefinitions: "This ready app has no registered flag definitions.",
|
|
476
|
+
noFlagDescription: "No description supplied.",
|
|
477
|
+
selected: "Selected",
|
|
478
|
+
openFlag: "Open feature flag",
|
|
479
|
+
confirm: "Confirm",
|
|
480
|
+
name: "Name",
|
|
481
|
+
appId: "App ID",
|
|
482
|
+
flagKey: "Feature flag",
|
|
462
483
|
},
|
|
463
484
|
providerCorpusNotifier: {
|
|
464
485
|
completed: "Provider corpus job completed",
|
|
@@ -10801,6 +10822,224 @@ for (const [locale, overrides] of Object.entries(
|
|
|
10801
10822
|
}
|
|
10802
10823
|
}
|
|
10803
10824
|
|
|
10825
|
+
const translatedFeatureFlagAdminTranslations = {
|
|
10826
|
+
"zh-CN": {
|
|
10827
|
+
agents: {
|
|
10828
|
+
featureFlags: "功能开关",
|
|
10829
|
+
featureFlagsDescription: "查看已注册应用开关,并进行可逆的发布调整。",
|
|
10830
|
+
reloadFlags: "重新加载开关",
|
|
10831
|
+
flagsUnavailable: "功能开关不可用",
|
|
10832
|
+
flagsUnreachable: "无法连接工作区目录。连接恢复后重试。",
|
|
10833
|
+
flagsEmpty: "没有应用报告功能开关",
|
|
10834
|
+
flagsEmptyDetail: "连接的应用准备就绪后,已注册开关会显示在这里。",
|
|
10835
|
+
flagsNotReady: "此应用状态为 {{status}},不会将其开关状态假定为关闭。",
|
|
10836
|
+
noFlagDefinitions: "此应用没有注册功能开关定义。",
|
|
10837
|
+
noFlagDescription: "未提供说明。",
|
|
10838
|
+
selected: "已选择",
|
|
10839
|
+
openFlag: "打开功能开关",
|
|
10840
|
+
confirm: "确认",
|
|
10841
|
+
name: "名称",
|
|
10842
|
+
appId: "应用 ID",
|
|
10843
|
+
flagKey: "功能开关",
|
|
10844
|
+
},
|
|
10845
|
+
},
|
|
10846
|
+
"es-ES": {
|
|
10847
|
+
agents: {
|
|
10848
|
+
featureFlags: "Indicadores de funciones",
|
|
10849
|
+
featureFlagsDescription:
|
|
10850
|
+
"Revisa los indicadores de las aplicaciones registradas y aplica cambios de lanzamiento reversibles.",
|
|
10851
|
+
reloadFlags: "Volver a cargar indicadores",
|
|
10852
|
+
flagsUnavailable: "Los indicadores de funciones no están disponibles",
|
|
10853
|
+
flagsUnreachable:
|
|
10854
|
+
"No se pudo acceder al directorio del espacio de trabajo. Inténtalo de nuevo cuando esté disponible.",
|
|
10855
|
+
flagsEmpty: "Ninguna aplicación informó indicadores",
|
|
10856
|
+
flagsEmptyDetail:
|
|
10857
|
+
"Los indicadores registrados aparecerán aquí cuando las aplicaciones conectadas estén listas.",
|
|
10858
|
+
flagsNotReady:
|
|
10859
|
+
"Esta aplicación está {{status}}; su estado no se supone desactivado.",
|
|
10860
|
+
noFlagDefinitions:
|
|
10861
|
+
"Esta aplicación lista no tiene definiciones de indicadores.",
|
|
10862
|
+
noFlagDescription: "No se proporcionó descripción.",
|
|
10863
|
+
selected: "Seleccionado",
|
|
10864
|
+
openFlag: "Abrir indicador",
|
|
10865
|
+
confirm: "Confirmar",
|
|
10866
|
+
name: "Nombre",
|
|
10867
|
+
appId: "ID de aplicación",
|
|
10868
|
+
flagKey: "Indicador de función",
|
|
10869
|
+
},
|
|
10870
|
+
},
|
|
10871
|
+
"fr-FR": {
|
|
10872
|
+
agents: {
|
|
10873
|
+
featureFlags: "Indicateurs de fonctionnalités",
|
|
10874
|
+
featureFlagsDescription:
|
|
10875
|
+
"Examinez les indicateurs d'applications enregistrées et appliquez des changements de déploiement réversibles.",
|
|
10876
|
+
reloadFlags: "Recharger les indicateurs",
|
|
10877
|
+
flagsUnavailable: "Les indicateurs de fonctionnalités sont indisponibles",
|
|
10878
|
+
flagsUnreachable:
|
|
10879
|
+
"Le répertoire de l'espace de travail est inaccessible. Réessayez lorsqu'il sera disponible.",
|
|
10880
|
+
flagsEmpty: "Aucune application n'a signalé d'indicateur",
|
|
10881
|
+
flagsEmptyDetail:
|
|
10882
|
+
"Les indicateurs enregistrés apparaîtront ici lorsque les applications connectées seront prêtes.",
|
|
10883
|
+
flagsNotReady:
|
|
10884
|
+
"Cette application est {{status}} ; son état n'est pas supposé désactivé.",
|
|
10885
|
+
noFlagDefinitions:
|
|
10886
|
+
"Cette application prête n'a aucune définition d'indicateur.",
|
|
10887
|
+
noFlagDescription: "Aucune description fournie.",
|
|
10888
|
+
selected: "Sélectionné",
|
|
10889
|
+
openFlag: "Ouvrir l'indicateur",
|
|
10890
|
+
confirm: "Confirmer",
|
|
10891
|
+
name: "Nom",
|
|
10892
|
+
appId: "ID d'application",
|
|
10893
|
+
flagKey: "Indicateur de fonctionnalité",
|
|
10894
|
+
},
|
|
10895
|
+
},
|
|
10896
|
+
"de-DE": {
|
|
10897
|
+
agents: {
|
|
10898
|
+
featureFlags: "Funktionsschalter",
|
|
10899
|
+
featureFlagsDescription:
|
|
10900
|
+
"Prüfe registrierte App-Schalter und nimm bewusste, rückgängig machbare Rollout-Änderungen vor.",
|
|
10901
|
+
reloadFlags: "Funktionsschalter neu laden",
|
|
10902
|
+
flagsUnavailable: "Funktionsschalter sind nicht verfügbar",
|
|
10903
|
+
flagsUnreachable:
|
|
10904
|
+
"Das Arbeitsbereichsverzeichnis konnte nicht erreicht werden. Versuche es erneut, wenn die Verbindung verfügbar ist.",
|
|
10905
|
+
flagsEmpty: "Keine Arbeitsbereichs-App meldet Funktionsschalter",
|
|
10906
|
+
flagsEmptyDetail:
|
|
10907
|
+
"Registrierte Schalter erscheinen hier, sobald verbundene Apps bereit sind.",
|
|
10908
|
+
flagsNotReady:
|
|
10909
|
+
"Diese App ist {{status}}; ihr Schalterzustand wird nicht als aus angenommen.",
|
|
10910
|
+
noFlagDefinitions:
|
|
10911
|
+
"Diese bereite App hat keine registrierten Schalterdefinitionen.",
|
|
10912
|
+
noFlagDescription: "Keine Beschreibung vorhanden.",
|
|
10913
|
+
selected: "Ausgewählt",
|
|
10914
|
+
openFlag: "Funktionsschalter öffnen",
|
|
10915
|
+
confirm: "Bestätigen",
|
|
10916
|
+
name: "Name",
|
|
10917
|
+
appId: "App-ID",
|
|
10918
|
+
flagKey: "Funktionsschalter",
|
|
10919
|
+
},
|
|
10920
|
+
},
|
|
10921
|
+
"pt-BR": {
|
|
10922
|
+
agents: {
|
|
10923
|
+
featureFlags: "Sinalizadores de recursos",
|
|
10924
|
+
featureFlagsDescription:
|
|
10925
|
+
"Revise sinalizadores de apps registrados e faça mudanças de lançamento reversíveis.",
|
|
10926
|
+
reloadFlags: "Recarregar sinalizadores",
|
|
10927
|
+
flagsUnavailable: "Sinalizadores de recursos indisponíveis",
|
|
10928
|
+
flagsUnreachable:
|
|
10929
|
+
"Não foi possível acessar o diretório do espaço de trabalho. Tente novamente quando estiver disponível.",
|
|
10930
|
+
flagsEmpty: "Nenhum app informou sinalizadores",
|
|
10931
|
+
flagsEmptyDetail:
|
|
10932
|
+
"Sinalizadores registrados aparecerão aqui quando os apps conectados estiverem prontos.",
|
|
10933
|
+
flagsNotReady:
|
|
10934
|
+
"Este app está {{status}}; seu estado não é considerado desligado.",
|
|
10935
|
+
noFlagDefinitions:
|
|
10936
|
+
"Este app pronto não tem definições de sinalizador registradas.",
|
|
10937
|
+
noFlagDescription: "Nenhuma descrição fornecida.",
|
|
10938
|
+
selected: "Selecionado",
|
|
10939
|
+
openFlag: "Abrir sinalizador",
|
|
10940
|
+
confirm: "Confirmar",
|
|
10941
|
+
name: "Nome",
|
|
10942
|
+
appId: "ID do app",
|
|
10943
|
+
flagKey: "Sinalizador de recurso",
|
|
10944
|
+
},
|
|
10945
|
+
},
|
|
10946
|
+
"ja-JP": {
|
|
10947
|
+
agents: {
|
|
10948
|
+
featureFlags: "機能フラグ",
|
|
10949
|
+
featureFlagsDescription:
|
|
10950
|
+
"登録済みアプリのフラグを確認し、元に戻せるロールアウト変更を行います。",
|
|
10951
|
+
reloadFlags: "機能フラグを再読み込み",
|
|
10952
|
+
flagsUnavailable: "機能フラグを利用できません",
|
|
10953
|
+
flagsUnreachable:
|
|
10954
|
+
"ワークスペースディレクトリに接続できません。接続可能になったら再試行してください。",
|
|
10955
|
+
flagsEmpty: "フラグを報告したワークスペースアプリはありません",
|
|
10956
|
+
flagsEmptyDetail:
|
|
10957
|
+
"接続済みアプリの準備ができると、登録済みフラグがここに表示されます。",
|
|
10958
|
+
flagsNotReady:
|
|
10959
|
+
"このアプリは {{status}} です。フラグ状態をオフとは見なしません。",
|
|
10960
|
+
noFlagDefinitions:
|
|
10961
|
+
"この準備済みアプリには登録済みフラグ定義がありません。",
|
|
10962
|
+
noFlagDescription: "説明はありません。",
|
|
10963
|
+
selected: "選択済み",
|
|
10964
|
+
openFlag: "機能フラグを開く",
|
|
10965
|
+
confirm: "確認",
|
|
10966
|
+
name: "名前",
|
|
10967
|
+
appId: "アプリ ID",
|
|
10968
|
+
flagKey: "機能フラグ",
|
|
10969
|
+
},
|
|
10970
|
+
},
|
|
10971
|
+
"ko-KR": {
|
|
10972
|
+
agents: {
|
|
10973
|
+
featureFlags: "기능 플래그",
|
|
10974
|
+
featureFlagsDescription:
|
|
10975
|
+
"등록된 앱 플래그를 검토하고 되돌릴 수 있는 출시 변경을 적용합니다.",
|
|
10976
|
+
reloadFlags: "기능 플래그 다시 불러오기",
|
|
10977
|
+
flagsUnavailable: "기능 플래그를 사용할 수 없습니다",
|
|
10978
|
+
flagsUnreachable:
|
|
10979
|
+
"작업 공간 디렉터리에 연결할 수 없습니다. 연결되면 다시 시도하세요.",
|
|
10980
|
+
flagsEmpty: "플래그를 보고한 작업 공간 앱이 없습니다",
|
|
10981
|
+
flagsEmptyDetail:
|
|
10982
|
+
"연결된 앱이 준비되면 등록된 플래그가 여기에 표시됩니다.",
|
|
10983
|
+
flagsNotReady:
|
|
10984
|
+
"이 앱은 {{status}} 상태이며 플래그가 꺼진 것으로 가정하지 않습니다.",
|
|
10985
|
+
noFlagDefinitions: "준비된 이 앱에는 등록된 플래그 정의가 없습니다.",
|
|
10986
|
+
noFlagDescription: "설명이 제공되지 않았습니다.",
|
|
10987
|
+
selected: "선택됨",
|
|
10988
|
+
openFlag: "기능 플래그 열기",
|
|
10989
|
+
confirm: "확인",
|
|
10990
|
+
name: "이름",
|
|
10991
|
+
appId: "앱 ID",
|
|
10992
|
+
flagKey: "기능 플래그",
|
|
10993
|
+
},
|
|
10994
|
+
},
|
|
10995
|
+
"hi-IN": {
|
|
10996
|
+
agents: {
|
|
10997
|
+
featureFlags: "फ़ीचर फ़्लैग",
|
|
10998
|
+
featureFlagsDescription:
|
|
10999
|
+
"पंजीकृत ऐप फ़्लैग देखें और वापस किए जा सकने वाले रोलआउट बदलाव करें।",
|
|
11000
|
+
reloadFlags: "फ़ीचर फ़्लैग फिर से लोड करें",
|
|
11001
|
+
flagsUnavailable: "फ़ीचर फ़्लैग उपलब्ध नहीं हैं",
|
|
11002
|
+
flagsUnreachable:
|
|
11003
|
+
"वर्कस्पेस डायरेक्टरी तक नहीं पहुँचा जा सका। कनेक्शन उपलब्ध होने पर फिर कोशिश करें।",
|
|
11004
|
+
flagsEmpty: "किसी वर्कस्पेस ऐप ने फ़्लैग की सूचना नहीं दी",
|
|
11005
|
+
flagsEmptyDetail: "कनेक्टेड ऐप तैयार होने पर पंजीकृत फ़्लैग यहाँ दिखाई देंगे।",
|
|
11006
|
+
flagsNotReady: "यह ऐप {{status}} है; इसकी फ़्लैग स्थिति को बंद नहीं माना जाता।",
|
|
11007
|
+
noFlagDefinitions: "इस तैयार ऐप में पंजीकृत फ़्लैग परिभाषाएँ नहीं हैं।",
|
|
11008
|
+
noFlagDescription: "कोई विवरण नहीं दिया गया।",
|
|
11009
|
+
selected: "चयनित",
|
|
11010
|
+
openFlag: "फ़ीचर फ़्लैग खोलें",
|
|
11011
|
+
confirm: "पुष्टि करें",
|
|
11012
|
+
name: "नाम",
|
|
11013
|
+
appId: "ऐप ID",
|
|
11014
|
+
flagKey: "फ़ीचर फ़्लैग",
|
|
11015
|
+
},
|
|
11016
|
+
},
|
|
11017
|
+
"ar-SA": {
|
|
11018
|
+
agents: {
|
|
11019
|
+
featureFlags: "علامات الميزات",
|
|
11020
|
+
featureFlagsDescription:
|
|
11021
|
+
"راجع علامات التطبيقات المسجلة ونفّذ تغييرات طرح قابلة للعكس.",
|
|
11022
|
+
reloadFlags: "إعادة تحميل علامات الميزات",
|
|
11023
|
+
flagsUnavailable: "علامات الميزات غير متاحة",
|
|
11024
|
+
flagsUnreachable:
|
|
11025
|
+
"تعذر الوصول إلى دليل مساحة العمل. أعد المحاولة عند توفر الاتصال.",
|
|
11026
|
+
flagsEmpty: "لم يبلغ أي تطبيق في مساحة العمل عن علامات",
|
|
11027
|
+
flagsEmptyDetail:
|
|
11028
|
+
"ستظهر العلامات المسجلة هنا عندما تصبح التطبيقات المتصلة جاهزة.",
|
|
11029
|
+
flagsNotReady:
|
|
11030
|
+
"حالة هذا التطبيق هي {{status}}؛ ولا يُفترض أن علاماته متوقفة.",
|
|
11031
|
+
noFlagDefinitions: "لا يحتوي هذا التطبيق الجاهز على تعريفات علامات مسجلة.",
|
|
11032
|
+
noFlagDescription: "لم يُقدَّم وصف.",
|
|
11033
|
+
selected: "محدد",
|
|
11034
|
+
openFlag: "فتح علامة الميزة",
|
|
11035
|
+
confirm: "تأكيد",
|
|
11036
|
+
name: "الاسم",
|
|
11037
|
+
appId: "معرّف التطبيق",
|
|
11038
|
+
flagKey: "علامة ميزة",
|
|
11039
|
+
},
|
|
11040
|
+
},
|
|
11041
|
+
} satisfies Partial<Record<LocaleCode, AnalyticsPartialMessages>>;
|
|
11042
|
+
|
|
10804
11043
|
const translatedDashboardAdminTranslations = {
|
|
10805
11044
|
"zh-CN": {
|
|
10806
11045
|
navigation: {
|
|
@@ -11161,6 +11400,18 @@ const translatedDashboardAdminTranslations = {
|
|
|
11161
11400
|
},
|
|
11162
11401
|
} satisfies Partial<Record<LocaleCode, AnalyticsPartialMessages>>;
|
|
11163
11402
|
|
|
11403
|
+
for (const [locale, overrides] of Object.entries(
|
|
11404
|
+
translatedFeatureFlagAdminTranslations,
|
|
11405
|
+
) as Array<[LocaleCode, AnalyticsPartialMessages]>) {
|
|
11406
|
+
const messages = messagesByLocale[locale];
|
|
11407
|
+
if (!messages) continue;
|
|
11408
|
+
for (const [section, sectionOverrides] of Object.entries(overrides) as Array<
|
|
11409
|
+
[Section, Partial<Messages[Section]>]
|
|
11410
|
+
>) {
|
|
11411
|
+
Object.assign(messages[section], sectionOverrides);
|
|
11412
|
+
}
|
|
11413
|
+
}
|
|
11414
|
+
|
|
11164
11415
|
for (const [locale, overrides] of Object.entries(
|
|
11165
11416
|
translatedDashboardAdminTranslations,
|
|
11166
11417
|
) as Array<[LocaleCode, AnalyticsPartialMessages]>) {
|
|
@@ -18,11 +18,13 @@ import {
|
|
|
18
18
|
IconLoader2,
|
|
19
19
|
IconMouse,
|
|
20
20
|
IconPlus,
|
|
21
|
+
IconToggleRight,
|
|
21
22
|
IconTrash,
|
|
22
23
|
} from "@tabler/icons-react";
|
|
23
24
|
import { useEffect, useMemo, useState, type FormEvent } from "react";
|
|
24
25
|
import { Link, useSearchParams } from "react-router";
|
|
25
26
|
|
|
27
|
+
import { FeatureFlagsFleetPanel } from "@/components/agents/FeatureFlagsFleetPanel";
|
|
26
28
|
import {
|
|
27
29
|
AlertDialog,
|
|
28
30
|
AlertDialogAction,
|
|
@@ -70,7 +72,7 @@ import {
|
|
|
70
72
|
} from "@/components/ui/table";
|
|
71
73
|
import { cn } from "@/lib/utils";
|
|
72
74
|
|
|
73
|
-
type AgentAdminView = "monitoring" | "dashboards" | "database";
|
|
75
|
+
type AgentAdminView = "monitoring" | "dashboards" | "database" | "flags";
|
|
74
76
|
|
|
75
77
|
interface DbAdminConnection {
|
|
76
78
|
id: string;
|
|
@@ -117,6 +119,7 @@ const AGENT_ADMIN_VIEWS: AgentAdminView[] = [
|
|
|
117
119
|
"monitoring",
|
|
118
120
|
"dashboards",
|
|
119
121
|
"database",
|
|
122
|
+
"flags",
|
|
120
123
|
];
|
|
121
124
|
|
|
122
125
|
function parseView(value: string | null): AgentAdminView {
|
|
@@ -383,7 +386,7 @@ export default function AgentsPage() {
|
|
|
383
386
|
const [searchParams, setSearchParams] = useSearchParams();
|
|
384
387
|
const view = parseView(searchParams.get("view"));
|
|
385
388
|
const selectedConnectionId = searchParams.get("db");
|
|
386
|
-
const isAdminView = view
|
|
389
|
+
const isAdminView = view !== "monitoring";
|
|
387
390
|
|
|
388
391
|
function setView(next: AgentAdminView) {
|
|
389
392
|
const params = new URLSearchParams(searchParams);
|
|
@@ -493,6 +496,21 @@ export default function AgentsPage() {
|
|
|
493
496
|
{t("agents.dashboardUsage")}
|
|
494
497
|
</button>
|
|
495
498
|
) : null}
|
|
499
|
+
{canManageOrg ? (
|
|
500
|
+
<button
|
|
501
|
+
type="button"
|
|
502
|
+
onClick={() => setView("flags")}
|
|
503
|
+
className={cn(
|
|
504
|
+
"inline-flex h-8 items-center gap-2 rounded-md px-3 text-sm font-medium transition-colors",
|
|
505
|
+
view === "flags"
|
|
506
|
+
? "bg-foreground text-background"
|
|
507
|
+
: "text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
508
|
+
)}
|
|
509
|
+
>
|
|
510
|
+
<IconToggleRight className="size-4" />
|
|
511
|
+
{t("agents.featureFlags")}
|
|
512
|
+
</button>
|
|
513
|
+
) : null}
|
|
496
514
|
{canManageOrg && view === "database" && (
|
|
497
515
|
<button
|
|
498
516
|
type="button"
|
|
@@ -512,6 +530,8 @@ export default function AgentsPage() {
|
|
|
512
530
|
/>
|
|
513
531
|
) : view === "dashboards" ? (
|
|
514
532
|
<DashboardUsageAdminPanel />
|
|
533
|
+
) : view === "flags" ? (
|
|
534
|
+
<FeatureFlagsFleetPanel />
|
|
515
535
|
) : (
|
|
516
536
|
<div className="min-w-0">
|
|
517
537
|
<div className="mb-4 max-w-3xl text-sm leading-6 text-muted-foreground">
|