@backstage/plugin-scaffolder-react 1.12.1 → 1.13.0-next.1
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 +40 -2
- package/alpha/package.json +1 -1
- package/dist/alpha.d.ts +59 -2
- package/dist/alpha.esm.js +1 -0
- package/dist/alpha.esm.js.map +1 -1
- package/dist/api/ref.esm.js +1 -1
- package/dist/api/ref.esm.js.map +1 -1
- package/dist/hooks/useEventStream.esm.js +18 -7
- package/dist/hooks/useEventStream.esm.js.map +1 -1
- package/dist/index.d.ts +33 -3
- package/dist/index.esm.js +1 -0
- package/dist/index.esm.js.map +1 -1
- package/dist/next/blueprints/FormFieldBlueprint.esm.js +23 -0
- package/dist/next/blueprints/FormFieldBlueprint.esm.js.map +1 -0
- package/dist/next/components/ScaffolderPageContextMenu/ScaffolderPageContextMenu.esm.js +1 -1
- package/dist/next/components/ScaffolderPageContextMenu/ScaffolderPageContextMenu.esm.js.map +1 -1
- package/dist/packages/opaque-internal/src/OpaqueType.esm.js +103 -0
- package/dist/packages/opaque-internal/src/OpaqueType.esm.js.map +1 -0
- package/dist/packages/scaffolder-internal/src/wiring/InternalFormField.esm.js +6 -0
- package/dist/packages/scaffolder-internal/src/wiring/InternalFormField.esm.js.map +1 -0
- package/dist/utils.esm.js +19 -0
- package/dist/utils.esm.js.map +1 -0
- package/package.json +28 -18
package/CHANGELOG.md
CHANGED
|
@@ -1,11 +1,49 @@
|
|
|
1
1
|
# @backstage/plugin-scaffolder-react
|
|
2
2
|
|
|
3
|
-
## 1.
|
|
3
|
+
## 1.13.0-next.1
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- d851b5b: Renamed Template Editor to Manage Templates.
|
|
4
8
|
|
|
5
9
|
### Patch Changes
|
|
6
10
|
|
|
11
|
+
- e969dc7: Move `@types/react` to a peer dependency.
|
|
12
|
+
- 785d68f: Add support for pagination in scaffolder tasks list
|
|
7
13
|
- Updated dependencies
|
|
8
|
-
- @backstage/
|
|
14
|
+
- @backstage/core-components@0.15.1-next.1
|
|
15
|
+
- @backstage/frontend-plugin-api@0.9.0-next.1
|
|
16
|
+
- @backstage/core-plugin-api@1.10.0-next.1
|
|
17
|
+
- @backstage/plugin-permission-react@0.4.27-next.1
|
|
18
|
+
- @backstage/version-bridge@1.0.10-next.0
|
|
19
|
+
- @backstage/plugin-catalog-react@1.14.0-next.1
|
|
20
|
+
- @backstage/theme@0.5.8-next.0
|
|
21
|
+
- @backstage/catalog-client@1.7.0
|
|
22
|
+
- @backstage/catalog-model@1.7.0
|
|
23
|
+
- @backstage/types@1.1.1
|
|
24
|
+
- @backstage/plugin-scaffolder-common@1.5.6
|
|
25
|
+
|
|
26
|
+
## 1.13.0-next.0
|
|
27
|
+
|
|
28
|
+
### Minor Changes
|
|
29
|
+
|
|
30
|
+
- bf6eaf3: Added support for `FormFieldBlueprint` to create field extensions in the Scaffolder plugin
|
|
31
|
+
|
|
32
|
+
### Patch Changes
|
|
33
|
+
|
|
34
|
+
- 11e0752: Make it possible to manually retry the scaffolder template from the step it failed
|
|
35
|
+
- Updated dependencies
|
|
36
|
+
- @backstage/frontend-plugin-api@0.9.0-next.0
|
|
37
|
+
- @backstage/core-components@0.15.1-next.0
|
|
38
|
+
- @backstage/core-plugin-api@1.10.0-next.0
|
|
39
|
+
- @backstage/plugin-catalog-react@1.13.1-next.0
|
|
40
|
+
- @backstage/catalog-client@1.7.0
|
|
41
|
+
- @backstage/catalog-model@1.7.0
|
|
42
|
+
- @backstage/theme@0.5.7
|
|
43
|
+
- @backstage/types@1.1.1
|
|
44
|
+
- @backstage/version-bridge@1.0.9
|
|
45
|
+
- @backstage/plugin-permission-react@0.4.27-next.0
|
|
46
|
+
- @backstage/plugin-scaffolder-common@1.5.6
|
|
9
47
|
|
|
10
48
|
## 1.12.0
|
|
11
49
|
|
package/alpha/package.json
CHANGED
package/dist/alpha.d.ts
CHANGED
|
@@ -4,10 +4,12 @@ import * as React from 'react';
|
|
|
4
4
|
import React__default, { ComponentType, ReactNode, PropsWithChildren, ReactElement } from 'react';
|
|
5
5
|
import { TemplatePresentationV1beta3, TemplateEntityV1beta3, TaskStep } from '@backstage/plugin-scaffolder-common';
|
|
6
6
|
import { UiSchema, FieldValidation, WidgetProps } from '@rjsf/utils';
|
|
7
|
-
import { TemplateParameterSchema, FieldExtensionOptions, FormProps, ReviewStepProps, LayoutOptions, CustomFieldValidator, TemplateGroupFilter, ScaffolderTaskOutput, ScaffolderRJSFFormProps, ScaffolderStep } from '@backstage/plugin-scaffolder-react';
|
|
7
|
+
import { TemplateParameterSchema, FieldExtensionOptions, FormProps, ReviewStepProps, LayoutOptions, CustomFieldValidator, TemplateGroupFilter, ScaffolderTaskOutput, ScaffolderRJSFFormProps, ScaffolderStep, FieldExtensionComponentProps, FieldSchema } from '@backstage/plugin-scaffolder-react';
|
|
8
8
|
import { ApiHolder, IconComponent } from '@backstage/core-plugin-api';
|
|
9
9
|
import { Overrides } from '@material-ui/core/styles/overrides';
|
|
10
10
|
import { StyleRules } from '@material-ui/core/styles/withStyles';
|
|
11
|
+
import * as _backstage_frontend_plugin_api from '@backstage/frontend-plugin-api';
|
|
12
|
+
import { z } from 'zod';
|
|
11
13
|
|
|
12
14
|
/**
|
|
13
15
|
* This is the parsed template schema that is returned from the {@link useTemplateSchema} hook.
|
|
@@ -314,4 +316,59 @@ declare module '@backstage/theme' {
|
|
|
314
316
|
}
|
|
315
317
|
}
|
|
316
318
|
|
|
317
|
-
|
|
319
|
+
/*
|
|
320
|
+
* Copyright 2024 The Backstage Authors
|
|
321
|
+
*
|
|
322
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
323
|
+
* you may not use this file except in compliance with the License.
|
|
324
|
+
* You may obtain a copy of the License at
|
|
325
|
+
*
|
|
326
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
327
|
+
*
|
|
328
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
329
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
330
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
331
|
+
* See the License for the specific language governing permissions and
|
|
332
|
+
* limitations under the License.
|
|
333
|
+
*/
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
/** @alpha */
|
|
338
|
+
interface FormField {
|
|
339
|
+
readonly $$type: '@backstage/scaffolder/FormField';
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/** @alpha */
|
|
343
|
+
type FormFieldExtensionData<TReturnValue extends z.ZodType = z.ZodType, TUiOptions extends z.ZodType = z.ZodType> = {
|
|
344
|
+
name: string;
|
|
345
|
+
component: (props: FieldExtensionComponentProps<z.output<TReturnValue>, z.output<TUiOptions>>) => JSX.Element | null;
|
|
346
|
+
validation?: CustomFieldValidator<z.output<TReturnValue>, z.output<TUiOptions>>;
|
|
347
|
+
schema?: FieldSchema<z.output<TReturnValue>, z.output<TUiOptions>>;
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* @alpha
|
|
352
|
+
* Creates extensions that are Field Extensions for the Scaffolder
|
|
353
|
+
* */
|
|
354
|
+
declare const FormFieldBlueprint: _backstage_frontend_plugin_api.ExtensionBlueprint<{
|
|
355
|
+
kind: "scaffolder-form-field";
|
|
356
|
+
name: undefined;
|
|
357
|
+
params: {
|
|
358
|
+
field: () => Promise<FormField>;
|
|
359
|
+
};
|
|
360
|
+
output: _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<() => Promise<FormField>, "scaffolder.form-field-loader", {}>;
|
|
361
|
+
inputs: {};
|
|
362
|
+
config: {};
|
|
363
|
+
configInput: {};
|
|
364
|
+
dataRefs: {
|
|
365
|
+
formFieldLoader: _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<() => Promise<FormField>, "scaffolder.form-field-loader", {}>;
|
|
366
|
+
};
|
|
367
|
+
}>;
|
|
368
|
+
/**
|
|
369
|
+
* @alpha
|
|
370
|
+
* Used to create a form field binding with typechecking for compliance
|
|
371
|
+
*/
|
|
372
|
+
declare function createFormField<TReturnValue extends z.ZodType, TUiOptions extends z.ZodType>(opts: FormFieldExtensionData<TReturnValue, TUiOptions>): FormField;
|
|
373
|
+
|
|
374
|
+
export { type BackstageOverrides, DefaultTemplateOutputs, EmbeddableWorkflow, Form, FormFieldBlueprint, type FormFieldExtensionData, type FormValidation, type ParsedTemplateSchema, ReviewState, type ReviewStateProps, ScaffolderField, type ScaffolderFieldProps, ScaffolderPageContextMenu, type ScaffolderPageContextMenuProps, type ScaffolderReactComponentsNameToClassKey, type ScaffolderReactTemplateCategoryPickerClassKey, SecretWidget, Stepper, type StepperProps, TaskLogStream, TaskSteps, type TaskStepsProps, TemplateCard, type TemplateCardProps, TemplateCategoryPicker, TemplateGroup, type TemplateGroupProps, TemplateGroups, type TemplateGroupsProps, Workflow, type WorkflowProps, createAsyncValidators, createFieldValidation, createFormField, extractSchemaFromStep, useFilteredSchemaProperties, useFormDataFromQuery, useTemplateParameterSchema, useTemplateSchema };
|
package/dist/alpha.esm.js
CHANGED
|
@@ -18,4 +18,5 @@ export { useFormDataFromQuery } from './next/hooks/useFormDataFromQuery.esm.js';
|
|
|
18
18
|
export { useTemplateSchema } from './next/hooks/useTemplateSchema.esm.js';
|
|
19
19
|
export { useTemplateParameterSchema } from './next/hooks/useTemplateParameterSchema.esm.js';
|
|
20
20
|
export { useFilteredSchemaProperties } from './next/hooks/useFilteredSchemaProperties.esm.js';
|
|
21
|
+
export { FormFieldBlueprint, createFormField } from './next/blueprints/FormFieldBlueprint.esm.js';
|
|
21
22
|
//# sourceMappingURL=alpha.esm.js.map
|
package/dist/alpha.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"alpha.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"alpha.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;"}
|
package/dist/api/ref.esm.js
CHANGED
package/dist/api/ref.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ref.esm.js","sources":["../../src/api/ref.ts"],"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 { createApiRef } from '@backstage/
|
|
1
|
+
{"version":3,"file":"ref.esm.js","sources":["../../src/api/ref.ts"],"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 { createApiRef } from '@backstage/frontend-plugin-api';\nimport { ScaffolderApi } from './types';\n\n/** @public */\nexport const scaffolderApiRef = createApiRef<ScaffolderApi>({\n id: 'plugin.scaffolder.service',\n});\n"],"names":[],"mappings":";;AAoBO,MAAM,mBAAmB,YAA4B,CAAA;AAAA,EAC1D,EAAI,EAAA,2BAAA;AACN,CAAC;;;;"}
|
|
@@ -55,6 +55,10 @@ function reducer(draft, action) {
|
|
|
55
55
|
return;
|
|
56
56
|
}
|
|
57
57
|
case "RECOVERED": {
|
|
58
|
+
draft.cancelled = false;
|
|
59
|
+
draft.completed = false;
|
|
60
|
+
draft.output = void 0;
|
|
61
|
+
draft.error = void 0;
|
|
58
62
|
for (const stepId in draft.steps) {
|
|
59
63
|
if (draft.steps.hasOwnProperty(stepId)) {
|
|
60
64
|
draft.steps[stepId].startedAt = void 0;
|
|
@@ -88,13 +92,18 @@ const useTaskEventStream = (taskId) => {
|
|
|
88
92
|
let subscription;
|
|
89
93
|
let logPusher;
|
|
90
94
|
let retryCount = 1;
|
|
95
|
+
let isTaskRecoverable = false;
|
|
91
96
|
const startStreamLogProcess = () => scaffolderApi.getTask(taskId).then(
|
|
92
97
|
(task) => {
|
|
93
98
|
if (didCancel) {
|
|
94
99
|
return;
|
|
95
100
|
}
|
|
101
|
+
isTaskRecoverable = task.spec.EXPERIMENTAL_recovery?.EXPERIMENTAL_strategy === "startOver";
|
|
96
102
|
dispatch({ type: "INIT", data: task });
|
|
97
|
-
const observable = scaffolderApi.streamLogs({
|
|
103
|
+
const observable = scaffolderApi.streamLogs({
|
|
104
|
+
isTaskRecoverable,
|
|
105
|
+
taskId
|
|
106
|
+
});
|
|
98
107
|
const collectedLogEvents = new Array();
|
|
99
108
|
function emitLogs() {
|
|
100
109
|
if (collectedLogEvents.length) {
|
|
@@ -150,12 +159,14 @@ const useTaskEventStream = (taskId) => {
|
|
|
150
159
|
);
|
|
151
160
|
void startStreamLogProcess();
|
|
152
161
|
return () => {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
subscription
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
162
|
+
if (!isTaskRecoverable) {
|
|
163
|
+
didCancel = true;
|
|
164
|
+
if (subscription) {
|
|
165
|
+
subscription.unsubscribe();
|
|
166
|
+
}
|
|
167
|
+
if (logPusher) {
|
|
168
|
+
clearInterval(logPusher);
|
|
169
|
+
}
|
|
159
170
|
}
|
|
160
171
|
};
|
|
161
172
|
}, [scaffolderApi, dispatch, taskId]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useEventStream.esm.js","sources":["../../src/hooks/useEventStream.ts"],"sourcesContent":["/*\n * Copyright 2021 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 */\nimport { useImmerReducer } from 'use-immer';\nimport { useEffect } from 'react';\n\nimport { useApi } from '@backstage/core-plugin-api';\nimport { Subscription } from '@backstage/types';\nimport {\n LogEvent,\n scaffolderApiRef,\n ScaffolderTask,\n ScaffolderTaskOutput,\n ScaffolderTaskStatus,\n} from '../api';\n\n/**\n * The status of the step being processed\n *\n * @public\n */\nexport type ScaffolderStep = {\n id: string;\n status: ScaffolderTaskStatus;\n endedAt?: string;\n startedAt?: string;\n};\n\n/**\n * A task event from the event stream\n *\n * @public\n */\nexport type TaskStream = {\n cancelled: boolean;\n loading: boolean;\n error?: Error;\n stepLogs: { [stepId in string]: string[] };\n completed: boolean;\n task?: ScaffolderTask;\n steps: { [stepId in string]: ScaffolderStep };\n output?: ScaffolderTaskOutput;\n};\n\ntype ReducerLogEntry = {\n createdAt: string;\n body: {\n stepId?: string;\n status?: ScaffolderTaskStatus;\n message: string;\n output?: ScaffolderTaskOutput;\n error?: Error;\n recoverStrategy?: 'none' | 'startOver';\n };\n};\n\ntype ReducerAction =\n | { type: 'INIT'; data: ScaffolderTask }\n | { type: 'CANCELLED' }\n | { type: 'RECOVERED'; data: ReducerLogEntry }\n | { type: 'LOGS'; data: ReducerLogEntry[] }\n | { type: 'COMPLETED'; data: ReducerLogEntry }\n | { type: 'ERROR'; data: Error };\n\nfunction reducer(draft: TaskStream, action: ReducerAction) {\n switch (action.type) {\n case 'INIT': {\n draft.steps = action.data.spec.steps.reduce((current, next) => {\n current[next.id] = { status: 'open', id: next.id };\n return current;\n }, {} as { [stepId in string]: ScaffolderStep });\n draft.stepLogs = action.data.spec.steps.reduce((current, next) => {\n current[next.id] = [];\n return current;\n }, {} as { [stepId in string]: string[] });\n draft.loading = false;\n draft.error = undefined;\n draft.completed = false;\n draft.task = action.data;\n return;\n }\n\n case 'LOGS': {\n const entries = action.data;\n const logLines = [];\n\n for (const entry of entries) {\n const logLine = `${entry.createdAt} ${entry.body.message}`;\n logLines.push(logLine);\n\n if (!entry.body.stepId || !draft.steps?.[entry.body.stepId]) {\n continue;\n }\n\n const currentStepLog = draft.stepLogs?.[entry.body.stepId];\n const currentStep = draft.steps?.[entry.body.stepId];\n\n if (currentStep) {\n if (entry.body.status && entry.body.status !== currentStep.status) {\n currentStep.status = entry.body.status;\n\n if (currentStep.status === 'processing') {\n currentStep.startedAt = entry.createdAt;\n }\n\n if (\n ['cancelled', 'completed', 'failed'].includes(currentStep.status)\n ) {\n currentStep.endedAt = entry.createdAt;\n }\n }\n }\n\n currentStepLog?.push(logLine);\n }\n\n return;\n }\n\n case 'COMPLETED': {\n draft.completed = true;\n draft.output = action.data.body.output;\n draft.error = action.data.body.error;\n\n return;\n }\n\n case 'CANCELLED': {\n draft.cancelled = true;\n return;\n }\n\n case 'RECOVERED': {\n for (const stepId in draft.steps) {\n if (draft.steps.hasOwnProperty(stepId)) {\n draft.steps[stepId].startedAt = undefined;\n draft.steps[stepId].endedAt = undefined;\n draft.steps[stepId].status = 'open';\n }\n }\n return;\n }\n\n case 'ERROR': {\n draft.error = action.data;\n draft.loading = false;\n draft.completed = true;\n return;\n }\n\n default:\n return;\n }\n}\n\n/**\n * A hook to stream the logs of a task being processed\n *\n * @public\n */\nexport const useTaskEventStream = (taskId: string): TaskStream => {\n const scaffolderApi = useApi(scaffolderApiRef);\n const [state, dispatch] = useImmerReducer(reducer, {\n cancelled: false,\n loading: true,\n completed: false,\n stepLogs: {} as { [stepId in string]: string[] },\n steps: {} as { [stepId in string]: ScaffolderStep },\n });\n\n useEffect(() => {\n let didCancel = false;\n let subscription: Subscription | undefined;\n let logPusher: NodeJS.Timeout | undefined;\n let retryCount = 1;\n const startStreamLogProcess = () =>\n scaffolderApi.getTask(taskId).then(\n task => {\n if (didCancel) {\n return;\n }\n dispatch({ type: 'INIT', data: task });\n\n // TODO(blam): Use a normal fetch to fetch the current log for the event stream\n // and use that for an INIT_EVENTs dispatch event, and then\n // use the last event ID to subscribe using after option to\n // stream logs. Without this, if you have a lot of logs, it can look like the\n // task is being rebuilt on load as it progresses through the steps at a slower\n // rate whilst it builds the status from the event logs\n const observable = scaffolderApi.streamLogs({ taskId });\n\n const collectedLogEvents = new Array<LogEvent>();\n\n function emitLogs() {\n if (collectedLogEvents.length) {\n const logs = collectedLogEvents.splice(\n 0,\n collectedLogEvents.length,\n );\n dispatch({ type: 'LOGS', data: logs });\n }\n }\n\n logPusher = setInterval(emitLogs, 500);\n\n subscription = observable.subscribe({\n next: event => {\n retryCount = 1;\n switch (event.type) {\n case 'log':\n return collectedLogEvents.push(event);\n case 'cancelled':\n dispatch({ type: 'CANCELLED' });\n return undefined;\n case 'completion':\n emitLogs();\n dispatch({ type: 'COMPLETED', data: event });\n return undefined;\n case 'recovered':\n dispatch({ type: 'RECOVERED', data: event });\n return undefined;\n default:\n throw new Error(\n `Unhandled event type ${event.type} in observer`,\n );\n }\n },\n error: error => {\n emitLogs();\n // in some cases the error is a refused connection from backend\n // this can happen from internet issues or proxy problems\n // so we try to reconnect again after some time\n // just to restart the fetch process\n // details here https://github.com/backstage/backstage/issues/15002\n\n const maxRetries = 3;\n\n if (!error.message) {\n error.message = `We cannot connect at the moment, trying again in some seconds... Retrying (${\n retryCount > maxRetries ? maxRetries : retryCount\n }/${maxRetries} retries)`;\n }\n\n setTimeout(() => {\n retryCount += 1;\n void startStreamLogProcess();\n }, 15000);\n\n dispatch({ type: 'ERROR', data: error });\n },\n });\n },\n error => {\n if (!didCancel) {\n dispatch({ type: 'ERROR', data: error });\n }\n },\n );\n void startStreamLogProcess();\n return () => {\n didCancel = true;\n if (subscription) {\n subscription.unsubscribe();\n }\n if (logPusher) {\n clearInterval(logPusher);\n }\n };\n }, [scaffolderApi, dispatch, taskId]);\n\n return state;\n};\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useEventStream.esm.js","sources":["../../src/hooks/useEventStream.ts"],"sourcesContent":["/*\n * Copyright 2021 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 */\nimport { useImmerReducer } from 'use-immer';\nimport { useEffect } from 'react';\n\nimport { useApi } from '@backstage/core-plugin-api';\nimport { Subscription } from '@backstage/types';\nimport {\n LogEvent,\n scaffolderApiRef,\n ScaffolderTask,\n ScaffolderTaskOutput,\n ScaffolderTaskStatus,\n} from '../api';\n\n/**\n * The status of the step being processed\n *\n * @public\n */\nexport type ScaffolderStep = {\n id: string;\n status: ScaffolderTaskStatus;\n endedAt?: string;\n startedAt?: string;\n};\n\n/**\n * A task event from the event stream\n *\n * @public\n */\nexport type TaskStream = {\n cancelled: boolean;\n loading: boolean;\n error?: Error;\n stepLogs: { [stepId in string]: string[] };\n completed: boolean;\n task?: ScaffolderTask;\n steps: { [stepId in string]: ScaffolderStep };\n output?: ScaffolderTaskOutput;\n};\n\ntype ReducerLogEntry = {\n createdAt: string;\n body: {\n stepId?: string;\n status?: ScaffolderTaskStatus;\n message: string;\n output?: ScaffolderTaskOutput;\n error?: Error;\n recoverStrategy?: 'none' | 'startOver';\n };\n};\n\ntype ReducerAction =\n | { type: 'INIT'; data: ScaffolderTask }\n | { type: 'CANCELLED' }\n | { type: 'RECOVERED'; data: ReducerLogEntry }\n | { type: 'LOGS'; data: ReducerLogEntry[] }\n | { type: 'COMPLETED'; data: ReducerLogEntry }\n | { type: 'ERROR'; data: Error };\n\nfunction reducer(draft: TaskStream, action: ReducerAction) {\n switch (action.type) {\n case 'INIT': {\n draft.steps = action.data.spec.steps.reduce((current, next) => {\n current[next.id] = { status: 'open', id: next.id };\n return current;\n }, {} as { [stepId in string]: ScaffolderStep });\n draft.stepLogs = action.data.spec.steps.reduce((current, next) => {\n current[next.id] = [];\n return current;\n }, {} as { [stepId in string]: string[] });\n draft.loading = false;\n draft.error = undefined;\n draft.completed = false;\n draft.task = action.data;\n return;\n }\n\n case 'LOGS': {\n const entries = action.data;\n const logLines = [];\n\n for (const entry of entries) {\n const logLine = `${entry.createdAt} ${entry.body.message}`;\n logLines.push(logLine);\n\n if (!entry.body.stepId || !draft.steps?.[entry.body.stepId]) {\n continue;\n }\n\n const currentStepLog = draft.stepLogs?.[entry.body.stepId];\n const currentStep = draft.steps?.[entry.body.stepId];\n\n if (currentStep) {\n if (entry.body.status && entry.body.status !== currentStep.status) {\n currentStep.status = entry.body.status;\n\n if (currentStep.status === 'processing') {\n currentStep.startedAt = entry.createdAt;\n }\n\n if (\n ['cancelled', 'completed', 'failed'].includes(currentStep.status)\n ) {\n currentStep.endedAt = entry.createdAt;\n }\n }\n }\n\n currentStepLog?.push(logLine);\n }\n\n return;\n }\n\n case 'COMPLETED': {\n draft.completed = true;\n draft.output = action.data.body.output;\n draft.error = action.data.body.error;\n\n return;\n }\n\n case 'CANCELLED': {\n draft.cancelled = true;\n return;\n }\n\n case 'RECOVERED': {\n draft.cancelled = false;\n draft.completed = false;\n draft.output = undefined;\n draft.error = undefined;\n\n for (const stepId in draft.steps) {\n if (draft.steps.hasOwnProperty(stepId)) {\n draft.steps[stepId].startedAt = undefined;\n draft.steps[stepId].endedAt = undefined;\n draft.steps[stepId].status = 'open';\n }\n }\n return;\n }\n\n case 'ERROR': {\n draft.error = action.data;\n draft.loading = false;\n draft.completed = true;\n return;\n }\n\n default:\n return;\n }\n}\n\n/**\n * A hook to stream the logs of a task being processed\n *\n * @public\n */\nexport const useTaskEventStream = (taskId: string): TaskStream => {\n const scaffolderApi = useApi(scaffolderApiRef);\n const [state, dispatch] = useImmerReducer(reducer, {\n cancelled: false,\n loading: true,\n completed: false,\n stepLogs: {} as { [stepId in string]: string[] },\n steps: {} as { [stepId in string]: ScaffolderStep },\n });\n\n useEffect(() => {\n let didCancel = false;\n let subscription: Subscription | undefined;\n let logPusher: NodeJS.Timeout | undefined;\n let retryCount = 1;\n let isTaskRecoverable = false;\n const startStreamLogProcess = () =>\n scaffolderApi.getTask(taskId).then(\n task => {\n if (didCancel) {\n return;\n }\n isTaskRecoverable =\n task.spec.EXPERIMENTAL_recovery?.EXPERIMENTAL_strategy ===\n 'startOver';\n dispatch({ type: 'INIT', data: task });\n\n // TODO(blam): Use a normal fetch to fetch the current log for the event stream\n // and use that for an INIT_EVENTs dispatch event, and then\n // use the last event ID to subscribe using after option to\n // stream logs. Without this, if you have a lot of logs, it can look like the\n // task is being rebuilt on load as it progresses through the steps at a slower\n // rate whilst it builds the status from the event logs\n const observable = scaffolderApi.streamLogs({\n isTaskRecoverable,\n taskId,\n });\n\n const collectedLogEvents = new Array<LogEvent>();\n\n function emitLogs() {\n if (collectedLogEvents.length) {\n const logs = collectedLogEvents.splice(\n 0,\n collectedLogEvents.length,\n );\n dispatch({ type: 'LOGS', data: logs });\n }\n }\n\n logPusher = setInterval(emitLogs, 500);\n\n subscription = observable.subscribe({\n next: event => {\n retryCount = 1;\n switch (event.type) {\n case 'log':\n return collectedLogEvents.push(event);\n case 'cancelled':\n dispatch({ type: 'CANCELLED' });\n return undefined;\n case 'completion':\n emitLogs();\n dispatch({ type: 'COMPLETED', data: event });\n return undefined;\n case 'recovered':\n dispatch({ type: 'RECOVERED', data: event });\n return undefined;\n default:\n throw new Error(\n `Unhandled event type ${event.type} in observer`,\n );\n }\n },\n error: error => {\n emitLogs();\n // in some cases the error is a refused connection from backend\n // this can happen from internet issues or proxy problems\n // so we try to reconnect again after some time\n // just to restart the fetch process\n // details here https://github.com/backstage/backstage/issues/15002\n\n const maxRetries = 3;\n\n if (!error.message) {\n error.message = `We cannot connect at the moment, trying again in some seconds... Retrying (${\n retryCount > maxRetries ? maxRetries : retryCount\n }/${maxRetries} retries)`;\n }\n\n setTimeout(() => {\n retryCount += 1;\n void startStreamLogProcess();\n }, 15000);\n\n dispatch({ type: 'ERROR', data: error });\n },\n });\n },\n error => {\n if (!didCancel) {\n dispatch({ type: 'ERROR', data: error });\n }\n },\n );\n void startStreamLogProcess();\n return () => {\n if (!isTaskRecoverable) {\n didCancel = true;\n if (subscription) {\n subscription.unsubscribe();\n }\n if (logPusher) {\n clearInterval(logPusher);\n }\n }\n };\n }, [scaffolderApi, dispatch, taskId]);\n\n return state;\n};\n"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
|
-
import * as _backstage_core_plugin_api from '@backstage/core-plugin-api';
|
|
3
2
|
import { ApiHolder, Extension } from '@backstage/core-plugin-api';
|
|
4
3
|
import React__default, { HTMLAttributes, ReactNode, FormEvent, ElementType, Ref, ComponentType, PropsWithChildren } from 'react';
|
|
5
4
|
import { JsonObject, JsonValue, Observable } from '@backstage/types';
|
|
@@ -7,6 +6,8 @@ import { JSONSchema7 } from 'json-schema';
|
|
|
7
6
|
import { StrictRJSFSchema, RJSFSchema, FormContextType, GenericObjectType, UiSchema, IdSchema, ErrorSchema, Registry, ValidatorType, TemplatesType, RegistryWidgetsType, RJSFValidationError, CustomValidator, ErrorTransformer, Experimental_DefaultFormStateBehavior, UIOptionsType, FieldValidation } from '@rjsf/utils';
|
|
8
7
|
import Form, { IChangeEvent, FormProps as FormProps$1 } from '@rjsf/core';
|
|
9
8
|
import { TemplateEntityV1beta3, TemplatePresentationV1beta3, TaskSpec, TaskStep } from '@backstage/plugin-scaffolder-common';
|
|
9
|
+
import * as _backstage_frontend_plugin_api from '@backstage/frontend-plugin-api';
|
|
10
|
+
import { z } from 'zod';
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* The props for the `Field` components
|
|
@@ -499,6 +500,7 @@ interface ScaffolderGetIntegrationsListResponse {
|
|
|
499
500
|
* @public
|
|
500
501
|
*/
|
|
501
502
|
interface ScaffolderStreamLogsOptions {
|
|
503
|
+
isTaskRecoverable?: boolean;
|
|
502
504
|
taskId: string;
|
|
503
505
|
after?: number;
|
|
504
506
|
}
|
|
@@ -544,10 +546,19 @@ interface ScaffolderApi {
|
|
|
544
546
|
* @param taskId - the id of the task
|
|
545
547
|
*/
|
|
546
548
|
cancelTask(taskId: string): Promise<void>;
|
|
549
|
+
/**
|
|
550
|
+
* Starts the task again from the point where it failed.
|
|
551
|
+
*
|
|
552
|
+
* @param taskId - the id of the task
|
|
553
|
+
*/
|
|
554
|
+
retry?(taskId: string): Promise<void>;
|
|
547
555
|
listTasks?(options: {
|
|
548
556
|
filterByOwnership: 'owned' | 'all';
|
|
557
|
+
limit?: number;
|
|
558
|
+
offset?: number;
|
|
549
559
|
}): Promise<{
|
|
550
560
|
tasks: ScaffolderTask[];
|
|
561
|
+
totalTasks?: number;
|
|
551
562
|
}>;
|
|
552
563
|
getIntegrationsList(options: ScaffolderGetIntegrationsListOptions): Promise<ScaffolderGetIntegrationsListResponse>;
|
|
553
564
|
/**
|
|
@@ -569,7 +580,7 @@ interface ScaffolderApi {
|
|
|
569
580
|
}
|
|
570
581
|
|
|
571
582
|
/** @public */
|
|
572
|
-
declare const scaffolderApiRef:
|
|
583
|
+
declare const scaffolderApiRef: _backstage_frontend_plugin_api.ApiRef<ScaffolderApi>;
|
|
573
584
|
|
|
574
585
|
/**
|
|
575
586
|
* Hook that returns all custom field extensions from the current outlet.
|
|
@@ -653,4 +664,23 @@ type TaskStream = {
|
|
|
653
664
|
*/
|
|
654
665
|
declare const useTaskEventStream: (taskId: string) => TaskStream;
|
|
655
666
|
|
|
656
|
-
|
|
667
|
+
/** @public */
|
|
668
|
+
declare function makeFieldSchema<TReturnType extends z.ZodType, TUiOptions extends z.ZodType>(options: {
|
|
669
|
+
output: (zImpl: typeof z) => TReturnType;
|
|
670
|
+
uiOptions?: (zImpl: typeof z) => TUiOptions;
|
|
671
|
+
}): FieldSchema<z.output<TReturnType>, z.output<TUiOptions>>;
|
|
672
|
+
/**
|
|
673
|
+
* @public
|
|
674
|
+
* FieldSchema encapsulates a JSONSchema7 along with the
|
|
675
|
+
* matching FieldExtensionComponentProps type for a field extension.
|
|
676
|
+
*/
|
|
677
|
+
interface FieldSchema<TReturn, TUiOptions> {
|
|
678
|
+
/** @deprecated use TProps instead */
|
|
679
|
+
readonly type: FieldExtensionComponentProps<TReturn, TUiOptions>;
|
|
680
|
+
/** @deprecated will be removed */
|
|
681
|
+
readonly uiOptionsType: TUiOptions;
|
|
682
|
+
readonly schema: CustomFieldExtensionSchema;
|
|
683
|
+
readonly TProps: FieldExtensionComponentProps<TReturn, TUiOptions>;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
export { type Action, type ActionExample, type CustomFieldExtensionSchema, type CustomFieldValidator, type FieldExtensionComponent, type FieldExtensionComponentProps, type FieldExtensionOptions, type FieldExtensionUiSchema, type FieldSchema, type FormProps, type LayoutComponent, type LayoutOptions, type LayoutTemplate, type ListActionsResponse, type LogEvent, type ReviewStepProps, type ScaffolderApi, type ScaffolderDryRunOptions, type ScaffolderDryRunResponse, ScaffolderFieldExtensions, type ScaffolderGetIntegrationsListOptions, type ScaffolderGetIntegrationsListResponse, ScaffolderLayouts, type ScaffolderOutputLink, type ScaffolderOutputText, type ScaffolderRJSFField, type ScaffolderRJSFFieldProps, type ScaffolderRJSFFormProps, type ScaffolderRJSFRegistryFieldsType, type ScaffolderScaffoldOptions, type ScaffolderScaffoldResponse, type ScaffolderStep, type ScaffolderStreamLogsOptions, type ScaffolderTask, type ScaffolderTaskOutput, type ScaffolderTaskStatus, type ScaffolderUseTemplateSecrets, SecretsContextProvider, type TaskStream, type TemplateGroupFilter, type TemplateParameterSchema, createScaffolderFieldExtension, createScaffolderLayout, makeFieldSchema, scaffolderApiRef, useCustomFieldExtensions, useCustomLayouts, useTaskEventStream, useTemplateSecrets };
|
package/dist/index.esm.js
CHANGED
|
@@ -5,4 +5,5 @@ export { useCustomFieldExtensions } from './hooks/useCustomFieldExtensions.esm.j
|
|
|
5
5
|
export { useCustomLayouts } from './hooks/useCustomLayouts.esm.js';
|
|
6
6
|
export { useTaskEventStream } from './hooks/useEventStream.esm.js';
|
|
7
7
|
export { ScaffolderLayouts, createScaffolderLayout } from './layouts/createScaffolderLayout.esm.js';
|
|
8
|
+
export { makeFieldSchema } from './utils.esm.js';
|
|
8
9
|
//# sourceMappingURL=index.esm.js.map
|
package/dist/index.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { createExtensionDataRef, createExtensionBlueprint } from '@backstage/frontend-plugin-api';
|
|
2
|
+
import { OpaqueFormField } from '../../packages/scaffolder-internal/src/wiring/InternalFormField.esm.js';
|
|
3
|
+
|
|
4
|
+
const formFieldExtensionDataRef = createExtensionDataRef().with({
|
|
5
|
+
id: "scaffolder.form-field-loader"
|
|
6
|
+
});
|
|
7
|
+
const FormFieldBlueprint = createExtensionBlueprint({
|
|
8
|
+
kind: "scaffolder-form-field",
|
|
9
|
+
attachTo: { id: "api:scaffolder/form-fields", input: "formFields" },
|
|
10
|
+
dataRefs: {
|
|
11
|
+
formFieldLoader: formFieldExtensionDataRef
|
|
12
|
+
},
|
|
13
|
+
output: [formFieldExtensionDataRef],
|
|
14
|
+
*factory(params) {
|
|
15
|
+
yield formFieldExtensionDataRef(params.field);
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
function createFormField(opts) {
|
|
19
|
+
return OpaqueFormField.createInstance("v1", opts);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export { FormFieldBlueprint, createFormField };
|
|
23
|
+
//# sourceMappingURL=FormFieldBlueprint.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FormFieldBlueprint.esm.js","sources":["../../../src/next/blueprints/FormFieldBlueprint.tsx"],"sourcesContent":["/*\n * Copyright 2024 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 */\nimport {\n createExtensionBlueprint,\n createExtensionDataRef,\n} from '@backstage/frontend-plugin-api';\nimport { z } from 'zod';\n\nimport { OpaqueFormField, FormField } from '@internal/scaffolder';\nimport { FormFieldExtensionData } from './types';\n\nconst formFieldExtensionDataRef = createExtensionDataRef<\n () => Promise<FormField>\n>().with({\n id: 'scaffolder.form-field-loader',\n});\n\n/**\n * @alpha\n * Creates extensions that are Field Extensions for the Scaffolder\n * */\nexport const FormFieldBlueprint = createExtensionBlueprint({\n kind: 'scaffolder-form-field',\n attachTo: { id: 'api:scaffolder/form-fields', input: 'formFields' },\n dataRefs: {\n formFieldLoader: formFieldExtensionDataRef,\n },\n output: [formFieldExtensionDataRef],\n *factory(params: { field: () => Promise<FormField> }) {\n yield formFieldExtensionDataRef(params.field);\n },\n});\n\n/**\n * @alpha\n * Used to create a form field binding with typechecking for compliance\n */\nexport function createFormField<\n TReturnValue extends z.ZodType,\n TUiOptions extends z.ZodType,\n>(opts: FormFieldExtensionData<TReturnValue, TUiOptions>): FormField {\n return OpaqueFormField.createInstance('v1', opts);\n}\n"],"names":[],"mappings":";;;AAwBA,MAAM,yBAAA,GAA4B,sBAEhC,EAAA,CAAE,IAAK,CAAA;AAAA,EACP,EAAI,EAAA,8BAAA;AACN,CAAC,CAAA,CAAA;AAMM,MAAM,qBAAqB,wBAAyB,CAAA;AAAA,EACzD,IAAM,EAAA,uBAAA;AAAA,EACN,QAAU,EAAA,EAAE,EAAI,EAAA,4BAAA,EAA8B,OAAO,YAAa,EAAA;AAAA,EAClE,QAAU,EAAA;AAAA,IACR,eAAiB,EAAA,yBAAA;AAAA,GACnB;AAAA,EACA,MAAA,EAAQ,CAAC,yBAAyB,CAAA;AAAA,EAClC,CAAC,QAAQ,MAA6C,EAAA;AACpD,IAAM,MAAA,yBAAA,CAA0B,OAAO,KAAK,CAAA,CAAA;AAAA,GAC9C;AACF,CAAC,EAAA;AAMM,SAAS,gBAGd,IAAmE,EAAA;AACnE,EAAO,OAAA,eAAA,CAAgB,cAAe,CAAA,IAAA,EAAM,IAAI,CAAA,CAAA;AAClD;;;;"}
|
|
@@ -55,7 +55,7 @@ function ScaffolderPageContextMenu(props) {
|
|
|
55
55
|
anchorOrigin: { vertical: "bottom", horizontal: "right" },
|
|
56
56
|
transformOrigin: { vertical: "top", horizontal: "right" }
|
|
57
57
|
},
|
|
58
|
-
/* @__PURE__ */ React.createElement(MenuList, null, onCreateClicked && /* @__PURE__ */ React.createElement(MenuItem, { onClick: onCreateClicked }, /* @__PURE__ */ React.createElement(ListItemIcon, null, /* @__PURE__ */ React.createElement(CreateComponentIcon, { fontSize: "small" })), /* @__PURE__ */ React.createElement(ListItemText, { primary: "Create" })), onEditorClicked && /* @__PURE__ */ React.createElement(MenuItem, { onClick: onEditorClicked }, /* @__PURE__ */ React.createElement(ListItemIcon, null, /* @__PURE__ */ React.createElement(Edit, { fontSize: "small" })), /* @__PURE__ */ React.createElement(ListItemText, { primary: "
|
|
58
|
+
/* @__PURE__ */ React.createElement(MenuList, null, onCreateClicked && /* @__PURE__ */ React.createElement(MenuItem, { onClick: onCreateClicked }, /* @__PURE__ */ React.createElement(ListItemIcon, null, /* @__PURE__ */ React.createElement(CreateComponentIcon, { fontSize: "small" })), /* @__PURE__ */ React.createElement(ListItemText, { primary: "Create" })), onEditorClicked && /* @__PURE__ */ React.createElement(MenuItem, { onClick: onEditorClicked }, /* @__PURE__ */ React.createElement(ListItemIcon, null, /* @__PURE__ */ React.createElement(Edit, { fontSize: "small" })), /* @__PURE__ */ React.createElement(ListItemText, { primary: "Manage Templates" })), onActionsClicked && /* @__PURE__ */ React.createElement(MenuItem, { onClick: onActionsClicked }, /* @__PURE__ */ React.createElement(ListItemIcon, null, /* @__PURE__ */ React.createElement(DescriptionIcon, { fontSize: "small" })), /* @__PURE__ */ React.createElement(ListItemText, { primary: "Installed Actions" })), onTasksClicked && /* @__PURE__ */ React.createElement(MenuItem, { onClick: onTasksClicked }, /* @__PURE__ */ React.createElement(ListItemIcon, null, /* @__PURE__ */ React.createElement(List, { fontSize: "small" })), /* @__PURE__ */ React.createElement(ListItemText, { primary: "Task List" })))
|
|
59
59
|
));
|
|
60
60
|
}
|
|
61
61
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScaffolderPageContextMenu.esm.js","sources":["../../../../src/next/components/ScaffolderPageContextMenu/ScaffolderPageContextMenu.tsx"],"sourcesContent":["/*\n * Copyright 2020 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 IconButton from '@material-ui/core/IconButton';\nimport ListItemIcon from '@material-ui/core/ListItemIcon';\nimport ListItemText from '@material-ui/core/ListItemText';\nimport MenuItem from '@material-ui/core/MenuItem';\nimport MenuList from '@material-ui/core/MenuList';\nimport Popover from '@material-ui/core/Popover';\nimport CreateComponentIcon from '@material-ui/icons/AddCircleOutline';\nimport { makeStyles } from '@material-ui/core/styles';\nimport Description from '@material-ui/icons/Description';\nimport Edit from '@material-ui/icons/Edit';\nimport List from '@material-ui/icons/List';\nimport MoreVert from '@material-ui/icons/MoreVert';\nimport React, { useState } from 'react';\n\nconst useStyles = makeStyles(theme => ({\n button: {\n color: theme.page.fontColor,\n },\n}));\n\n/**\n * @alpha\n */\nexport type ScaffolderPageContextMenuProps = {\n onEditorClicked?: () => void;\n onActionsClicked?: () => void;\n onTasksClicked?: () => void;\n onCreateClicked?: () => void;\n};\n\n/**\n * @alpha\n */\nexport function ScaffolderPageContextMenu(\n props: ScaffolderPageContextMenuProps,\n) {\n const { onEditorClicked, onActionsClicked, onTasksClicked, onCreateClicked } =\n props;\n const classes = useStyles();\n const [anchorEl, setAnchorEl] = useState<HTMLButtonElement>();\n\n if (!onEditorClicked && !onActionsClicked) {\n return null;\n }\n\n const onOpen = (event: React.SyntheticEvent<HTMLButtonElement>) => {\n setAnchorEl(event.currentTarget);\n };\n\n const onClose = () => {\n setAnchorEl(undefined);\n };\n\n return (\n <>\n <IconButton\n id=\"long-menu\"\n aria-label=\"more\"\n aria-controls=\"long-menu\"\n aria-expanded={!!anchorEl}\n aria-haspopup=\"true\"\n role=\"button\"\n onClick={onOpen}\n data-testid=\"menu-button\"\n color=\"inherit\"\n className={classes.button}\n >\n <MoreVert />\n </IconButton>\n <Popover\n aria-labelledby=\"long-menu\"\n open={Boolean(anchorEl)}\n onClose={onClose}\n anchorEl={anchorEl}\n anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}\n transformOrigin={{ vertical: 'top', horizontal: 'right' }}\n >\n <MenuList>\n {onCreateClicked && (\n <MenuItem onClick={onCreateClicked}>\n <ListItemIcon>\n <CreateComponentIcon fontSize=\"small\" />\n </ListItemIcon>\n <ListItemText primary=\"Create\" />\n </MenuItem>\n )}\n {onEditorClicked && (\n <MenuItem onClick={onEditorClicked}>\n <ListItemIcon>\n <Edit fontSize=\"small\" />\n </ListItemIcon>\n <ListItemText primary=\"
|
|
1
|
+
{"version":3,"file":"ScaffolderPageContextMenu.esm.js","sources":["../../../../src/next/components/ScaffolderPageContextMenu/ScaffolderPageContextMenu.tsx"],"sourcesContent":["/*\n * Copyright 2020 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 IconButton from '@material-ui/core/IconButton';\nimport ListItemIcon from '@material-ui/core/ListItemIcon';\nimport ListItemText from '@material-ui/core/ListItemText';\nimport MenuItem from '@material-ui/core/MenuItem';\nimport MenuList from '@material-ui/core/MenuList';\nimport Popover from '@material-ui/core/Popover';\nimport CreateComponentIcon from '@material-ui/icons/AddCircleOutline';\nimport { makeStyles } from '@material-ui/core/styles';\nimport Description from '@material-ui/icons/Description';\nimport Edit from '@material-ui/icons/Edit';\nimport List from '@material-ui/icons/List';\nimport MoreVert from '@material-ui/icons/MoreVert';\nimport React, { useState } from 'react';\n\nconst useStyles = makeStyles(theme => ({\n button: {\n color: theme.page.fontColor,\n },\n}));\n\n/**\n * @alpha\n */\nexport type ScaffolderPageContextMenuProps = {\n onEditorClicked?: () => void;\n onActionsClicked?: () => void;\n onTasksClicked?: () => void;\n onCreateClicked?: () => void;\n};\n\n/**\n * @alpha\n */\nexport function ScaffolderPageContextMenu(\n props: ScaffolderPageContextMenuProps,\n) {\n const { onEditorClicked, onActionsClicked, onTasksClicked, onCreateClicked } =\n props;\n const classes = useStyles();\n const [anchorEl, setAnchorEl] = useState<HTMLButtonElement>();\n\n if (!onEditorClicked && !onActionsClicked) {\n return null;\n }\n\n const onOpen = (event: React.SyntheticEvent<HTMLButtonElement>) => {\n setAnchorEl(event.currentTarget);\n };\n\n const onClose = () => {\n setAnchorEl(undefined);\n };\n\n return (\n <>\n <IconButton\n id=\"long-menu\"\n aria-label=\"more\"\n aria-controls=\"long-menu\"\n aria-expanded={!!anchorEl}\n aria-haspopup=\"true\"\n role=\"button\"\n onClick={onOpen}\n data-testid=\"menu-button\"\n color=\"inherit\"\n className={classes.button}\n >\n <MoreVert />\n </IconButton>\n <Popover\n aria-labelledby=\"long-menu\"\n open={Boolean(anchorEl)}\n onClose={onClose}\n anchorEl={anchorEl}\n anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}\n transformOrigin={{ vertical: 'top', horizontal: 'right' }}\n >\n <MenuList>\n {onCreateClicked && (\n <MenuItem onClick={onCreateClicked}>\n <ListItemIcon>\n <CreateComponentIcon fontSize=\"small\" />\n </ListItemIcon>\n <ListItemText primary=\"Create\" />\n </MenuItem>\n )}\n {onEditorClicked && (\n <MenuItem onClick={onEditorClicked}>\n <ListItemIcon>\n <Edit fontSize=\"small\" />\n </ListItemIcon>\n <ListItemText primary=\"Manage Templates\" />\n </MenuItem>\n )}\n {onActionsClicked && (\n <MenuItem onClick={onActionsClicked}>\n <ListItemIcon>\n <Description fontSize=\"small\" />\n </ListItemIcon>\n <ListItemText primary=\"Installed Actions\" />\n </MenuItem>\n )}\n {onTasksClicked && (\n <MenuItem onClick={onTasksClicked}>\n <ListItemIcon>\n <List fontSize=\"small\" />\n </ListItemIcon>\n <ListItemText primary=\"Task List\" />\n </MenuItem>\n )}\n </MenuList>\n </Popover>\n </>\n );\n}\n"],"names":["Description"],"mappings":"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"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
class OpaqueType {
|
|
2
|
+
/**
|
|
3
|
+
* Creates a new opaque type.
|
|
4
|
+
*
|
|
5
|
+
* @param options.type The type identifier of the opaque type
|
|
6
|
+
* @param options.versions The available versions of the opaque type
|
|
7
|
+
* @returns A new opaque type helper
|
|
8
|
+
*/
|
|
9
|
+
static create(options) {
|
|
10
|
+
return new OpaqueType(options.type, new Set(options.versions));
|
|
11
|
+
}
|
|
12
|
+
#type;
|
|
13
|
+
#versions;
|
|
14
|
+
constructor(type, versions) {
|
|
15
|
+
this.#type = type;
|
|
16
|
+
this.#versions = versions;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The internal version of the opaque type, used like this: `typeof MyOpaqueType.TPublic`
|
|
20
|
+
*
|
|
21
|
+
* @remarks
|
|
22
|
+
*
|
|
23
|
+
* This property is only useful for type checking, its runtime value is `undefined`.
|
|
24
|
+
*/
|
|
25
|
+
TPublic = void 0;
|
|
26
|
+
/**
|
|
27
|
+
* The internal version of the opaque type, used like this: `typeof MyOpaqueType.TInternal`
|
|
28
|
+
*
|
|
29
|
+
* @remarks
|
|
30
|
+
*
|
|
31
|
+
* This property is only useful for type checking, its runtime value is `undefined`.
|
|
32
|
+
*/
|
|
33
|
+
TInternal = void 0;
|
|
34
|
+
/**
|
|
35
|
+
* @param value Input value expected to be an instance of this opaque type
|
|
36
|
+
* @returns True if the value matches this opaque type
|
|
37
|
+
*/
|
|
38
|
+
isType = (value) => {
|
|
39
|
+
return this.#isThisInternalType(value);
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* @param value Input value expected to be an instance of this opaque type
|
|
43
|
+
* @throws If the value is not an instance of this opaque type or is of an unsupported version
|
|
44
|
+
* @returns The internal version of the opaque type
|
|
45
|
+
*/
|
|
46
|
+
toInternal = (value) => {
|
|
47
|
+
if (!this.#isThisInternalType(value)) {
|
|
48
|
+
throw new TypeError(
|
|
49
|
+
`Invalid opaque type, expected '${this.#type}', but got '${this.#stringifyUnknown(value)}'`
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
if (!this.#versions.has(value.version)) {
|
|
53
|
+
const versions = Array.from(this.#versions).map(this.#stringifyVersion);
|
|
54
|
+
if (versions.length > 1) {
|
|
55
|
+
versions[versions.length - 1] = `or ${versions[versions.length - 1]}`;
|
|
56
|
+
}
|
|
57
|
+
const expected = versions.length > 2 ? versions.join(", ") : versions.join(" ");
|
|
58
|
+
throw new TypeError(
|
|
59
|
+
`Invalid opaque type instance, got version ${this.#stringifyVersion(
|
|
60
|
+
value.version
|
|
61
|
+
)}, expected ${expected}`
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
return value;
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Creates an instance of the opaque type, returning the public type.
|
|
68
|
+
*
|
|
69
|
+
* @param version The version of the instance to create
|
|
70
|
+
* @param value The remaining public and internal properties of the instance
|
|
71
|
+
* @returns An instance of the opaque type
|
|
72
|
+
*/
|
|
73
|
+
createInstance(version, props) {
|
|
74
|
+
return Object.assign(props, {
|
|
75
|
+
$$type: this.#type,
|
|
76
|
+
...version && { version }
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
#isThisInternalType(value) {
|
|
80
|
+
if (value === null || typeof value !== "object") {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
return value.$$type === this.#type;
|
|
84
|
+
}
|
|
85
|
+
#stringifyUnknown(value) {
|
|
86
|
+
if (typeof value !== "object") {
|
|
87
|
+
return `<${typeof value}>`;
|
|
88
|
+
}
|
|
89
|
+
if (value === null) {
|
|
90
|
+
return "<null>";
|
|
91
|
+
}
|
|
92
|
+
if ("$$type" in value) {
|
|
93
|
+
return String(value.$$type);
|
|
94
|
+
}
|
|
95
|
+
return String(value);
|
|
96
|
+
}
|
|
97
|
+
#stringifyVersion = (version) => {
|
|
98
|
+
return version ? `'${version}'` : "undefined";
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export { OpaqueType };
|
|
103
|
+
//# sourceMappingURL=OpaqueType.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OpaqueType.esm.js","sources":["../../../../../../packages/opaque-internal/src/OpaqueType.ts"],"sourcesContent":["/*\n * Copyright 2024 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\n// TODO(Rugvip): This lives here temporarily, but should be moved to a more\n// central location. It's useful for backend packages too so we'll need to have\n// it in a common package, but it might also be that we want to make it\n// available publicly too in which case it would make sense to have this be part\n// of @backstage/version-bridge. The problem with exporting it from there is\n// that it would need to be very stable at that point, so it might be a bit\n// early to put it there already.\n\n/**\n * A helper for working with opaque types.\n */\nexport class OpaqueType<\n T extends {\n public: { $$type: string };\n versions: { version: string | undefined };\n },\n> {\n /**\n * Creates a new opaque type.\n *\n * @param options.type The type identifier of the opaque type\n * @param options.versions The available versions of the opaque type\n * @returns A new opaque type helper\n */\n static create<\n T extends {\n public: { $$type: string };\n versions: { version: string | undefined };\n },\n >(options: {\n type: T['public']['$$type'];\n versions: Array<T['versions']['version']>;\n }) {\n return new OpaqueType<T>(options.type, new Set(options.versions));\n }\n\n #type: string;\n #versions: Set<string | undefined>;\n\n private constructor(type: string, versions: Set<string | undefined>) {\n this.#type = type;\n this.#versions = versions;\n }\n\n /**\n * The internal version of the opaque type, used like this: `typeof MyOpaqueType.TPublic`\n *\n * @remarks\n *\n * This property is only useful for type checking, its runtime value is `undefined`.\n */\n TPublic: T['public'] = undefined as any;\n\n /**\n * The internal version of the opaque type, used like this: `typeof MyOpaqueType.TInternal`\n *\n * @remarks\n *\n * This property is only useful for type checking, its runtime value is `undefined`.\n */\n TInternal: T['public'] & T['versions'] = undefined as any;\n\n /**\n * @param value Input value expected to be an instance of this opaque type\n * @returns True if the value matches this opaque type\n */\n isType = (value: unknown): value is T['public'] => {\n return this.#isThisInternalType(value);\n };\n\n /**\n * @param value Input value expected to be an instance of this opaque type\n * @throws If the value is not an instance of this opaque type or is of an unsupported version\n * @returns The internal version of the opaque type\n */\n toInternal = (value: unknown): T['public'] & T['versions'] => {\n if (!this.#isThisInternalType(value)) {\n throw new TypeError(\n `Invalid opaque type, expected '${\n this.#type\n }', but got '${this.#stringifyUnknown(value)}'`,\n );\n }\n\n if (!this.#versions.has(value.version)) {\n const versions = Array.from(this.#versions).map(this.#stringifyVersion);\n if (versions.length > 1) {\n versions[versions.length - 1] = `or ${versions[versions.length - 1]}`;\n }\n const expected =\n versions.length > 2 ? versions.join(', ') : versions.join(' ');\n throw new TypeError(\n `Invalid opaque type instance, got version ${this.#stringifyVersion(\n value.version,\n )}, expected ${expected}`,\n );\n }\n\n return value;\n };\n\n /**\n * Creates an instance of the opaque type, returning the public type.\n *\n * @param version The version of the instance to create\n * @param value The remaining public and internal properties of the instance\n * @returns An instance of the opaque type\n */\n createInstance<\n TVersion extends T['versions']['version'],\n TPublic extends T['public'],\n >(\n version: TVersion,\n props: Omit<T['public'], '$$type'> &\n (T['versions'] extends infer UVersion\n ? UVersion extends { version: TVersion }\n ? Omit<UVersion, 'version'>\n : never\n : never) &\n Object, // & Object to allow for object properties too, e.g. toString()\n ): TPublic {\n return Object.assign(props as object, {\n $$type: this.#type,\n ...(version && { version }),\n }) as unknown as TPublic;\n }\n\n #isThisInternalType(value: unknown): value is T['public'] & T['versions'] {\n if (value === null || typeof value !== 'object') {\n return false;\n }\n return (value as T['public']).$$type === this.#type;\n }\n\n #stringifyUnknown(value: unknown) {\n if (typeof value !== 'object') {\n return `<${typeof value}>`;\n }\n if (value === null) {\n return '<null>';\n }\n if ('$$type' in value) {\n return String(value.$$type);\n }\n return String(value);\n }\n\n #stringifyVersion = (version: string | undefined) => {\n return version ? `'${version}'` : 'undefined';\n };\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { OpaqueType } from '../../../opaque-internal/src/OpaqueType.esm.js';
|
|
2
|
+
|
|
3
|
+
const OpaqueFormField = OpaqueType.create({ type: "@backstage/scaffolder/FormField", versions: ["v1"] });
|
|
4
|
+
|
|
5
|
+
export { OpaqueFormField };
|
|
6
|
+
//# sourceMappingURL=InternalFormField.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InternalFormField.esm.js","sources":["../../../../../../../packages/scaffolder-internal/src/wiring/InternalFormField.ts"],"sourcesContent":["/*\n * Copyright 2024 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 { OpaqueType } from '@internal/opaque';\nimport { z } from 'zod';\n\nimport { FormFieldExtensionData } from '@backstage/plugin-scaffolder-react/alpha';\n\n/** @alpha */\nexport interface FormField {\n readonly $$type: '@backstage/scaffolder/FormField';\n}\n\n/** @alpha */\nexport const OpaqueFormField = OpaqueType.create<{\n public: FormField;\n versions: FormFieldExtensionData<z.ZodType, z.ZodType> & {\n readonly version: 'v1';\n };\n}>({ type: '@backstage/scaffolder/FormField', versions: ['v1'] });\n"],"names":[],"mappings":";;AA2Ba,MAAA,eAAA,GAAkB,UAAW,CAAA,MAAA,CAKvC,EAAE,IAAA,EAAM,mCAAmC,QAAU,EAAA,CAAC,IAAI,CAAA,EAAG;;;;"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import zodToJsonSchema from 'zod-to-json-schema';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
function makeFieldSchema(options) {
|
|
5
|
+
const { output, uiOptions } = options;
|
|
6
|
+
return {
|
|
7
|
+
TProps: void 0,
|
|
8
|
+
schema: {
|
|
9
|
+
returnValue: zodToJsonSchema(output(z)),
|
|
10
|
+
uiOptions: uiOptions && zodToJsonSchema(uiOptions(z))
|
|
11
|
+
},
|
|
12
|
+
// These will be removed - just here for backwards compat whilst we're moving across
|
|
13
|
+
type: void 0,
|
|
14
|
+
uiOptionsType: void 0
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export { makeFieldSchema };
|
|
19
|
+
//# sourceMappingURL=utils.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.esm.js","sources":["../src/utils.ts"],"sourcesContent":["/*\n * Copyright 2024 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 zodToJsonSchema from 'zod-to-json-schema';\nimport { JSONSchema7 } from 'json-schema';\nimport { z } from 'zod';\nimport {\n CustomFieldExtensionSchema,\n FieldExtensionComponentProps,\n} from './extensions';\n\n/** @public */\nexport function makeFieldSchema<\n TReturnType extends z.ZodType,\n TUiOptions extends z.ZodType,\n>(options: {\n output: (zImpl: typeof z) => TReturnType;\n uiOptions?: (zImpl: typeof z) => TUiOptions;\n}): FieldSchema<z.output<TReturnType>, z.output<TUiOptions>> {\n const { output, uiOptions } = options;\n return {\n TProps: undefined as any,\n schema: {\n returnValue: zodToJsonSchema(output(z)) as JSONSchema7,\n uiOptions: uiOptions && (zodToJsonSchema(uiOptions(z)) as JSONSchema7),\n },\n\n // These will be removed - just here for backwards compat whilst we're moving across\n type: undefined as any,\n uiOptionsType: undefined as any,\n };\n}\n\n/**\n * @public\n * FieldSchema encapsulates a JSONSchema7 along with the\n * matching FieldExtensionComponentProps type for a field extension.\n */\nexport interface FieldSchema<TReturn, TUiOptions> {\n /** @deprecated use TProps instead */\n readonly type: FieldExtensionComponentProps<TReturn, TUiOptions>;\n /** @deprecated will be removed */\n readonly uiOptionsType: TUiOptions;\n\n readonly schema: CustomFieldExtensionSchema;\n readonly TProps: FieldExtensionComponentProps<TReturn, TUiOptions>;\n}\n"],"names":[],"mappings":";;;AAyBO,SAAS,gBAGd,OAG2D,EAAA;AAC3D,EAAM,MAAA,EAAE,MAAQ,EAAA,SAAA,EAAc,GAAA,OAAA,CAAA;AAC9B,EAAO,OAAA;AAAA,IACL,MAAQ,EAAA,KAAA,CAAA;AAAA,IACR,MAAQ,EAAA;AAAA,MACN,WAAa,EAAA,eAAA,CAAgB,MAAO,CAAA,CAAC,CAAC,CAAA;AAAA,MACtC,SAAW,EAAA,SAAA,IAAc,eAAgB,CAAA,SAAA,CAAU,CAAC,CAAC,CAAA;AAAA,KACvD;AAAA;AAAA,IAGA,IAAM,EAAA,KAAA,CAAA;AAAA,IACN,aAAe,EAAA,KAAA,CAAA;AAAA,GACjB,CAAA;AACF;;;;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/plugin-scaffolder-react",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.13.0-next.1",
|
|
4
4
|
"description": "A frontend library that helps other Backstage plugins interact with the Scaffolder",
|
|
5
5
|
"backstage": {
|
|
6
6
|
"role": "web-library",
|
|
@@ -57,16 +57,17 @@
|
|
|
57
57
|
"test": "backstage-cli package test"
|
|
58
58
|
},
|
|
59
59
|
"dependencies": {
|
|
60
|
-
"@backstage/catalog-client": "
|
|
61
|
-
"@backstage/catalog-model": "
|
|
62
|
-
"@backstage/core-components": "
|
|
63
|
-
"@backstage/core-plugin-api": "
|
|
64
|
-
"@backstage/plugin-
|
|
65
|
-
"@backstage/plugin-
|
|
66
|
-
"@backstage/plugin-
|
|
67
|
-
"@backstage/
|
|
68
|
-
"@backstage/
|
|
69
|
-
"@backstage/
|
|
60
|
+
"@backstage/catalog-client": "1.7.0",
|
|
61
|
+
"@backstage/catalog-model": "1.7.0",
|
|
62
|
+
"@backstage/core-components": "0.15.1-next.1",
|
|
63
|
+
"@backstage/core-plugin-api": "1.10.0-next.1",
|
|
64
|
+
"@backstage/frontend-plugin-api": "0.9.0-next.1",
|
|
65
|
+
"@backstage/plugin-catalog-react": "1.14.0-next.1",
|
|
66
|
+
"@backstage/plugin-permission-react": "0.4.27-next.1",
|
|
67
|
+
"@backstage/plugin-scaffolder-common": "1.5.6",
|
|
68
|
+
"@backstage/theme": "0.5.8-next.0",
|
|
69
|
+
"@backstage/types": "1.1.1",
|
|
70
|
+
"@backstage/version-bridge": "1.0.10-next.0",
|
|
70
71
|
"@material-ui/core": "^4.12.2",
|
|
71
72
|
"@material-ui/icons": "^4.9.1",
|
|
72
73
|
"@material-ui/lab": "4.0.0-alpha.61",
|
|
@@ -76,7 +77,6 @@
|
|
|
76
77
|
"@rjsf/utils": "5.21.1",
|
|
77
78
|
"@rjsf/validator-ajv8": "5.21.1",
|
|
78
79
|
"@types/json-schema": "^7.0.9",
|
|
79
|
-
"@types/react": "^16.13.1 || ^17.0.0 || ^18.0.0",
|
|
80
80
|
"ajv-errors": "^3.0.0",
|
|
81
81
|
"classnames": "^2.2.6",
|
|
82
82
|
"flatted": "3.3.1",
|
|
@@ -93,24 +93,34 @@
|
|
|
93
93
|
"zod-to-json-schema": "^3.20.4"
|
|
94
94
|
},
|
|
95
95
|
"devDependencies": {
|
|
96
|
-
"@backstage/cli": "
|
|
97
|
-
"@backstage/core-app-api": "
|
|
98
|
-
"@backstage/plugin-catalog": "
|
|
99
|
-
"@backstage/plugin-catalog-common": "
|
|
100
|
-
"@backstage/plugin-permission-common": "
|
|
101
|
-
"@backstage/test-utils": "
|
|
96
|
+
"@backstage/cli": "0.28.0-next.1",
|
|
97
|
+
"@backstage/core-app-api": "1.15.1-next.1",
|
|
98
|
+
"@backstage/plugin-catalog": "1.24.0-next.1",
|
|
99
|
+
"@backstage/plugin-catalog-common": "1.1.0",
|
|
100
|
+
"@backstage/plugin-permission-common": "0.8.1",
|
|
101
|
+
"@backstage/test-utils": "1.6.1-next.1",
|
|
102
102
|
"@testing-library/dom": "^10.0.0",
|
|
103
103
|
"@testing-library/jest-dom": "^6.0.0",
|
|
104
104
|
"@testing-library/react": "^16.0.0",
|
|
105
105
|
"@testing-library/user-event": "^14.0.0",
|
|
106
106
|
"@types/humanize-duration": "^3.18.1",
|
|
107
107
|
"@types/luxon": "^3.0.0",
|
|
108
|
+
"@types/react": "^18.0.0",
|
|
109
|
+
"react": "^18.0.2",
|
|
110
|
+
"react-dom": "^18.0.2",
|
|
111
|
+
"react-router-dom": "^6.3.0",
|
|
108
112
|
"swr": "^2.0.0"
|
|
109
113
|
},
|
|
110
114
|
"peerDependencies": {
|
|
115
|
+
"@types/react": "^16.13.1 || ^17.0.0 || ^18.0.0",
|
|
111
116
|
"react": "^16.13.1 || ^17.0.0 || ^18.0.0",
|
|
112
117
|
"react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0",
|
|
113
118
|
"react-router-dom": "6.0.0-beta.0 || ^6.3.0"
|
|
114
119
|
},
|
|
120
|
+
"peerDependenciesMeta": {
|
|
121
|
+
"@types/react": {
|
|
122
|
+
"optional": true
|
|
123
|
+
}
|
|
124
|
+
},
|
|
115
125
|
"module": "./dist/index.esm.js"
|
|
116
126
|
}
|