@patternfly/quickstarts 2.2.1 → 2.2.4

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 (203) hide show
  1. package/README.md +20 -20
  2. package/dist/ConsoleShared/src/components/markdown-extensions/code-extension.d.ts +7 -0
  3. package/dist/ConsoleShared/src/components/markdown-extensions/index.d.ts +1 -0
  4. package/dist/HelpTopicDrawer.d.ts +8 -2
  5. package/dist/QuickStartDrawer.d.ts +21 -2
  6. package/dist/index.d.ts +1 -0
  7. package/dist/index.es.js +127 -21
  8. package/dist/index.es.js.map +1 -1
  9. package/dist/index.js +126 -19
  10. package/dist/index.js.map +1 -1
  11. package/dist/patternfly-docs/quick-starts/design-guidelines/design-guidelines.md +105 -0
  12. package/dist/patternfly-docs/quick-starts/design-guidelines/img/card-elements copy.png +0 -0
  13. package/dist/patternfly-docs/quick-starts/design-guidelines/img/card-elements.png +0 -0
  14. package/dist/patternfly-docs/quick-starts/design-guidelines/img/catalog-elements.png +0 -0
  15. package/dist/patternfly-docs/quick-starts/design-guidelines/img/check-your-work.png +0 -0
  16. package/dist/patternfly-docs/quick-starts/design-guidelines/img/introduction-screen.png +0 -0
  17. package/dist/patternfly-docs/quick-starts/design-guidelines/img/mixed-catalog.png +0 -0
  18. package/dist/patternfly-docs/quick-starts/design-guidelines/img/prerequisites.png +0 -0
  19. package/dist/patternfly-docs/quick-starts/design-guidelines/img/qs-context.png +0 -0
  20. package/dist/patternfly-docs/quick-starts/design-guidelines/img/side-panel-elements.png +0 -0
  21. package/dist/patternfly-docs/quick-starts/design-guidelines/img/side-panel-resized.png +0 -0
  22. package/dist/patternfly-docs/quick-starts/design-guidelines/img/side-panel.png +0 -0
  23. package/dist/patternfly-docs/quick-starts/design-guidelines/img/task-no.png +0 -0
  24. package/dist/patternfly-docs/quick-starts/design-guidelines/img/task-yes.png +0 -0
  25. package/dist/patternfly-docs/quick-starts/design-guidelines/img/task.png +0 -0
  26. package/dist/patternfly-docs/quick-starts/examples/Basic.jsx +73 -0
  27. package/dist/patternfly-docs/quick-starts/examples/HelpTopic.jsx +53 -0
  28. package/dist/patternfly-docs/quick-starts/examples/about.md +77 -0
  29. package/dist/patternfly-docs/quick-starts/examples/basic.md +27 -0
  30. package/dist/patternfly-docs/quick-starts/examples/example-data/example-help-topics.js +173 -0
  31. package/dist/patternfly-docs/quick-starts/examples/example-data/example-quickstarts.js +215 -0
  32. package/dist/patternfly-docs/quick-starts/examples/example-data/index.js +15 -0
  33. package/dist/patternfly-docs/quick-starts/examples/help-topics.md +25 -0
  34. package/dist/patternfly-docs/quick-starts/examples/img/catalog.png +0 -0
  35. package/dist/patternfly-docs/quick-starts/examples/img/help-topic.png +0 -0
  36. package/dist/patternfly-docs/quick-starts/examples/img/side-panel.png +0 -0
  37. package/dist/patternfly-nested.css +11 -1
  38. package/dist/quickstarts-base.css +49 -11
  39. package/dist/quickstarts-full.es.js +451 -305
  40. package/dist/quickstarts-full.es.js.map +1 -1
  41. package/dist/quickstarts-standalone.css +5 -15
  42. package/dist/quickstarts-standalone.min.css +1 -1
  43. package/dist/quickstarts.css +49 -11
  44. package/dist/quickstarts.min.css +1 -1
  45. package/dist/utils/asciidoc-procedure-parser.d.ts +12 -0
  46. package/dist/utils/help-topic-types.d.ts +7 -1
  47. package/package.json +11 -4
  48. package/src/ConsoleInternal/components/_icon-and-text.scss +14 -0
  49. package/src/ConsoleInternal/components/_markdown-view.scss +19 -0
  50. package/src/ConsoleInternal/components/catalog/_catalog.scss +390 -0
  51. package/src/ConsoleInternal/components/markdown-view.tsx +305 -0
  52. package/src/ConsoleInternal/components/utils/_status-box.scss +58 -0
  53. package/src/ConsoleInternal/components/utils/camel-case-wrap.tsx +33 -0
  54. package/src/ConsoleInternal/components/utils/index.tsx +3 -0
  55. package/src/ConsoleInternal/components/utils/router.ts +47 -0
  56. package/src/ConsoleInternal/components/utils/status-box.tsx +94 -0
  57. package/src/ConsoleInternal/module/k8s/types.ts +53 -0
  58. package/src/ConsoleShared/index.ts +1 -0
  59. package/src/ConsoleShared/src/components/index.ts +7 -0
  60. package/src/ConsoleShared/src/components/layout/PageLayout.scss +29 -0
  61. package/src/ConsoleShared/src/components/markdown-extensions/MarkdownCopyClipboard.tsx +93 -0
  62. package/src/ConsoleShared/src/components/markdown-extensions/__tests__/MarkdownCopyClipboard.spec.tsx +25 -0
  63. package/src/ConsoleShared/src/components/markdown-extensions/__tests__/test-data.ts +5 -0
  64. package/src/ConsoleShared/src/components/markdown-extensions/admonition-extension.tsx +66 -0
  65. package/src/ConsoleShared/src/components/markdown-extensions/code-extension.tsx +25 -0
  66. package/src/ConsoleShared/src/components/markdown-extensions/const.ts +3 -0
  67. package/src/ConsoleShared/src/components/markdown-extensions/index.ts +5 -0
  68. package/src/ConsoleShared/src/components/markdown-extensions/inline-clipboard-extension.tsx +45 -0
  69. package/src/ConsoleShared/src/components/markdown-extensions/multiline-clipboard-extension.tsx +50 -0
  70. package/src/ConsoleShared/src/components/markdown-extensions/showdown-extension.scss +52 -0
  71. package/src/ConsoleShared/src/components/markdown-extensions/utils.ts +3 -0
  72. package/src/ConsoleShared/src/components/markdown-highlight-extension/MarkdownHighlightExtension.tsx +64 -0
  73. package/src/ConsoleShared/src/components/markdown-highlight-extension/highlight-consts.ts +9 -0
  74. package/src/ConsoleShared/src/components/markdown-highlight-extension/index.ts +1 -0
  75. package/src/ConsoleShared/src/components/modal/Modal.scss +3 -0
  76. package/src/ConsoleShared/src/components/modal/Modal.tsx +19 -0
  77. package/src/ConsoleShared/src/components/modal/index.ts +1 -0
  78. package/src/ConsoleShared/src/components/popper/Portal.tsx +23 -0
  79. package/src/ConsoleShared/src/components/popper/SimplePopper.tsx +90 -0
  80. package/src/ConsoleShared/src/components/popper/index.ts +2 -0
  81. package/src/ConsoleShared/src/components/spotlight/InteractiveSpotlight.tsx +58 -0
  82. package/src/ConsoleShared/src/components/spotlight/Spotlight.tsx +35 -0
  83. package/src/ConsoleShared/src/components/spotlight/StaticSpotlight.tsx +32 -0
  84. package/src/ConsoleShared/src/components/spotlight/index.ts +1 -0
  85. package/src/ConsoleShared/src/components/spotlight/spotlight.scss +63 -0
  86. package/src/ConsoleShared/src/components/status/GenericStatus.tsx +33 -0
  87. package/src/ConsoleShared/src/components/status/NotStartedIcon.tsx +27 -0
  88. package/src/ConsoleShared/src/components/status/PopoverStatus.tsx +42 -0
  89. package/src/ConsoleShared/src/components/status/Status.tsx +38 -0
  90. package/src/ConsoleShared/src/components/status/StatusIconAndText.tsx +42 -0
  91. package/src/ConsoleShared/src/components/status/icons.tsx +77 -0
  92. package/src/ConsoleShared/src/components/status/index.tsx +1 -0
  93. package/src/ConsoleShared/src/components/status/statuses.tsx +36 -0
  94. package/src/ConsoleShared/src/components/status/types.ts +7 -0
  95. package/src/ConsoleShared/src/components/utils/FallbackImg.tsx +20 -0
  96. package/src/ConsoleShared/src/components/utils/index.ts +1 -0
  97. package/src/ConsoleShared/src/constants/index.ts +1 -0
  98. package/src/ConsoleShared/src/constants/ui.ts +1 -0
  99. package/src/ConsoleShared/src/hooks/index.ts +6 -0
  100. package/src/ConsoleShared/src/hooks/scroll.ts +52 -0
  101. package/src/ConsoleShared/src/hooks/useBoundingClientRect.ts +18 -0
  102. package/src/ConsoleShared/src/hooks/useEventListener.ts +14 -0
  103. package/src/ConsoleShared/src/hooks/useForceRender.ts +6 -0
  104. package/src/ConsoleShared/src/hooks/useResizeObserver.ts +20 -0
  105. package/src/ConsoleShared/src/hooks/useScrollShadows.ts +45 -0
  106. package/src/ConsoleShared/src/index.ts +4 -0
  107. package/src/ConsoleShared/src/utils/index.ts +1 -0
  108. package/src/ConsoleShared/src/utils/useCombineRefs.ts +17 -0
  109. package/src/HelpTopicDrawer.tsx +124 -0
  110. package/src/HelpTopicPanelContent.tsx +152 -0
  111. package/src/QuickStartCatalogPage.tsx +190 -0
  112. package/src/QuickStartCloseModal.tsx +47 -0
  113. package/src/QuickStartController.tsx +113 -0
  114. package/src/QuickStartDrawer.scss +11 -0
  115. package/src/QuickStartDrawer.tsx +265 -0
  116. package/src/QuickStartMarkdownView.tsx +75 -0
  117. package/src/QuickStartPanelContent.scss +46 -0
  118. package/src/QuickStartPanelContent.tsx +153 -0
  119. package/src/__tests__/quick-start-utils.spec.tsx +16 -0
  120. package/src/catalog/Catalog/QuickStartCatalogHeader.tsx +18 -0
  121. package/src/catalog/Catalog/QuickStartCatalogSection.tsx +9 -0
  122. package/src/catalog/Catalog/QuickStartCatalogToolbar.tsx +12 -0
  123. package/src/catalog/Catalog/index.ts +3 -0
  124. package/src/catalog/QuickStartCatalog.scss +8 -0
  125. package/src/catalog/QuickStartCatalog.tsx +42 -0
  126. package/src/catalog/QuickStartTile.scss +11 -0
  127. package/src/catalog/QuickStartTile.tsx +105 -0
  128. package/src/catalog/QuickStartTileDescription.scss +29 -0
  129. package/src/catalog/QuickStartTileDescription.tsx +79 -0
  130. package/src/catalog/QuickStartTileFooter.tsx +101 -0
  131. package/src/catalog/QuickStartTileFooterExternal.tsx +40 -0
  132. package/src/catalog/QuickStartTileHeader.scss +12 -0
  133. package/src/catalog/QuickStartTileHeader.tsx +77 -0
  134. package/src/catalog/Toolbar/QuickStartCatalogFilter.scss +25 -0
  135. package/src/catalog/Toolbar/QuickStartCatalogFilter.tsx +34 -0
  136. package/src/catalog/Toolbar/QuickStartCatalogFilterItems.tsx +199 -0
  137. package/src/catalog/__tests__/QuickStartCatalog.spec.tsx +35 -0
  138. package/src/catalog/__tests__/QuickStartTile.spec.tsx +38 -0
  139. package/src/catalog/__tests__/QuickStartTileDescription.spec.tsx +44 -0
  140. package/src/catalog/index.ts +9 -0
  141. package/src/controller/QuickStartConclusion.tsx +63 -0
  142. package/src/controller/QuickStartContent.scss +12 -0
  143. package/src/controller/QuickStartContent.tsx +72 -0
  144. package/src/controller/QuickStartFooter.scss +13 -0
  145. package/src/controller/QuickStartFooter.tsx +128 -0
  146. package/src/controller/QuickStartIntroduction.scss +35 -0
  147. package/src/controller/QuickStartIntroduction.tsx +66 -0
  148. package/src/controller/QuickStartTaskHeader.scss +58 -0
  149. package/src/controller/QuickStartTaskHeader.tsx +116 -0
  150. package/src/controller/QuickStartTaskHeaderList.scss +17 -0
  151. package/src/controller/QuickStartTaskHeaderList.tsx +35 -0
  152. package/src/controller/QuickStartTaskReview.scss +30 -0
  153. package/src/controller/QuickStartTaskReview.tsx +81 -0
  154. package/src/controller/QuickStartTasks.scss +89 -0
  155. package/src/controller/QuickStartTasks.tsx +75 -0
  156. package/src/controller/__tests__/QuickStartConclusion.spec.tsx +95 -0
  157. package/src/controller/__tests__/QuickStartContent.spec.tsx +52 -0
  158. package/src/controller/__tests__/QuickStartFooter.spec.tsx +148 -0
  159. package/src/controller/__tests__/QuickStartTaskHeader.spec.tsx +56 -0
  160. package/src/controller/__tests__/QuickStartTaskReview.spec.tsx +45 -0
  161. package/src/controller/__tests__/QuickStartTasks.spec.tsx +81 -0
  162. package/src/data/mocks/json/explore-pipeline-quickstart.ts +66 -0
  163. package/src/data/mocks/json/explore-serverless-quickstart.ts +90 -0
  164. package/src/data/mocks/json/monitor-sampleapp-quickstart.ts +77 -0
  165. package/src/data/mocks/json/tour-icons.ts +3 -0
  166. package/src/data/mocks/yamls/add-healthchecks-quickstart.yaml +67 -0
  167. package/src/data/mocks/yamls/explore-pipeline-quickstart.yaml +57 -0
  168. package/src/data/mocks/yamls/explore-serverless-quickstart.yaml +83 -0
  169. package/src/data/mocks/yamls/install-associate-pipeline-quickstart.yaml +74 -0
  170. package/src/data/mocks/yamls/monitor-sampleapp-quickstart.yaml +66 -0
  171. package/src/data/mocks/yamls/sample-application-quickstart.yaml +97 -0
  172. package/src/data/mocks/yamls/serverless-application-quickstart.yaml +141 -0
  173. package/src/data/quick-start-test-data.ts +10 -0
  174. package/src/data/test-utils.ts +11 -0
  175. package/src/declaration.d.ts +2 -0
  176. package/src/index.ts +17 -0
  177. package/src/locales/en/quickstart.json +46 -0
  178. package/src/styles/_base.scss +54 -0
  179. package/src/styles/_dark-custom-override.scss +62 -0
  180. package/src/styles/legacy-bootstrap/README.md +21 -0
  181. package/src/styles/legacy-bootstrap/_code.scss +44 -0
  182. package/src/styles/legacy-bootstrap/_tables.scss +38 -0
  183. package/src/styles/legacy-bootstrap/_type.scss +90 -0
  184. package/src/styles/legacy-bootstrap/_variables.scss +48 -0
  185. package/src/styles/legacy-bootstrap.scss +5 -0
  186. package/src/styles/patternfly-global-entry.ts +1 -0
  187. package/src/styles/patternfly-global.scss +28 -0
  188. package/src/styles/patternfly-nested-entry.ts +1 -0
  189. package/src/styles/patternfly-nested.scss +18 -0
  190. package/src/styles/quickstarts-standalone-entry.ts +1 -0
  191. package/src/styles/quickstarts-standalone.scss +7 -0
  192. package/src/styles/style.scss +12 -0
  193. package/src/styles/vendor-entry.ts +1 -0
  194. package/src/styles/vendor.scss +7 -0
  195. package/src/utils/PluralResolver.ts +356 -0
  196. package/src/utils/asciidoc-procedure-parser.ts +132 -0
  197. package/src/utils/const.ts +10 -0
  198. package/src/utils/help-topic-context.tsx +74 -0
  199. package/src/utils/help-topic-types.ts +16 -0
  200. package/src/utils/quick-start-context.tsx +477 -0
  201. package/src/utils/quick-start-types.ts +72 -0
  202. package/src/utils/quick-start-utils.ts +92 -0
  203. package/src/utils/useLocalStorage.ts +38 -0
@@ -0,0 +1,190 @@
1
+ import * as React from 'react';
2
+ import {
3
+ Button,
4
+ Divider,
5
+ EmptyState,
6
+ EmptyStateBody,
7
+ EmptyStateIcon,
8
+ EmptyStatePrimary,
9
+ Text,
10
+ Title,
11
+ } from '@patternfly/react-core';
12
+ import SearchIcon from '@patternfly/react-icons/dist/js/icons/search-icon';
13
+ import { EmptyBox, LoadingBox, clearFilterParams } from '@console/internal/components/utils';
14
+ import QuickStartCatalog from './catalog/QuickStartCatalog';
15
+ import QuickStartCatalogFilter from './catalog/Toolbar/QuickStartCatalogFilter';
16
+ import { QuickStartContext, QuickStartContextValues } from './utils/quick-start-context';
17
+ import { QuickStart } from './utils/quick-start-types';
18
+ import { filterQuickStarts } from './utils/quick-start-utils';
19
+
20
+ export type QuickStartCatalogPageProps = {
21
+ quickStarts?: QuickStart[];
22
+ showFilter?: boolean;
23
+ sortFnc?: (q1: QuickStart, q2: QuickStart) => number;
24
+ title?: string;
25
+ hint?: string;
26
+ showTitle?: boolean;
27
+ };
28
+
29
+ export const QuickStartCatalogEmptyState = ({ clearFilters }) => {
30
+ const { getResource } = React.useContext<QuickStartContextValues>(QuickStartContext);
31
+ return (
32
+ <EmptyState>
33
+ <EmptyStateIcon icon={SearchIcon} />
34
+ <Title size="lg" headingLevel="h4">
35
+ {getResource('No results found')}
36
+ </Title>
37
+ <EmptyStateBody>
38
+ {getResource(
39
+ 'No results match the filter criteria. Remove filters or clear all filters to show results.',
40
+ )}
41
+ </EmptyStateBody>
42
+ <EmptyStatePrimary>
43
+ <Button variant="link" onClick={clearFilters} data-test="clear-filter button">
44
+ {getResource('Clear all filters')}
45
+ </Button>
46
+ </EmptyStatePrimary>
47
+ </EmptyState>
48
+ );
49
+ };
50
+
51
+ export const QuickStartCatalogPage: React.FC<QuickStartCatalogPageProps> = ({
52
+ quickStarts,
53
+ showFilter,
54
+ sortFnc = (q1, q2) => q1.spec.displayName.localeCompare(q2.spec.displayName),
55
+ title,
56
+ hint,
57
+ showTitle = true,
58
+ }) => {
59
+ const sortFncCallback = React.useCallback(sortFnc, []);
60
+ const {
61
+ allQuickStarts = [],
62
+ setAllQuickStarts,
63
+ allQuickStartStates,
64
+ getResource,
65
+ filter,
66
+ setFilter,
67
+ loading,
68
+ } = React.useContext<QuickStartContextValues>(QuickStartContext);
69
+
70
+ React.useEffect(() => {
71
+ // passed through prop, not context
72
+ if (quickStarts && JSON.stringify(quickStarts) !== JSON.stringify(allQuickStarts)) {
73
+ setAllQuickStarts(quickStarts);
74
+ }
75
+ }, [quickStarts, allQuickStarts, setAllQuickStarts]);
76
+
77
+ const initialFilteredQuickStarts = showFilter
78
+ ? filterQuickStarts(
79
+ allQuickStarts,
80
+ filter.keyword,
81
+ filter.status.statusFilters,
82
+ allQuickStartStates,
83
+ ).sort(sortFncCallback)
84
+ : allQuickStarts;
85
+
86
+ const [filteredQuickStarts, setFilteredQuickStarts] = React.useState(initialFilteredQuickStarts);
87
+ React.useEffect(() => {
88
+ const filteredQs = showFilter
89
+ ? filterQuickStarts(
90
+ allQuickStarts,
91
+ filter.keyword,
92
+ filter.status.statusFilters,
93
+ allQuickStartStates,
94
+ ).sort(sortFncCallback)
95
+ : allQuickStarts;
96
+ // also needs a check whether the content of the QS changed
97
+ if (
98
+ filteredQs.length !== filteredQuickStarts.length ||
99
+ JSON.stringify(filteredQs) !== JSON.stringify(filteredQuickStarts)
100
+ ) {
101
+ setFilteredQuickStarts(filteredQs);
102
+ }
103
+ }, [
104
+ allQuickStarts,
105
+ allQuickStartStates,
106
+ showFilter,
107
+ filter.keyword,
108
+ filter.status.statusFilters,
109
+ sortFncCallback,
110
+ filteredQuickStarts,
111
+ ]);
112
+
113
+ const clearFilters = () => {
114
+ setFilter('keyword', '');
115
+ setFilter('status', []);
116
+ clearFilterParams();
117
+ setFilteredQuickStarts(
118
+ allQuickStarts.sort((q1, q2) => q1.spec.displayName.localeCompare(q2.spec.displayName)),
119
+ );
120
+ };
121
+
122
+ const onSearchInputChange = (searchValue) => {
123
+ const result = filterQuickStarts(
124
+ allQuickStarts,
125
+ searchValue,
126
+ filter.status.statusFilters,
127
+ allQuickStartStates,
128
+ ).sort((q1, q2) => q1.spec.displayName.localeCompare(q2.spec.displayName));
129
+ if (searchValue !== filter.keyword) {
130
+ setFilter('keyword', searchValue);
131
+ }
132
+ if (result.length !== filteredQuickStarts.length) {
133
+ setFilteredQuickStarts(result);
134
+ }
135
+ };
136
+
137
+ const onStatusChange = (statusList) => {
138
+ const result = filterQuickStarts(
139
+ allQuickStarts,
140
+ filter.keyword,
141
+ statusList,
142
+ allQuickStartStates,
143
+ ).sort((q1, q2) => q1.spec.displayName.localeCompare(q2.spec.displayName));
144
+ if (JSON.stringify(statusList) !== JSON.stringify(filter.status)) {
145
+ setFilter('status', statusList);
146
+ }
147
+ if (result.length !== filteredQuickStarts.length) {
148
+ setFilteredQuickStarts(result);
149
+ }
150
+ };
151
+
152
+ if (loading) {
153
+ return <LoadingBox />;
154
+ }
155
+
156
+ if (!allQuickStarts || allQuickStarts.length === 0) {
157
+ return <EmptyBox label={getResource('Quick Starts')} />;
158
+ }
159
+
160
+ return (
161
+ <div className="pfext-quick-start__base">
162
+ {showTitle && (
163
+ <div className="pfext-page-layout__header">
164
+ <Text component="h1" className="pfext-page-layout__title" data-test="page-title">
165
+ {title || getResource('Quick Starts')}
166
+ </Text>
167
+ {hint && <div className="pfext-page-layout__hint">{hint}</div>}
168
+ </div>
169
+ )}
170
+ {showTitle && <Divider component="div" />}
171
+ {showFilter && (
172
+ <>
173
+ <QuickStartCatalogFilter
174
+ quickStartsCount={filteredQuickStarts.length}
175
+ onSearchInputChange={onSearchInputChange}
176
+ onStatusChange={onStatusChange}
177
+ />
178
+ <Divider component="div" />
179
+ </>
180
+ )}
181
+ <>
182
+ {filteredQuickStarts.length === 0 ? (
183
+ <QuickStartCatalogEmptyState clearFilters={clearFilters} />
184
+ ) : (
185
+ <QuickStartCatalog quickStarts={filteredQuickStarts} />
186
+ )}
187
+ </>
188
+ </div>
189
+ );
190
+ };
@@ -0,0 +1,47 @@
1
+ import * as React from 'react';
2
+ import { Button, Flex, FlexItem, ModalVariant } from '@patternfly/react-core';
3
+ import { Modal } from '@console/shared';
4
+ import { QuickStartContext, QuickStartContextValues } from './utils/quick-start-context';
5
+
6
+ type QuickStartCloseModalProps = {
7
+ isOpen: boolean;
8
+ onConfirm: () => void;
9
+ onCancel: () => void;
10
+ };
11
+
12
+ const QuickStartCloseModal: React.FC<QuickStartCloseModalProps> = ({
13
+ isOpen,
14
+ onConfirm,
15
+ onCancel,
16
+ }) => {
17
+ const { getResource } = React.useContext<QuickStartContextValues>(QuickStartContext);
18
+ return (
19
+ <Modal
20
+ className="pfext-quick-start-drawer__modal pfext-quick-start__base"
21
+ isOpen={isOpen}
22
+ variant={ModalVariant.small}
23
+ showClose={false}
24
+ data-test="leave-quickstart"
25
+ title={getResource('Leave quick start?')}
26
+ footer={
27
+ <Flex>
28
+ <FlexItem align={{ default: 'alignRight' }}>
29
+ <Button variant="secondary" data-test="cancel button" onClick={onCancel}>
30
+ {getResource('Cancel')}
31
+ </Button>
32
+ </FlexItem>
33
+ <FlexItem>
34
+ <Button variant="primary" data-test="leave button" onClick={onConfirm}>
35
+ {getResource('Leave')}
36
+ </Button>
37
+ </FlexItem>
38
+ </Flex>
39
+ }
40
+ isFullScreen
41
+ >
42
+ {getResource('Your progress will be saved.')}
43
+ </Modal>
44
+ );
45
+ };
46
+
47
+ export default QuickStartCloseModal;
@@ -0,0 +1,113 @@
1
+ import * as React from 'react';
2
+ import QuickStartContent from './controller/QuickStartContent';
3
+ import QuickStartFooter from './controller/QuickStartFooter';
4
+ import { QuickStartContext, QuickStartContextValues } from './utils/quick-start-context';
5
+ import { QuickStart, QuickStartStatus, QuickStartTaskStatus } from './utils/quick-start-types';
6
+
7
+ type QuickStartControllerProps = {
8
+ quickStart: QuickStart;
9
+ nextQuickStarts?: QuickStart[];
10
+ footerClass: string;
11
+ contentRef: React.Ref<HTMLDivElement>;
12
+ };
13
+
14
+ const QuickStartController: React.FC<QuickStartControllerProps> = ({
15
+ quickStart,
16
+ nextQuickStarts,
17
+ contentRef,
18
+ footerClass,
19
+ }) => {
20
+ const {
21
+ metadata: { name },
22
+ spec: { tasks = [] },
23
+ } = quickStart;
24
+ const totalTasks = tasks?.length;
25
+ const {
26
+ activeQuickStartState,
27
+ setActiveQuickStart,
28
+ setQuickStartTaskNumber,
29
+ setQuickStartTaskStatus,
30
+ nextStep,
31
+ previousStep,
32
+ } = React.useContext<QuickStartContextValues>(QuickStartContext);
33
+ const status = activeQuickStartState?.status as QuickStartStatus;
34
+ const taskNumber = activeQuickStartState?.taskNumber as number;
35
+ const allTaskStatuses = tasks.map(
36
+ (task, index) => activeQuickStartState[`taskStatus${index}`],
37
+ ) as QuickStartTaskStatus[];
38
+
39
+ const handleQuickStartChange = React.useCallback(
40
+ (quickStartId: string) => setActiveQuickStart(quickStartId),
41
+ [setActiveQuickStart],
42
+ );
43
+
44
+ const handleTaskStatusChange = React.useCallback(
45
+ (newTaskStatus: QuickStartTaskStatus) => setQuickStartTaskStatus(newTaskStatus),
46
+ [setQuickStartTaskStatus],
47
+ );
48
+
49
+ const getQuickStartActiveTask = React.useCallback(() => {
50
+ let activeTaskNumber = 0;
51
+ while (
52
+ activeTaskNumber !== totalTasks &&
53
+ activeQuickStartState[`taskStatus${activeTaskNumber}`] !== QuickStartTaskStatus.INIT
54
+ ) {
55
+ activeTaskNumber++;
56
+ }
57
+ return activeTaskNumber;
58
+ }, [totalTasks, activeQuickStartState]);
59
+
60
+ const handleQuickStartContinue = React.useCallback(() => {
61
+ const activeTaskNumber = getQuickStartActiveTask();
62
+ setQuickStartTaskNumber(name, activeTaskNumber);
63
+ }, [getQuickStartActiveTask, setQuickStartTaskNumber, name]);
64
+
65
+ const handleNext = React.useCallback(() => {
66
+ if (status === QuickStartStatus.COMPLETE && taskNumber === totalTasks) {
67
+ return handleQuickStartChange('');
68
+ }
69
+
70
+ if (status !== QuickStartStatus.NOT_STARTED && taskNumber === -1) {
71
+ return handleQuickStartContinue();
72
+ }
73
+
74
+ return nextStep(totalTasks);
75
+ }, [handleQuickStartChange, nextStep, status, taskNumber, totalTasks, handleQuickStartContinue]);
76
+
77
+ const handleBack = React.useCallback(() => {
78
+ return previousStep();
79
+ }, [previousStep]);
80
+
81
+ const handleTaskSelect = React.useCallback(
82
+ (selectedTaskNumber: number) => {
83
+ setQuickStartTaskNumber(name, selectedTaskNumber);
84
+ },
85
+ [name, setQuickStartTaskNumber],
86
+ );
87
+
88
+ return (
89
+ <>
90
+ <QuickStartContent
91
+ quickStart={quickStart}
92
+ nextQuickStarts={nextQuickStarts}
93
+ taskNumber={taskNumber}
94
+ allTaskStatuses={allTaskStatuses}
95
+ onTaskSelect={handleTaskSelect}
96
+ onTaskReview={handleTaskStatusChange}
97
+ onQuickStartChange={handleQuickStartChange}
98
+ ref={contentRef}
99
+ />
100
+ <QuickStartFooter
101
+ status={status}
102
+ taskNumber={taskNumber}
103
+ totalTasks={totalTasks}
104
+ onNext={handleNext}
105
+ onBack={handleBack}
106
+ footerClass={footerClass}
107
+ quickStartId={quickStart.metadata.name}
108
+ />
109
+ </>
110
+ );
111
+ };
112
+
113
+ export default QuickStartController;
@@ -0,0 +1,11 @@
1
+ .pfext-quick-start-drawer {
2
+ &__body {
3
+ display: flex;
4
+ flex-direction: column;
5
+ z-index: 0;
6
+ position: relative;
7
+ }
8
+ &__modal > .pf-c-modal-box__footer {
9
+ display: block;
10
+ }
11
+ }
@@ -0,0 +1,265 @@
1
+ import './QuickStartDrawer.scss';
2
+ import * as React from 'react';
3
+ import { Drawer, DrawerContent, DrawerContentBody } from '@patternfly/react-core';
4
+ import QuickStartCloseModal from './QuickStartCloseModal';
5
+ import QuickStartPanelContent from './QuickStartPanelContent';
6
+ import {
7
+ getDefaultQuickStartState,
8
+ QuickStartContext,
9
+ QuickStartContextValues,
10
+ useValuesForQuickStartContext,
11
+ } from './utils/quick-start-context';
12
+ import { QUICKSTART_ID_FILTER_KEY } from './utils/const';
13
+ import { QuickStart, QuickStartStatus, AllQuickStartStates } from './utils/quick-start-types';
14
+ import { getQuickStartByName } from './utils/quick-start-utils';
15
+
16
+ export interface QuickStartContainerProps extends React.HTMLProps<HTMLDivElement> {
17
+ /** array of quick starts */
18
+ quickStarts: QuickStart[];
19
+ /** id of the currently active quick start */
20
+ activeQuickStartID: string;
21
+ /** setter for the active quick starts */
22
+ setActiveQuickStartID: React.Dispatch<React.SetStateAction<string>>;
23
+ /** quick starts state object */
24
+ allQuickStartStates: AllQuickStartStates;
25
+ /** setter for the quick starts state object */
26
+ setAllQuickStartStates: React.Dispatch<React.SetStateAction<AllQuickStartStates>>;
27
+ /** content to render within the container */
28
+ children?: React.ReactNode;
29
+ /** element to render the drawer panel into */
30
+ appendTo?: HTMLElement | (() => HTMLElement);
31
+ /** if true, the panel will take up the full browser width */
32
+ fullWidth?: boolean;
33
+ /** callback when an in-progress quick start is closed */
34
+ onCloseInProgress?: any;
35
+ /** callback when a not-in-progress quick start is closed */
36
+ onCloseNotInProgress?: any;
37
+ /** true to show footer buttons in the catalog tiles (default true) */
38
+ showCardFooters?: boolean;
39
+ /** true to use legacy drawer header variant colors */
40
+ useLegacyHeaderColors?: boolean;
41
+ /** text resources object */
42
+ resourceBundle?: any;
43
+ /** language of the current resource bundle
44
+ * Add custom strings: https://github.com/patternfly/patternfly-quickstarts/tree/main/packages/module#localization
45
+ */
46
+ language?: string;
47
+ /** if true, will show a loading spinner on the catalog page (default false) */
48
+ loading?: boolean;
49
+ /** if true, will update the browser URL with ?quickstart={ID} (default true) */
50
+ useQueryParams?: boolean;
51
+ /** if true, the TaskReview component, aka "Check your work", will be shown regardless of task status */
52
+ alwaysShowTaskReview?: boolean;
53
+ /**
54
+ * Additional markdown extensions and renderers to use
55
+ * Example usage: https://github.com/patternfly/patternfly-quickstarts/tree/main/packages/module#markdown-extensions
56
+ */
57
+ markdown?: {
58
+ extensions?: any[];
59
+ renderExtension?: (docContext: HTMLDocument, rootSelector: string) => React.ReactNode;
60
+ };
61
+ /** additional quick start context props */
62
+ contextProps?: QuickStartContextValues;
63
+ }
64
+
65
+ export const QuickStartContainer: React.FC<QuickStartContainerProps> = ({
66
+ quickStarts,
67
+ children,
68
+ activeQuickStartID,
69
+ allQuickStartStates,
70
+ setActiveQuickStartID,
71
+ setAllQuickStartStates,
72
+ appendTo,
73
+ fullWidth,
74
+ onCloseInProgress,
75
+ onCloseNotInProgress,
76
+ resourceBundle,
77
+ showCardFooters,
78
+ useLegacyHeaderColors,
79
+ language,
80
+ loading = false,
81
+ useQueryParams = true,
82
+ markdown,
83
+ contextProps,
84
+ alwaysShowTaskReview = true,
85
+ ...props
86
+ }: QuickStartContainerProps) => {
87
+ const valuesForQuickstartContext: QuickStartContextValues = useValuesForQuickStartContext({
88
+ allQuickStarts: quickStarts,
89
+ activeQuickStartID,
90
+ setActiveQuickStartID,
91
+ allQuickStartStates,
92
+ setAllQuickStartStates,
93
+ footer: {
94
+ show: showCardFooters,
95
+ },
96
+ useLegacyHeaderColors,
97
+ language,
98
+ resourceBundle: {
99
+ ...resourceBundle,
100
+ // Start: "Let's go!",
101
+ // Continue: 'Resume',
102
+ // Restart: 'Start over',
103
+ },
104
+ loading,
105
+ useQueryParams,
106
+ markdown,
107
+ alwaysShowTaskReview,
108
+ ...contextProps,
109
+ });
110
+
111
+ React.useEffect(() => {
112
+ if (
113
+ quickStarts &&
114
+ JSON.stringify(quickStarts) !== JSON.stringify(valuesForQuickstartContext.allQuickStarts)
115
+ ) {
116
+ valuesForQuickstartContext.setAllQuickStarts(quickStarts);
117
+ }
118
+ }, [quickStarts, valuesForQuickstartContext]);
119
+
120
+ React.useEffect(() => {
121
+ if (loading !== valuesForQuickstartContext.loading) {
122
+ valuesForQuickstartContext.setLoading(loading);
123
+ }
124
+ }, [loading, valuesForQuickstartContext]);
125
+
126
+ const drawerProps = {
127
+ appendTo,
128
+ fullWidth,
129
+ onCloseInProgress,
130
+ onCloseNotInProgress,
131
+ ...props,
132
+ };
133
+
134
+ return (
135
+ <QuickStartContext.Provider value={valuesForQuickstartContext}>
136
+ <QuickStartDrawer {...drawerProps}>{children}</QuickStartDrawer>
137
+ </QuickStartContext.Provider>
138
+ );
139
+ };
140
+
141
+ export interface QuickStartDrawerProps extends React.HTMLProps<HTMLDivElement> {
142
+ quickStarts?: QuickStart[];
143
+ children?: React.ReactNode;
144
+ appendTo?: HTMLElement | (() => HTMLElement);
145
+ fullWidth?: boolean;
146
+ onCloseInProgress?: any;
147
+ onCloseNotInProgress?: any;
148
+ }
149
+
150
+ export const QuickStartDrawer: React.FC<QuickStartDrawerProps> = ({
151
+ quickStarts = [],
152
+ children,
153
+ appendTo,
154
+ fullWidth,
155
+ onCloseInProgress,
156
+ onCloseNotInProgress,
157
+ ...props
158
+ }) => {
159
+ const {
160
+ activeQuickStartID,
161
+ setActiveQuickStart,
162
+ allQuickStarts = [],
163
+ activeQuickStartState,
164
+ allQuickStartStates,
165
+ setAllQuickStartStates,
166
+ useLegacyHeaderColors,
167
+ } = React.useContext<QuickStartContextValues>(QuickStartContext);
168
+ const combinedQuickStarts = allQuickStarts.concat(quickStarts);
169
+ React.useEffect(() => {
170
+ const params = new URLSearchParams(window.location.search);
171
+ // if there is a quick start param, but the quick start is not active, set it
172
+ // this can happen if a new browser session is opened or an incognito window for example
173
+ const quickStartIdFromParam = params.get(QUICKSTART_ID_FILTER_KEY) || '';
174
+ if (quickStartIdFromParam && activeQuickStartID !== quickStartIdFromParam) {
175
+ const activeQuickStart = getQuickStartByName(quickStartIdFromParam, combinedQuickStarts);
176
+ // don't try to load a quick start that is actually just an external resource (spec.link)
177
+ if (combinedQuickStarts.length > 0 && activeQuickStart && !activeQuickStart.spec.link) {
178
+ setActiveQuickStart(quickStartIdFromParam);
179
+ }
180
+ }
181
+ }, [activeQuickStartID, combinedQuickStarts, setActiveQuickStart]);
182
+
183
+ React.useEffect(() => {
184
+ // If activeQuickStartID was changed through prop from QuickStartContainer, need to init the state if it does not exist yet
185
+ if (activeQuickStartID && !allQuickStartStates[activeQuickStartID]) {
186
+ setAllQuickStartStates({
187
+ ...allQuickStartStates,
188
+ [activeQuickStartID]: getDefaultQuickStartState(),
189
+ });
190
+ }
191
+ }, [activeQuickStartID, allQuickStartStates, setAllQuickStartStates]);
192
+
193
+ const [modalOpen, setModalOpen] = React.useState<boolean>(false);
194
+ const activeQuickStartStatus = activeQuickStartState?.status;
195
+ const onClose = () => setActiveQuickStart('');
196
+ const handleClose = () => {
197
+ if (activeQuickStartStatus === QuickStartStatus.IN_PROGRESS) {
198
+ if (onCloseInProgress) {
199
+ onCloseInProgress();
200
+ } else {
201
+ setModalOpen(true);
202
+ }
203
+ } else if (onCloseNotInProgress) {
204
+ onCloseNotInProgress();
205
+ } else {
206
+ onClose();
207
+ }
208
+ };
209
+
210
+ const onModalConfirm = () => {
211
+ setModalOpen(false);
212
+ onClose();
213
+ };
214
+
215
+ const onModalCancel = () => setModalOpen(false);
216
+
217
+ const fullWidthPanelStyle = fullWidth
218
+ ? {
219
+ style: {
220
+ flex: 1,
221
+ },
222
+ }
223
+ : {};
224
+
225
+ const fullWidthBodyStyle = fullWidth
226
+ ? {
227
+ style: {
228
+ display: activeQuickStartID ? 'none' : 'flex',
229
+ },
230
+ }
231
+ : {};
232
+
233
+ const panelContent = (
234
+ <QuickStartPanelContent
235
+ quickStarts={combinedQuickStarts}
236
+ handleClose={handleClose}
237
+ activeQuickStartID={activeQuickStartID}
238
+ appendTo={appendTo}
239
+ isResizable={!fullWidth}
240
+ headerVariant={useLegacyHeaderColors ? '' : 'blue-white'}
241
+ {...fullWidthPanelStyle}
242
+ />
243
+ );
244
+
245
+ return (
246
+ <>
247
+ <Drawer isExpanded={!!activeQuickStartID} isInline {...props}>
248
+ {children ? (
249
+ <DrawerContent panelContent={panelContent} {...fullWidthBodyStyle}>
250
+ <DrawerContentBody className="pfext-quick-start-drawer__body">
251
+ {children}
252
+ </DrawerContentBody>
253
+ </DrawerContent>
254
+ ) : (
255
+ <div className="pf-c-drawer__main">{panelContent}</div>
256
+ )}
257
+ </Drawer>
258
+ <QuickStartCloseModal
259
+ isOpen={modalOpen}
260
+ onConfirm={onModalConfirm}
261
+ onCancel={onModalCancel}
262
+ />
263
+ </>
264
+ );
265
+ };
@@ -0,0 +1,75 @@
1
+ import * as React from 'react';
2
+ import { SyncMarkdownView } from '@console/internal/components/markdown-view';
3
+ import {
4
+ MarkdownCopyClipboard,
5
+ MarkdownHighlightExtension,
6
+ useInlineCopyClipboardShowdownExtension,
7
+ useMultilineCopyClipboardShowdownExtension,
8
+ useAdmonitionShowdownExtension,
9
+ useCodeShowdownExtension,
10
+ } from '@console/shared';
11
+ import { HIGHLIGHT_REGEXP } from '@console/shared/src/components/markdown-highlight-extension/highlight-consts';
12
+ import { QuickStartContext, QuickStartContextValues } from './utils/quick-start-context';
13
+
14
+ export const removeParagraphWrap = (markdown: string) => markdown.replace(/^<p>|<\/p>$/g, '');
15
+
16
+ type QuickStartMarkdownViewProps = {
17
+ content: string;
18
+ exactHeight?: boolean;
19
+ className?: string;
20
+ };
21
+
22
+ const QuickStartMarkdownView: React.FC<QuickStartMarkdownViewProps> = ({
23
+ content,
24
+ exactHeight,
25
+ className,
26
+ }) => {
27
+ const { markdown } = React.useContext<QuickStartContextValues>(QuickStartContext);
28
+ const inlineCopyClipboardShowdownExtension = useInlineCopyClipboardShowdownExtension();
29
+ const multilineCopyClipboardShowdownExtension = useMultilineCopyClipboardShowdownExtension();
30
+ const admonitionShowdownExtension = useAdmonitionShowdownExtension();
31
+ const codeShowdownExtension = useCodeShowdownExtension();
32
+ return (
33
+ <SyncMarkdownView
34
+ inline
35
+ content={content}
36
+ exactHeight={exactHeight}
37
+ extensions={[
38
+ {
39
+ type: 'lang',
40
+ regex: HIGHLIGHT_REGEXP,
41
+ replace: (text: string, linkLabel: string, linkType: string, linkId: string): string => {
42
+ if (!linkLabel || !linkType || !linkId) {
43
+ return text;
44
+ }
45
+ return `<button class="pf-c-button pf-m-inline pf-m-link" data-highlight="${linkId}">${linkLabel}</button>`;
46
+ },
47
+ },
48
+ {
49
+ type: 'output',
50
+ filter: function(text) {
51
+ // check HTML for patterns like: <em>Status: unknown</em>{#extension-requirement-status}
52
+ // and replace with <em id="extension-requirement-status">Status: unknown</em>
53
+ return text.replace(/<em>(.*)<\/em>{#(.*)}/g, '<em id="$2">$1</em>');
54
+ },
55
+ },
56
+ inlineCopyClipboardShowdownExtension,
57
+ multilineCopyClipboardShowdownExtension,
58
+ admonitionShowdownExtension,
59
+ codeShowdownExtension,
60
+ ...(markdown ? markdown.extensions : []),
61
+ ]}
62
+ renderExtension={(docContext, rootSelector) => (
63
+ <>
64
+ <MarkdownHighlightExtension docContext={docContext} rootSelector={rootSelector} />
65
+ <MarkdownCopyClipboard docContext={docContext} rootSelector={rootSelector} />
66
+ {markdown &&
67
+ markdown.renderExtension &&
68
+ markdown.renderExtension(docContext, rootSelector)}
69
+ </>
70
+ )}
71
+ className={className}
72
+ />
73
+ );
74
+ };
75
+ export default QuickStartMarkdownView;