@anyshift/backstage-plugin-anyshift 0.1.0-beta.1 → 0.1.0-beta.3
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/CHANGELOG.md +10 -0
- package/dist/api/AnyshiftApi.esm.js +5 -2
- package/dist/api/AnyshiftApi.esm.js.map +1 -1
- package/dist/components/explorer/AnyshiftExplorerPage.esm.js +125 -12
- package/dist/components/explorer/AnyshiftExplorerPage.esm.js.map +1 -1
- package/dist/index.d.ts +7 -1
- package/dist/package.json.esm.js +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.0-beta.3
|
|
4
|
+
|
|
5
|
+
- Show durable catalog reconciliation status on the global dashboard.
|
|
6
|
+
- Add a permission-aware **Reconcile now** operator action.
|
|
7
|
+
|
|
8
|
+
## 0.1.0-beta.2
|
|
9
|
+
|
|
10
|
+
- Coordinate the frontend package with the trusted catalog synchronization beta.
|
|
11
|
+
- Show configured, excluded, active, unclassified, and managed catalog coverage.
|
|
12
|
+
|
|
3
13
|
## 0.1.0-beta.1
|
|
4
14
|
|
|
5
15
|
- Add discoverable dashboard, navigation, API, and entity-content extensions.
|
|
@@ -47,11 +47,14 @@ class AnyshiftClient {
|
|
|
47
47
|
body: JSON.stringify({ sql })
|
|
48
48
|
});
|
|
49
49
|
}
|
|
50
|
+
async reconcileCatalog() {
|
|
51
|
+
return this.request("/anyshift/reconcile", { method: "POST" }, "catalog");
|
|
52
|
+
}
|
|
50
53
|
async get(path) {
|
|
51
54
|
return this.request(path, { method: "GET" });
|
|
52
55
|
}
|
|
53
|
-
async request(path, init) {
|
|
54
|
-
const baseUrl = await this.discoveryApi.getBaseUrl(
|
|
56
|
+
async request(path, init, pluginId = "anyshift") {
|
|
57
|
+
const baseUrl = await this.discoveryApi.getBaseUrl(pluginId);
|
|
55
58
|
const response = await this.fetchApi.fetch(`${baseUrl}${path}`, init);
|
|
56
59
|
const text = await response.text();
|
|
57
60
|
let payload;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AnyshiftApi.esm.js","sources":["../../src/api/AnyshiftApi.ts"],"sourcesContent":["import {\n createApiRef,\n type DiscoveryApi,\n type FetchApi,\n} from '@backstage/frontend-plugin-api';\nimport type {\n BriefSectionName,\n BriefSectionResponse,\n AnyshiftCapabilities,\n CatalogSummary,\n DatadogSignals,\n EstateInsights,\n QueryResult,\n ServiceBrief,\n} from './types';\n\nexport interface AnyshiftApi {\n capabilities(): Promise<AnyshiftCapabilities>;\n brief(\n kind: string,\n target: string,\n options?: BriefRequestOptions,\n ): Promise<ServiceBrief>;\n briefSection(\n kind: string,\n target: string,\n section: BriefSectionName,\n options?: BriefRequestOptions,\n ): Promise<BriefSectionResponse>;\n insights(): Promise<EstateInsights>;\n datadogSignals(options?: { refresh?: boolean }): Promise<DatadogSignals>;\n inventory(\n type: string,\n options?: { limit?: number; offset?: number },\n ): Promise<CatalogSummary>;\n query(sql: string): Promise<QueryResult>;\n}\n\nexport interface BriefRequestOptions {\n namespace?: string;\n refresh?: boolean;\n}\n\nexport const anyshiftApiRef = createApiRef<AnyshiftApi>({\n id: 'plugin.anyshift.service',\n});\n\nexport class AnyshiftClient implements AnyshiftApi {\n private readonly discoveryApi: DiscoveryApi;\n private readonly fetchApi: FetchApi;\n\n constructor(options: { discoveryApi: DiscoveryApi; fetchApi: FetchApi }) {\n this.discoveryApi = options.discoveryApi;\n this.fetchApi = options.fetchApi;\n }\n\n async capabilities(): Promise<AnyshiftCapabilities> {\n return this.get('/capabilities');\n }\n\n async brief(\n kind: string,\n target: string,\n options: BriefRequestOptions = {},\n ): Promise<ServiceBrief> {\n return this.get(\n `/brief/${encodeURIComponent(kind)}/${encodeURIComponent(\n target,\n )}${briefQuery(options)}`,\n );\n }\n\n async briefSection(\n kind: string,\n target: string,\n section: BriefSectionName,\n options: BriefRequestOptions = {},\n ): Promise<BriefSectionResponse> {\n return this.get(\n `/brief/${encodeURIComponent(kind)}/${encodeURIComponent(\n target,\n )}/sections/${encodeURIComponent(section)}${briefQuery(options)}`,\n );\n }\n\n async insights(): Promise<EstateInsights> {\n return this.get('/insights');\n }\n\n async datadogSignals(\n options: { refresh?: boolean } = {},\n ): Promise<DatadogSignals> {\n return this.get(`/signals/datadog${options.refresh ? '?refresh=1' : ''}`);\n }\n\n async inventory(\n type: string,\n options: { limit?: number; offset?: number } = {},\n ): Promise<CatalogSummary> {\n const params = new URLSearchParams({ type });\n if (options.limit !== undefined) params.set('limit', String(options.limit));\n if (options.offset !== undefined)\n params.set('offset', String(options.offset));\n return this.get(`/inventory?${params}`);\n }\n\n async query(sql: string): Promise<QueryResult> {\n return this.request('/query', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ sql }),\n });\n }\n\n private async get<T>(path: string): Promise<T> {\n return this.request(path, { method: 'GET' });\n }\n\n private async request<T>(path: string
|
|
1
|
+
{"version":3,"file":"AnyshiftApi.esm.js","sources":["../../src/api/AnyshiftApi.ts"],"sourcesContent":["import {\n createApiRef,\n type DiscoveryApi,\n type FetchApi,\n} from '@backstage/frontend-plugin-api';\nimport type {\n BriefSectionName,\n BriefSectionResponse,\n AnyshiftCapabilities,\n CatalogSummary,\n CatalogSyncReport,\n DatadogSignals,\n EstateInsights,\n QueryResult,\n ServiceBrief,\n} from './types';\n\nexport interface AnyshiftApi {\n capabilities(): Promise<AnyshiftCapabilities>;\n brief(\n kind: string,\n target: string,\n options?: BriefRequestOptions,\n ): Promise<ServiceBrief>;\n briefSection(\n kind: string,\n target: string,\n section: BriefSectionName,\n options?: BriefRequestOptions,\n ): Promise<BriefSectionResponse>;\n insights(): Promise<EstateInsights>;\n datadogSignals(options?: { refresh?: boolean }): Promise<DatadogSignals>;\n inventory(\n type: string,\n options?: { limit?: number; offset?: number },\n ): Promise<CatalogSummary>;\n query(sql: string): Promise<QueryResult>;\n reconcileCatalog(): Promise<CatalogSyncAccepted>;\n}\n\nexport interface BriefRequestOptions {\n namespace?: string;\n refresh?: boolean;\n}\n\nexport interface CatalogSyncAccepted {\n accepted: true;\n acceptedAt: string;\n previous?: CatalogSyncReport;\n}\n\nexport const anyshiftApiRef = createApiRef<AnyshiftApi>({\n id: 'plugin.anyshift.service',\n});\n\nexport class AnyshiftClient implements AnyshiftApi {\n private readonly discoveryApi: DiscoveryApi;\n private readonly fetchApi: FetchApi;\n\n constructor(options: { discoveryApi: DiscoveryApi; fetchApi: FetchApi }) {\n this.discoveryApi = options.discoveryApi;\n this.fetchApi = options.fetchApi;\n }\n\n async capabilities(): Promise<AnyshiftCapabilities> {\n return this.get('/capabilities');\n }\n\n async brief(\n kind: string,\n target: string,\n options: BriefRequestOptions = {},\n ): Promise<ServiceBrief> {\n return this.get(\n `/brief/${encodeURIComponent(kind)}/${encodeURIComponent(\n target,\n )}${briefQuery(options)}`,\n );\n }\n\n async briefSection(\n kind: string,\n target: string,\n section: BriefSectionName,\n options: BriefRequestOptions = {},\n ): Promise<BriefSectionResponse> {\n return this.get(\n `/brief/${encodeURIComponent(kind)}/${encodeURIComponent(\n target,\n )}/sections/${encodeURIComponent(section)}${briefQuery(options)}`,\n );\n }\n\n async insights(): Promise<EstateInsights> {\n return this.get('/insights');\n }\n\n async datadogSignals(\n options: { refresh?: boolean } = {},\n ): Promise<DatadogSignals> {\n return this.get(`/signals/datadog${options.refresh ? '?refresh=1' : ''}`);\n }\n\n async inventory(\n type: string,\n options: { limit?: number; offset?: number } = {},\n ): Promise<CatalogSummary> {\n const params = new URLSearchParams({ type });\n if (options.limit !== undefined) params.set('limit', String(options.limit));\n if (options.offset !== undefined)\n params.set('offset', String(options.offset));\n return this.get(`/inventory?${params}`);\n }\n\n async query(sql: string): Promise<QueryResult> {\n return this.request('/query', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ sql }),\n });\n }\n\n async reconcileCatalog(): Promise<CatalogSyncAccepted> {\n return this.request('/anyshift/reconcile', { method: 'POST' }, 'catalog');\n }\n\n private async get<T>(path: string): Promise<T> {\n return this.request(path, { method: 'GET' });\n }\n\n private async request<T>(\n path: string,\n init: RequestInit,\n pluginId = 'anyshift',\n ): Promise<T> {\n const baseUrl = await this.discoveryApi.getBaseUrl(pluginId);\n const response = await this.fetchApi.fetch(`${baseUrl}${path}`, init);\n const text = await response.text();\n let payload: any;\n try {\n payload = text ? JSON.parse(text) : {};\n } catch {\n payload = {};\n }\n if (!response.ok) {\n throw new Error(\n payload?.error?.message ||\n `Anyshift request failed (${response.status})`,\n );\n }\n return payload as T;\n }\n}\n\nfunction briefQuery(options: BriefRequestOptions): string {\n const params = new URLSearchParams();\n if (options.namespace) params.set('namespace', options.namespace);\n if (options.refresh) params.set('refresh', '1');\n const query = params.toString();\n return query ? `?${query}` : '';\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
2
2
|
import { useState, useEffect } from 'react';
|
|
3
|
-
import { Typography,
|
|
3
|
+
import { Typography, Grid, Button, TextField } from '@material-ui/core';
|
|
4
4
|
import { Page, Header, Content, Progress, ContentHeader, InfoCard } from '@backstage/core-components';
|
|
5
5
|
import { useApi } from '@backstage/frontend-plugin-api';
|
|
6
6
|
import { usePermission } from '@backstage/plugin-permission-react';
|
|
7
|
-
import { anyshiftQueryPermission } from '@anyshift/backstage-plugin-anyshift-common';
|
|
7
|
+
import { anyshiftQueryPermission, anyshiftCatalogSyncPermission, ANYSHIFT_CATALOG_SYNC_ERROR_ANNOTATION, ANYSHIFT_CATALOG_SYNC_FINISHED_AT_ANNOTATION, ANYSHIFT_CATALOG_SYNC_TRIGGER_ANNOTATION, ANYSHIFT_CATALOG_SYNC_STATUS_ANNOTATION } from '@anyshift/backstage-plugin-anyshift-common';
|
|
8
8
|
import { catalogApiRef, EntityRefLink } from '@backstage/plugin-catalog-react';
|
|
9
9
|
import { anyshiftApiRef } from '../../api/AnyshiftApi.esm.js';
|
|
10
10
|
import { TimelinePresenter, ImpactPresenter } from '../entity/SectionPresenters.esm.js';
|
|
11
11
|
import { DatadogOperationsRadar } from './DatadogOperationsRadar.esm.js';
|
|
12
12
|
|
|
13
13
|
const DEFAULT_QUERY = "SELECT * FROM resources WHERE type = deployment LIMIT 10";
|
|
14
|
+
const CATALOG_SYNC_STATUS_ENTITY = "anyshift-catalog-sync";
|
|
14
15
|
function isDeterministicSelect(value) {
|
|
15
16
|
const sql = value.trim();
|
|
16
17
|
return /^SELECT\b/i.test(sql) && sql.length <= 4096 && !sql.includes(";") && !sql.includes("--") && !sql.includes("/*");
|
|
@@ -27,6 +28,44 @@ function matchesCatalogEntity(entity, value) {
|
|
|
27
28
|
];
|
|
28
29
|
return searchable.some((item) => item?.toLocaleLowerCase().includes(query));
|
|
29
30
|
}
|
|
31
|
+
function summarizeCatalogSync(entities) {
|
|
32
|
+
const components = entities.filter(
|
|
33
|
+
(entity) => entity.kind.toLowerCase() === "component"
|
|
34
|
+
);
|
|
35
|
+
const configured = components.filter(
|
|
36
|
+
(entity) => entity.metadata.annotations?.["anyshift.io/target"]
|
|
37
|
+
);
|
|
38
|
+
const excluded = components.filter(
|
|
39
|
+
(entity) => entity.metadata.annotations?.["anyshift.io/catalog-sync"]?.toLowerCase() === "excluded"
|
|
40
|
+
);
|
|
41
|
+
return {
|
|
42
|
+
components: components.length,
|
|
43
|
+
configured: configured.length,
|
|
44
|
+
excluded: excluded.length,
|
|
45
|
+
unclassified: Math.max(
|
|
46
|
+
0,
|
|
47
|
+
components.length - configured.length - excluded.length
|
|
48
|
+
),
|
|
49
|
+
observed: configured.filter(
|
|
50
|
+
(entity) => entity.metadata.annotations?.["anyshift.io/observed-service"]
|
|
51
|
+
).length,
|
|
52
|
+
managedResources: entities.filter(
|
|
53
|
+
(entity) => entity.kind.toLowerCase() === "resource" && entity.metadata.name !== CATALOG_SYNC_STATUS_ENTITY && entity.metadata.annotations?.["anyshift.io/managed-by"] === "catalog-provider"
|
|
54
|
+
).length
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function catalogSyncStatus(entities) {
|
|
58
|
+
const entity = entities.find(
|
|
59
|
+
(candidate) => candidate.kind.toLowerCase() === "resource" && candidate.metadata.name === CATALOG_SYNC_STATUS_ENTITY
|
|
60
|
+
);
|
|
61
|
+
const annotations = entity?.metadata.annotations ?? {};
|
|
62
|
+
return {
|
|
63
|
+
status: annotations[ANYSHIFT_CATALOG_SYNC_STATUS_ANNOTATION] ?? "waiting",
|
|
64
|
+
trigger: annotations[ANYSHIFT_CATALOG_SYNC_TRIGGER_ANNOTATION],
|
|
65
|
+
finishedAt: annotations[ANYSHIFT_CATALOG_SYNC_FINISHED_AT_ANNOTATION],
|
|
66
|
+
error: annotations[ANYSHIFT_CATALOG_SYNC_ERROR_ANNOTATION]
|
|
67
|
+
};
|
|
68
|
+
}
|
|
30
69
|
const EstateInsightsGrid = ({
|
|
31
70
|
insights
|
|
32
71
|
}) => /* @__PURE__ */ jsx(Fragment, { children: insights.sections.map((item) => /* @__PURE__ */ jsx(Grid, { item: true, xs: 12, md: 6, children: /* @__PURE__ */ jsx(InfoCard, { title: item.title, children: item.section.state === "error" ? /* @__PURE__ */ jsx(Typography, { color: "error", children: item.section.message }) : item.section.state === "empty" || item.section.state === "unsupported" || item.section.data === void 0 ? /* @__PURE__ */ jsx(Typography, { color: "textSecondary", children: item.section.message || "No insight evidence is available." }) : item.id === "recent-change" ? /* @__PURE__ */ jsx(
|
|
@@ -42,6 +81,9 @@ const AnyshiftExplorerPage = () => {
|
|
|
42
81
|
const queryPermission = usePermission({
|
|
43
82
|
permission: anyshiftQueryPermission
|
|
44
83
|
});
|
|
84
|
+
const catalogSyncPermission = usePermission({
|
|
85
|
+
permission: anyshiftCatalogSyncPermission
|
|
86
|
+
});
|
|
45
87
|
const [queryEnabled, setQueryEnabled] = useState(false);
|
|
46
88
|
const [insights, setInsights] = useState();
|
|
47
89
|
const [insightError, setInsightError] = useState();
|
|
@@ -54,6 +96,9 @@ const AnyshiftExplorerPage = () => {
|
|
|
54
96
|
const [sql, setSql] = useState(DEFAULT_QUERY);
|
|
55
97
|
const [queryResult, setQueryResult] = useState();
|
|
56
98
|
const [queryError, setQueryError] = useState();
|
|
99
|
+
const [requestingSync, setRequestingSync] = useState(false);
|
|
100
|
+
const [syncRequestMessage, setSyncRequestMessage] = useState();
|
|
101
|
+
const [syncRequestError, setSyncRequestError] = useState();
|
|
57
102
|
useEffect(() => {
|
|
58
103
|
api.capabilities().then((capabilities) => setQueryEnabled(capabilities.queryEnabled)).catch(() => setQueryEnabled(false));
|
|
59
104
|
}, [api]);
|
|
@@ -70,17 +115,16 @@ const AnyshiftExplorerPage = () => {
|
|
|
70
115
|
useEffect(() => {
|
|
71
116
|
catalogApi.getEntities({
|
|
72
117
|
filter: [{ kind: "Component" }, { kind: "Resource" }]
|
|
73
|
-
}).then(
|
|
74
|
-
(response) => setCatalogEntities(
|
|
75
|
-
response.items.filter(
|
|
76
|
-
(entity) => entity.metadata.annotations?.["anyshift.io/target"]
|
|
77
|
-
)
|
|
78
|
-
)
|
|
79
|
-
).catch((error) => {
|
|
118
|
+
}).then((response) => setCatalogEntities(response.items)).catch((error) => {
|
|
80
119
|
setCatalogError(error instanceof Error ? error.message : String(error));
|
|
81
120
|
});
|
|
82
121
|
}, [catalogApi]);
|
|
83
|
-
const
|
|
122
|
+
const anyshiftEntities = catalogEntities.filter(
|
|
123
|
+
(entity) => entity.metadata.annotations?.["anyshift.io/target"]
|
|
124
|
+
);
|
|
125
|
+
const syncSummary = summarizeCatalogSync(catalogEntities);
|
|
126
|
+
const syncStatus = catalogSyncStatus(catalogEntities);
|
|
127
|
+
const matchingEntities = anyshiftEntities.filter((entity) => matchesCatalogEntity(entity, catalogQuery)).slice(0, 12);
|
|
84
128
|
const runQuery = async () => {
|
|
85
129
|
if (!isDeterministicSelect(sql)) {
|
|
86
130
|
setQueryError("Enter one deterministic SELECT query.");
|
|
@@ -104,6 +148,23 @@ const AnyshiftExplorerPage = () => {
|
|
|
104
148
|
setRefreshingDatadog(false);
|
|
105
149
|
}
|
|
106
150
|
};
|
|
151
|
+
const requestCatalogSync = async () => {
|
|
152
|
+
setRequestingSync(true);
|
|
153
|
+
setSyncRequestError(void 0);
|
|
154
|
+
setSyncRequestMessage(void 0);
|
|
155
|
+
try {
|
|
156
|
+
const accepted = await api.reconcileCatalog();
|
|
157
|
+
setSyncRequestMessage(
|
|
158
|
+
`Reconciliation accepted ${formatTimestamp(accepted.acceptedAt)}.`
|
|
159
|
+
);
|
|
160
|
+
} catch (error) {
|
|
161
|
+
setSyncRequestError(
|
|
162
|
+
error instanceof Error ? error.message : String(error)
|
|
163
|
+
);
|
|
164
|
+
} finally {
|
|
165
|
+
setRequestingSync(false);
|
|
166
|
+
}
|
|
167
|
+
};
|
|
107
168
|
return /* @__PURE__ */ jsxs(Page, { themeId: "tool", children: [
|
|
108
169
|
/* @__PURE__ */ jsx(
|
|
109
170
|
Header,
|
|
@@ -117,12 +178,60 @@ const AnyshiftExplorerPage = () => {
|
|
|
117
178
|
DatadogOperationsRadar,
|
|
118
179
|
{
|
|
119
180
|
signals: datadogSignals,
|
|
120
|
-
catalogEntities,
|
|
181
|
+
catalogEntities: anyshiftEntities,
|
|
121
182
|
onRefresh: refreshDatadog,
|
|
122
183
|
refreshing: refreshingDatadog,
|
|
123
184
|
error: datadogError
|
|
124
185
|
}
|
|
125
186
|
) : datadogError ? /* @__PURE__ */ jsx(Typography, { color: "error", children: datadogError }) : /* @__PURE__ */ jsx(Progress, {}),
|
|
187
|
+
/* @__PURE__ */ jsx(ContentHeader, { title: "Catalog synchronization" }),
|
|
188
|
+
/* @__PURE__ */ jsx(InfoCard, { subheader: "GitHub ownership stays authoritative; Anyshift adds observed infrastructure context", children: /* @__PURE__ */ jsxs(Grid, { container: true, spacing: 2, children: [
|
|
189
|
+
/* @__PURE__ */ jsxs(Grid, { item: true, xs: 6, md: 2, children: [
|
|
190
|
+
/* @__PURE__ */ jsx(Typography, { variant: "h5", children: syncSummary.configured }),
|
|
191
|
+
/* @__PURE__ */ jsx(Typography, { color: "textSecondary", children: "Configured" })
|
|
192
|
+
] }),
|
|
193
|
+
/* @__PURE__ */ jsxs(Grid, { item: true, xs: 6, md: 2, children: [
|
|
194
|
+
/* @__PURE__ */ jsx(Typography, { variant: "h5", children: syncSummary.excluded }),
|
|
195
|
+
/* @__PURE__ */ jsx(Typography, { color: "textSecondary", children: "Excluded" })
|
|
196
|
+
] }),
|
|
197
|
+
/* @__PURE__ */ jsxs(Grid, { item: true, xs: 6, md: 2, children: [
|
|
198
|
+
/* @__PURE__ */ jsx(Typography, { variant: "h5", children: syncSummary.unclassified }),
|
|
199
|
+
/* @__PURE__ */ jsx(Typography, { color: "textSecondary", children: "Unclassified" })
|
|
200
|
+
] }),
|
|
201
|
+
/* @__PURE__ */ jsxs(Grid, { item: true, xs: 6, md: 2, children: [
|
|
202
|
+
/* @__PURE__ */ jsx(Typography, { variant: "h5", children: syncSummary.observed }),
|
|
203
|
+
/* @__PURE__ */ jsx(Typography, { color: "textSecondary", children: "Active matches" })
|
|
204
|
+
] }),
|
|
205
|
+
/* @__PURE__ */ jsxs(Grid, { item: true, xs: 6, md: 2, children: [
|
|
206
|
+
/* @__PURE__ */ jsx(Typography, { variant: "h5", children: syncSummary.managedResources }),
|
|
207
|
+
/* @__PURE__ */ jsx(Typography, { color: "textSecondary", children: "Managed resources" })
|
|
208
|
+
] }),
|
|
209
|
+
/* @__PURE__ */ jsxs(Grid, { item: true, xs: 12, children: [
|
|
210
|
+
/* @__PURE__ */ jsxs(Typography, { children: [
|
|
211
|
+
"Last reconciliation: ",
|
|
212
|
+
/* @__PURE__ */ jsx("strong", { children: syncStatus.status }),
|
|
213
|
+
syncStatus.finishedAt ? ` \xB7 ${formatTimestamp(syncStatus.finishedAt)}` : "",
|
|
214
|
+
syncStatus.trigger ? ` \xB7 ${syncStatus.trigger}` : ""
|
|
215
|
+
] }),
|
|
216
|
+
syncStatus.error && /* @__PURE__ */ jsxs(Typography, { color: "error", children: [
|
|
217
|
+
"Last failure: ",
|
|
218
|
+
syncStatus.error
|
|
219
|
+
] }),
|
|
220
|
+
catalogSyncPermission.allowed && /* @__PURE__ */ jsx(
|
|
221
|
+
Button,
|
|
222
|
+
{
|
|
223
|
+
variant: "outlined",
|
|
224
|
+
color: "primary",
|
|
225
|
+
disabled: requestingSync,
|
|
226
|
+
onClick: requestCatalogSync,
|
|
227
|
+
style: { marginTop: 12 },
|
|
228
|
+
children: requestingSync ? "Requesting\u2026" : "Reconcile now"
|
|
229
|
+
}
|
|
230
|
+
),
|
|
231
|
+
syncRequestMessage && /* @__PURE__ */ jsx(Typography, { color: "textSecondary", children: syncRequestMessage }),
|
|
232
|
+
syncRequestError && /* @__PURE__ */ jsx(Typography, { color: "error", children: syncRequestError })
|
|
233
|
+
] })
|
|
234
|
+
] }) }),
|
|
126
235
|
/* @__PURE__ */ jsx(ContentHeader, { title: "Find a service" }),
|
|
127
236
|
/* @__PURE__ */ jsxs(InfoCard, { subheader: "Anyshift-annotated Components and Resources in the Backstage catalog", children: [
|
|
128
237
|
/* @__PURE__ */ jsx(
|
|
@@ -188,6 +297,10 @@ const AnyshiftExplorerPage = () => {
|
|
|
188
297
|
] })
|
|
189
298
|
] });
|
|
190
299
|
};
|
|
300
|
+
function formatTimestamp(value) {
|
|
301
|
+
const parsed = Date.parse(value);
|
|
302
|
+
return Number.isNaN(parsed) ? value : new Date(parsed).toLocaleString();
|
|
303
|
+
}
|
|
191
304
|
|
|
192
|
-
export { AnyshiftExplorerPage, EstateInsightsGrid, isDeterministicSelect, matchesCatalogEntity };
|
|
305
|
+
export { AnyshiftExplorerPage, EstateInsightsGrid, catalogSyncStatus, isDeterministicSelect, matchesCatalogEntity, summarizeCatalogSync };
|
|
193
306
|
//# sourceMappingURL=AnyshiftExplorerPage.esm.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AnyshiftExplorerPage.esm.js","sources":["../../../src/components/explorer/AnyshiftExplorerPage.tsx"],"sourcesContent":["import { useEffect, useState } from 'react';\nimport { Button, Grid, TextField, Typography } from '@material-ui/core';\nimport {\n Content,\n ContentHeader,\n Header,\n InfoCard,\n Page,\n Progress,\n} from '@backstage/core-components';\nimport { useApi } from '@backstage/frontend-plugin-api';\nimport { usePermission } from '@backstage/plugin-permission-react';\nimport { anyshiftQueryPermission } from '@anyshift/backstage-plugin-anyshift-common';\nimport type { Entity } from '@backstage/catalog-model';\nimport { catalogApiRef, EntityRefLink } from '@backstage/plugin-catalog-react';\nimport { anyshiftApiRef } from '../../api/AnyshiftApi';\nimport type {\n DatadogSignals,\n EstateInsights,\n QueryResult,\n} from '../../api/types';\nimport {\n ImpactPresenter,\n TimelinePresenter,\n} from '../entity/SectionPresenters';\nimport { DatadogOperationsRadar } from './DatadogOperationsRadar';\n\nconst DEFAULT_QUERY =\n 'SELECT * FROM resources WHERE type = deployment LIMIT 10';\n\nexport function isDeterministicSelect(value: string): boolean {\n const sql = value.trim();\n return (\n /^SELECT\\b/i.test(sql) &&\n sql.length <= 4_096 &&\n !sql.includes(';') &&\n !sql.includes('--') &&\n !sql.includes('/*')\n );\n}\n\nexport function matchesCatalogEntity(entity: Entity, value: string): boolean {\n const query = value.trim().toLocaleLowerCase();\n if (!query) return true;\n const searchable = [\n entity.metadata.name,\n entity.metadata.title,\n entity.metadata.description,\n entity.metadata.annotations?.['anyshift.io/target'],\n typeof entity.spec?.owner === 'string' ? entity.spec.owner : undefined,\n ];\n return searchable.some(item => item?.toLocaleLowerCase().includes(query));\n}\n\nexport const EstateInsightsGrid = ({\n insights,\n}: {\n insights: EstateInsights;\n}) => (\n <>\n {insights.sections.map(item => (\n <Grid item xs={12} md={6} key={item.id}>\n <InfoCard title={item.title}>\n {item.section.state === 'error' ? (\n <Typography color=\"error\">{item.section.message}</Typography>\n ) : item.section.state === 'empty' ||\n item.section.state === 'unsupported' ||\n item.section.data === undefined ? (\n <Typography color=\"textSecondary\">\n {item.section.message || 'No insight evidence is available.'}\n </Typography>\n ) : item.id === 'recent-change' ? (\n <TimelinePresenter\n data={item.section.data}\n fallbackLabel=\"Deployment\"\n />\n ) : (\n <ImpactPresenter data={item.section.data} />\n )}\n </InfoCard>\n </Grid>\n ))}\n </>\n);\n\nexport const AnyshiftExplorerPage = () => {\n const api = useApi(anyshiftApiRef);\n const catalogApi = useApi(catalogApiRef);\n const queryPermission = usePermission({\n permission: anyshiftQueryPermission,\n });\n const [queryEnabled, setQueryEnabled] = useState(false);\n const [insights, setInsights] = useState<EstateInsights>();\n const [insightError, setInsightError] = useState<string>();\n const [datadogSignals, setDatadogSignals] = useState<DatadogSignals>();\n const [datadogError, setDatadogError] = useState<string>();\n const [refreshingDatadog, setRefreshingDatadog] = useState(false);\n const [catalogEntities, setCatalogEntities] = useState<Entity[]>([]);\n const [catalogError, setCatalogError] = useState<string>();\n const [catalogQuery, setCatalogQuery] = useState('');\n const [sql, setSql] = useState(DEFAULT_QUERY);\n const [queryResult, setQueryResult] = useState<QueryResult>();\n const [queryError, setQueryError] = useState<string>();\n\n useEffect(() => {\n api\n .capabilities()\n .then(capabilities => setQueryEnabled(capabilities.queryEnabled))\n .catch(() => setQueryEnabled(false));\n }, [api]);\n\n useEffect(() => {\n api\n .datadogSignals()\n .then(setDatadogSignals)\n .catch(error => {\n setDatadogError(error instanceof Error ? error.message : String(error));\n });\n }, [api]);\n\n useEffect(() => {\n api\n .insights()\n .then(setInsights)\n .catch(error => {\n setInsightError(error instanceof Error ? error.message : String(error));\n });\n }, [api]);\n\n useEffect(() => {\n catalogApi\n .getEntities({\n filter: [{ kind: 'Component' }, { kind: 'Resource' }],\n })\n .then(response =>\n setCatalogEntities(\n response.items.filter(\n entity => entity.metadata.annotations?.['anyshift.io/target'],\n ),\n ),\n )\n .catch(error => {\n setCatalogError(error instanceof Error ? error.message : String(error));\n });\n }, [catalogApi]);\n\n const matchingEntities = catalogEntities\n .filter(entity => matchesCatalogEntity(entity, catalogQuery))\n .slice(0, 12);\n\n const runQuery = async () => {\n if (!isDeterministicSelect(sql)) {\n setQueryError('Enter one deterministic SELECT query.');\n return;\n }\n setQueryError(undefined);\n try {\n setQueryResult(await api.query(sql.trim()));\n } catch (error) {\n setQueryError(error instanceof Error ? error.message : String(error));\n }\n };\n\n const refreshDatadog = async () => {\n setRefreshingDatadog(true);\n setDatadogError(undefined);\n try {\n setDatadogSignals(await api.datadogSignals({ refresh: true }));\n } catch (error) {\n setDatadogError(error instanceof Error ? error.message : String(error));\n } finally {\n setRefreshingDatadog(false);\n }\n };\n\n return (\n <Page themeId=\"tool\">\n <Header\n title=\"Anyshift\"\n subtitle=\"Live infrastructure context for your software catalog\"\n />\n <Content>\n {datadogSignals ? (\n <DatadogOperationsRadar\n signals={datadogSignals}\n catalogEntities={catalogEntities}\n onRefresh={refreshDatadog}\n refreshing={refreshingDatadog}\n error={datadogError}\n />\n ) : datadogError ? (\n <Typography color=\"error\">{datadogError}</Typography>\n ) : (\n <Progress />\n )}\n <ContentHeader title=\"Find a service\" />\n <InfoCard subheader=\"Anyshift-annotated Components and Resources in the Backstage catalog\">\n <TextField\n fullWidth\n variant=\"outlined\"\n label=\"Search services and resources\"\n value={catalogQuery}\n onChange={event => setCatalogQuery(event.target.value)}\n />\n {catalogError && (\n <Typography color=\"error\">{catalogError}</Typography>\n )}\n {!catalogError && matchingEntities.length === 0 ? (\n <Typography color=\"textSecondary\" style={{ marginTop: 12 }}>\n No matching Anyshift catalog entities.\n </Typography>\n ) : (\n <ul>\n {matchingEntities.map(entity => (\n <li\n key={`${entity.kind}:${\n entity.metadata.namespace ?? 'default'\n }/${entity.metadata.name}`}\n >\n <EntityRefLink entityRef={entity} />\n {entity.metadata.description\n ? ` - ${entity.metadata.description}`\n : null}\n </li>\n ))}\n </ul>\n )}\n </InfoCard>\n <ContentHeader title=\"Estate insights\" />\n {insightError && <Typography color=\"error\">{insightError}</Typography>}\n {!insights && !insightError ? <Progress /> : null}\n <Grid container spacing={3}>\n {insights && <EstateInsightsGrid insights={insights} />}\n {queryEnabled && queryPermission.allowed && (\n <Grid item xs={12}>\n <InfoCard\n title=\"Advanced query\"\n subheader=\"Deterministic Graph API SELECT queries only\"\n >\n <TextField\n fullWidth\n multiline\n minRows={2}\n variant=\"outlined\"\n value={sql}\n onChange={event => setSql(event.target.value)}\n />\n <Button\n variant=\"contained\"\n color=\"primary\"\n onClick={runQuery}\n style={{ marginTop: 12 }}\n >\n Run query\n </Button>\n {queryError && (\n <Typography color=\"error\">{queryError}</Typography>\n )}\n {queryResult && (\n <pre style={{ whiteSpace: 'pre-wrap', fontSize: 12 }}>\n {JSON.stringify(queryResult, null, 2)}\n </pre>\n )}\n </InfoCard>\n </Grid>\n )}\n </Grid>\n </Content>\n </Page>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AnyshiftExplorerPage.esm.js","sources":["../../../src/components/explorer/AnyshiftExplorerPage.tsx"],"sourcesContent":["import { useEffect, useState } from 'react';\nimport { Button, Grid, TextField, Typography } from '@material-ui/core';\nimport {\n Content,\n ContentHeader,\n Header,\n InfoCard,\n Page,\n Progress,\n} from '@backstage/core-components';\nimport { useApi } from '@backstage/frontend-plugin-api';\nimport { usePermission } from '@backstage/plugin-permission-react';\nimport {\n ANYSHIFT_CATALOG_SYNC_ERROR_ANNOTATION,\n ANYSHIFT_CATALOG_SYNC_FINISHED_AT_ANNOTATION,\n ANYSHIFT_CATALOG_SYNC_STATUS_ANNOTATION,\n ANYSHIFT_CATALOG_SYNC_TRIGGER_ANNOTATION,\n anyshiftCatalogSyncPermission,\n anyshiftQueryPermission,\n} from '@anyshift/backstage-plugin-anyshift-common';\nimport type { Entity } from '@backstage/catalog-model';\nimport { catalogApiRef, EntityRefLink } from '@backstage/plugin-catalog-react';\nimport { anyshiftApiRef } from '../../api/AnyshiftApi';\nimport type {\n DatadogSignals,\n EstateInsights,\n QueryResult,\n} from '../../api/types';\nimport {\n ImpactPresenter,\n TimelinePresenter,\n} from '../entity/SectionPresenters';\nimport { DatadogOperationsRadar } from './DatadogOperationsRadar';\n\nconst DEFAULT_QUERY =\n 'SELECT * FROM resources WHERE type = deployment LIMIT 10';\nconst CATALOG_SYNC_STATUS_ENTITY = 'anyshift-catalog-sync';\n\nexport function isDeterministicSelect(value: string): boolean {\n const sql = value.trim();\n return (\n /^SELECT\\b/i.test(sql) &&\n sql.length <= 4_096 &&\n !sql.includes(';') &&\n !sql.includes('--') &&\n !sql.includes('/*')\n );\n}\n\nexport function matchesCatalogEntity(entity: Entity, value: string): boolean {\n const query = value.trim().toLocaleLowerCase();\n if (!query) return true;\n const searchable = [\n entity.metadata.name,\n entity.metadata.title,\n entity.metadata.description,\n entity.metadata.annotations?.['anyshift.io/target'],\n typeof entity.spec?.owner === 'string' ? entity.spec.owner : undefined,\n ];\n return searchable.some(item => item?.toLocaleLowerCase().includes(query));\n}\n\nexport function summarizeCatalogSync(entities: Entity[]) {\n const components = entities.filter(\n entity => entity.kind.toLowerCase() === 'component',\n );\n const configured = components.filter(\n entity => entity.metadata.annotations?.['anyshift.io/target'],\n );\n const excluded = components.filter(\n entity =>\n entity.metadata.annotations?.[\n 'anyshift.io/catalog-sync'\n ]?.toLowerCase() === 'excluded',\n );\n return {\n components: components.length,\n configured: configured.length,\n excluded: excluded.length,\n unclassified: Math.max(\n 0,\n components.length - configured.length - excluded.length,\n ),\n observed: configured.filter(\n entity => entity.metadata.annotations?.['anyshift.io/observed-service'],\n ).length,\n managedResources: entities.filter(\n entity =>\n entity.kind.toLowerCase() === 'resource' &&\n entity.metadata.name !== CATALOG_SYNC_STATUS_ENTITY &&\n entity.metadata.annotations?.['anyshift.io/managed-by'] ===\n 'catalog-provider',\n ).length,\n };\n}\n\nexport function catalogSyncStatus(entities: Entity[]) {\n const entity = entities.find(\n candidate =>\n candidate.kind.toLowerCase() === 'resource' &&\n candidate.metadata.name === CATALOG_SYNC_STATUS_ENTITY,\n );\n const annotations = entity?.metadata.annotations ?? {};\n return {\n status: annotations[ANYSHIFT_CATALOG_SYNC_STATUS_ANNOTATION] ?? 'waiting',\n trigger: annotations[ANYSHIFT_CATALOG_SYNC_TRIGGER_ANNOTATION],\n finishedAt: annotations[ANYSHIFT_CATALOG_SYNC_FINISHED_AT_ANNOTATION],\n error: annotations[ANYSHIFT_CATALOG_SYNC_ERROR_ANNOTATION],\n };\n}\n\nexport const EstateInsightsGrid = ({\n insights,\n}: {\n insights: EstateInsights;\n}) => (\n <>\n {insights.sections.map(item => (\n <Grid item xs={12} md={6} key={item.id}>\n <InfoCard title={item.title}>\n {item.section.state === 'error' ? (\n <Typography color=\"error\">{item.section.message}</Typography>\n ) : item.section.state === 'empty' ||\n item.section.state === 'unsupported' ||\n item.section.data === undefined ? (\n <Typography color=\"textSecondary\">\n {item.section.message || 'No insight evidence is available.'}\n </Typography>\n ) : item.id === 'recent-change' ? (\n <TimelinePresenter\n data={item.section.data}\n fallbackLabel=\"Deployment\"\n />\n ) : (\n <ImpactPresenter data={item.section.data} />\n )}\n </InfoCard>\n </Grid>\n ))}\n </>\n);\n\nexport const AnyshiftExplorerPage = () => {\n const api = useApi(anyshiftApiRef);\n const catalogApi = useApi(catalogApiRef);\n const queryPermission = usePermission({\n permission: anyshiftQueryPermission,\n });\n const catalogSyncPermission = usePermission({\n permission: anyshiftCatalogSyncPermission,\n });\n const [queryEnabled, setQueryEnabled] = useState(false);\n const [insights, setInsights] = useState<EstateInsights>();\n const [insightError, setInsightError] = useState<string>();\n const [datadogSignals, setDatadogSignals] = useState<DatadogSignals>();\n const [datadogError, setDatadogError] = useState<string>();\n const [refreshingDatadog, setRefreshingDatadog] = useState(false);\n const [catalogEntities, setCatalogEntities] = useState<Entity[]>([]);\n const [catalogError, setCatalogError] = useState<string>();\n const [catalogQuery, setCatalogQuery] = useState('');\n const [sql, setSql] = useState(DEFAULT_QUERY);\n const [queryResult, setQueryResult] = useState<QueryResult>();\n const [queryError, setQueryError] = useState<string>();\n const [requestingSync, setRequestingSync] = useState(false);\n const [syncRequestMessage, setSyncRequestMessage] = useState<string>();\n const [syncRequestError, setSyncRequestError] = useState<string>();\n\n useEffect(() => {\n api\n .capabilities()\n .then(capabilities => setQueryEnabled(capabilities.queryEnabled))\n .catch(() => setQueryEnabled(false));\n }, [api]);\n\n useEffect(() => {\n api\n .datadogSignals()\n .then(setDatadogSignals)\n .catch(error => {\n setDatadogError(error instanceof Error ? error.message : String(error));\n });\n }, [api]);\n\n useEffect(() => {\n api\n .insights()\n .then(setInsights)\n .catch(error => {\n setInsightError(error instanceof Error ? error.message : String(error));\n });\n }, [api]);\n\n useEffect(() => {\n catalogApi\n .getEntities({\n filter: [{ kind: 'Component' }, { kind: 'Resource' }],\n })\n .then(response => setCatalogEntities(response.items))\n .catch(error => {\n setCatalogError(error instanceof Error ? error.message : String(error));\n });\n }, [catalogApi]);\n\n const anyshiftEntities = catalogEntities.filter(\n entity => entity.metadata.annotations?.['anyshift.io/target'],\n );\n const syncSummary = summarizeCatalogSync(catalogEntities);\n const syncStatus = catalogSyncStatus(catalogEntities);\n const matchingEntities = anyshiftEntities\n .filter(entity => matchesCatalogEntity(entity, catalogQuery))\n .slice(0, 12);\n\n const runQuery = async () => {\n if (!isDeterministicSelect(sql)) {\n setQueryError('Enter one deterministic SELECT query.');\n return;\n }\n setQueryError(undefined);\n try {\n setQueryResult(await api.query(sql.trim()));\n } catch (error) {\n setQueryError(error instanceof Error ? error.message : String(error));\n }\n };\n\n const refreshDatadog = async () => {\n setRefreshingDatadog(true);\n setDatadogError(undefined);\n try {\n setDatadogSignals(await api.datadogSignals({ refresh: true }));\n } catch (error) {\n setDatadogError(error instanceof Error ? error.message : String(error));\n } finally {\n setRefreshingDatadog(false);\n }\n };\n\n const requestCatalogSync = async () => {\n setRequestingSync(true);\n setSyncRequestError(undefined);\n setSyncRequestMessage(undefined);\n try {\n const accepted = await api.reconcileCatalog();\n setSyncRequestMessage(\n `Reconciliation accepted ${formatTimestamp(accepted.acceptedAt)}.`,\n );\n } catch (error) {\n setSyncRequestError(\n error instanceof Error ? error.message : String(error),\n );\n } finally {\n setRequestingSync(false);\n }\n };\n\n return (\n <Page themeId=\"tool\">\n <Header\n title=\"Anyshift\"\n subtitle=\"Live infrastructure context for your software catalog\"\n />\n <Content>\n {datadogSignals ? (\n <DatadogOperationsRadar\n signals={datadogSignals}\n catalogEntities={anyshiftEntities}\n onRefresh={refreshDatadog}\n refreshing={refreshingDatadog}\n error={datadogError}\n />\n ) : datadogError ? (\n <Typography color=\"error\">{datadogError}</Typography>\n ) : (\n <Progress />\n )}\n <ContentHeader title=\"Catalog synchronization\" />\n <InfoCard subheader=\"GitHub ownership stays authoritative; Anyshift adds observed infrastructure context\">\n <Grid container spacing={2}>\n <Grid item xs={6} md={2}>\n <Typography variant=\"h5\">{syncSummary.configured}</Typography>\n <Typography color=\"textSecondary\">Configured</Typography>\n </Grid>\n <Grid item xs={6} md={2}>\n <Typography variant=\"h5\">{syncSummary.excluded}</Typography>\n <Typography color=\"textSecondary\">Excluded</Typography>\n </Grid>\n <Grid item xs={6} md={2}>\n <Typography variant=\"h5\">{syncSummary.unclassified}</Typography>\n <Typography color=\"textSecondary\">Unclassified</Typography>\n </Grid>\n <Grid item xs={6} md={2}>\n <Typography variant=\"h5\">{syncSummary.observed}</Typography>\n <Typography color=\"textSecondary\">Active matches</Typography>\n </Grid>\n <Grid item xs={6} md={2}>\n <Typography variant=\"h5\">\n {syncSummary.managedResources}\n </Typography>\n <Typography color=\"textSecondary\">Managed resources</Typography>\n </Grid>\n <Grid item xs={12}>\n <Typography>\n Last reconciliation: <strong>{syncStatus.status}</strong>\n {syncStatus.finishedAt\n ? ` · ${formatTimestamp(syncStatus.finishedAt)}`\n : ''}\n {syncStatus.trigger ? ` · ${syncStatus.trigger}` : ''}\n </Typography>\n {syncStatus.error && (\n <Typography color=\"error\">\n Last failure: {syncStatus.error}\n </Typography>\n )}\n {catalogSyncPermission.allowed && (\n <Button\n variant=\"outlined\"\n color=\"primary\"\n disabled={requestingSync}\n onClick={requestCatalogSync}\n style={{ marginTop: 12 }}\n >\n {requestingSync ? 'Requesting…' : 'Reconcile now'}\n </Button>\n )}\n {syncRequestMessage && (\n <Typography color=\"textSecondary\">\n {syncRequestMessage}\n </Typography>\n )}\n {syncRequestError && (\n <Typography color=\"error\">{syncRequestError}</Typography>\n )}\n </Grid>\n </Grid>\n </InfoCard>\n <ContentHeader title=\"Find a service\" />\n <InfoCard subheader=\"Anyshift-annotated Components and Resources in the Backstage catalog\">\n <TextField\n fullWidth\n variant=\"outlined\"\n label=\"Search services and resources\"\n value={catalogQuery}\n onChange={event => setCatalogQuery(event.target.value)}\n />\n {catalogError && (\n <Typography color=\"error\">{catalogError}</Typography>\n )}\n {!catalogError && matchingEntities.length === 0 ? (\n <Typography color=\"textSecondary\" style={{ marginTop: 12 }}>\n No matching Anyshift catalog entities.\n </Typography>\n ) : (\n <ul>\n {matchingEntities.map(entity => (\n <li\n key={`${entity.kind}:${\n entity.metadata.namespace ?? 'default'\n }/${entity.metadata.name}`}\n >\n <EntityRefLink entityRef={entity} />\n {entity.metadata.description\n ? ` - ${entity.metadata.description}`\n : null}\n </li>\n ))}\n </ul>\n )}\n </InfoCard>\n <ContentHeader title=\"Estate insights\" />\n {insightError && <Typography color=\"error\">{insightError}</Typography>}\n {!insights && !insightError ? <Progress /> : null}\n <Grid container spacing={3}>\n {insights && <EstateInsightsGrid insights={insights} />}\n {queryEnabled && queryPermission.allowed && (\n <Grid item xs={12}>\n <InfoCard\n title=\"Advanced query\"\n subheader=\"Deterministic Graph API SELECT queries only\"\n >\n <TextField\n fullWidth\n multiline\n minRows={2}\n variant=\"outlined\"\n value={sql}\n onChange={event => setSql(event.target.value)}\n />\n <Button\n variant=\"contained\"\n color=\"primary\"\n onClick={runQuery}\n style={{ marginTop: 12 }}\n >\n Run query\n </Button>\n {queryError && (\n <Typography color=\"error\">{queryError}</Typography>\n )}\n {queryResult && (\n <pre style={{ whiteSpace: 'pre-wrap', fontSize: 12 }}>\n {JSON.stringify(queryResult, null, 2)}\n </pre>\n )}\n </InfoCard>\n </Grid>\n )}\n </Grid>\n </Content>\n </Page>\n );\n};\n\nfunction formatTimestamp(value: string): string {\n const parsed = Date.parse(value);\n return Number.isNaN(parsed) ? value : new Date(parsed).toLocaleString();\n}\n"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import * as _backstage_catalog_model from '@backstage/catalog-model';
|
|
|
2
2
|
import * as react from 'react';
|
|
3
3
|
import * as _backstage_filter_predicates from '@backstage/filter-predicates';
|
|
4
4
|
import * as _backstage_frontend_plugin_api from '@backstage/frontend-plugin-api';
|
|
5
|
-
import { AnyshiftCapabilities, ServiceBrief, BriefSectionName, BriefSectionResponse, EstateInsights, DatadogSignals, CatalogSummary, QueryResult } from '@anyshift/backstage-plugin-anyshift-common';
|
|
5
|
+
import { AnyshiftCapabilities, ServiceBrief, BriefSectionName, BriefSectionResponse, EstateInsights, DatadogSignals, CatalogSummary, QueryResult, CatalogSyncReport } from '@anyshift/backstage-plugin-anyshift-common';
|
|
6
6
|
export { ANYSHIFT_KIND_ANNOTATION, ANYSHIFT_OBSERVED_SERVICE_ANNOTATION, ANYSHIFT_RESOURCE_ID_ANNOTATION, ANYSHIFT_RESOURCE_TYPE_ANNOTATION, ANYSHIFT_TARGET_ANNOTATION, BriefSection, CatalogSummary, EstateInsights, GITHUB_PROJECT_SLUG_ANNOTATION, QueryResult, ServiceBrief, anyshiftQueryPermission, anyshiftViewPermission } from '@anyshift/backstage-plugin-anyshift-common';
|
|
7
7
|
|
|
8
8
|
declare const anyshiftPlugin: _backstage_frontend_plugin_api.OverridableFrontendPlugin<{
|
|
@@ -114,11 +114,17 @@ interface AnyshiftApi {
|
|
|
114
114
|
offset?: number;
|
|
115
115
|
}): Promise<CatalogSummary>;
|
|
116
116
|
query(sql: string): Promise<QueryResult>;
|
|
117
|
+
reconcileCatalog(): Promise<CatalogSyncAccepted>;
|
|
117
118
|
}
|
|
118
119
|
interface BriefRequestOptions {
|
|
119
120
|
namespace?: string;
|
|
120
121
|
refresh?: boolean;
|
|
121
122
|
}
|
|
123
|
+
interface CatalogSyncAccepted {
|
|
124
|
+
accepted: true;
|
|
125
|
+
acceptedAt: string;
|
|
126
|
+
previous?: CatalogSyncReport;
|
|
127
|
+
}
|
|
122
128
|
declare const anyshiftApiRef: _backstage_frontend_plugin_api.ApiRef<AnyshiftApi> & {
|
|
123
129
|
readonly $$type: "@backstage/ApiRef";
|
|
124
130
|
};
|
package/dist/package.json.esm.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@anyshift/backstage-plugin-anyshift",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.3",
|
|
4
4
|
"description": "Read-only Anyshift infrastructure context for Backstage",
|
|
5
5
|
"main": "dist/index.esm.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"clean": "backstage-cli package clean"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@anyshift/backstage-plugin-anyshift-common": "^0.1.0-beta.
|
|
48
|
+
"@anyshift/backstage-plugin-anyshift-common": "^0.1.0-beta.3",
|
|
49
49
|
"@backstage/catalog-model": "^1.9.0",
|
|
50
50
|
"@backstage/core-components": "^0.18.11",
|
|
51
51
|
"@backstage/frontend-plugin-api": "^0.17.2",
|