@backstage/plugin-scaffolder-react 1.19.2-next.1 → 1.19.2

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,28 @@
1
1
  # @backstage/plugin-scaffolder-react
2
2
 
3
+ ## 1.19.2
4
+
5
+ ### Patch Changes
6
+
7
+ - e61f89e: Don't change loading to false until we've actually got some log state
8
+ - Updated dependencies
9
+ - @backstage/plugin-catalog-react@1.21.2
10
+ - @backstage/core-components@0.18.2
11
+ - @backstage/frontend-plugin-api@0.12.1
12
+ - @backstage/theme@0.7.0
13
+ - @backstage/core-plugin-api@1.11.1
14
+ - @backstage/plugin-permission-react@0.4.37
15
+ - @backstage/plugin-scaffolder-common@1.7.2
16
+
17
+ ## 1.19.2-next.2
18
+
19
+ ### Patch Changes
20
+
21
+ - e61f89e: Don't change loading to false until we've actually got some log state
22
+ - Updated dependencies
23
+ - @backstage/core-components@0.18.2-next.2
24
+ - @backstage/theme@0.6.9-next.0
25
+
3
26
  ## 1.19.2-next.1
4
27
 
5
28
  ### Patch Changes
@@ -14,7 +14,6 @@ function reducer(draft, action) {
14
14
  current[next.id] = [];
15
15
  return current;
16
16
  }, {});
17
- draft.loading = false;
18
17
  draft.error = void 0;
19
18
  draft.completed = false;
20
19
  draft.task = action.data;
@@ -22,6 +21,9 @@ function reducer(draft, action) {
22
21
  }
23
22
  case "LOGS": {
24
23
  const entries = action.data;
24
+ if (draft.loading && entries.length > 0) {
25
+ draft.loading = false;
26
+ }
25
27
  for (const entry of entries) {
26
28
  const logLine = `${entry.createdAt} ${entry.body.message}`;
27
29
  if (!entry.body.stepId || !draft.steps?.[entry.body.stepId]) {
@@ -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 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: '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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"}
package/dist/index.d.ts CHANGED
@@ -565,7 +565,7 @@ declare const useCustomLayouts: <TComponentDataType = LayoutOptions<any>>(outlet
565
565
  */
566
566
  type ScaffolderStep = {
567
567
  id: string;
568
- status: ScaffolderTaskStatus;
568
+ status: ScaffolderTaskStatus$1;
569
569
  endedAt?: string;
570
570
  startedAt?: string;
571
571
  };
@@ -582,11 +582,11 @@ type TaskStream = {
582
582
  [stepId in string]: string[];
583
583
  };
584
584
  completed: boolean;
585
- task?: ScaffolderTask;
585
+ task?: ScaffolderTask$1;
586
586
  steps: {
587
587
  [stepId in string]: ScaffolderStep;
588
588
  };
589
- output?: ScaffolderTaskOutput;
589
+ output?: ScaffolderTaskOutput$1;
590
590
  };
591
591
  /**
592
592
  * A hook to stream the logs of a task being processed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/plugin-scaffolder-react",
3
- "version": "1.19.2-next.1",
3
+ "version": "1.19.2",
4
4
  "description": "A frontend library that helps other Backstage plugins interact with the Scaffolder",
5
5
  "backstage": {
6
6
  "role": "web-library",
@@ -66,17 +66,17 @@
66
66
  "test": "backstage-cli package test"
67
67
  },
68
68
  "dependencies": {
69
- "@backstage/catalog-client": "1.12.0",
70
- "@backstage/catalog-model": "1.7.5",
71
- "@backstage/core-components": "0.18.2-next.1",
72
- "@backstage/core-plugin-api": "1.11.1-next.0",
73
- "@backstage/frontend-plugin-api": "0.12.1-next.1",
74
- "@backstage/plugin-catalog-react": "1.21.2-next.1",
75
- "@backstage/plugin-permission-react": "0.4.37-next.0",
76
- "@backstage/plugin-scaffolder-common": "1.7.2-next.1",
77
- "@backstage/theme": "0.6.8",
78
- "@backstage/types": "1.2.2",
79
- "@backstage/version-bridge": "1.0.11",
69
+ "@backstage/catalog-client": "^1.12.0",
70
+ "@backstage/catalog-model": "^1.7.5",
71
+ "@backstage/core-components": "^0.18.2",
72
+ "@backstage/core-plugin-api": "^1.11.1",
73
+ "@backstage/frontend-plugin-api": "^0.12.1",
74
+ "@backstage/plugin-catalog-react": "^1.21.2",
75
+ "@backstage/plugin-permission-react": "^0.4.37",
76
+ "@backstage/plugin-scaffolder-common": "^1.7.2",
77
+ "@backstage/theme": "^0.7.0",
78
+ "@backstage/types": "^1.2.2",
79
+ "@backstage/version-bridge": "^1.0.11",
80
80
  "@material-ui/core": "^4.12.2",
81
81
  "@material-ui/icons": "^4.9.1",
82
82
  "@material-ui/lab": "4.0.0-alpha.61",
@@ -104,12 +104,12 @@
104
104
  "zod-to-json-schema": "^3.20.4"
105
105
  },
106
106
  "devDependencies": {
107
- "@backstage/cli": "0.34.4-next.1",
108
- "@backstage/core-app-api": "1.19.1-next.0",
109
- "@backstage/plugin-catalog": "1.31.4-next.1",
110
- "@backstage/plugin-catalog-common": "1.1.6-next.0",
111
- "@backstage/plugin-permission-common": "0.9.2-next.0",
112
- "@backstage/test-utils": "1.7.12-next.0",
107
+ "@backstage/cli": "^0.34.4",
108
+ "@backstage/core-app-api": "^1.19.1",
109
+ "@backstage/plugin-catalog": "^1.31.4",
110
+ "@backstage/plugin-catalog-common": "^1.1.6",
111
+ "@backstage/plugin-permission-common": "^0.9.2",
112
+ "@backstage/test-utils": "^1.7.12",
113
113
  "@testing-library/dom": "^10.0.0",
114
114
  "@testing-library/jest-dom": "^6.0.0",
115
115
  "@testing-library/react": "^16.0.0",