@patternfly/quickstarts 2.2.2 → 2.3.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.
Files changed (195) hide show
  1. package/README.md +4 -4
  2. package/dist/HelpTopicDrawer.d.ts +8 -2
  3. package/dist/QuickStartDrawer.d.ts +21 -2
  4. package/dist/controller/QuickStartTaskHeader.d.ts +1 -1
  5. package/dist/index.d.ts +1 -0
  6. package/dist/index.es.js +104 -4
  7. package/dist/index.es.js.map +1 -1
  8. package/dist/index.js +104 -3
  9. package/dist/index.js.map +1 -1
  10. package/dist/patternfly-docs/quick-starts/design-guidelines/design-guidelines.md +105 -0
  11. package/dist/patternfly-docs/quick-starts/design-guidelines/img/card-elements copy.png +0 -0
  12. package/dist/patternfly-docs/quick-starts/design-guidelines/img/card-elements.png +0 -0
  13. package/dist/patternfly-docs/quick-starts/design-guidelines/img/catalog-elements.png +0 -0
  14. package/dist/patternfly-docs/quick-starts/design-guidelines/img/check-your-work.png +0 -0
  15. package/dist/patternfly-docs/quick-starts/design-guidelines/img/introduction-screen.png +0 -0
  16. package/dist/patternfly-docs/quick-starts/design-guidelines/img/mixed-catalog.png +0 -0
  17. package/dist/patternfly-docs/quick-starts/design-guidelines/img/prerequisites.png +0 -0
  18. package/dist/patternfly-docs/quick-starts/design-guidelines/img/qs-context.png +0 -0
  19. package/dist/patternfly-docs/quick-starts/design-guidelines/img/side-panel-elements.png +0 -0
  20. package/dist/patternfly-docs/quick-starts/design-guidelines/img/side-panel-resized.png +0 -0
  21. package/dist/patternfly-docs/quick-starts/design-guidelines/img/side-panel.png +0 -0
  22. package/dist/patternfly-docs/quick-starts/design-guidelines/img/task-no.png +0 -0
  23. package/dist/patternfly-docs/quick-starts/design-guidelines/img/task-yes.png +0 -0
  24. package/dist/patternfly-docs/quick-starts/design-guidelines/img/task.png +0 -0
  25. package/dist/patternfly-docs/quick-starts/examples/Basic.jsx +73 -0
  26. package/dist/patternfly-docs/quick-starts/examples/HelpTopic.jsx +53 -0
  27. package/dist/patternfly-docs/quick-starts/examples/about.md +77 -0
  28. package/dist/patternfly-docs/quick-starts/examples/basic.md +27 -0
  29. package/dist/patternfly-docs/quick-starts/examples/example-data/example-help-topics.js +173 -0
  30. package/dist/patternfly-docs/quick-starts/examples/example-data/example-quickstarts.js +215 -0
  31. package/dist/patternfly-docs/quick-starts/examples/example-data/index.js +15 -0
  32. package/dist/patternfly-docs/quick-starts/examples/help-topics.md +25 -0
  33. package/dist/patternfly-docs/quick-starts/examples/img/catalog.png +0 -0
  34. package/dist/patternfly-docs/quick-starts/examples/img/help-topic.png +0 -0
  35. package/dist/patternfly-docs/quick-starts/examples/img/side-panel.png +0 -0
  36. package/dist/quickstarts-full.es.js +104 -4
  37. package/dist/quickstarts-full.es.js.map +1 -1
  38. package/dist/utils/asciidoc-procedure-parser.d.ts +12 -0
  39. package/package.json +11 -4
  40. package/src/ConsoleInternal/components/_icon-and-text.scss +14 -0
  41. package/src/ConsoleInternal/components/_markdown-view.scss +19 -0
  42. package/src/ConsoleInternal/components/catalog/_catalog.scss +390 -0
  43. package/src/ConsoleInternal/components/markdown-view.tsx +305 -0
  44. package/src/ConsoleInternal/components/utils/_status-box.scss +58 -0
  45. package/src/ConsoleInternal/components/utils/camel-case-wrap.tsx +33 -0
  46. package/src/ConsoleInternal/components/utils/index.tsx +3 -0
  47. package/src/ConsoleInternal/components/utils/router.ts +47 -0
  48. package/src/ConsoleInternal/components/utils/status-box.tsx +94 -0
  49. package/src/ConsoleInternal/module/k8s/types.ts +53 -0
  50. package/src/ConsoleShared/index.ts +1 -0
  51. package/src/ConsoleShared/src/components/index.ts +7 -0
  52. package/src/ConsoleShared/src/components/layout/PageLayout.scss +29 -0
  53. package/src/ConsoleShared/src/components/markdown-extensions/MarkdownCopyClipboard.tsx +93 -0
  54. package/src/ConsoleShared/src/components/markdown-extensions/__tests__/MarkdownCopyClipboard.spec.tsx +25 -0
  55. package/src/ConsoleShared/src/components/markdown-extensions/__tests__/test-data.ts +5 -0
  56. package/src/ConsoleShared/src/components/markdown-extensions/admonition-extension.tsx +66 -0
  57. package/src/ConsoleShared/src/components/markdown-extensions/code-extension.tsx +25 -0
  58. package/src/ConsoleShared/src/components/markdown-extensions/const.ts +3 -0
  59. package/src/ConsoleShared/src/components/markdown-extensions/index.ts +5 -0
  60. package/src/ConsoleShared/src/components/markdown-extensions/inline-clipboard-extension.tsx +45 -0
  61. package/src/ConsoleShared/src/components/markdown-extensions/multiline-clipboard-extension.tsx +50 -0
  62. package/src/ConsoleShared/src/components/markdown-extensions/showdown-extension.scss +52 -0
  63. package/src/ConsoleShared/src/components/markdown-extensions/utils.ts +3 -0
  64. package/src/ConsoleShared/src/components/markdown-highlight-extension/MarkdownHighlightExtension.tsx +64 -0
  65. package/src/ConsoleShared/src/components/markdown-highlight-extension/highlight-consts.ts +9 -0
  66. package/src/ConsoleShared/src/components/markdown-highlight-extension/index.ts +1 -0
  67. package/src/ConsoleShared/src/components/modal/Modal.scss +3 -0
  68. package/src/ConsoleShared/src/components/modal/Modal.tsx +19 -0
  69. package/src/ConsoleShared/src/components/modal/index.ts +1 -0
  70. package/src/ConsoleShared/src/components/popper/Portal.tsx +23 -0
  71. package/src/ConsoleShared/src/components/popper/SimplePopper.tsx +90 -0
  72. package/src/ConsoleShared/src/components/popper/index.ts +2 -0
  73. package/src/ConsoleShared/src/components/spotlight/InteractiveSpotlight.tsx +58 -0
  74. package/src/ConsoleShared/src/components/spotlight/Spotlight.tsx +35 -0
  75. package/src/ConsoleShared/src/components/spotlight/StaticSpotlight.tsx +32 -0
  76. package/src/ConsoleShared/src/components/spotlight/index.ts +1 -0
  77. package/src/ConsoleShared/src/components/spotlight/spotlight.scss +63 -0
  78. package/src/ConsoleShared/src/components/status/GenericStatus.tsx +33 -0
  79. package/src/ConsoleShared/src/components/status/NotStartedIcon.tsx +27 -0
  80. package/src/ConsoleShared/src/components/status/PopoverStatus.tsx +42 -0
  81. package/src/ConsoleShared/src/components/status/Status.tsx +38 -0
  82. package/src/ConsoleShared/src/components/status/StatusIconAndText.tsx +42 -0
  83. package/src/ConsoleShared/src/components/status/icons.tsx +77 -0
  84. package/src/ConsoleShared/src/components/status/index.tsx +1 -0
  85. package/src/ConsoleShared/src/components/status/statuses.tsx +36 -0
  86. package/src/ConsoleShared/src/components/status/types.ts +7 -0
  87. package/src/ConsoleShared/src/components/utils/FallbackImg.tsx +20 -0
  88. package/src/ConsoleShared/src/components/utils/index.ts +1 -0
  89. package/src/ConsoleShared/src/constants/index.ts +1 -0
  90. package/src/ConsoleShared/src/constants/ui.ts +1 -0
  91. package/src/ConsoleShared/src/hooks/index.ts +6 -0
  92. package/src/ConsoleShared/src/hooks/scroll.ts +52 -0
  93. package/src/ConsoleShared/src/hooks/useBoundingClientRect.ts +18 -0
  94. package/src/ConsoleShared/src/hooks/useEventListener.ts +14 -0
  95. package/src/ConsoleShared/src/hooks/useForceRender.ts +6 -0
  96. package/src/ConsoleShared/src/hooks/useResizeObserver.ts +20 -0
  97. package/src/ConsoleShared/src/hooks/useScrollShadows.ts +45 -0
  98. package/src/ConsoleShared/src/index.ts +4 -0
  99. package/src/ConsoleShared/src/utils/index.ts +1 -0
  100. package/src/ConsoleShared/src/utils/useCombineRefs.ts +17 -0
  101. package/src/HelpTopicDrawer.tsx +124 -0
  102. package/src/HelpTopicPanelContent.tsx +152 -0
  103. package/src/QuickStartCatalogPage.tsx +190 -0
  104. package/src/QuickStartCloseModal.tsx +47 -0
  105. package/src/QuickStartController.tsx +113 -0
  106. package/src/QuickStartDrawer.scss +11 -0
  107. package/src/QuickStartDrawer.tsx +265 -0
  108. package/src/QuickStartMarkdownView.tsx +75 -0
  109. package/src/QuickStartPanelContent.scss +46 -0
  110. package/src/QuickStartPanelContent.tsx +153 -0
  111. package/src/__tests__/quick-start-utils.spec.tsx +16 -0
  112. package/src/catalog/Catalog/QuickStartCatalogHeader.tsx +18 -0
  113. package/src/catalog/Catalog/QuickStartCatalogSection.tsx +9 -0
  114. package/src/catalog/Catalog/QuickStartCatalogToolbar.tsx +12 -0
  115. package/src/catalog/Catalog/index.ts +3 -0
  116. package/src/catalog/QuickStartCatalog.scss +8 -0
  117. package/src/catalog/QuickStartCatalog.tsx +42 -0
  118. package/src/catalog/QuickStartTile.scss +11 -0
  119. package/src/catalog/QuickStartTile.tsx +105 -0
  120. package/src/catalog/QuickStartTileDescription.scss +29 -0
  121. package/src/catalog/QuickStartTileDescription.tsx +79 -0
  122. package/src/catalog/QuickStartTileFooter.tsx +101 -0
  123. package/src/catalog/QuickStartTileFooterExternal.tsx +40 -0
  124. package/src/catalog/QuickStartTileHeader.scss +12 -0
  125. package/src/catalog/QuickStartTileHeader.tsx +77 -0
  126. package/src/catalog/Toolbar/QuickStartCatalogFilter.scss +25 -0
  127. package/src/catalog/Toolbar/QuickStartCatalogFilter.tsx +34 -0
  128. package/src/catalog/Toolbar/QuickStartCatalogFilterItems.tsx +199 -0
  129. package/src/catalog/__tests__/QuickStartCatalog.spec.tsx +35 -0
  130. package/src/catalog/__tests__/QuickStartTile.spec.tsx +38 -0
  131. package/src/catalog/__tests__/QuickStartTileDescription.spec.tsx +44 -0
  132. package/src/catalog/index.ts +9 -0
  133. package/src/controller/QuickStartConclusion.tsx +63 -0
  134. package/src/controller/QuickStartContent.scss +12 -0
  135. package/src/controller/QuickStartContent.tsx +72 -0
  136. package/src/controller/QuickStartFooter.scss +13 -0
  137. package/src/controller/QuickStartFooter.tsx +128 -0
  138. package/src/controller/QuickStartIntroduction.scss +35 -0
  139. package/src/controller/QuickStartIntroduction.tsx +66 -0
  140. package/src/controller/QuickStartTaskHeader.scss +58 -0
  141. package/src/controller/QuickStartTaskHeader.tsx +116 -0
  142. package/src/controller/QuickStartTaskHeaderList.scss +17 -0
  143. package/src/controller/QuickStartTaskHeaderList.tsx +35 -0
  144. package/src/controller/QuickStartTaskReview.scss +30 -0
  145. package/src/controller/QuickStartTaskReview.tsx +81 -0
  146. package/src/controller/QuickStartTasks.scss +89 -0
  147. package/src/controller/QuickStartTasks.tsx +75 -0
  148. package/src/controller/__tests__/QuickStartConclusion.spec.tsx +95 -0
  149. package/src/controller/__tests__/QuickStartContent.spec.tsx +52 -0
  150. package/src/controller/__tests__/QuickStartFooter.spec.tsx +148 -0
  151. package/src/controller/__tests__/QuickStartTaskHeader.spec.tsx +56 -0
  152. package/src/controller/__tests__/QuickStartTaskReview.spec.tsx +45 -0
  153. package/src/controller/__tests__/QuickStartTasks.spec.tsx +81 -0
  154. package/src/data/mocks/json/explore-pipeline-quickstart.ts +66 -0
  155. package/src/data/mocks/json/explore-serverless-quickstart.ts +90 -0
  156. package/src/data/mocks/json/monitor-sampleapp-quickstart.ts +77 -0
  157. package/src/data/mocks/json/tour-icons.ts +3 -0
  158. package/src/data/mocks/yamls/add-healthchecks-quickstart.yaml +67 -0
  159. package/src/data/mocks/yamls/explore-pipeline-quickstart.yaml +57 -0
  160. package/src/data/mocks/yamls/explore-serverless-quickstart.yaml +83 -0
  161. package/src/data/mocks/yamls/install-associate-pipeline-quickstart.yaml +74 -0
  162. package/src/data/mocks/yamls/monitor-sampleapp-quickstart.yaml +66 -0
  163. package/src/data/mocks/yamls/sample-application-quickstart.yaml +97 -0
  164. package/src/data/mocks/yamls/serverless-application-quickstart.yaml +141 -0
  165. package/src/data/quick-start-test-data.ts +10 -0
  166. package/src/data/test-utils.ts +11 -0
  167. package/src/declaration.d.ts +2 -0
  168. package/src/index.ts +17 -0
  169. package/src/locales/en/quickstart.json +46 -0
  170. package/src/styles/_base.scss +54 -0
  171. package/src/styles/_dark-custom-override.scss +62 -0
  172. package/src/styles/legacy-bootstrap/README.md +21 -0
  173. package/src/styles/legacy-bootstrap/_code.scss +44 -0
  174. package/src/styles/legacy-bootstrap/_tables.scss +38 -0
  175. package/src/styles/legacy-bootstrap/_type.scss +90 -0
  176. package/src/styles/legacy-bootstrap/_variables.scss +48 -0
  177. package/src/styles/legacy-bootstrap.scss +5 -0
  178. package/src/styles/patternfly-global-entry.ts +1 -0
  179. package/src/styles/patternfly-global.scss +28 -0
  180. package/src/styles/patternfly-nested-entry.ts +1 -0
  181. package/src/styles/patternfly-nested.scss +18 -0
  182. package/src/styles/quickstarts-standalone-entry.ts +1 -0
  183. package/src/styles/quickstarts-standalone.scss +7 -0
  184. package/src/styles/style.scss +12 -0
  185. package/src/styles/vendor-entry.ts +1 -0
  186. package/src/styles/vendor.scss +7 -0
  187. package/src/utils/PluralResolver.ts +356 -0
  188. package/src/utils/asciidoc-procedure-parser.ts +132 -0
  189. package/src/utils/const.ts +10 -0
  190. package/src/utils/help-topic-context.tsx +74 -0
  191. package/src/utils/help-topic-types.ts +16 -0
  192. package/src/utils/quick-start-context.tsx +477 -0
  193. package/src/utils/quick-start-types.ts +72 -0
  194. package/src/utils/quick-start-utils.ts +92 -0
  195. package/src/utils/useLocalStorage.ts +38 -0
@@ -0,0 +1,477 @@
1
+ import React, { createContext, useCallback } from 'react';
2
+ import { removeQueryArgument, setQueryArgument } from '../ConsoleInternal/components/utils/router';
3
+ import en from '../locales/en/quickstart.json';
4
+ import {
5
+ QUICKSTART_ID_FILTER_KEY,
6
+ QUICKSTART_SEARCH_FILTER_KEY,
7
+ QUICKSTART_STATUS_FILTER_KEY,
8
+ QUICKSTART_TASKS_INITIAL_STATES,
9
+ } from './const';
10
+ import PluralResolver from './PluralResolver';
11
+ import {
12
+ AllQuickStartStates,
13
+ QuickStart,
14
+ QuickStartState,
15
+ QuickStartStatus,
16
+ QuickStartTaskStatus,
17
+ } from './quick-start-types';
18
+ import { getQuickStartStatusCount, getTaskStatusKey } from './quick-start-utils';
19
+
20
+ const pluralResolver = new PluralResolver({ simplifyPluralSuffix: true });
21
+
22
+ export type FooterProps = {
23
+ show?: boolean;
24
+ };
25
+
26
+ export const getDefaultQuickStartState = (
27
+ totalTasks?: number,
28
+ initialStatus?: QuickStartStatus,
29
+ ) => {
30
+ const defaultQuickStartState = {
31
+ status: initialStatus || QuickStartStatus.NOT_STARTED,
32
+ taskNumber: -1,
33
+ };
34
+ if (totalTasks) {
35
+ for (let i = 0; i < totalTasks; i++) {
36
+ defaultQuickStartState[getTaskStatusKey(i)] = QuickStartTaskStatus.INIT;
37
+ }
38
+ }
39
+ return defaultQuickStartState;
40
+ };
41
+
42
+ export type QuickStartContextValues = {
43
+ allQuickStarts?: QuickStart[];
44
+ setAllQuickStarts?: React.Dispatch<React.SetStateAction<QuickStart[]>>;
45
+ activeQuickStartID?: string;
46
+ setActiveQuickStartID?: React.Dispatch<React.SetStateAction<string>>;
47
+ allQuickStartStates?: AllQuickStartStates;
48
+ setAllQuickStartStates?: React.Dispatch<React.SetStateAction<AllQuickStartStates>>;
49
+ activeQuickStartState?: QuickStartState;
50
+ setActiveQuickStart?: (quickStartId: string, totalTasks?: number) => void;
51
+ startQuickStart?: (quickStartId: string, totalTasks?: number) => void;
52
+ restartQuickStart?: (quickStartId: string, totalTasks: number) => void;
53
+ nextStep?: (totalTasks: number) => void;
54
+ previousStep?: () => void;
55
+ setQuickStartTaskNumber?: (quickStartId: string, taskNumber: number) => void;
56
+ setQuickStartTaskStatus?: (taskStatus: QuickStartTaskStatus) => void;
57
+ getQuickStartForId?: (id: string) => QuickStartState;
58
+ footer?: FooterProps;
59
+ useLegacyHeaderColors?: boolean;
60
+ useQueryParams?: boolean;
61
+ markdown?: {
62
+ extensions?: any[];
63
+ renderExtension?: (docContext: HTMLDocument, rootSelector: string) => React.ReactNode;
64
+ };
65
+ resourceBundle?: any;
66
+ getResource?: any;
67
+ setResourceBundle?: any;
68
+ language?: string;
69
+ setLanguage?: any;
70
+ filter?: {
71
+ keyword?: string;
72
+ status?: {
73
+ statusTypes?: any;
74
+ statusFilters?: any;
75
+ };
76
+ };
77
+ setFilter?: any;
78
+ loading?: boolean;
79
+ setLoading?: any;
80
+ alwaysShowTaskReview?: boolean;
81
+ setAlwaysShowTaskReview?: any;
82
+ };
83
+
84
+ export const QuickStartContextDefaults = {
85
+ allQuickStarts: [],
86
+ activeQuickStartID: '',
87
+ allQuickStartStates: {},
88
+ activeQuickStartState: {},
89
+ setAllQuickStarts: () => {},
90
+ resourceBundle: en,
91
+ getResource: () => '',
92
+ language: 'en',
93
+ useQueryParams: true,
94
+ filter: {
95
+ keyword: '',
96
+ status: {
97
+ statusTypes: {},
98
+ statusFilters: [],
99
+ },
100
+ },
101
+ setFilter: () => {},
102
+ footer: null,
103
+ useLegacyHeaderColors: false,
104
+ markdown: null,
105
+ loading: false,
106
+ alwaysShowTaskReview: true,
107
+ };
108
+ export const QuickStartContext = createContext<QuickStartContextValues>(QuickStartContextDefaults);
109
+
110
+ export const getResource = (resource: string, options: any, resourceBundle: any, lng: string) => {
111
+ if (options && !isNaN(options.count)) {
112
+ const suffix = pluralResolver.getSuffix(lng, options.count);
113
+ if (suffix && resourceBundle[`${resource}_${suffix}`]) {
114
+ // needs plural
115
+ return resourceBundle[`${resource}_${suffix}`];
116
+ }
117
+ }
118
+ return (resourceBundle && resourceBundle[resource]) || '';
119
+ };
120
+
121
+ export const useValuesForQuickStartContext = (
122
+ value: QuickStartContextValues = {},
123
+ ): QuickStartContextValues => {
124
+ const combinedValue = {
125
+ ...QuickStartContextDefaults,
126
+ ...value,
127
+ };
128
+ const {
129
+ activeQuickStartID,
130
+ setActiveQuickStartID,
131
+ setAllQuickStartStates,
132
+ useQueryParams,
133
+ allQuickStartStates,
134
+ allQuickStarts = [],
135
+ footer,
136
+ useLegacyHeaderColors,
137
+ markdown,
138
+ } = combinedValue;
139
+ const [quickStarts, setQuickStarts] = React.useState(combinedValue.allQuickStarts || []);
140
+ const [resourceBundle, setResourceBundle] = React.useState({
141
+ ...en,
142
+ ...combinedValue.resourceBundle,
143
+ });
144
+ const [language, setLanguage] = React.useState(combinedValue.language);
145
+ const changeResourceBundle = (bundle: any, lng?: string) => {
146
+ lng && setLanguage(lng);
147
+ setResourceBundle({
148
+ ...en,
149
+ ...bundle,
150
+ });
151
+ };
152
+ const findResource = useCallback(
153
+ (resource: string, count?: number) => {
154
+ return getResource(
155
+ resource,
156
+ count !== undefined ? { count } : null,
157
+ resourceBundle,
158
+ language,
159
+ );
160
+ },
161
+ [resourceBundle, language],
162
+ );
163
+ const [loading, setLoading] = React.useState(combinedValue.loading);
164
+ const [alwaysShowTaskReview, setAlwaysShowTaskReview] = React.useState(
165
+ combinedValue.alwaysShowTaskReview,
166
+ );
167
+
168
+ const initialSearchParams = new URLSearchParams(window.location.search);
169
+ const initialSearchQuery = initialSearchParams.get(QUICKSTART_SEARCH_FILTER_KEY) || '';
170
+ const initialStatusFilters =
171
+ initialSearchParams.get(QUICKSTART_STATUS_FILTER_KEY)?.split(',') || [];
172
+
173
+ const quickStartStatusCount = getQuickStartStatusCount(allQuickStartStates, allQuickStarts);
174
+ const [statusTypes, setStatusTypes] = React.useState({
175
+ [QuickStartStatus.COMPLETE]: findResource('Complete ({{statusCount, number}})').replace(
176
+ '{{statusCount, number}}',
177
+ quickStartStatusCount[QuickStartStatus.COMPLETE],
178
+ ),
179
+ [QuickStartStatus.IN_PROGRESS]: findResource('In progress ({{statusCount, number}})').replace(
180
+ '{{statusCount, number}}',
181
+ quickStartStatusCount[QuickStartStatus.IN_PROGRESS],
182
+ ),
183
+ [QuickStartStatus.NOT_STARTED]: findResource('Not started ({{statusCount, number}})').replace(
184
+ '{{statusCount, number}}',
185
+ quickStartStatusCount[QuickStartStatus.NOT_STARTED],
186
+ ),
187
+ });
188
+ const [statusFilters, setStatusFilters] = React.useState<string[]>(initialStatusFilters);
189
+
190
+ const [filterKeyword, setFilterKeyword] = React.useState(initialSearchQuery);
191
+
192
+ const setFilter = (type: 'keyword' | 'status', val: any) => {
193
+ if (type === 'keyword') {
194
+ setFilterKeyword(val);
195
+ } else if (type === 'status') {
196
+ setStatusFilters(val);
197
+ }
198
+ };
199
+
200
+ React.useEffect(() => {
201
+ const updatedQuickStartStatusCount = getQuickStartStatusCount(allQuickStartStates, quickStarts);
202
+ setStatusTypes({
203
+ [QuickStartStatus.COMPLETE]: findResource('Complete ({{statusCount, number}})').replace(
204
+ '{{statusCount, number}}',
205
+ updatedQuickStartStatusCount[QuickStartStatus.COMPLETE],
206
+ ),
207
+ [QuickStartStatus.IN_PROGRESS]: findResource('In progress ({{statusCount, number}})').replace(
208
+ '{{statusCount, number}}',
209
+ updatedQuickStartStatusCount[QuickStartStatus.IN_PROGRESS],
210
+ ),
211
+ [QuickStartStatus.NOT_STARTED]: findResource('Not started ({{statusCount, number}})').replace(
212
+ '{{statusCount, number}}',
213
+ updatedQuickStartStatusCount[QuickStartStatus.NOT_STARTED],
214
+ ),
215
+ });
216
+ }, [allQuickStartStates, findResource, quickStarts]);
217
+
218
+ const updateAllQuickStarts = (qs: QuickStart[]) => {
219
+ setQuickStarts(qs);
220
+ };
221
+
222
+ const setActiveQuickStart = useCallback(
223
+ (quickStartId: string, totalTasks?: number) => {
224
+ setActiveQuickStartID((id) => {
225
+ if (!quickStartId || id === quickStartId) {
226
+ useQueryParams && removeQueryArgument(QUICKSTART_ID_FILTER_KEY);
227
+ return '';
228
+ }
229
+ useQueryParams && setQueryArgument(QUICKSTART_ID_FILTER_KEY, quickStartId);
230
+ return quickStartId;
231
+ });
232
+ setAllQuickStartStates((qs) =>
233
+ !quickStartId || qs[quickStartId]
234
+ ? qs
235
+ : { ...qs, [quickStartId]: getDefaultQuickStartState(totalTasks) },
236
+ );
237
+ },
238
+ [setActiveQuickStartID, setAllQuickStartStates, useQueryParams],
239
+ );
240
+
241
+ const startQuickStart = useCallback(
242
+ (quickStartId: string, totalTasks?: number) => {
243
+ setActiveQuickStartID((id) => {
244
+ if (!id || id !== quickStartId) {
245
+ useQueryParams && setQueryArgument(QUICKSTART_ID_FILTER_KEY, quickStartId);
246
+ return quickStartId;
247
+ }
248
+ useQueryParams && setQueryArgument(QUICKSTART_ID_FILTER_KEY, id);
249
+ return id;
250
+ });
251
+ setAllQuickStartStates((qs) => {
252
+ if (qs.hasOwnProperty(quickStartId)) {
253
+ return {
254
+ ...qs,
255
+ [quickStartId]: {
256
+ ...qs[quickStartId],
257
+ status: QuickStartStatus.IN_PROGRESS,
258
+ },
259
+ };
260
+ }
261
+ return {
262
+ ...qs,
263
+ [quickStartId]: getDefaultQuickStartState(totalTasks, QuickStartStatus.IN_PROGRESS),
264
+ };
265
+ });
266
+ },
267
+ [setActiveQuickStartID, setAllQuickStartStates, useQueryParams],
268
+ );
269
+
270
+ const restartQuickStart = useCallback(
271
+ (quickStartId: string, totalTasks: number) => {
272
+ setActiveQuickStartID((id) => {
273
+ if (!id || id !== quickStartId) {
274
+ useQueryParams && setQueryArgument(QUICKSTART_ID_FILTER_KEY, quickStartId);
275
+ return quickStartId;
276
+ }
277
+ useQueryParams && setQueryArgument(QUICKSTART_ID_FILTER_KEY, id);
278
+ return id;
279
+ });
280
+ setAllQuickStartStates((qs) => ({
281
+ ...qs,
282
+ [quickStartId]: getDefaultQuickStartState(totalTasks, QuickStartStatus.NOT_STARTED),
283
+ }));
284
+ },
285
+ [setActiveQuickStartID, setAllQuickStartStates, useQueryParams],
286
+ );
287
+
288
+ // When alwaysShowTaskReview preference is enabled, skip visited step and go directly to review
289
+ const stepAfterInitial = alwaysShowTaskReview
290
+ ? QuickStartTaskStatus.REVIEW
291
+ : QuickStartTaskStatus.VISITED;
292
+
293
+ const nextStep = useCallback(
294
+ (totalTasks: number) => {
295
+ if (!activeQuickStartID) {
296
+ return;
297
+ }
298
+
299
+ setAllQuickStartStates((qs) => {
300
+ const quickStart = qs[activeQuickStartID];
301
+ const status = quickStart?.status;
302
+ const taskNumber = quickStart?.taskNumber as number;
303
+ const taskStatus = quickStart[getTaskStatusKey(taskNumber)];
304
+
305
+ let updatedStatus;
306
+ let updatedTaskNumber;
307
+ let updatedTaskStatus;
308
+
309
+ if (status === QuickStartStatus.NOT_STARTED) {
310
+ updatedStatus = QuickStartStatus.IN_PROGRESS;
311
+ } else if (
312
+ status === QuickStartStatus.IN_PROGRESS &&
313
+ !QUICKSTART_TASKS_INITIAL_STATES.includes(taskStatus as any) &&
314
+ taskNumber === totalTasks - 1
315
+ ) {
316
+ updatedStatus = QuickStartStatus.COMPLETE;
317
+ }
318
+
319
+ if (taskStatus === QuickStartTaskStatus.VISITED) {
320
+ updatedTaskStatus = QuickStartTaskStatus.REVIEW;
321
+ }
322
+
323
+ if (taskNumber < totalTasks && !updatedTaskStatus) {
324
+ updatedTaskNumber = taskNumber + 1;
325
+ }
326
+
327
+ const markInitialStepVisitedOrReview =
328
+ updatedTaskNumber > -1 &&
329
+ quickStart[getTaskStatusKey(updatedTaskNumber)] === QuickStartTaskStatus.INIT
330
+ ? stepAfterInitial
331
+ : quickStart[getTaskStatusKey(updatedTaskNumber)];
332
+ const newState = {
333
+ ...qs,
334
+ [activeQuickStartID]: {
335
+ ...quickStart,
336
+ ...(updatedStatus ? { status: updatedStatus } : {}),
337
+ ...(updatedTaskNumber > -1
338
+ ? {
339
+ taskNumber: updatedTaskNumber,
340
+ [getTaskStatusKey(updatedTaskNumber)]: markInitialStepVisitedOrReview,
341
+ }
342
+ : {}),
343
+ ...(updatedTaskStatus ? { [getTaskStatusKey(taskNumber)]: updatedTaskStatus } : {}),
344
+ },
345
+ };
346
+ return newState;
347
+ });
348
+ },
349
+ [activeQuickStartID, setAllQuickStartStates, stepAfterInitial],
350
+ );
351
+
352
+ const previousStep = useCallback(() => {
353
+ setAllQuickStartStates((qs) => {
354
+ const quickStart = qs[activeQuickStartID];
355
+ const taskNumber = quickStart?.taskNumber as number;
356
+
357
+ if (taskNumber < 0) {
358
+ return qs;
359
+ }
360
+
361
+ return {
362
+ ...qs,
363
+ [activeQuickStartID]: {
364
+ ...quickStart,
365
+ taskNumber: taskNumber - 1,
366
+ },
367
+ };
368
+ });
369
+ }, [activeQuickStartID, setAllQuickStartStates]);
370
+
371
+ const setQuickStartTaskNumber = useCallback(
372
+ (quickStartId: string, taskNumber: number) => {
373
+ setAllQuickStartStates((qs) => {
374
+ const quickStart = qs[quickStartId];
375
+ const status = quickStart?.status;
376
+ let updatedStatus;
377
+ if (taskNumber > -1 && status === QuickStartStatus.NOT_STARTED) {
378
+ updatedStatus = QuickStartStatus.IN_PROGRESS;
379
+ }
380
+
381
+ let updatedTaskStatus = {};
382
+ for (let taskIndex = 0; taskIndex <= taskNumber; taskIndex++) {
383
+ const taskStatus = quickStart[getTaskStatusKey(taskIndex)];
384
+ const newTaskStatus =
385
+ taskStatus === QuickStartTaskStatus.INIT ? stepAfterInitial : undefined;
386
+ if (newTaskStatus) {
387
+ updatedTaskStatus = {
388
+ ...updatedTaskStatus,
389
+ [getTaskStatusKey(taskIndex)]: newTaskStatus,
390
+ };
391
+ }
392
+ }
393
+ const updatedQuickStart = {
394
+ ...quickStart,
395
+ ...(updatedStatus ? { status: updatedStatus } : {}),
396
+ taskNumber,
397
+ ...updatedTaskStatus,
398
+ };
399
+ return { ...qs, [quickStartId]: updatedQuickStart };
400
+ });
401
+ },
402
+ [setAllQuickStartStates, stepAfterInitial],
403
+ );
404
+
405
+ const setQuickStartTaskStatus = useCallback(
406
+ (taskStatus: QuickStartTaskStatus) => {
407
+ const quickStart = allQuickStartStates[activeQuickStartID];
408
+ const { taskNumber } = quickStart;
409
+ const updatedQuickStart = {
410
+ ...quickStart,
411
+ [getTaskStatusKey(taskNumber as any)]: taskStatus,
412
+ };
413
+ setAllQuickStartStates((qs) => ({
414
+ ...qs,
415
+ [activeQuickStartID]: updatedQuickStart,
416
+ }));
417
+ },
418
+ [allQuickStartStates, activeQuickStartID, setAllQuickStartStates],
419
+ );
420
+
421
+ const activeQuickStartState = allQuickStartStates?.[activeQuickStartID] ?? {};
422
+
423
+ const getQuickStartForId = useCallback((id: string) => allQuickStartStates[id], [
424
+ allQuickStartStates,
425
+ ]);
426
+
427
+ return {
428
+ allQuickStarts: quickStarts,
429
+ setAllQuickStarts: updateAllQuickStarts, // revisit if this should be in public context API
430
+ activeQuickStartID,
431
+ setActiveQuickStartID,
432
+ allQuickStartStates,
433
+ setAllQuickStartStates,
434
+ activeQuickStartState,
435
+ setActiveQuickStart: value.setActiveQuickStart || setActiveQuickStart,
436
+ startQuickStart: value.startQuickStart || startQuickStart,
437
+ restartQuickStart: value.restartQuickStart || restartQuickStart,
438
+ nextStep: value.nextStep || nextStep,
439
+ previousStep: value.previousStep || previousStep,
440
+ setQuickStartTaskNumber, // revisit if this should be in public context API
441
+ setQuickStartTaskStatus, // revisit if this should be in public context API
442
+ getQuickStartForId,
443
+ footer,
444
+ useLegacyHeaderColors,
445
+ useQueryParams,
446
+ markdown,
447
+ resourceBundle,
448
+ getResource: findResource, // revisit if this should be in public context API
449
+ setResourceBundle: changeResourceBundle,
450
+ language,
451
+ setLanguage,
452
+ // revisit if this should be in public context API
453
+ filter: {
454
+ keyword: filterKeyword,
455
+ status: {
456
+ statusTypes,
457
+ statusFilters,
458
+ },
459
+ },
460
+ setFilter, // revisit if this should be in public context API
461
+ loading,
462
+ setLoading,
463
+ alwaysShowTaskReview,
464
+ setAlwaysShowTaskReview,
465
+ };
466
+ };
467
+
468
+ export const QuickStartContextProvider: React.FC<{
469
+ children: React.ReactNode;
470
+ value: QuickStartContextValues;
471
+ }> = ({ children, value }) => {
472
+ return (
473
+ <QuickStartContext.Provider value={useValuesForQuickStartContext(value)}>
474
+ {children}
475
+ </QuickStartContext.Provider>
476
+ );
477
+ };
@@ -0,0 +1,72 @@
1
+ import {
2
+ AccessReviewResourceAttributes,
3
+ ObjectMetadata,
4
+ } from '../ConsoleInternal/module/k8s/types';
5
+
6
+ export type QuickStart = {
7
+ apiVersion?: string;
8
+ kind?: string;
9
+ metadata: ObjectMetadata;
10
+ spec: QuickStartSpec;
11
+ };
12
+
13
+ export type QuickStartSpec = {
14
+ version?: number;
15
+ displayName: string;
16
+ durationMinutes?: number;
17
+ icon: React.ReactNode;
18
+ description: string;
19
+ prerequisites?: string[];
20
+ introduction?: string;
21
+ tasks?: QuickStartTask[];
22
+ conclusion?: string;
23
+ nextQuickStart?: string[];
24
+ accessReviewResources?: AccessReviewResourceAttributes[];
25
+ link?: QuickStartExternal;
26
+ type?: QuickStartType;
27
+ };
28
+
29
+ export type QuickStartTask = {
30
+ title?: string;
31
+ description?: string;
32
+ review?: QuickStartTaskReview;
33
+ summary?: QuickStartTaskSummary;
34
+ };
35
+
36
+ export type QuickStartTaskReview = {
37
+ instructions?: string;
38
+ failedTaskHelp?: string;
39
+ };
40
+
41
+ export type QuickStartTaskSummary = {
42
+ success?: string;
43
+ failed?: string;
44
+ };
45
+
46
+ export type AllQuickStartStates = Record<string, QuickStartState>;
47
+
48
+ export type QuickStartState = Record<string, string | number | QuickStartStatus>;
49
+
50
+ export enum QuickStartStatus {
51
+ COMPLETE = 'Complete',
52
+ IN_PROGRESS = 'In Progress',
53
+ NOT_STARTED = 'Not started',
54
+ }
55
+
56
+ export enum QuickStartTaskStatus {
57
+ INIT = 'Initial',
58
+ VISITED = 'Visited',
59
+ REVIEW = 'Review',
60
+ SUCCESS = 'Success',
61
+ FAILED = 'Failed',
62
+ }
63
+
64
+ export type QuickStartExternal = {
65
+ href: string;
66
+ text?: string;
67
+ };
68
+
69
+ export type QuickStartType = {
70
+ text: string;
71
+ color?: 'blue' | 'cyan' | 'green' | 'orange' | 'purple' | 'red' | 'grey';
72
+ };
@@ -0,0 +1,92 @@
1
+ import { AllQuickStartStates, QuickStart, QuickStartStatus } from './quick-start-types';
2
+
3
+ export const QUICK_START_NAME = 'console.openshift.io/name';
4
+
5
+ export const getQuickStartByName = (name: string, quickStarts: QuickStart[]): QuickStart =>
6
+ quickStarts.find((quickStart) => quickStart.metadata.name === name);
7
+
8
+ export const getQuickStartStatus = (
9
+ allQuickStartStates: AllQuickStartStates,
10
+ quickStartID: string,
11
+ ): QuickStartStatus =>
12
+ (allQuickStartStates?.[quickStartID]?.status as QuickStartStatus) ?? QuickStartStatus.NOT_STARTED;
13
+
14
+ export const getTaskStatusKey = (taskNumber: number): string => `taskStatus${taskNumber}`;
15
+
16
+ export const getQuickStartStatusCount = (
17
+ allQuickStartStates: AllQuickStartStates,
18
+ quickStarts: QuickStart[],
19
+ ): Record<QuickStartStatus, number> => {
20
+ return quickStarts.reduce(
21
+ (totals, item) => {
22
+ totals[getQuickStartStatus(allQuickStartStates, item.metadata.name)]++;
23
+ return totals;
24
+ },
25
+ {
26
+ [QuickStartStatus.IN_PROGRESS]: 0,
27
+ [QuickStartStatus.COMPLETE]: 0,
28
+ [QuickStartStatus.NOT_STARTED]: 0,
29
+ },
30
+ );
31
+ };
32
+
33
+ declare const window: Window & {
34
+ SERVER_FLAGS: {
35
+ quickStarts: any;
36
+ };
37
+ };
38
+
39
+ export const getDisabledQuickStarts = (): string[] => {
40
+ let disabledQuickStarts = [];
41
+ const quickStartServerData = window.SERVER_FLAGS?.quickStarts;
42
+ try {
43
+ if (quickStartServerData) {
44
+ disabledQuickStarts = JSON.parse(quickStartServerData).disabled ?? [];
45
+ }
46
+ } catch (e) {
47
+ // eslint-disable-next-line no-console
48
+ console.error('error while parsing SERVER_FLAG.quickStarts', e);
49
+ }
50
+ return disabledQuickStarts;
51
+ };
52
+
53
+ export const isDisabledQuickStart = (
54
+ quickstart: QuickStart,
55
+ disabledQuickStarts: string[],
56
+ ): boolean => {
57
+ const quickStartName =
58
+ quickstart.metadata.annotations?.[QUICK_START_NAME] ?? quickstart.metadata.name;
59
+ return disabledQuickStarts.includes(quickStartName);
60
+ };
61
+
62
+ export const filterQuickStarts = (
63
+ quickStarts: QuickStart[],
64
+ filterText: string,
65
+ statusFilters: string[],
66
+ allQuickStartStates: AllQuickStartStates,
67
+ ): QuickStart[] => {
68
+ const searchText = filterText.toLowerCase();
69
+ return quickStarts.filter(
70
+ ({ metadata: { name }, spec: { displayName, prerequisites = [], description } }) => {
71
+ const matchesFilter =
72
+ statusFilters.length > 0
73
+ ? statusFilters.includes(getQuickStartStatus(allQuickStartStates, name))
74
+ : true;
75
+ const matchesText =
76
+ displayName.toLowerCase().includes(searchText) ||
77
+ description.toLowerCase().includes(searchText) ||
78
+ prerequisites.some((text) => text.toLowerCase().includes(searchText));
79
+
80
+ return matchesFilter && matchesText;
81
+ },
82
+ );
83
+ };
84
+
85
+ export const camelize = (str: string) => {
86
+ return str.replace(/(?:^\w|[A-Z]|\b\w|\s+)/g, function(match, index) {
87
+ if (+match === 0) {
88
+ return '';
89
+ } // or if (/\s+/.test(match)) for white spaces
90
+ return index === 0 ? match.toLowerCase() : match.toUpperCase();
91
+ });
92
+ };
@@ -0,0 +1,38 @@
1
+ import { useState } from 'react';
2
+
3
+ export const useLocalStorage = (key: string, initialValue: any) => {
4
+ // State to store our value
5
+ // Pass initial state function to useState so logic is only executed once
6
+ const [storedValue, setStoredValue] = useState(() => {
7
+ try {
8
+ // Get from local storage by key
9
+ const item = window.localStorage.getItem(key);
10
+ // Parse stored json or if none return initialValue
11
+ return item ? JSON.parse(item) : initialValue;
12
+ } catch (error) {
13
+ // If error also return initialValue
14
+ // eslint-disable-next-line no-console
15
+ console.log(error);
16
+ return initialValue;
17
+ }
18
+ });
19
+
20
+ // Return a wrapped version of useState's setter function that ...
21
+ // ... persists the new value to localStorage.
22
+ const setValue = (value: any) => {
23
+ try {
24
+ // Allow value to be a function so we have same API as useState
25
+ const valueToStore = value instanceof Function ? value(storedValue) : value;
26
+ // Save state
27
+ setStoredValue(valueToStore);
28
+ // Save to local storage
29
+ window.localStorage.setItem(key, JSON.stringify(valueToStore));
30
+ } catch (error) {
31
+ // A more advanced implementation would handle the error case
32
+ // eslint-disable-next-line no-console
33
+ console.log(error);
34
+ }
35
+ };
36
+
37
+ return [storedValue, setValue];
38
+ };