@backstage/plugin-scaffolder-react 2.1.0-next.1 → 2.1.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,27 @@
1
1
  # @backstage/plugin-scaffolder-react
2
2
 
3
+ ## 2.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 5ff93bf: Added functionality to register a Template Outputs Component in the new frontend system.
8
+
9
+ ### Patch Changes
10
+
11
+ - 736d84e: Use locale-insensitive Unicode casing for consistent string handling across environments.
12
+ - ffaca06: Fixed several issues with scaffolder task event stream reconnection: retry timers are now properly cancelled on cleanup, concurrent reconnect attempts are guarded against, and tab visibility changes reconnect the stream using the last seen event cursor without re-fetching the task.
13
+ - 7c1019c: Fixed the scaffolder wizard not scrolling to the top on step change when the app uses the new frontend system (no `<main>` element).
14
+ - Updated dependencies
15
+ - @backstage/core-components@0.18.14
16
+ - @backstage/plugin-scaffolder-common@2.3.0
17
+ - @backstage/ui@0.18.0
18
+ - @backstage/catalog-client@1.16.2
19
+ - @backstage/catalog-model@1.10.1
20
+ - @backstage/plugin-catalog-react@3.2.3
21
+ - @backstage/frontend-plugin-api@0.18.1
22
+ - @backstage/core-plugin-api@1.12.10
23
+ - @backstage/plugin-permission-react@0.5.5
24
+
3
25
  ## 2.1.0-next.1
4
26
 
5
27
  ### Patch Changes
@@ -70,6 +70,11 @@ function reducer(draft, action) {
70
70
  }
71
71
  return;
72
72
  }
73
+ case "RECONNECTING": {
74
+ draft.error = void 0;
75
+ draft.completed = false;
76
+ return;
77
+ }
73
78
  case "ERROR": {
74
79
  draft.error = action.data;
75
80
  draft.loading = false;
@@ -93,84 +98,144 @@ const useTaskEventStream = (taskId) => {
93
98
  let didCancel = false;
94
99
  let subscription;
95
100
  let logPusher;
101
+ let retryTimer;
96
102
  let retryCount = 1;
97
103
  let isTaskRecoverable = false;
98
- const startStreamLogProcess = () => scaffolderApi.getTask(taskId).then(
99
- (task) => {
100
- if (didCancel) {
101
- return;
104
+ let lastSeenEventId;
105
+ let isStreamComplete = false;
106
+ let hasInitialized = false;
107
+ let startGeneration = 0;
108
+ let currentEmitLogs;
109
+ const cleanUpStream = () => {
110
+ currentEmitLogs?.();
111
+ currentEmitLogs = void 0;
112
+ if (subscription) {
113
+ subscription.unsubscribe();
114
+ subscription = void 0;
115
+ }
116
+ if (logPusher) {
117
+ clearInterval(logPusher);
118
+ logPusher = void 0;
119
+ }
120
+ if (retryTimer) {
121
+ clearTimeout(retryTimer);
122
+ retryTimer = void 0;
123
+ }
124
+ };
125
+ function reconnectStream() {
126
+ dispatch({ type: "RECONNECTING" });
127
+ const generation = ++startGeneration;
128
+ cleanUpStream();
129
+ subscribeToStream(generation);
130
+ }
131
+ function subscribeToStream(generation) {
132
+ const observable = scaffolderApi.streamLogs({
133
+ isTaskRecoverable,
134
+ taskId,
135
+ after: lastSeenEventId
136
+ });
137
+ const collectedLogEvents = new Array();
138
+ function emitLogs() {
139
+ if (collectedLogEvents.length) {
140
+ const logs = collectedLogEvents.splice(0, collectedLogEvents.length);
141
+ dispatch({ type: "LOGS", data: logs });
102
142
  }
103
- isTaskRecoverable = task.spec.EXPERIMENTAL_recovery?.EXPERIMENTAL_strategy === "startOver";
104
- dispatch({ type: "INIT", data: task });
105
- const observable = scaffolderApi.streamLogs({
106
- isTaskRecoverable,
107
- taskId
108
- });
109
- const collectedLogEvents = new Array();
110
- function emitLogs() {
111
- if (collectedLogEvents.length) {
112
- const logs = collectedLogEvents.splice(
113
- 0,
114
- collectedLogEvents.length
115
- );
116
- dispatch({ type: "LOGS", data: logs });
143
+ }
144
+ currentEmitLogs = emitLogs;
145
+ logPusher = setInterval(emitLogs, 500);
146
+ subscription = observable.subscribe({
147
+ next: (event) => {
148
+ retryCount = 1;
149
+ if (event.id !== void 0) {
150
+ lastSeenEventId = event.id;
151
+ }
152
+ switch (event.type) {
153
+ case "log":
154
+ return collectedLogEvents.push(event);
155
+ case "cancelled":
156
+ if (!isTaskRecoverable) {
157
+ isStreamComplete = true;
158
+ }
159
+ emitLogs();
160
+ dispatch({ type: "CANCELLED" });
161
+ if (isStreamComplete) {
162
+ cleanUpStream();
163
+ }
164
+ return void 0;
165
+ case "completion":
166
+ if (!isTaskRecoverable) {
167
+ isStreamComplete = true;
168
+ }
169
+ emitLogs();
170
+ dispatch({ type: "COMPLETED", data: event });
171
+ if (isStreamComplete) {
172
+ cleanUpStream();
173
+ }
174
+ return void 0;
175
+ case "recovered":
176
+ isStreamComplete = false;
177
+ dispatch({ type: "RECOVERED", data: event });
178
+ return void 0;
179
+ default:
180
+ throw new Error(`Unhandled event type ${event.type} in observer`);
181
+ }
182
+ },
183
+ error: (error) => {
184
+ cleanUpStream();
185
+ if (isStreamComplete || generation !== startGeneration || didCancel) {
186
+ return;
187
+ }
188
+ const maxRetries = 3;
189
+ if (!error.message) {
190
+ error.message = `We cannot connect at the moment, trying again in some seconds... Retrying (${retryCount > maxRetries ? maxRetries : retryCount}/${maxRetries} retries)`;
117
191
  }
192
+ retryTimer = setTimeout(() => {
193
+ retryTimer = void 0;
194
+ retryCount += 1;
195
+ reconnectStream();
196
+ }, 15e3);
197
+ dispatch({ type: "ERROR", data: error });
118
198
  }
119
- logPusher = setInterval(emitLogs, 500);
120
- subscription = observable.subscribe({
121
- next: (event) => {
122
- retryCount = 1;
123
- switch (event.type) {
124
- case "log":
125
- return collectedLogEvents.push(event);
126
- case "cancelled":
127
- dispatch({ type: "CANCELLED" });
128
- return void 0;
129
- case "completion":
130
- emitLogs();
131
- dispatch({ type: "COMPLETED", data: event });
132
- return void 0;
133
- case "recovered":
134
- dispatch({ type: "RECOVERED", data: event });
135
- return void 0;
136
- default:
137
- throw new Error(
138
- `Unhandled event type ${event.type} in observer`
139
- );
140
- }
141
- },
142
- error: (error) => {
143
- emitLogs();
144
- const maxRetries = 3;
145
- if (!error.message) {
146
- error.message = `We cannot connect at the moment, trying again in some seconds... Retrying (${retryCount > maxRetries ? maxRetries : retryCount}/${maxRetries} retries)`;
147
- }
148
- setTimeout(() => {
149
- retryCount += 1;
150
- void startStreamLogProcess();
151
- }, 15e3);
199
+ });
200
+ }
201
+ const startStreamLogProcess = () => {
202
+ const generation = ++startGeneration;
203
+ cleanUpStream();
204
+ return scaffolderApi.getTask(taskId).then(
205
+ (task) => {
206
+ if (didCancel || generation !== startGeneration) {
207
+ return;
208
+ }
209
+ isTaskRecoverable = task.spec.EXPERIMENTAL_recovery?.EXPERIMENTAL_strategy === "startOver";
210
+ hasInitialized = true;
211
+ dispatch({ type: "INIT", data: task });
212
+ subscribeToStream(generation);
213
+ },
214
+ (error) => {
215
+ if (!didCancel && generation === startGeneration) {
152
216
  dispatch({ type: "ERROR", data: error });
153
217
  }
154
- });
155
- },
156
- (error) => {
157
- if (!didCancel) {
158
- dispatch({ type: "ERROR", data: error });
159
218
  }
160
- }
161
- );
219
+ );
220
+ };
162
221
  void startStreamLogProcess();
163
- return () => {
164
- if (!isTaskRecoverable) {
165
- didCancel = true;
166
- if (subscription) {
167
- subscription.unsubscribe();
168
- }
169
- if (logPusher) {
170
- clearInterval(logPusher);
171
- }
222
+ const onVisibilityChange = () => {
223
+ if (didCancel || isStreamComplete) return;
224
+ if (document.hidden) {
225
+ startGeneration++;
226
+ cleanUpStream();
227
+ } else if (hasInitialized) {
228
+ reconnectStream();
229
+ } else {
230
+ void startStreamLogProcess();
172
231
  }
173
232
  };
233
+ document.addEventListener("visibilitychange", onVisibilityChange);
234
+ return () => {
235
+ didCancel = true;
236
+ cleanUpStream();
237
+ document.removeEventListener("visibilitychange", onVisibilityChange);
238
+ };
174
239
  }, [scaffolderApi, dispatch, taskId]);
175
240
  return state;
176
241
  };
@@ -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 ScaffolderTaskStatus,\n ScaffolderTaskOutput,\n ScaffolderTask,\n LogEvent,\n} from '@backstage/plugin-scaffolder-common';\nimport { scaffolderApiRef } 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.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 // only set loading as false once we have logs,\n // otherwise things flicker from pending to loaded.\n if (draft.loading && entries.length > 0) {\n draft.loading = false;\n }\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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"}
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 ScaffolderTaskStatus,\n ScaffolderTaskOutput,\n ScaffolderTask,\n LogEvent,\n} from '@backstage/plugin-scaffolder-common';\nimport { scaffolderApiRef } 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: 'RECONNECTING' }\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.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 // only set loading as false once we have logs,\n // otherwise things flicker from pending to loaded.\n if (draft.loading && entries.length > 0) {\n draft.loading = false;\n }\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 'RECONNECTING': {\n draft.error = undefined;\n draft.completed = false;\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 retryTimer: ReturnType<typeof setTimeout> | undefined;\n let retryCount = 1;\n let isTaskRecoverable = false;\n let lastSeenEventId: number | undefined;\n let isStreamComplete = false;\n let hasInitialized = false;\n let startGeneration = 0;\n let currentEmitLogs: (() => void) | undefined;\n\n const cleanUpStream = () => {\n currentEmitLogs?.();\n currentEmitLogs = undefined;\n if (subscription) {\n subscription.unsubscribe();\n subscription = undefined;\n }\n if (logPusher) {\n clearInterval(logPusher);\n logPusher = undefined;\n }\n if (retryTimer) {\n clearTimeout(retryTimer);\n retryTimer = undefined;\n }\n };\n\n function reconnectStream() {\n dispatch({ type: 'RECONNECTING' });\n const generation = ++startGeneration;\n cleanUpStream();\n subscribeToStream(generation);\n }\n\n function subscribeToStream(generation: number) {\n const observable = scaffolderApi.streamLogs({\n isTaskRecoverable,\n taskId,\n after: lastSeenEventId,\n });\n\n const collectedLogEvents = new Array<LogEvent>();\n\n function emitLogs() {\n if (collectedLogEvents.length) {\n const logs = collectedLogEvents.splice(0, collectedLogEvents.length);\n dispatch({ type: 'LOGS', data: logs });\n }\n }\n\n currentEmitLogs = emitLogs;\n logPusher = setInterval(emitLogs, 500);\n\n subscription = observable.subscribe({\n next: event => {\n retryCount = 1;\n if (event.id !== undefined) {\n lastSeenEventId = event.id;\n }\n switch (event.type) {\n case 'log':\n return collectedLogEvents.push(event);\n case 'cancelled':\n if (!isTaskRecoverable) {\n isStreamComplete = true;\n }\n emitLogs();\n dispatch({ type: 'CANCELLED' });\n if (isStreamComplete) {\n cleanUpStream();\n }\n return undefined;\n case 'completion':\n if (!isTaskRecoverable) {\n isStreamComplete = true;\n }\n emitLogs();\n dispatch({ type: 'COMPLETED', data: event });\n if (isStreamComplete) {\n cleanUpStream();\n }\n return undefined;\n case 'recovered':\n isStreamComplete = false;\n dispatch({ type: 'RECOVERED', data: event });\n return undefined;\n default:\n throw new Error(`Unhandled event type ${event.type} in observer`);\n }\n },\n error: error => {\n cleanUpStream();\n\n if (isStreamComplete || generation !== startGeneration || didCancel) {\n return;\n }\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 retryTimer = setTimeout(() => {\n retryTimer = undefined;\n retryCount += 1;\n reconnectStream();\n }, 15000);\n\n dispatch({ type: 'ERROR', data: error });\n },\n });\n }\n\n const startStreamLogProcess = () => {\n const generation = ++startGeneration;\n cleanUpStream();\n\n return scaffolderApi.getTask(taskId).then(\n task => {\n if (didCancel || generation !== startGeneration) {\n return;\n }\n isTaskRecoverable =\n task.spec.EXPERIMENTAL_recovery?.EXPERIMENTAL_strategy ===\n 'startOver';\n\n hasInitialized = true;\n dispatch({ type: 'INIT', data: task });\n subscribeToStream(generation);\n },\n error => {\n if (!didCancel && generation === startGeneration) {\n dispatch({ type: 'ERROR', data: error });\n }\n },\n );\n };\n void startStreamLogProcess();\n\n const onVisibilityChange = () => {\n if (didCancel || isStreamComplete) return;\n if (document.hidden) {\n startGeneration++;\n cleanUpStream();\n } else if (hasInitialized) {\n reconnectStream();\n } else {\n void startStreamLogProcess();\n }\n };\n document.addEventListener('visibilitychange', onVisibilityChange);\n\n return () => {\n didCancel = true;\n cleanUpStream();\n document.removeEventListener('visibilitychange', onVisibilityChange);\n };\n }, [scaffolderApi, dispatch, taskId]);\n\n return state;\n};\n"],"names":[],"mappings":"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"}
@@ -20,7 +20,7 @@ function processSchema(key, value, schema, formState) {
20
20
  return [];
21
21
  }
22
22
  }
23
- if (definitionInSchema["ui:widget"] === "password" || definitionInSchema["ui:field"]?.toLocaleLowerCase("en-us") === "secret") {
23
+ if (definitionInSchema["ui:widget"] === "password" || definitionInSchema["ui:field"]?.toLowerCase() === "secret") {
24
24
  return [[name, "******"]];
25
25
  }
26
26
  if (definitionInSchema.enum && definitionInSchema.enumNames) {
@@ -1 +1 @@
1
- {"version":3,"file":"ReviewState.esm.js","sources":["../../../../src/next/components/ReviewState/ReviewState.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 */\nimport { StructuredMetadataTable } from '@backstage/core-components';\nimport { JsonObject, JsonValue } from '@backstage/types';\nimport { Draft07 as JSONSchema } from 'json-schema-library';\nimport { ParsedTemplateSchema } from '../../hooks/useTemplateSchema';\nimport { isJsonObject, formatKey, findSchemaForKey } from './util';\n\n/**\n * The props for the {@link ReviewState} component.\n * @alpha\n */\nexport type ReviewStateProps = {\n schemas: ParsedTemplateSchema[];\n formState: JsonObject;\n};\n\nfunction processSchema(\n key: string,\n value: JsonValue | undefined,\n schema: ParsedTemplateSchema,\n formState: JsonObject,\n): [string, JsonValue | undefined][] {\n const parsedSchema = new JSONSchema(schema.mergedSchema);\n const definitionInSchema = parsedSchema.getSchema({\n pointer: `#/${key}`,\n data: formState,\n });\n\n const name =\n definitionInSchema?.['ui:backstage']?.review?.name ??\n definitionInSchema?.title ??\n formatKey(key);\n\n if (definitionInSchema) {\n const backstageReviewOptions = definitionInSchema['ui:backstage']?.review;\n if (backstageReviewOptions) {\n if (backstageReviewOptions.mask) {\n return [[name, backstageReviewOptions.mask]];\n }\n if (backstageReviewOptions.show === false) {\n return [];\n }\n }\n\n if (\n definitionInSchema['ui:widget'] === 'password' ||\n definitionInSchema['ui:field']?.toLocaleLowerCase('en-us') === 'secret'\n ) {\n return [[name, '******']];\n }\n\n if (definitionInSchema.enum && definitionInSchema.enumNames) {\n return [\n [\n name,\n definitionInSchema.enumNames[\n definitionInSchema.enum.indexOf(value)\n ] || value,\n ],\n ];\n }\n\n if (backstageReviewOptions?.explode !== false && isJsonObject(value)) {\n // Recurse nested objects\n return Object.entries(value).flatMap(([nestedKey, nestedValue]) =>\n processSchema(`${key}/${nestedKey}`, nestedValue, schema, formState),\n );\n }\n }\n\n return [[name, value]];\n}\n\n/**\n * The component used by the {@link Stepper} to render the review step.\n * @alpha\n */\nexport const ReviewState = (props: ReviewStateProps) => {\n const reviewData = Object.fromEntries(\n Object.entries(props.formState)\n .flatMap(([key, value]) => {\n const schema = findSchemaForKey(key, props.schemas, props.formState);\n return schema\n ? processSchema(key, value, schema, props.formState)\n : [[formatKey(key), value]];\n })\n .filter(prop => prop.length > 0),\n );\n return (\n <StructuredMetadataTable\n metadata={reviewData}\n options={{ titleFormat: key => key }}\n />\n );\n};\n"],"names":["JSONSchema"],"mappings":";;;;;AA8BA,SAAS,aAAA,CACP,GAAA,EACA,KAAA,EACA,MAAA,EACA,SAAA,EACmC;AACnC,EAAA,MAAM,YAAA,GAAe,IAAIA,OAAA,CAAW,MAAA,CAAO,YAAY,CAAA;AACvD,EAAA,MAAM,kBAAA,GAAqB,aAAa,SAAA,CAAU;AAAA,IAChD,OAAA,EAAS,KAAK,GAAG,CAAA,CAAA;AAAA,IACjB,IAAA,EAAM;AAAA,GACP,CAAA;AAED,EAAA,MAAM,IAAA,GACJ,qBAAqB,cAAc,CAAA,EAAG,QAAQ,IAAA,IAC9C,kBAAA,EAAoB,KAAA,IACpB,SAAA,CAAU,GAAG,CAAA;AAEf,EAAA,IAAI,kBAAA,EAAoB;AACtB,IAAA,MAAM,sBAAA,GAAyB,kBAAA,CAAmB,cAAc,CAAA,EAAG,MAAA;AACnE,IAAA,IAAI,sBAAA,EAAwB;AAC1B,MAAA,IAAI,uBAAuB,IAAA,EAAM;AAC/B,QAAA,OAAO,CAAC,CAAC,IAAA,EAAM,sBAAA,CAAuB,IAAI,CAAC,CAAA;AAAA,MAC7C;AACA,MAAA,IAAI,sBAAA,CAAuB,SAAS,KAAA,EAAO;AACzC,QAAA,OAAO,EAAC;AAAA,MACV;AAAA,IACF;AAEA,IAAA,IACE,kBAAA,CAAmB,WAAW,CAAA,KAAM,UAAA,IACpC,kBAAA,CAAmB,UAAU,CAAA,EAAG,iBAAA,CAAkB,OAAO,CAAA,KAAM,QAAA,EAC/D;AACA,MAAA,OAAO,CAAC,CAAC,IAAA,EAAM,QAAQ,CAAC,CAAA;AAAA,IAC1B;AAEA,IAAA,IAAI,kBAAA,CAAmB,IAAA,IAAQ,kBAAA,CAAmB,SAAA,EAAW;AAC3D,MAAA,OAAO;AAAA,QACL;AAAA,UACE,IAAA;AAAA,UACA,mBAAmB,SAAA,CACjB,kBAAA,CAAmB,KAAK,OAAA,CAAQ,KAAK,CACvC,CAAA,IAAK;AAAA;AACP,OACF;AAAA,IACF;AAEA,IAAA,IAAI,sBAAA,EAAwB,OAAA,KAAY,KAAA,IAAS,YAAA,CAAa,KAAK,CAAA,EAAG;AAEpE,MAAA,OAAO,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA,CAAE,OAAA;AAAA,QAAQ,CAAC,CAAC,SAAA,EAAW,WAAW,CAAA,KAC3D,aAAA,CAAc,CAAA,EAAG,GAAG,CAAA,CAAA,EAAI,SAAS,CAAA,CAAA,EAAI,WAAA,EAAa,QAAQ,SAAS;AAAA,OACrE;AAAA,IACF;AAAA,EACF;AAEA,EAAA,OAAO,CAAC,CAAC,IAAA,EAAM,KAAK,CAAC,CAAA;AACvB;AAMO,MAAM,WAAA,GAAc,CAAC,KAAA,KAA4B;AACtD,EAAA,MAAM,aAAa,MAAA,CAAO,WAAA;AAAA,IACxB,MAAA,CAAO,OAAA,CAAQ,KAAA,CAAM,SAAS,CAAA,CAC3B,QAAQ,CAAC,CAAC,GAAA,EAAK,KAAK,CAAA,KAAM;AACzB,MAAA,MAAM,SAAS,gBAAA,CAAiB,GAAA,EAAK,KAAA,CAAM,OAAA,EAAS,MAAM,SAAS,CAAA;AACnE,MAAA,OAAO,MAAA,GACH,aAAA,CAAc,GAAA,EAAK,KAAA,EAAO,QAAQ,KAAA,CAAM,SAAS,CAAA,GACjD,CAAC,CAAC,SAAA,CAAU,GAAG,CAAA,EAAG,KAAK,CAAC,CAAA;AAAA,IAC9B,CAAC,CAAA,CACA,MAAA,CAAO,CAAA,IAAA,KAAQ,IAAA,CAAK,SAAS,CAAC;AAAA,GACnC;AACA,EAAA,uBACE,GAAA;AAAA,IAAC,uBAAA;AAAA,IAAA;AAAA,MACC,QAAA,EAAU,UAAA;AAAA,MACV,OAAA,EAAS,EAAE,WAAA,EAAa,CAAA,GAAA,KAAO,GAAA;AAAI;AAAA,GACrC;AAEJ;;;;"}
1
+ {"version":3,"file":"ReviewState.esm.js","sources":["../../../../src/next/components/ReviewState/ReviewState.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 */\nimport { StructuredMetadataTable } from '@backstage/core-components';\nimport { JsonObject, JsonValue } from '@backstage/types';\nimport { Draft07 as JSONSchema } from 'json-schema-library';\nimport { ParsedTemplateSchema } from '../../hooks/useTemplateSchema';\nimport { isJsonObject, formatKey, findSchemaForKey } from './util';\n\n/**\n * The props for the {@link ReviewState} component.\n * @alpha\n */\nexport type ReviewStateProps = {\n schemas: ParsedTemplateSchema[];\n formState: JsonObject;\n};\n\nfunction processSchema(\n key: string,\n value: JsonValue | undefined,\n schema: ParsedTemplateSchema,\n formState: JsonObject,\n): [string, JsonValue | undefined][] {\n const parsedSchema = new JSONSchema(schema.mergedSchema);\n const definitionInSchema = parsedSchema.getSchema({\n pointer: `#/${key}`,\n data: formState,\n });\n\n const name =\n definitionInSchema?.['ui:backstage']?.review?.name ??\n definitionInSchema?.title ??\n formatKey(key);\n\n if (definitionInSchema) {\n const backstageReviewOptions = definitionInSchema['ui:backstage']?.review;\n if (backstageReviewOptions) {\n if (backstageReviewOptions.mask) {\n return [[name, backstageReviewOptions.mask]];\n }\n if (backstageReviewOptions.show === false) {\n return [];\n }\n }\n\n if (\n definitionInSchema['ui:widget'] === 'password' ||\n definitionInSchema['ui:field']?.toLowerCase() === 'secret'\n ) {\n return [[name, '******']];\n }\n\n if (definitionInSchema.enum && definitionInSchema.enumNames) {\n return [\n [\n name,\n definitionInSchema.enumNames[\n definitionInSchema.enum.indexOf(value)\n ] || value,\n ],\n ];\n }\n\n if (backstageReviewOptions?.explode !== false && isJsonObject(value)) {\n // Recurse nested objects\n return Object.entries(value).flatMap(([nestedKey, nestedValue]) =>\n processSchema(`${key}/${nestedKey}`, nestedValue, schema, formState),\n );\n }\n }\n\n return [[name, value]];\n}\n\n/**\n * The component used by the {@link Stepper} to render the review step.\n * @alpha\n */\nexport const ReviewState = (props: ReviewStateProps) => {\n const reviewData = Object.fromEntries(\n Object.entries(props.formState)\n .flatMap(([key, value]) => {\n const schema = findSchemaForKey(key, props.schemas, props.formState);\n return schema\n ? processSchema(key, value, schema, props.formState)\n : [[formatKey(key), value]];\n })\n .filter(prop => prop.length > 0),\n );\n return (\n <StructuredMetadataTable\n metadata={reviewData}\n options={{ titleFormat: key => key }}\n />\n );\n};\n"],"names":["JSONSchema"],"mappings":";;;;;AA8BA,SAAS,aAAA,CACP,GAAA,EACA,KAAA,EACA,MAAA,EACA,SAAA,EACmC;AACnC,EAAA,MAAM,YAAA,GAAe,IAAIA,OAAA,CAAW,MAAA,CAAO,YAAY,CAAA;AACvD,EAAA,MAAM,kBAAA,GAAqB,aAAa,SAAA,CAAU;AAAA,IAChD,OAAA,EAAS,KAAK,GAAG,CAAA,CAAA;AAAA,IACjB,IAAA,EAAM;AAAA,GACP,CAAA;AAED,EAAA,MAAM,IAAA,GACJ,qBAAqB,cAAc,CAAA,EAAG,QAAQ,IAAA,IAC9C,kBAAA,EAAoB,KAAA,IACpB,SAAA,CAAU,GAAG,CAAA;AAEf,EAAA,IAAI,kBAAA,EAAoB;AACtB,IAAA,MAAM,sBAAA,GAAyB,kBAAA,CAAmB,cAAc,CAAA,EAAG,MAAA;AACnE,IAAA,IAAI,sBAAA,EAAwB;AAC1B,MAAA,IAAI,uBAAuB,IAAA,EAAM;AAC/B,QAAA,OAAO,CAAC,CAAC,IAAA,EAAM,sBAAA,CAAuB,IAAI,CAAC,CAAA;AAAA,MAC7C;AACA,MAAA,IAAI,sBAAA,CAAuB,SAAS,KAAA,EAAO;AACzC,QAAA,OAAO,EAAC;AAAA,MACV;AAAA,IACF;AAEA,IAAA,IACE,kBAAA,CAAmB,WAAW,CAAA,KAAM,UAAA,IACpC,mBAAmB,UAAU,CAAA,EAAG,WAAA,EAAY,KAAM,QAAA,EAClD;AACA,MAAA,OAAO,CAAC,CAAC,IAAA,EAAM,QAAQ,CAAC,CAAA;AAAA,IAC1B;AAEA,IAAA,IAAI,kBAAA,CAAmB,IAAA,IAAQ,kBAAA,CAAmB,SAAA,EAAW;AAC3D,MAAA,OAAO;AAAA,QACL;AAAA,UACE,IAAA;AAAA,UACA,mBAAmB,SAAA,CACjB,kBAAA,CAAmB,KAAK,OAAA,CAAQ,KAAK,CACvC,CAAA,IAAK;AAAA;AACP,OACF;AAAA,IACF;AAEA,IAAA,IAAI,sBAAA,EAAwB,OAAA,KAAY,KAAA,IAAS,YAAA,CAAa,KAAK,CAAA,EAAG;AAEpE,MAAA,OAAO,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA,CAAE,OAAA;AAAA,QAAQ,CAAC,CAAC,SAAA,EAAW,WAAW,CAAA,KAC3D,aAAA,CAAc,CAAA,EAAG,GAAG,CAAA,CAAA,EAAI,SAAS,CAAA,CAAA,EAAI,WAAA,EAAa,QAAQ,SAAS;AAAA,OACrE;AAAA,IACF;AAAA,EACF;AAEA,EAAA,OAAO,CAAC,CAAC,IAAA,EAAM,KAAK,CAAC,CAAA;AACvB;AAMO,MAAM,WAAA,GAAc,CAAC,KAAA,KAA4B;AACtD,EAAA,MAAM,aAAa,MAAA,CAAO,WAAA;AAAA,IACxB,MAAA,CAAO,OAAA,CAAQ,KAAA,CAAM,SAAS,CAAA,CAC3B,QAAQ,CAAC,CAAC,GAAA,EAAK,KAAK,CAAA,KAAM;AACzB,MAAA,MAAM,SAAS,gBAAA,CAAiB,GAAA,EAAK,KAAA,CAAM,OAAA,EAAS,MAAM,SAAS,CAAA;AACnE,MAAA,OAAO,MAAA,GACH,aAAA,CAAc,GAAA,EAAK,KAAA,EAAO,QAAQ,KAAA,CAAM,SAAS,CAAA,GACjD,CAAC,CAAC,SAAA,CAAU,GAAG,CAAA,EAAG,KAAK,CAAC,CAAA;AAAA,IAC9B,CAAC,CAAA,CACA,MAAA,CAAO,CAAA,IAAA,KAAQ,IAAA,CAAK,SAAS,CAAC;AAAA,GACnC;AACA,EAAA,uBACE,GAAA;AAAA,IAAC,uBAAA;AAAA,IAAA;AAAA,MACC,QAAA,EAAU,UAAA;AAAA,MACV,OAAA,EAAS,EAAE,WAAA,EAAa,CAAA,GAAA,KAAO,GAAA;AAAI;AAAA,GACrC;AAEJ;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/plugin-scaffolder-react",
3
- "version": "2.1.0-next.1",
3
+ "version": "2.1.0",
4
4
  "description": "A frontend library that helps other Backstage plugins interact with the Scaffolder",
5
5
  "backstage": {
6
6
  "role": "web-library",
@@ -74,18 +74,18 @@
74
74
  "test": "backstage-cli package test"
75
75
  },
76
76
  "dependencies": {
77
- "@backstage/catalog-client": "1.16.2-next.0",
78
- "@backstage/catalog-model": "1.10.0",
79
- "@backstage/core-components": "0.18.14-next.1",
80
- "@backstage/core-plugin-api": "1.12.10-next.0",
81
- "@backstage/frontend-plugin-api": "0.18.1-next.0",
82
- "@backstage/plugin-catalog-react": "3.2.3-next.1",
83
- "@backstage/plugin-permission-react": "0.5.5-next.0",
84
- "@backstage/plugin-scaffolder-common": "2.3.0-next.1",
85
- "@backstage/theme": "0.7.3",
86
- "@backstage/types": "1.2.2",
87
- "@backstage/ui": "0.18.0-next.1",
88
- "@backstage/version-bridge": "1.0.12",
77
+ "@backstage/catalog-client": "^1.16.2",
78
+ "@backstage/catalog-model": "^1.10.1",
79
+ "@backstage/core-components": "^0.18.14",
80
+ "@backstage/core-plugin-api": "^1.12.10",
81
+ "@backstage/frontend-plugin-api": "^0.18.1",
82
+ "@backstage/plugin-catalog-react": "^3.2.3",
83
+ "@backstage/plugin-permission-react": "^0.5.5",
84
+ "@backstage/plugin-scaffolder-common": "^2.3.0",
85
+ "@backstage/theme": "^0.7.3",
86
+ "@backstage/types": "^1.2.2",
87
+ "@backstage/ui": "^0.18.0",
88
+ "@backstage/version-bridge": "^1.0.12",
89
89
  "@material-ui/core": "^4.12.2",
90
90
  "@material-ui/icons": "^4.9.1",
91
91
  "@material-ui/lab": "4.0.0-alpha.61",
@@ -114,13 +114,13 @@
114
114
  "zod-to-json-schema": "^3.25.1"
115
115
  },
116
116
  "devDependencies": {
117
- "@backstage/cli": "0.36.6-next.0",
118
- "@backstage/core-app-api": "1.20.5-next.1",
119
- "@backstage/frontend-test-utils": "0.6.4-next.1",
120
- "@backstage/plugin-catalog": "2.0.9-next.1",
121
- "@backstage/plugin-catalog-common": "1.1.10",
122
- "@backstage/plugin-permission-common": "0.9.10",
123
- "@backstage/test-utils": "1.7.22-next.1",
117
+ "@backstage/cli": "^0.36.6",
118
+ "@backstage/core-app-api": "^1.20.5",
119
+ "@backstage/frontend-test-utils": "^0.6.4",
120
+ "@backstage/plugin-catalog": "^2.0.9",
121
+ "@backstage/plugin-catalog-common": "^1.2.0",
122
+ "@backstage/plugin-permission-common": "^0.9.11",
123
+ "@backstage/test-utils": "^1.7.22",
124
124
  "@testing-library/dom": "^10.0.0",
125
125
  "@testing-library/jest-dom": "^6.0.0",
126
126
  "@testing-library/react": "^16.0.0",
@@ -133,7 +133,7 @@
133
133
  "swr": "^2.0.0"
134
134
  },
135
135
  "peerDependencies": {
136
- "@backstage/frontend-test-utils": "0.6.4-next.1",
136
+ "@backstage/frontend-test-utils": "^0.6.4",
137
137
  "@types/react": "^17.0.0 || ^18.0.0",
138
138
  "react": "^17.0.0 || ^18.0.0",
139
139
  "react-dom": "^17.0.0 || ^18.0.0",