@patternfly/quickstarts 2.2.3 → 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.
- package/dist/HelpTopicDrawer.d.ts +8 -2
- package/dist/QuickStartDrawer.d.ts +21 -2
- package/dist/index.es.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/patternfly-docs/quick-starts/design-guidelines/design-guidelines.md +105 -0
- package/dist/patternfly-docs/quick-starts/design-guidelines/img/card-elements copy.png +0 -0
- package/dist/patternfly-docs/quick-starts/design-guidelines/img/card-elements.png +0 -0
- package/dist/patternfly-docs/quick-starts/design-guidelines/img/catalog-elements.png +0 -0
- package/dist/patternfly-docs/quick-starts/design-guidelines/img/check-your-work.png +0 -0
- package/dist/patternfly-docs/quick-starts/design-guidelines/img/introduction-screen.png +0 -0
- package/dist/patternfly-docs/quick-starts/design-guidelines/img/mixed-catalog.png +0 -0
- package/dist/patternfly-docs/quick-starts/design-guidelines/img/prerequisites.png +0 -0
- package/dist/patternfly-docs/quick-starts/design-guidelines/img/qs-context.png +0 -0
- package/dist/patternfly-docs/quick-starts/design-guidelines/img/side-panel-elements.png +0 -0
- package/dist/patternfly-docs/quick-starts/design-guidelines/img/side-panel-resized.png +0 -0
- package/dist/patternfly-docs/quick-starts/design-guidelines/img/side-panel.png +0 -0
- package/dist/patternfly-docs/quick-starts/design-guidelines/img/task-no.png +0 -0
- package/dist/patternfly-docs/quick-starts/design-guidelines/img/task-yes.png +0 -0
- package/dist/patternfly-docs/quick-starts/design-guidelines/img/task.png +0 -0
- package/dist/patternfly-docs/quick-starts/examples/Basic.jsx +73 -0
- package/dist/patternfly-docs/quick-starts/examples/HelpTopic.jsx +53 -0
- package/dist/patternfly-docs/quick-starts/examples/about.md +77 -0
- package/dist/patternfly-docs/quick-starts/examples/basic.md +27 -0
- package/dist/patternfly-docs/quick-starts/examples/example-data/example-help-topics.js +173 -0
- package/dist/patternfly-docs/quick-starts/examples/example-data/example-quickstarts.js +215 -0
- package/dist/patternfly-docs/quick-starts/examples/example-data/index.js +15 -0
- package/dist/patternfly-docs/quick-starts/examples/help-topics.md +25 -0
- package/dist/patternfly-docs/quick-starts/examples/img/catalog.png +0 -0
- package/dist/patternfly-docs/quick-starts/examples/img/help-topic.png +0 -0
- package/dist/patternfly-docs/quick-starts/examples/img/side-panel.png +0 -0
- package/dist/quickstarts-full.es.js.map +1 -1
- package/package.json +11 -4
- package/src/ConsoleInternal/components/_icon-and-text.scss +14 -0
- package/src/ConsoleInternal/components/_markdown-view.scss +19 -0
- package/src/ConsoleInternal/components/catalog/_catalog.scss +390 -0
- package/src/ConsoleInternal/components/markdown-view.tsx +305 -0
- package/src/ConsoleInternal/components/utils/_status-box.scss +58 -0
- package/src/ConsoleInternal/components/utils/camel-case-wrap.tsx +33 -0
- package/src/ConsoleInternal/components/utils/index.tsx +3 -0
- package/src/ConsoleInternal/components/utils/router.ts +47 -0
- package/src/ConsoleInternal/components/utils/status-box.tsx +94 -0
- package/src/ConsoleInternal/module/k8s/types.ts +53 -0
- package/src/ConsoleShared/index.ts +1 -0
- package/src/ConsoleShared/src/components/index.ts +7 -0
- package/src/ConsoleShared/src/components/layout/PageLayout.scss +29 -0
- package/src/ConsoleShared/src/components/markdown-extensions/MarkdownCopyClipboard.tsx +93 -0
- package/src/ConsoleShared/src/components/markdown-extensions/__tests__/MarkdownCopyClipboard.spec.tsx +25 -0
- package/src/ConsoleShared/src/components/markdown-extensions/__tests__/test-data.ts +5 -0
- package/src/ConsoleShared/src/components/markdown-extensions/admonition-extension.tsx +66 -0
- package/src/ConsoleShared/src/components/markdown-extensions/code-extension.tsx +25 -0
- package/src/ConsoleShared/src/components/markdown-extensions/const.ts +3 -0
- package/src/ConsoleShared/src/components/markdown-extensions/index.ts +5 -0
- package/src/ConsoleShared/src/components/markdown-extensions/inline-clipboard-extension.tsx +45 -0
- package/src/ConsoleShared/src/components/markdown-extensions/multiline-clipboard-extension.tsx +50 -0
- package/src/ConsoleShared/src/components/markdown-extensions/showdown-extension.scss +52 -0
- package/src/ConsoleShared/src/components/markdown-extensions/utils.ts +3 -0
- package/src/ConsoleShared/src/components/markdown-highlight-extension/MarkdownHighlightExtension.tsx +64 -0
- package/src/ConsoleShared/src/components/markdown-highlight-extension/highlight-consts.ts +9 -0
- package/src/ConsoleShared/src/components/markdown-highlight-extension/index.ts +1 -0
- package/src/ConsoleShared/src/components/modal/Modal.scss +3 -0
- package/src/ConsoleShared/src/components/modal/Modal.tsx +19 -0
- package/src/ConsoleShared/src/components/modal/index.ts +1 -0
- package/src/ConsoleShared/src/components/popper/Portal.tsx +23 -0
- package/src/ConsoleShared/src/components/popper/SimplePopper.tsx +90 -0
- package/src/ConsoleShared/src/components/popper/index.ts +2 -0
- package/src/ConsoleShared/src/components/spotlight/InteractiveSpotlight.tsx +58 -0
- package/src/ConsoleShared/src/components/spotlight/Spotlight.tsx +35 -0
- package/src/ConsoleShared/src/components/spotlight/StaticSpotlight.tsx +32 -0
- package/src/ConsoleShared/src/components/spotlight/index.ts +1 -0
- package/src/ConsoleShared/src/components/spotlight/spotlight.scss +63 -0
- package/src/ConsoleShared/src/components/status/GenericStatus.tsx +33 -0
- package/src/ConsoleShared/src/components/status/NotStartedIcon.tsx +27 -0
- package/src/ConsoleShared/src/components/status/PopoverStatus.tsx +42 -0
- package/src/ConsoleShared/src/components/status/Status.tsx +38 -0
- package/src/ConsoleShared/src/components/status/StatusIconAndText.tsx +42 -0
- package/src/ConsoleShared/src/components/status/icons.tsx +77 -0
- package/src/ConsoleShared/src/components/status/index.tsx +1 -0
- package/src/ConsoleShared/src/components/status/statuses.tsx +36 -0
- package/src/ConsoleShared/src/components/status/types.ts +7 -0
- package/src/ConsoleShared/src/components/utils/FallbackImg.tsx +20 -0
- package/src/ConsoleShared/src/components/utils/index.ts +1 -0
- package/src/ConsoleShared/src/constants/index.ts +1 -0
- package/src/ConsoleShared/src/constants/ui.ts +1 -0
- package/src/ConsoleShared/src/hooks/index.ts +6 -0
- package/src/ConsoleShared/src/hooks/scroll.ts +52 -0
- package/src/ConsoleShared/src/hooks/useBoundingClientRect.ts +18 -0
- package/src/ConsoleShared/src/hooks/useEventListener.ts +14 -0
- package/src/ConsoleShared/src/hooks/useForceRender.ts +6 -0
- package/src/ConsoleShared/src/hooks/useResizeObserver.ts +20 -0
- package/src/ConsoleShared/src/hooks/useScrollShadows.ts +45 -0
- package/src/ConsoleShared/src/index.ts +4 -0
- package/src/ConsoleShared/src/utils/index.ts +1 -0
- package/src/ConsoleShared/src/utils/useCombineRefs.ts +17 -0
- package/src/HelpTopicDrawer.tsx +124 -0
- package/src/HelpTopicPanelContent.tsx +152 -0
- package/src/QuickStartCatalogPage.tsx +190 -0
- package/src/QuickStartCloseModal.tsx +47 -0
- package/src/QuickStartController.tsx +113 -0
- package/src/QuickStartDrawer.scss +11 -0
- package/src/QuickStartDrawer.tsx +265 -0
- package/src/QuickStartMarkdownView.tsx +75 -0
- package/src/QuickStartPanelContent.scss +46 -0
- package/src/QuickStartPanelContent.tsx +153 -0
- package/src/__tests__/quick-start-utils.spec.tsx +16 -0
- package/src/catalog/Catalog/QuickStartCatalogHeader.tsx +18 -0
- package/src/catalog/Catalog/QuickStartCatalogSection.tsx +9 -0
- package/src/catalog/Catalog/QuickStartCatalogToolbar.tsx +12 -0
- package/src/catalog/Catalog/index.ts +3 -0
- package/src/catalog/QuickStartCatalog.scss +8 -0
- package/src/catalog/QuickStartCatalog.tsx +42 -0
- package/src/catalog/QuickStartTile.scss +11 -0
- package/src/catalog/QuickStartTile.tsx +105 -0
- package/src/catalog/QuickStartTileDescription.scss +29 -0
- package/src/catalog/QuickStartTileDescription.tsx +79 -0
- package/src/catalog/QuickStartTileFooter.tsx +101 -0
- package/src/catalog/QuickStartTileFooterExternal.tsx +40 -0
- package/src/catalog/QuickStartTileHeader.scss +12 -0
- package/src/catalog/QuickStartTileHeader.tsx +77 -0
- package/src/catalog/Toolbar/QuickStartCatalogFilter.scss +25 -0
- package/src/catalog/Toolbar/QuickStartCatalogFilter.tsx +34 -0
- package/src/catalog/Toolbar/QuickStartCatalogFilterItems.tsx +199 -0
- package/src/catalog/__tests__/QuickStartCatalog.spec.tsx +35 -0
- package/src/catalog/__tests__/QuickStartTile.spec.tsx +38 -0
- package/src/catalog/__tests__/QuickStartTileDescription.spec.tsx +44 -0
- package/src/catalog/index.ts +9 -0
- package/src/controller/QuickStartConclusion.tsx +63 -0
- package/src/controller/QuickStartContent.scss +12 -0
- package/src/controller/QuickStartContent.tsx +72 -0
- package/src/controller/QuickStartFooter.scss +13 -0
- package/src/controller/QuickStartFooter.tsx +128 -0
- package/src/controller/QuickStartIntroduction.scss +35 -0
- package/src/controller/QuickStartIntroduction.tsx +66 -0
- package/src/controller/QuickStartTaskHeader.scss +58 -0
- package/src/controller/QuickStartTaskHeader.tsx +116 -0
- package/src/controller/QuickStartTaskHeaderList.scss +17 -0
- package/src/controller/QuickStartTaskHeaderList.tsx +35 -0
- package/src/controller/QuickStartTaskReview.scss +30 -0
- package/src/controller/QuickStartTaskReview.tsx +81 -0
- package/src/controller/QuickStartTasks.scss +89 -0
- package/src/controller/QuickStartTasks.tsx +75 -0
- package/src/controller/__tests__/QuickStartConclusion.spec.tsx +95 -0
- package/src/controller/__tests__/QuickStartContent.spec.tsx +52 -0
- package/src/controller/__tests__/QuickStartFooter.spec.tsx +148 -0
- package/src/controller/__tests__/QuickStartTaskHeader.spec.tsx +56 -0
- package/src/controller/__tests__/QuickStartTaskReview.spec.tsx +45 -0
- package/src/controller/__tests__/QuickStartTasks.spec.tsx +81 -0
- package/src/data/mocks/json/explore-pipeline-quickstart.ts +66 -0
- package/src/data/mocks/json/explore-serverless-quickstart.ts +90 -0
- package/src/data/mocks/json/monitor-sampleapp-quickstart.ts +77 -0
- package/src/data/mocks/json/tour-icons.ts +3 -0
- package/src/data/mocks/yamls/add-healthchecks-quickstart.yaml +67 -0
- package/src/data/mocks/yamls/explore-pipeline-quickstart.yaml +57 -0
- package/src/data/mocks/yamls/explore-serverless-quickstart.yaml +83 -0
- package/src/data/mocks/yamls/install-associate-pipeline-quickstart.yaml +74 -0
- package/src/data/mocks/yamls/monitor-sampleapp-quickstart.yaml +66 -0
- package/src/data/mocks/yamls/sample-application-quickstart.yaml +97 -0
- package/src/data/mocks/yamls/serverless-application-quickstart.yaml +141 -0
- package/src/data/quick-start-test-data.ts +10 -0
- package/src/data/test-utils.ts +11 -0
- package/src/declaration.d.ts +2 -0
- package/src/index.ts +17 -0
- package/src/locales/en/quickstart.json +46 -0
- package/src/styles/_base.scss +54 -0
- package/src/styles/_dark-custom-override.scss +62 -0
- package/src/styles/legacy-bootstrap/README.md +21 -0
- package/src/styles/legacy-bootstrap/_code.scss +44 -0
- package/src/styles/legacy-bootstrap/_tables.scss +38 -0
- package/src/styles/legacy-bootstrap/_type.scss +90 -0
- package/src/styles/legacy-bootstrap/_variables.scss +48 -0
- package/src/styles/legacy-bootstrap.scss +5 -0
- package/src/styles/patternfly-global-entry.ts +1 -0
- package/src/styles/patternfly-global.scss +28 -0
- package/src/styles/patternfly-nested-entry.ts +1 -0
- package/src/styles/patternfly-nested.scss +18 -0
- package/src/styles/quickstarts-standalone-entry.ts +1 -0
- package/src/styles/quickstarts-standalone.scss +7 -0
- package/src/styles/style.scss +12 -0
- package/src/styles/vendor-entry.ts +1 -0
- package/src/styles/vendor.scss +7 -0
- package/src/utils/PluralResolver.ts +356 -0
- package/src/utils/asciidoc-procedure-parser.ts +132 -0
- package/src/utils/const.ts +10 -0
- package/src/utils/help-topic-context.tsx +74 -0
- package/src/utils/help-topic-types.ts +16 -0
- package/src/utils/quick-start-context.tsx +477 -0
- package/src/utils/quick-start-types.ts +72 -0
- package/src/utils/quick-start-utils.ts +92 -0
- 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
|
+
};
|