@backstage/plugin-devtools 0.1.35-next.1 → 0.1.36-next.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/CHANGELOG.md CHANGED
@@ -1,5 +1,32 @@
1
1
  # @backstage/plugin-devtools
2
2
 
3
+ ## 0.1.36-next.0
4
+
5
+ ### Patch Changes
6
+
7
+ - f2612c2: Fixes an issue where a user lacking permission to schedule tasks can now easily see the issue through a custom icon + tooltip.
8
+ - Updated dependencies
9
+ - @backstage/core-components@0.18.6-next.0
10
+ - @backstage/core-compat-api@0.5.7-next.0
11
+ - @backstage/frontend-plugin-api@0.14.0-next.0
12
+ - @backstage/core-plugin-api@1.12.2-next.0
13
+ - @backstage/errors@1.2.7
14
+ - @backstage/plugin-devtools-common@0.1.22-next.0
15
+ - @backstage/plugin-devtools-react@0.1.1-next.0
16
+ - @backstage/plugin-permission-react@0.4.40-next.0
17
+
18
+ ## 0.1.35
19
+
20
+ ### Patch Changes
21
+
22
+ - be6cef5: Add support for adding `unprocessed-entities` and other tabs to `devtools` when using the New Frontend system
23
+ - Updated dependencies
24
+ - @backstage/frontend-plugin-api@0.13.3
25
+ - @backstage/core-components@0.18.5
26
+ - @backstage/plugin-devtools-react@0.1.0
27
+ - @backstage/plugin-devtools-common@0.1.21
28
+ - @backstage/core-compat-api@0.5.6
29
+
3
30
  ## 0.1.35-next.1
4
31
 
5
32
  ### Patch Changes
package/README.md CHANGED
@@ -166,6 +166,39 @@ You can also add tabs to show content from other plugins that fit well with the
166
166
 
167
167
  #### Catalog Unprocessed Entities Tab
168
168
 
169
+ ##### New Frontend System
170
+
171
+ Create an extension and/or load a 3rd party extension to add additional tabs.
172
+
173
+ ```shell
174
+ yarn --cwd plugins/<your-plugin> add @backstage/plugin-devtools-react
175
+ ```
176
+
177
+ ```tsx
178
+ import { DevToolsContentBlueprint } from '@backstage/plugin-devtools-react';
179
+
180
+ export const unprocessedEntitiesDevToolsContent = DevToolsContentBlueprint.make(
181
+ {
182
+ disabled: true,
183
+ params: {
184
+ path: 'unprocessed-entities',
185
+ title: 'Unprocessed Entities',
186
+ loader: () =>
187
+ import('../components/UnprocessedEntities').then(m => (
188
+ <m.UnprocessedEntitiesContent />
189
+ )),
190
+ },
191
+ },
192
+ );
193
+
194
+ const appFeature = createFrontendModule({
195
+ pluginId: 'catalog-unprocessed-entities',
196
+ extensions: [unprocessedEntitiesDevToolsContent],
197
+ });
198
+ ```
199
+
200
+ ##### Old System
201
+
169
202
  Here's how to add the Catalog Unprocessed Entities tab:
170
203
 
171
204
  1. Install and setup the [Catalog Unprocessed Entities plugin](https://github.com/backstage/backstage/tree/master/plugins/catalog-unprocessed-entities) as per its documentation
@@ -1,5 +1,5 @@
1
1
  import { jsx } from 'react/jsx-runtime';
2
- import { ApiBlueprint, fetchApiRef, discoveryApiRef, PageBlueprint, NavItemBlueprint, createFrontendPlugin } from '@backstage/frontend-plugin-api';
2
+ import { ApiBlueprint, fetchApiRef, discoveryApiRef, PageBlueprint, createExtensionInput, coreExtensionData, NavItemBlueprint, createFrontendPlugin } from '@backstage/frontend-plugin-api';
3
3
  import { devToolsApiRef } from '../api/DevToolsApi.esm.js';
4
4
  import { DevToolsClient } from '../api/DevToolsClient.esm.js';
5
5
  import BuildIcon from '@material-ui/icons/Build';
@@ -15,11 +15,33 @@ const devToolsApi = ApiBlueprint.make({
15
15
  factory: ({ discoveryApi, fetchApi }) => new DevToolsClient({ discoveryApi, fetchApi })
16
16
  })
17
17
  });
18
- const devToolsPage = PageBlueprint.make({
19
- params: {
20
- path: "/devtools",
21
- routeRef: rootRouteRef,
22
- loader: () => import('../components/DevToolsPage/index.esm.js').then((m) => /* @__PURE__ */ jsx(m.DevToolsPage, {}))
18
+ const devToolsPage = PageBlueprint.makeWithOverrides({
19
+ inputs: {
20
+ contents: createExtensionInput(
21
+ [
22
+ coreExtensionData.reactElement,
23
+ coreExtensionData.routePath,
24
+ coreExtensionData.routeRef.optional(),
25
+ coreExtensionData.title
26
+ ],
27
+ {
28
+ optional: true
29
+ }
30
+ )
31
+ },
32
+ factory(originalFactory, { inputs }) {
33
+ return originalFactory({
34
+ path: "/devtools",
35
+ routeRef: rootRouteRef,
36
+ loader: () => {
37
+ const contents = inputs.contents.map((content) => ({
38
+ path: content.get(coreExtensionData.routePath),
39
+ title: content.get(coreExtensionData.title),
40
+ children: content.get(coreExtensionData.reactElement)
41
+ }));
42
+ return import('../components/DevToolsPage/index.esm.js').then((m) => /* @__PURE__ */ jsx(m.DevToolsPage, { contents }));
43
+ }
44
+ });
23
45
  }
24
46
  });
25
47
  const devToolsNavItem = NavItemBlueprint.make({
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.esm.js","sources":["../../src/alpha/plugin.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n createFrontendPlugin,\n discoveryApiRef,\n fetchApiRef,\n ApiBlueprint,\n PageBlueprint,\n NavItemBlueprint,\n} from '@backstage/frontend-plugin-api';\n\nimport { devToolsApiRef, DevToolsClient } from '../api';\nimport BuildIcon from '@material-ui/icons/Build';\nimport { rootRouteRef } from '../routes';\n\n/** @alpha */\nexport const devToolsApi = ApiBlueprint.make({\n params: defineParams =>\n defineParams({\n api: devToolsApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n fetchApi: fetchApiRef,\n },\n factory: ({ discoveryApi, fetchApi }) =>\n new DevToolsClient({ discoveryApi, fetchApi }),\n }),\n});\n\n/** @alpha */\nexport const devToolsPage = PageBlueprint.make({\n params: {\n path: '/devtools',\n routeRef: rootRouteRef,\n loader: () =>\n import('../components/DevToolsPage').then(m => <m.DevToolsPage />),\n },\n});\n\n/** @alpha */\nexport const devToolsNavItem = NavItemBlueprint.make({\n params: {\n title: 'DevTools',\n routeRef: rootRouteRef,\n icon: BuildIcon,\n },\n});\n\n/** @alpha */\nexport default createFrontendPlugin({\n pluginId: 'devtools',\n info: { packageJson: () => import('../../package.json') },\n routes: {\n root: rootRouteRef,\n },\n extensions: [devToolsApi, devToolsPage, devToolsNavItem],\n});\n"],"names":[],"mappings":";;;;;;;AA8BO,MAAM,WAAA,GAAc,aAAa,IAAA,CAAK;AAAA,EAC3C,MAAA,EAAQ,kBACN,YAAA,CAAa;AAAA,IACX,GAAA,EAAK,cAAA;AAAA,IACL,IAAA,EAAM;AAAA,MACJ,YAAA,EAAc,eAAA;AAAA,MACd,QAAA,EAAU;AAAA,KACZ;AAAA,IACA,OAAA,EAAS,CAAC,EAAE,YAAA,EAAc,QAAA,EAAS,KACjC,IAAI,cAAA,CAAe,EAAE,YAAA,EAAc,QAAA,EAAU;AAAA,GAChD;AACL,CAAC;AAGM,MAAM,YAAA,GAAe,cAAc,IAAA,CAAK;AAAA,EAC7C,MAAA,EAAQ;AAAA,IACN,IAAA,EAAM,WAAA;AAAA,IACN,QAAA,EAAU,YAAA;AAAA,IACV,MAAA,EAAQ,MACN,OAAO,yCAA4B,CAAA,CAAE,IAAA,CAAK,CAAA,CAAA,qBAAK,GAAA,CAAC,CAAA,CAAE,YAAA,EAAF,EAAe,CAAE;AAAA;AAEvE,CAAC;AAGM,MAAM,eAAA,GAAkB,iBAAiB,IAAA,CAAK;AAAA,EACnD,MAAA,EAAQ;AAAA,IACN,KAAA,EAAO,UAAA;AAAA,IACP,QAAA,EAAU,YAAA;AAAA,IACV,IAAA,EAAM;AAAA;AAEV,CAAC;AAGD,aAAe,oBAAA,CAAqB;AAAA,EAClC,QAAA,EAAU,UAAA;AAAA,EACV,MAAM,EAAE,WAAA,EAAa,MAAM,OAAO,wBAAoB,CAAA,EAAE;AAAA,EACxD,MAAA,EAAQ;AAAA,IACN,IAAA,EAAM;AAAA,GACR;AAAA,EACA,UAAA,EAAY,CAAC,WAAA,EAAa,YAAA,EAAc,eAAe;AACzD,CAAC,CAAA;;;;"}
1
+ {"version":3,"file":"plugin.esm.js","sources":["../../src/alpha/plugin.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n createFrontendPlugin,\n discoveryApiRef,\n fetchApiRef,\n ApiBlueprint,\n PageBlueprint,\n NavItemBlueprint,\n createExtensionInput,\n coreExtensionData,\n} from '@backstage/frontend-plugin-api';\n\nimport { devToolsApiRef, DevToolsClient } from '../api';\nimport BuildIcon from '@material-ui/icons/Build';\nimport { rootRouteRef } from '../routes';\n\n/** @alpha */\nexport const devToolsApi = ApiBlueprint.make({\n params: defineParams =>\n defineParams({\n api: devToolsApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n fetchApi: fetchApiRef,\n },\n factory: ({ discoveryApi, fetchApi }) =>\n new DevToolsClient({ discoveryApi, fetchApi }),\n }),\n});\n\n/** @alpha */\nexport const devToolsPage = PageBlueprint.makeWithOverrides({\n inputs: {\n contents: createExtensionInput(\n [\n coreExtensionData.reactElement,\n coreExtensionData.routePath,\n coreExtensionData.routeRef.optional(),\n coreExtensionData.title,\n ],\n {\n optional: true,\n },\n ),\n },\n factory(originalFactory, { inputs }) {\n return originalFactory({\n path: '/devtools',\n routeRef: rootRouteRef,\n loader: () => {\n const contents = inputs.contents.map(content => ({\n path: content.get(coreExtensionData.routePath),\n title: content.get(coreExtensionData.title),\n children: content.get(coreExtensionData.reactElement),\n }));\n return import('../components/DevToolsPage').then(m => (\n <m.DevToolsPage contents={contents} />\n ));\n },\n });\n },\n});\n\n/** @alpha */\nexport const devToolsNavItem = NavItemBlueprint.make({\n params: {\n title: 'DevTools',\n routeRef: rootRouteRef,\n icon: BuildIcon,\n },\n});\n\n/** @alpha */\nexport default createFrontendPlugin({\n pluginId: 'devtools',\n info: { packageJson: () => import('../../package.json') },\n routes: {\n root: rootRouteRef,\n },\n extensions: [devToolsApi, devToolsPage, devToolsNavItem],\n});\n"],"names":[],"mappings":";;;;;;;AAgCO,MAAM,WAAA,GAAc,aAAa,IAAA,CAAK;AAAA,EAC3C,MAAA,EAAQ,kBACN,YAAA,CAAa;AAAA,IACX,GAAA,EAAK,cAAA;AAAA,IACL,IAAA,EAAM;AAAA,MACJ,YAAA,EAAc,eAAA;AAAA,MACd,QAAA,EAAU;AAAA,KACZ;AAAA,IACA,OAAA,EAAS,CAAC,EAAE,YAAA,EAAc,QAAA,EAAS,KACjC,IAAI,cAAA,CAAe,EAAE,YAAA,EAAc,QAAA,EAAU;AAAA,GAChD;AACL,CAAC;AAGM,MAAM,YAAA,GAAe,cAAc,iBAAA,CAAkB;AAAA,EAC1D,MAAA,EAAQ;AAAA,IACN,QAAA,EAAU,oBAAA;AAAA,MACR;AAAA,QACE,iBAAA,CAAkB,YAAA;AAAA,QAClB,iBAAA,CAAkB,SAAA;AAAA,QAClB,iBAAA,CAAkB,SAAS,QAAA,EAAS;AAAA,QACpC,iBAAA,CAAkB;AAAA,OACpB;AAAA,MACA;AAAA,QACE,QAAA,EAAU;AAAA;AACZ;AACF,GACF;AAAA,EACA,OAAA,CAAQ,eAAA,EAAiB,EAAE,MAAA,EAAO,EAAG;AACnC,IAAA,OAAO,eAAA,CAAgB;AAAA,MACrB,IAAA,EAAM,WAAA;AAAA,MACN,QAAA,EAAU,YAAA;AAAA,MACV,QAAQ,MAAM;AACZ,QAAA,MAAM,QAAA,GAAW,MAAA,CAAO,QAAA,CAAS,GAAA,CAAI,CAAA,OAAA,MAAY;AAAA,UAC/C,IAAA,EAAM,OAAA,CAAQ,GAAA,CAAI,iBAAA,CAAkB,SAAS,CAAA;AAAA,UAC7C,KAAA,EAAO,OAAA,CAAQ,GAAA,CAAI,iBAAA,CAAkB,KAAK,CAAA;AAAA,UAC1C,QAAA,EAAU,OAAA,CAAQ,GAAA,CAAI,iBAAA,CAAkB,YAAY;AAAA,SACtD,CAAE,CAAA;AACF,QAAA,OAAO,OAAO,yCAA4B,CAAA,CAAE,IAAA,CAAK,CAAA,CAAA,yBAC9C,CAAA,CAAE,YAAA,EAAF,EAAe,QAAA,EAAoB,CACrC,CAAA;AAAA,MACH;AAAA,KACD,CAAA;AAAA,EACH;AACF,CAAC;AAGM,MAAM,eAAA,GAAkB,iBAAiB,IAAA,CAAK;AAAA,EACnD,MAAA,EAAQ;AAAA,IACN,KAAA,EAAO,UAAA;AAAA,IACP,QAAA,EAAU,YAAA;AAAA,IACV,IAAA,EAAM;AAAA;AAEV,CAAC;AAGD,aAAe,oBAAA,CAAqB;AAAA,EAClC,QAAA,EAAU,UAAA;AAAA,EACV,MAAM,EAAE,WAAA,EAAa,MAAM,OAAO,wBAAoB,CAAA,EAAE;AAAA,EACxD,MAAA,EAAQ;AAAA,IACN,IAAA,EAAM;AAAA,GACR;AAAA,EACA,UAAA,EAAY,CAAC,WAAA,EAAa,YAAA,EAAc,eAAe;AACzD,CAAC,CAAA;;;;"}
package/dist/alpha.d.ts CHANGED
@@ -33,8 +33,6 @@ declare const _default: _backstage_frontend_plugin_api.OverridableFrontendPlugin
33
33
  };
34
34
  }>;
35
35
  "page:devtools": _backstage_frontend_plugin_api.OverridableExtensionDefinition<{
36
- kind: "page";
37
- name: undefined;
38
36
  config: {
39
37
  path: string | undefined;
40
38
  };
@@ -44,7 +42,17 @@ declare const _default: _backstage_frontend_plugin_api.OverridableFrontendPlugin
44
42
  output: _backstage_frontend_plugin_api.ExtensionDataRef<string, "core.routing.path", {}> | _backstage_frontend_plugin_api.ExtensionDataRef<react.JSX.Element, "core.reactElement", {}> | _backstage_frontend_plugin_api.ExtensionDataRef<_backstage_frontend_plugin_api.RouteRef<_backstage_frontend_plugin_api.AnyRouteRefParams>, "core.routing.ref", {
45
43
  optional: true;
46
44
  }>;
47
- inputs: {};
45
+ inputs: {
46
+ contents: _backstage_frontend_plugin_api.ExtensionInput<_backstage_frontend_plugin_api.ConfigurableExtensionDataRef<string, "core.title", {}> | _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<react.JSX.Element, "core.reactElement", {}> | _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<string, "core.routing.path", {}> | _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<_backstage_frontend_plugin_api.RouteRef<_backstage_frontend_plugin_api.AnyRouteRefParams>, "core.routing.ref", {
47
+ optional: true;
48
+ }>, {
49
+ singleton: false;
50
+ optional: true;
51
+ internal: false;
52
+ }>;
53
+ };
54
+ kind: "page";
55
+ name: undefined;
48
56
  params: {
49
57
  defaultPath?: [Error: `Use the 'path' param instead`];
50
58
  path: string;
@@ -18,6 +18,7 @@ import { useTriggerScheduledTask } from '../../../hooks/useTriggerScheduledTask.
18
18
  import RefreshIcon from '@material-ui/icons/Refresh';
19
19
  import NightsStay from '@material-ui/icons/NightsStay';
20
20
  import ErrorIcon from '@material-ui/icons/Error';
21
+ import BlockIcon from '@material-ui/icons/Block';
21
22
  import CircularProgress from '@material-ui/core/CircularProgress';
22
23
  import { ScheduledTaskDetailPanel } from './ScheduledTaskDetailedPanel.esm.js';
23
24
  import { RequirePermission } from '@backstage/plugin-permission-react';
@@ -63,6 +64,7 @@ const StatusDisplay = ({
63
64
  icon,
64
65
  /* @__PURE__ */ jsx(Typography, { variant: "body2", style: { marginLeft: 8 }, children: text })
65
66
  ] });
67
+ const CreateNotAllowed = () => /* @__PURE__ */ jsx(Tooltip, { title: "You are not allowed to perform this action", children: /* @__PURE__ */ jsx(BlockIcon, { color: "disabled" }) });
66
68
  const ScheduledTasksContent = () => {
67
69
  const classes = useStyles();
68
70
  const configApi = useApi(configApiRef);
@@ -142,30 +144,38 @@ const ScheduledTasksContent = () => {
142
144
  },
143
145
  {
144
146
  title: "Actions",
145
- render: (rowData) => /* @__PURE__ */ jsx(RequirePermission, { permission: devToolsTaskSchedulerCreatePermission, children: /* @__PURE__ */ jsx(Tooltip, { title: "Run Task", children: /* @__PURE__ */ jsx(
146
- IconButton,
147
+ render: (rowData) => /* @__PURE__ */ jsx(
148
+ RequirePermission,
147
149
  {
148
- "aria-label": "Trigger",
149
- disabled: isTriggering,
150
- onClick: () => {
151
- triggerTask(selectedPlugin, rowData.taskId);
152
- if (triggerError) {
153
- alertApi.post({
154
- message: `Error triggering task ${rowData.taskId}: ${error}`,
155
- severity: "error"
156
- });
157
- } else {
158
- alertApi.post({
159
- message: `Successfully triggered task ${rowData.taskId}`,
160
- severity: "success"
161
- });
150
+ permission: devToolsTaskSchedulerCreatePermission,
151
+ errorPage: /* @__PURE__ */ jsx(CreateNotAllowed, {}),
152
+ children: /* @__PURE__ */ jsx(Tooltip, { title: "Run Task", children: /* @__PURE__ */ jsx(
153
+ IconButton,
154
+ {
155
+ "aria-label": "Trigger",
156
+ disabled: isTriggering,
157
+ onClick: () => {
158
+ triggerTask(selectedPlugin, rowData.taskId);
159
+ if (triggerError) {
160
+ alertApi.post({
161
+ message: `Error triggering task ${rowData.taskId}: ${error}`,
162
+ severity: "error"
163
+ });
164
+ } else {
165
+ alertApi.post({
166
+ message: `Successfully triggered task ${rowData.taskId}`,
167
+ severity: "success"
168
+ });
169
+ }
170
+ },
171
+ children: /* @__PURE__ */ jsx(RefreshIcon, {})
162
172
  }
163
- },
164
- children: /* @__PURE__ */ jsx(RefreshIcon, {})
173
+ ) })
165
174
  }
166
- ) }) }),
175
+ ),
167
176
  sorting: false,
168
- width: "10%"
177
+ width: "10%",
178
+ align: "center"
169
179
  }
170
180
  ];
171
181
  return /* @__PURE__ */ jsxs(Box, { children: [
@@ -1 +1 @@
1
- {"version":3,"file":"ScheduledTasksContent.esm.js","sources":["../../../../src/components/Content/ScheduledTasksContent/ScheduledTasksContent.tsx"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useState } from 'react';\nimport Box from '@material-ui/core/Box';\nimport Typography from '@material-ui/core/Typography';\nimport IconButton from '@material-ui/core/IconButton';\nimport Tooltip from '@material-ui/core/Tooltip';\nimport Autocomplete from '@material-ui/lab/Autocomplete';\nimport TextField from '@material-ui/core/TextField';\nimport { makeStyles, createStyles, Theme } from '@material-ui/core/styles';\nimport {\n ErrorPanel,\n Progress,\n Table,\n TableColumn,\n} from '@backstage/core-components';\nimport Alert from '@material-ui/lab/Alert';\nimport { useScheduledTasks, useTriggerScheduledTask } from '../../../hooks';\nimport { TaskApiTasksResponse } from '@backstage/plugin-devtools-common/alpha';\nimport { alertApiRef, configApiRef, useApi } from '@backstage/core-plugin-api';\nimport RefreshIcon from '@material-ui/icons/Refresh';\nimport NightsStay from '@material-ui/icons/NightsStay';\nimport ErrorIcon from '@material-ui/icons/Error';\nimport CircularProgress from '@material-ui/core/CircularProgress';\nimport { ScheduledTaskDetailPanel } from './ScheduledTaskDetailedPanel';\nimport { RequirePermission } from '@backstage/plugin-permission-react';\nimport { devToolsTaskSchedulerCreatePermission } from '@backstage/plugin-devtools-common/alpha';\n\nconst useStyles = makeStyles((theme: Theme) =>\n createStyles({\n paperStyle: {\n display: 'flex',\n marginBottom: theme.spacing(2),\n },\n flexContainer: {\n display: 'flex',\n flexDirection: 'row',\n padding: 0,\n },\n formControl: {\n minWidth: 240,\n marginBottom: theme.spacing(2),\n },\n detailPanel: {\n padding: theme.spacing(2),\n backgroundColor: theme.palette.background.default,\n },\n detailLabel: {\n fontWeight: 'bold',\n marginRight: theme.spacing(1),\n },\n errorIcon: {\n color: theme.palette.error.main,\n marginRight: theme.spacing(1),\n fontSize: '1.2rem',\n },\n detailPanelAlert: {\n marginBottom: theme.spacing(2),\n },\n }),\n);\n\nconst StatusDisplay = ({\n icon,\n text,\n}: {\n icon: React.ReactNode;\n text: string;\n}) => (\n <Box display=\"flex\" alignItems=\"center\">\n {icon}\n <Typography variant=\"body2\" style={{ marginLeft: 8 }}>\n {text}\n </Typography>\n </Box>\n);\n\n/** @public */\nexport const ScheduledTasksContent = () => {\n const classes = useStyles();\n const configApi = useApi(configApiRef);\n const alertApi = useApi(alertApiRef);\n const plugins =\n configApi.getOptionalStringArray('devTools.scheduledTasks.plugins') || [];\n const [selectedPlugin, setSelectedPlugin] = useState(plugins[0] || '');\n const { scheduledTasks, loading, error } = useScheduledTasks(selectedPlugin);\n const { triggerTask, isTriggering, triggerError } = useTriggerScheduledTask();\n\n const [inputValue, setInputValue] = useState('');\n\n const handleAutocompleteChange = (_event: any, newValue: string | null) => {\n setSelectedPlugin(newValue || '');\n };\n\n const handleCommitChange = () => {\n if (inputValue !== selectedPlugin) {\n setSelectedPlugin(inputValue);\n }\n };\n\n const handleKeyDown = (event: React.KeyboardEvent) => {\n if (event.key === 'Enter') {\n handleCommitChange();\n // Prevent Autocomplete's default behavior (which might select a filtered item)\n event.preventDefault();\n event.stopPropagation();\n }\n };\n\n if (!plugins || plugins.length === 0) {\n return (\n <Alert severity=\"info\">\n No plugins configured for scheduled tasks. Please configure\n `devTools.scheduledTasks.plugins` in app-config.yaml.\n </Alert>\n );\n }\n\n const columns: TableColumn<TaskApiTasksResponse>[] = [\n {\n title: 'Task ID',\n field: 'taskId',\n width: '35%',\n render: (rowData: TaskApiTasksResponse) => {\n const errorIconStyle: React.CSSProperties = {\n color: '#f44336',\n marginRight: '8px',\n fontSize: '1.2rem',\n verticalAlign: 'middle',\n };\n\n return (\n <Box display=\"flex\" alignItems=\"center\">\n {rowData.taskState?.lastRunError && (\n <ErrorIcon style={errorIconStyle} />\n )}\n <Typography>{rowData.taskId}</Typography>\n </Box>\n );\n },\n },\n {\n title: 'Status',\n field: 'taskState.status',\n width: '15%',\n render: (rowData: TaskApiTasksResponse) => {\n const status = rowData.taskState?.status;\n\n if (status === 'idle') {\n return (\n <StatusDisplay icon={<NightsStay fontSize=\"small\" />} text=\"Idle\" />\n );\n }\n\n if (status === 'running') {\n return (\n <StatusDisplay\n icon={<CircularProgress color=\"inherit\" size=\"30px\" />}\n text=\"Running\"\n />\n );\n }\n\n return <Typography variant=\"body2\">{status || 'N/A'}</Typography>;\n },\n },\n {\n title: 'Last Run',\n field: 'taskState.lastRunEndedAt',\n width: '25%',\n render: (rowData: TaskApiTasksResponse) =>\n rowData.taskState?.lastRunEndedAt\n ? new Date(rowData.taskState.lastRunEndedAt).toLocaleString()\n : 'N/A',\n },\n {\n title: 'Next Run',\n width: '15%',\n render: (rowData: TaskApiTasksResponse) =>\n rowData.taskState?.status === 'idle' && rowData.taskState.startsAt\n ? new Date(rowData.taskState.startsAt).toLocaleString()\n : 'N/A',\n },\n {\n title: 'Actions',\n render: (rowData: TaskApiTasksResponse) => (\n <RequirePermission permission={devToolsTaskSchedulerCreatePermission}>\n <Tooltip title=\"Run Task\">\n <IconButton\n aria-label=\"Trigger\"\n disabled={isTriggering}\n onClick={() => {\n triggerTask(selectedPlugin, rowData.taskId);\n if (triggerError) {\n alertApi.post({\n message: `Error triggering task ${rowData.taskId}: ${error}`,\n severity: 'error',\n });\n } else {\n alertApi.post({\n message: `Successfully triggered task ${rowData.taskId}`,\n severity: 'success',\n });\n }\n }}\n >\n <RefreshIcon />\n </IconButton>\n </Tooltip>\n </RequirePermission>\n ),\n sorting: false,\n width: '10%',\n },\n ];\n\n return (\n <Box>\n <Autocomplete\n className={classes.formControl}\n classes={{ root: classes.formControl }}\n freeSolo\n options={plugins}\n value={selectedPlugin}\n inputValue={inputValue}\n onChange={handleAutocompleteChange}\n onInputChange={(_event, newInputValue) => {\n setInputValue(newInputValue);\n }}\n renderInput={params => (\n <TextField\n {...params}\n label=\"Select Plugin\"\n variant=\"outlined\"\n onKeyDown={handleKeyDown}\n onBlur={handleCommitChange}\n />\n )}\n />\n\n {loading && <Progress />}\n\n {error && (\n <ErrorPanel\n error={new Error(`No scheduled tasks found for \"${selectedPlugin}\"`)}\n title=\"No Scheduled Tasks Found\"\n >\n <Typography variant=\"body2\">\n The plugin ID \"{selectedPlugin}\" doesn't have any scheduled tasks or\n may contain a typo.\n </Typography>\n <Typography variant=\"body2\" style={{ marginTop: 8 }}>\n Please verify:\n </Typography>\n <ul>\n <li>\n <Typography variant=\"body2\">\n The plugin ID is spelled correctly\n </Typography>\n </li>\n <li>\n <Typography variant=\"body2\">\n The plugin has registered scheduled tasks\n </Typography>\n </li>\n </ul>\n </ErrorPanel>\n )}\n\n {!loading && !error && (\n <Table\n title={`Scheduled Tasks (${selectedPlugin})`}\n options={{\n paging: true,\n search: true,\n sorting: true,\n searchFieldAlignment: 'right',\n }}\n columns={columns}\n data={scheduledTasks || []}\n emptyContent={\n <Alert severity=\"info\">\n No scheduled tasks found for {selectedPlugin}.\n </Alert>\n }\n detailPanel={({ rowData }) => {\n return <ScheduledTaskDetailPanel rowData={rowData} />;\n }}\n />\n )}\n </Box>\n );\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ScheduledTasksContent.esm.js","sources":["../../../../src/components/Content/ScheduledTasksContent/ScheduledTasksContent.tsx"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useState } from 'react';\nimport Box from '@material-ui/core/Box';\nimport Typography from '@material-ui/core/Typography';\nimport IconButton from '@material-ui/core/IconButton';\nimport Tooltip from '@material-ui/core/Tooltip';\nimport Autocomplete from '@material-ui/lab/Autocomplete';\nimport TextField from '@material-ui/core/TextField';\nimport { makeStyles, createStyles, Theme } from '@material-ui/core/styles';\nimport {\n ErrorPanel,\n Progress,\n Table,\n TableColumn,\n} from '@backstage/core-components';\nimport Alert from '@material-ui/lab/Alert';\nimport { useScheduledTasks, useTriggerScheduledTask } from '../../../hooks';\nimport { TaskApiTasksResponse } from '@backstage/plugin-devtools-common/alpha';\nimport { alertApiRef, configApiRef, useApi } from '@backstage/core-plugin-api';\nimport RefreshIcon from '@material-ui/icons/Refresh';\nimport NightsStay from '@material-ui/icons/NightsStay';\nimport ErrorIcon from '@material-ui/icons/Error';\nimport BlockIcon from '@material-ui/icons/Block';\nimport CircularProgress from '@material-ui/core/CircularProgress';\nimport { ScheduledTaskDetailPanel } from './ScheduledTaskDetailedPanel';\nimport { RequirePermission } from '@backstage/plugin-permission-react';\nimport { devToolsTaskSchedulerCreatePermission } from '@backstage/plugin-devtools-common/alpha';\n\nconst useStyles = makeStyles((theme: Theme) =>\n createStyles({\n paperStyle: {\n display: 'flex',\n marginBottom: theme.spacing(2),\n },\n flexContainer: {\n display: 'flex',\n flexDirection: 'row',\n padding: 0,\n },\n formControl: {\n minWidth: 240,\n marginBottom: theme.spacing(2),\n },\n detailPanel: {\n padding: theme.spacing(2),\n backgroundColor: theme.palette.background.default,\n },\n detailLabel: {\n fontWeight: 'bold',\n marginRight: theme.spacing(1),\n },\n errorIcon: {\n color: theme.palette.error.main,\n marginRight: theme.spacing(1),\n fontSize: '1.2rem',\n },\n detailPanelAlert: {\n marginBottom: theme.spacing(2),\n },\n }),\n);\n\nconst StatusDisplay = ({\n icon,\n text,\n}: {\n icon: React.ReactNode;\n text: string;\n}) => (\n <Box display=\"flex\" alignItems=\"center\">\n {icon}\n <Typography variant=\"body2\" style={{ marginLeft: 8 }}>\n {text}\n </Typography>\n </Box>\n);\n\nconst CreateNotAllowed = () => (\n <Tooltip title=\"You are not allowed to perform this action\">\n <BlockIcon color=\"disabled\" />\n </Tooltip>\n);\n\n/** @public */\nexport const ScheduledTasksContent = () => {\n const classes = useStyles();\n const configApi = useApi(configApiRef);\n const alertApi = useApi(alertApiRef);\n const plugins =\n configApi.getOptionalStringArray('devTools.scheduledTasks.plugins') || [];\n const [selectedPlugin, setSelectedPlugin] = useState(plugins[0] || '');\n const { scheduledTasks, loading, error } = useScheduledTasks(selectedPlugin);\n const { triggerTask, isTriggering, triggerError } = useTriggerScheduledTask();\n\n const [inputValue, setInputValue] = useState('');\n\n const handleAutocompleteChange = (_event: any, newValue: string | null) => {\n setSelectedPlugin(newValue || '');\n };\n\n const handleCommitChange = () => {\n if (inputValue !== selectedPlugin) {\n setSelectedPlugin(inputValue);\n }\n };\n\n const handleKeyDown = (event: React.KeyboardEvent) => {\n if (event.key === 'Enter') {\n handleCommitChange();\n // Prevent Autocomplete's default behavior (which might select a filtered item)\n event.preventDefault();\n event.stopPropagation();\n }\n };\n\n if (!plugins || plugins.length === 0) {\n return (\n <Alert severity=\"info\">\n No plugins configured for scheduled tasks. Please configure\n `devTools.scheduledTasks.plugins` in app-config.yaml.\n </Alert>\n );\n }\n\n const columns: TableColumn<TaskApiTasksResponse>[] = [\n {\n title: 'Task ID',\n field: 'taskId',\n width: '35%',\n render: (rowData: TaskApiTasksResponse) => {\n const errorIconStyle: React.CSSProperties = {\n color: '#f44336',\n marginRight: '8px',\n fontSize: '1.2rem',\n verticalAlign: 'middle',\n };\n\n return (\n <Box display=\"flex\" alignItems=\"center\">\n {rowData.taskState?.lastRunError && (\n <ErrorIcon style={errorIconStyle} />\n )}\n <Typography>{rowData.taskId}</Typography>\n </Box>\n );\n },\n },\n {\n title: 'Status',\n field: 'taskState.status',\n width: '15%',\n render: (rowData: TaskApiTasksResponse) => {\n const status = rowData.taskState?.status;\n\n if (status === 'idle') {\n return (\n <StatusDisplay icon={<NightsStay fontSize=\"small\" />} text=\"Idle\" />\n );\n }\n\n if (status === 'running') {\n return (\n <StatusDisplay\n icon={<CircularProgress color=\"inherit\" size=\"30px\" />}\n text=\"Running\"\n />\n );\n }\n\n return <Typography variant=\"body2\">{status || 'N/A'}</Typography>;\n },\n },\n {\n title: 'Last Run',\n field: 'taskState.lastRunEndedAt',\n width: '25%',\n render: (rowData: TaskApiTasksResponse) =>\n rowData.taskState?.lastRunEndedAt\n ? new Date(rowData.taskState.lastRunEndedAt).toLocaleString()\n : 'N/A',\n },\n {\n title: 'Next Run',\n width: '15%',\n render: (rowData: TaskApiTasksResponse) =>\n rowData.taskState?.status === 'idle' && rowData.taskState.startsAt\n ? new Date(rowData.taskState.startsAt).toLocaleString()\n : 'N/A',\n },\n {\n title: 'Actions',\n render: (rowData: TaskApiTasksResponse) => (\n <RequirePermission\n permission={devToolsTaskSchedulerCreatePermission}\n errorPage={<CreateNotAllowed />}\n >\n <Tooltip title=\"Run Task\">\n <IconButton\n aria-label=\"Trigger\"\n disabled={isTriggering}\n onClick={() => {\n triggerTask(selectedPlugin, rowData.taskId);\n if (triggerError) {\n alertApi.post({\n message: `Error triggering task ${rowData.taskId}: ${error}`,\n severity: 'error',\n });\n } else {\n alertApi.post({\n message: `Successfully triggered task ${rowData.taskId}`,\n severity: 'success',\n });\n }\n }}\n >\n <RefreshIcon />\n </IconButton>\n </Tooltip>\n </RequirePermission>\n ),\n sorting: false,\n width: '10%',\n align: 'center',\n },\n ];\n\n return (\n <Box>\n <Autocomplete\n className={classes.formControl}\n classes={{ root: classes.formControl }}\n freeSolo\n options={plugins}\n value={selectedPlugin}\n inputValue={inputValue}\n onChange={handleAutocompleteChange}\n onInputChange={(_event, newInputValue) => {\n setInputValue(newInputValue);\n }}\n renderInput={params => (\n <TextField\n {...params}\n label=\"Select Plugin\"\n variant=\"outlined\"\n onKeyDown={handleKeyDown}\n onBlur={handleCommitChange}\n />\n )}\n />\n\n {loading && <Progress />}\n\n {error && (\n <ErrorPanel\n error={new Error(`No scheduled tasks found for \"${selectedPlugin}\"`)}\n title=\"No Scheduled Tasks Found\"\n >\n <Typography variant=\"body2\">\n The plugin ID \"{selectedPlugin}\" doesn't have any scheduled tasks or\n may contain a typo.\n </Typography>\n <Typography variant=\"body2\" style={{ marginTop: 8 }}>\n Please verify:\n </Typography>\n <ul>\n <li>\n <Typography variant=\"body2\">\n The plugin ID is spelled correctly\n </Typography>\n </li>\n <li>\n <Typography variant=\"body2\">\n The plugin has registered scheduled tasks\n </Typography>\n </li>\n </ul>\n </ErrorPanel>\n )}\n\n {!loading && !error && (\n <Table\n title={`Scheduled Tasks (${selectedPlugin})`}\n options={{\n paging: true,\n search: true,\n sorting: true,\n searchFieldAlignment: 'right',\n }}\n columns={columns}\n data={scheduledTasks || []}\n emptyContent={\n <Alert severity=\"info\">\n No scheduled tasks found for {selectedPlugin}.\n </Alert>\n }\n detailPanel={({ rowData }) => {\n return <ScheduledTaskDetailPanel rowData={rowData} />;\n }}\n />\n )}\n </Box>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -1,17 +1,27 @@
1
1
  import { jsxs, jsx } from 'react/jsx-runtime';
2
2
  import { devToolsInfoReadPermission, devToolsConfigReadPermission } from '@backstage/plugin-devtools-common';
3
- import { devToolsTaskSchedulerReadPermission } from '@backstage/plugin-devtools-common/alpha';
4
3
  import { ConfigContent } from '../Content/ConfigContent/ConfigContent.esm.js';
5
- import { DevToolsLayout } from '../DevToolsLayout/DevToolsLayout.esm.js';
6
4
  import { InfoContent } from '../Content/InfoContent/InfoContent.esm.js';
7
- import { RequirePermission } from '@backstage/plugin-permission-react';
5
+ import '../Content/ExternalDependenciesContent/ExternalDependenciesContent.esm.js';
8
6
  import { ScheduledTasksContent } from '../Content/ScheduledTasksContent/ScheduledTasksContent.esm.js';
9
7
  import '../Content/ScheduledTasksContent/ScheduledTaskDetailedPanel.esm.js';
8
+ import { devToolsTaskSchedulerReadPermission } from '@backstage/plugin-devtools-common/alpha';
9
+ import { DevToolsLayout } from '../DevToolsLayout/DevToolsLayout.esm.js';
10
+ import { RequirePermission } from '@backstage/plugin-permission-react';
10
11
 
11
- const DefaultDevToolsPage = () => /* @__PURE__ */ jsxs(DevToolsLayout, { children: [
12
+ const DefaultDevToolsPage = ({ contents }) => /* @__PURE__ */ jsxs(DevToolsLayout, { children: [
12
13
  /* @__PURE__ */ jsx(DevToolsLayout.Route, { path: "info", title: "Info", children: /* @__PURE__ */ jsx(RequirePermission, { permission: devToolsInfoReadPermission, children: /* @__PURE__ */ jsx(InfoContent, {}) }) }),
13
14
  /* @__PURE__ */ jsx(DevToolsLayout.Route, { path: "config", title: "Config", children: /* @__PURE__ */ jsx(RequirePermission, { permission: devToolsConfigReadPermission, children: /* @__PURE__ */ jsx(ConfigContent, {}) }) }),
14
- /* @__PURE__ */ jsx(DevToolsLayout.Route, { path: "scheduled-tasks", title: "Scheduled Tasks", children: /* @__PURE__ */ jsx(RequirePermission, { permission: devToolsTaskSchedulerReadPermission, children: /* @__PURE__ */ jsx(ScheduledTasksContent, {}) }) })
15
+ /* @__PURE__ */ jsx(DevToolsLayout.Route, { path: "scheduled-tasks", title: "Scheduled Tasks", children: /* @__PURE__ */ jsx(RequirePermission, { permission: devToolsTaskSchedulerReadPermission, children: /* @__PURE__ */ jsx(ScheduledTasksContent, {}) }) }),
16
+ contents?.map((content, index) => /* @__PURE__ */ jsx(
17
+ DevToolsLayout.Route,
18
+ {
19
+ path: content.path,
20
+ title: content.title,
21
+ children: content.children
22
+ },
23
+ `extension-${index}`
24
+ ))
15
25
  ] });
16
26
 
17
27
  export { DefaultDevToolsPage };
@@ -1 +1 @@
1
- {"version":3,"file":"DefaultDevToolsPage.esm.js","sources":["../../../src/components/DefaultDevToolsPage/DefaultDevToolsPage.tsx"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n devToolsConfigReadPermission,\n devToolsInfoReadPermission,\n} from '@backstage/plugin-devtools-common';\nimport { devToolsTaskSchedulerReadPermission } from '@backstage/plugin-devtools-common/alpha';\nimport { ConfigContent } from '../Content/ConfigContent';\nimport { DevToolsLayout } from '../DevToolsLayout';\nimport { InfoContent } from '../Content/InfoContent';\nimport { RequirePermission } from '@backstage/plugin-permission-react';\nimport { ScheduledTasksContent } from '../Content/ScheduledTasksContent';\n\n/** @public */\nexport const DefaultDevToolsPage = () => (\n <DevToolsLayout>\n <DevToolsLayout.Route path=\"info\" title=\"Info\">\n <RequirePermission permission={devToolsInfoReadPermission}>\n <InfoContent />\n </RequirePermission>\n </DevToolsLayout.Route>\n <DevToolsLayout.Route path=\"config\" title=\"Config\">\n <RequirePermission permission={devToolsConfigReadPermission}>\n <ConfigContent />\n </RequirePermission>\n </DevToolsLayout.Route>\n <DevToolsLayout.Route path=\"scheduled-tasks\" title=\"Scheduled Tasks\">\n <RequirePermission permission={devToolsTaskSchedulerReadPermission}>\n <ScheduledTasksContent />\n </RequirePermission>\n </DevToolsLayout.Route>\n </DevToolsLayout>\n);\n"],"names":[],"mappings":";;;;;;;;;;AA4BO,MAAM,mBAAA,GAAsB,sBACjC,IAAA,CAAC,cAAA,EAAA,EACC,QAAA,EAAA;AAAA,kBAAA,GAAA,CAAC,cAAA,CAAe,KAAA,EAAf,EAAqB,IAAA,EAAK,QAAO,KAAA,EAAM,MAAA,EACtC,QAAA,kBAAA,GAAA,CAAC,iBAAA,EAAA,EAAkB,UAAA,EAAY,0BAAA,EAC7B,QAAA,kBAAA,GAAA,CAAC,WAAA,EAAA,EAAY,GACf,CAAA,EACF,CAAA;AAAA,kBACA,GAAA,CAAC,cAAA,CAAe,KAAA,EAAf,EAAqB,MAAK,QAAA,EAAS,KAAA,EAAM,QAAA,EACxC,QAAA,kBAAA,GAAA,CAAC,qBAAkB,UAAA,EAAY,4BAAA,EAC7B,QAAA,kBAAA,GAAA,CAAC,aAAA,EAAA,EAAc,GACjB,CAAA,EACF,CAAA;AAAA,kBACA,GAAA,CAAC,cAAA,CAAe,KAAA,EAAf,EAAqB,MAAK,iBAAA,EAAkB,KAAA,EAAM,iBAAA,EACjD,QAAA,kBAAA,GAAA,CAAC,qBAAkB,UAAA,EAAY,mCAAA,EAC7B,QAAA,kBAAA,GAAA,CAAC,qBAAA,EAAA,EAAsB,GACzB,CAAA,EACF;AAAA,CAAA,EACF;;;;"}
1
+ {"version":3,"file":"DefaultDevToolsPage.esm.js","sources":["../../../src/components/DefaultDevToolsPage/DefaultDevToolsPage.tsx"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n devToolsConfigReadPermission,\n devToolsInfoReadPermission,\n} from '@backstage/plugin-devtools-common';\n\nimport { ConfigContent } from '../Content';\nimport { devToolsTaskSchedulerReadPermission } from '@backstage/plugin-devtools-common/alpha';\nimport { DevToolsLayout } from '../DevToolsLayout';\nimport { InfoContent } from '../Content';\nimport { RequirePermission } from '@backstage/plugin-permission-react';\nimport { ScheduledTasksContent } from '../Content/ScheduledTasksContent';\nimport { DevToolsPageProps } from '../DevToolsPage';\n\n/** @public */\nexport const DefaultDevToolsPage = ({ contents }: DevToolsPageProps) => (\n <DevToolsLayout>\n <DevToolsLayout.Route path=\"info\" title=\"Info\">\n <RequirePermission permission={devToolsInfoReadPermission}>\n <InfoContent />\n </RequirePermission>\n </DevToolsLayout.Route>\n <DevToolsLayout.Route path=\"config\" title=\"Config\">\n <RequirePermission permission={devToolsConfigReadPermission}>\n <ConfigContent />\n </RequirePermission>\n </DevToolsLayout.Route>\n <DevToolsLayout.Route path=\"scheduled-tasks\" title=\"Scheduled Tasks\">\n <RequirePermission permission={devToolsTaskSchedulerReadPermission}>\n <ScheduledTasksContent />\n </RequirePermission>\n </DevToolsLayout.Route>\n {contents?.map((content, index) => (\n <DevToolsLayout.Route\n key={`extension-${index}`}\n path={content.path}\n title={content.title}\n >\n {content.children}\n </DevToolsLayout.Route>\n ))}\n </DevToolsLayout>\n);\n"],"names":[],"mappings":";;;;;;;;;;;AA8BO,MAAM,sBAAsB,CAAC,EAAE,QAAA,EAAS,0BAC5C,cAAA,EAAA,EACC,QAAA,EAAA;AAAA,kBAAA,GAAA,CAAC,cAAA,CAAe,KAAA,EAAf,EAAqB,IAAA,EAAK,QAAO,KAAA,EAAM,MAAA,EACtC,QAAA,kBAAA,GAAA,CAAC,iBAAA,EAAA,EAAkB,UAAA,EAAY,0BAAA,EAC7B,QAAA,kBAAA,GAAA,CAAC,WAAA,EAAA,EAAY,GACf,CAAA,EACF,CAAA;AAAA,kBACA,GAAA,CAAC,cAAA,CAAe,KAAA,EAAf,EAAqB,MAAK,QAAA,EAAS,KAAA,EAAM,QAAA,EACxC,QAAA,kBAAA,GAAA,CAAC,qBAAkB,UAAA,EAAY,4BAAA,EAC7B,QAAA,kBAAA,GAAA,CAAC,aAAA,EAAA,EAAc,GACjB,CAAA,EACF,CAAA;AAAA,kBACA,GAAA,CAAC,cAAA,CAAe,KAAA,EAAf,EAAqB,MAAK,iBAAA,EAAkB,KAAA,EAAM,iBAAA,EACjD,QAAA,kBAAA,GAAA,CAAC,qBAAkB,UAAA,EAAY,mCAAA,EAC7B,QAAA,kBAAA,GAAA,CAAC,qBAAA,EAAA,EAAsB,GACzB,CAAA,EACF,CAAA;AAAA,EACC,QAAA,EAAU,GAAA,CAAI,CAAC,OAAA,EAAS,KAAA,qBACvB,GAAA;AAAA,IAAC,cAAA,CAAe,KAAA;AAAA,IAAf;AAAA,MAEC,MAAM,OAAA,CAAQ,IAAA;AAAA,MACd,OAAO,OAAA,CAAQ,KAAA;AAAA,MAEd,QAAA,EAAA,OAAA,CAAQ;AAAA,KAAA;AAAA,IAJJ,aAAa,KAAK,CAAA;AAAA,GAM1B;AAAA,CAAA,EACH;;;;"}
@@ -2,9 +2,9 @@ import { jsx, Fragment } from 'react/jsx-runtime';
2
2
  import { useOutlet } from 'react-router-dom';
3
3
  import { DefaultDevToolsPage } from '../DefaultDevToolsPage/DefaultDevToolsPage.esm.js';
4
4
 
5
- const DevToolsPage = () => {
5
+ const DevToolsPage = ({ contents }) => {
6
6
  const outlet = useOutlet();
7
- return /* @__PURE__ */ jsx(Fragment, { children: outlet || /* @__PURE__ */ jsx(DefaultDevToolsPage, {}) });
7
+ return /* @__PURE__ */ jsx(Fragment, { children: outlet || /* @__PURE__ */ jsx(DefaultDevToolsPage, { contents }) });
8
8
  };
9
9
 
10
10
  export { DevToolsPage };
@@ -1 +1 @@
1
- {"version":3,"file":"DevToolsPage.esm.js","sources":["../../../src/components/DevToolsPage/DevToolsPage.tsx"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useOutlet } from 'react-router-dom';\nimport { DefaultDevToolsPage } from '../DefaultDevToolsPage';\n\nexport const DevToolsPage = () => {\n const outlet = useOutlet();\n\n return <>{outlet || <DefaultDevToolsPage />}</>;\n};\n"],"names":[],"mappings":";;;;AAmBO,MAAM,eAAe,MAAM;AAChC,EAAA,MAAM,SAAS,SAAA,EAAU;AAEzB,EAAA,uBAAO,GAAA,CAAA,QAAA,EAAA,EAAG,QAAA,EAAA,MAAA,oBAAU,GAAA,CAAC,mBAAA,EAAA,EAAoB,CAAA,EAAG,CAAA;AAC9C;;;;"}
1
+ {"version":3,"file":"DevToolsPage.esm.js","sources":["../../../src/components/DevToolsPage/DevToolsPage.tsx"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useOutlet } from 'react-router-dom';\nimport { DefaultDevToolsPage } from '../DefaultDevToolsPage';\nimport { ReactElement } from 'react';\n\n/**\n @public\n */\nexport interface DevToolsPageProps {\n contents?: DevToolsPageContent[];\n}\n\n/**\n @public\n */\nexport interface DevToolsPageContent {\n title: string;\n path: string;\n children: ReactElement;\n}\n\nexport const DevToolsPage = ({ contents }: DevToolsPageProps) => {\n const outlet = useOutlet();\n\n return <>{outlet || <DefaultDevToolsPage contents={contents} />}</>;\n};\n"],"names":[],"mappings":";;;;AAoCO,MAAM,YAAA,GAAe,CAAC,EAAE,QAAA,EAAS,KAAyB;AAC/D,EAAA,MAAM,SAAS,SAAA,EAAU;AAEzB,EAAA,uBAAO,GAAA,CAAA,QAAA,EAAA,EAAG,QAAA,EAAA,MAAA,oBAAU,GAAA,CAAC,mBAAA,EAAA,EAAoB,UAAoB,CAAA,EAAG,CAAA;AAClE;;;;"}
package/dist/index.d.ts CHANGED
@@ -1,15 +1,8 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode, ElementType, ReactElement } from 'react';
2
3
  import * as _backstage_core_plugin_api from '@backstage/core-plugin-api';
3
4
  import { TaskApiTasksResponse } from '@backstage/plugin-devtools-common/alpha';
4
5
  import { TabProps } from '@material-ui/core/Tab';
5
- import { ReactNode, ElementType } from 'react';
6
-
7
- /** @public */
8
- declare const devToolsPlugin: _backstage_core_plugin_api.BackstagePlugin<{
9
- root: _backstage_core_plugin_api.RouteRef<undefined>;
10
- }, {}>;
11
- /** @public */
12
- declare const DevToolsPage: () => react_jsx_runtime.JSX.Element;
13
6
 
14
7
  /** @public */
15
8
  declare const ConfigContent: () => react_jsx_runtime.JSX.Element;
@@ -61,5 +54,27 @@ declare const DevToolsLayout: {
61
54
  Route: (props: SubRoute) => null;
62
55
  };
63
56
 
57
+ /**
58
+ @public
59
+ */
60
+ interface DevToolsPageProps {
61
+ contents?: DevToolsPageContent[];
62
+ }
63
+ /**
64
+ @public
65
+ */
66
+ interface DevToolsPageContent {
67
+ title: string;
68
+ path: string;
69
+ children: ReactElement;
70
+ }
71
+
72
+ /** @public */
73
+ declare const devToolsPlugin: _backstage_core_plugin_api.BackstagePlugin<{
74
+ root: _backstage_core_plugin_api.RouteRef<undefined>;
75
+ }, {}>;
76
+ /** @public */
77
+ declare const DevToolsPage: ({ contents }: DevToolsPageProps) => react_jsx_runtime.JSX.Element;
78
+
64
79
  export { ConfigContent, DevToolsLayout, DevToolsPage, ExternalDependenciesContent, InfoContent, ScheduledTaskDetailPanel, ScheduledTasksContent, devToolsPlugin };
65
- export type { DevToolsLayoutProps, SubRoute };
80
+ export type { DevToolsLayoutProps, DevToolsPageContent, DevToolsPageProps, SubRoute };
@@ -1,12 +1,13 @@
1
1
  var name = "@backstage/plugin-devtools";
2
- var version = "0.1.35-next.1";
2
+ var version = "0.1.36-next.0";
3
3
  var backstage = {
4
4
  role: "frontend-plugin",
5
5
  pluginId: "devtools",
6
6
  pluginPackages: [
7
7
  "@backstage/plugin-devtools",
8
8
  "@backstage/plugin-devtools-backend",
9
- "@backstage/plugin-devtools-common"
9
+ "@backstage/plugin-devtools-common",
10
+ "@backstage/plugin-devtools-react"
10
11
  ]
11
12
  };
12
13
  var publishConfig = {
@@ -57,6 +58,7 @@ var dependencies = {
57
58
  "@backstage/errors": "workspace:^",
58
59
  "@backstage/frontend-plugin-api": "workspace:^",
59
60
  "@backstage/plugin-devtools-common": "workspace:^",
61
+ "@backstage/plugin-devtools-react": "workspace:^",
60
62
  "@backstage/plugin-permission-react": "workspace:^",
61
63
  "@material-ui/core": "^4.9.13",
62
64
  "@material-ui/icons": "^4.9.1",
@@ -1 +1 @@
1
- {"version":3,"file":"package.json.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"package.json.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
package/package.json CHANGED
@@ -1,13 +1,14 @@
1
1
  {
2
2
  "name": "@backstage/plugin-devtools",
3
- "version": "0.1.35-next.1",
3
+ "version": "0.1.36-next.0",
4
4
  "backstage": {
5
5
  "role": "frontend-plugin",
6
6
  "pluginId": "devtools",
7
7
  "pluginPackages": [
8
8
  "@backstage/plugin-devtools",
9
9
  "@backstage/plugin-devtools-backend",
10
- "@backstage/plugin-devtools-common"
10
+ "@backstage/plugin-devtools-common",
11
+ "@backstage/plugin-devtools-react"
11
12
  ],
12
13
  "features": {
13
14
  "./alpha": "@backstage/FrontendPlugin"
@@ -64,13 +65,14 @@
64
65
  "test": "backstage-cli package test"
65
66
  },
66
67
  "dependencies": {
67
- "@backstage/core-compat-api": "0.5.6-next.0",
68
- "@backstage/core-components": "0.18.5-next.0",
69
- "@backstage/core-plugin-api": "1.12.1",
68
+ "@backstage/core-compat-api": "0.5.7-next.0",
69
+ "@backstage/core-components": "0.18.6-next.0",
70
+ "@backstage/core-plugin-api": "1.12.2-next.0",
70
71
  "@backstage/errors": "1.2.7",
71
- "@backstage/frontend-plugin-api": "0.13.2",
72
- "@backstage/plugin-devtools-common": "0.1.20",
73
- "@backstage/plugin-permission-react": "0.4.39",
72
+ "@backstage/frontend-plugin-api": "0.14.0-next.0",
73
+ "@backstage/plugin-devtools-common": "0.1.22-next.0",
74
+ "@backstage/plugin-devtools-react": "0.1.1-next.0",
75
+ "@backstage/plugin-permission-react": "0.4.40-next.0",
74
76
  "@material-ui/core": "^4.9.13",
75
77
  "@material-ui/icons": "^4.9.1",
76
78
  "@material-ui/lab": "^4.0.0-alpha.57",
@@ -79,8 +81,8 @@
79
81
  "react-use": "^17.2.4"
80
82
  },
81
83
  "devDependencies": {
82
- "@backstage/cli": "0.35.2-next.1",
83
- "@backstage/dev-utils": "1.1.19-next.2",
84
+ "@backstage/cli": "0.35.3-next.0",
85
+ "@backstage/dev-utils": "1.1.20-next.0",
84
86
  "@testing-library/jest-dom": "^6.0.0",
85
87
  "@types/lodash": "^4.14.151",
86
88
  "@types/react": "^18.0.0",