Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add learning resources creator #54

Merged
merged 145 commits into from
Jul 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
145 commits
Select commit Hold shift + click to select a range
afa1f24
Temporarily replace app with Creator component
randomnetcat May 31, 2024
0ba4429
Add basic type selection
randomnetcat May 31, 2024
a7bf3e5
Add named types for item kinds
randomnetcat May 31, 2024
5b95f92
Use Patternfly FormGroup for radio buttons
randomnetcat May 31, 2024
74e857d
Add form with bundle input
randomnetcat May 31, 2024
757c816
Add title input
randomnetcat May 31, 2024
2a41447
Add description input
randomnetcat May 31, 2024
f7a863f
Unify input prop types
randomnetcat May 31, 2024
809cb75
Use a loop for common item inputs
randomnetcat May 31, 2024
9c226a8
Add placeholders
randomnetcat May 31, 2024
71230c4
Add URL input when type is documentation
randomnetcat May 31, 2024
bc454d9
Add separate ItemFormContainer
randomnetcat May 31, 2024
b844b30
Add duration input when type is quickstart
randomnetcat Jun 3, 2024
2095e93
Add required indicators to field groups
randomnetcat Jun 3, 2024
d2c20cb
Move type field to own component
randomnetcat Jun 3, 2024
3f6e3c4
Add labeled FormGroup around type input
randomnetcat Jun 3, 2024
f486bde
Add labels to DurationInput
randomnetcat Jun 3, 2024
41f21c4
Use InputProps for all applicable components
randomnetcat Jun 3, 2024
895f89c
Use grid to divide screen into columns
randomnetcat Jun 3, 2024
63fe92d
Make step headers fancy
randomnetcat Jun 3, 2024
a44ad47
Remove incorrect section around title
randomnetcat Jun 3, 2024
9bcb86d
Clamp duration input at 0
randomnetcat Jun 3, 2024
5911dbc
Show tile preview with QuickStartCatalog
randomnetcat Jun 3, 2024
fd1a592
Move QuickStartTile usage to separate component
randomnetcat Jun 3, 2024
ffbf33d
Move lr-c-quickstart_tile into WrappedQuickStartTile
randomnetcat Jun 3, 2024
415328f
Use WrappedQuickStartTile in Creator
randomnetcat Jun 3, 2024
a019c0a
Move label colors to itemKindMeta
randomnetcat Jun 3, 2024
caaef7a
Make creator look minimally usable
randomnetcat Jun 3, 2024
136617e
Make page header full row
randomnetcat Jun 3, 2024
b0aa6ef
Add "Live card preview" header
randomnetcat Jun 3, 2024
cca87ed
Use margin-inline-end for rc-step-index
randomnetcat Jun 3, 2024
0a1af74
Define ItemKind using itemKindMeta
randomnetcat Jun 3, 2024
735b42c
Add new item types
randomnetcat Jun 3, 2024
85da4a6
Define fields in item metadata
randomnetcat Jun 3, 2024
873dcd6
Use useMemo for QuickStart
randomnetcat Jun 4, 2024
da4e54c
Half-functioning quickstart tester
randomnetcat Jun 4, 2024
904b6e7
Use QuickStartDrawer directly
randomnetcat Jun 4, 2024
d1a22bd
Add skeleton of wizard
randomnetcat Jun 11, 2024
9c7bcdb
Move duration field into wizard
randomnetcat Jun 11, 2024
66942da
Properly set input IDs for labels
randomnetcat Jun 11, 2024
c356b06
Remove now-unused components
randomnetcat Jun 11, 2024
9bc45b3
Allow selecting multiple bundles
randomnetcat Jun 11, 2024
713afae
Prevent attempt to read quickstart tasks when they don't exist
randomnetcat Jun 11, 2024
e3a7677
Require progressing through wizard in order
randomnetcat Jun 11, 2024
e22d011
Use cast instead of lambda for inputItemDesc
randomnetcat Jun 11, 2024
f1d73b7
Remove uses of useId
randomnetcat Jun 11, 2024
220e4c5
Add task overview page
randomnetcat Jun 11, 2024
c636b52
Separate Creator code into several files
randomnetcat Jun 11, 2024
bea729c
Use hidden steps instead of setting key on Wizard
randomnetcat Jun 11, 2024
34c9fd8
Allow adding more tasks
randomnetcat Jun 11, 2024
b317e9a
Add dependency on Patternfly code-editor
randomnetcat Jun 12, 2024
d36592c
Add basic panel editing
randomnetcat Jun 12, 2024
57f25d0
Allow removing tasks
randomnetcat Jun 12, 2024
0a80fad
Cleanup task array modification
randomnetcat Jun 12, 2024
745bc44
Remove ItemFormElement
randomnetcat Jun 12, 2024
1626e83
Add label to remove task buttons
randomnetcat Jun 12, 2024
f40c91a
Move string array input to component
randomnetcat Jun 13, 2024
aff7352
Allow modifying quickstart prerequisites
randomnetcat Jun 13, 2024
3a618bd
Allow editing task work-check values
randomnetcat Jun 13, 2024
044fd14
Fix setting value of CodeEditor
randomnetcat Jun 13, 2024
616c9e6
Add yaml dependency
randomnetcat Jun 13, 2024
759f352
Add rendering of files and basic display
randomnetcat Jun 13, 2024
28eab33
Improve quickstart name generation
randomnetcat Jun 13, 2024
6ba3e4c
Remove log statement
randomnetcat Jun 13, 2024
15c2b06
Don't include icon in quickstart file
randomnetcat Jun 13, 2024
a92c292
Add ability to download files
randomnetcat Jun 13, 2024
17663f0
Restore original app homepage
randomnetcat Jun 14, 2024
758cbeb
Allow switching between viewer and creator
randomnetcat Jun 14, 2024
d916513
Use a flag to enable creator
randomnetcat Jun 14, 2024
b7d7c3f
Accept YAML for step config rather than form fields
randomnetcat Jun 14, 2024
802be3f
Include per-type metadata in export
randomnetcat Jun 18, 2024
93d11f4
Use footer config from chrome in creator
randomnetcat Jun 18, 2024
1922ff3
Use react-router for creator/viewer parts
randomnetcat Jun 18, 2024
46abe7a
Update quickstarts extension
randomnetcat Jun 26, 2024
943b4ba
Ensure quickstart is not focused on
randomnetcat Jun 26, 2024
35f4df5
Fix task editor description
randomnetcat Jun 26, 2024
4497217
Don't use useMemo for selectedType
randomnetcat Jun 27, 2024
1d291f7
Remove unnecessary string template
randomnetcat Jun 27, 2024
bb387c8
Remove unnecessary children node
randomnetcat Jun 27, 2024
59fa5fe
Remove memo of getAvailableBundles()
randomnetcat Jun 27, 2024
2e5e041
Normalize SelectMultiTypeahead hooks
randomnetcat Jun 27, 2024
c385d92
Remove useMemo import from CreatorInputs
randomnetcat Jun 27, 2024
389ff29
Import icons from dynamic rather than esm
randomnetcat Jun 27, 2024
a460c63
Use undefined to indicate no results in SelectMultiTypeahead
randomnetcat Jun 27, 2024
440896c
Remove extraneous lambda
randomnetcat Jun 27, 2024
d536e08
Replace only whitespace in quickstart name
randomnetcat Jun 27, 2024
3e17d5c
Don't useMemo another selectedType
randomnetcat Jun 27, 2024
ddb1cff
Use whitespace regex in SelectMultiTypeahead
randomnetcat Jun 27, 2024
9e26349
Use a single Form element
randomnetcat Jun 27, 2024
3ace393
Prevent form submission
randomnetcat Jun 27, 2024
177e218
Fix nested FormGroups
randomnetcat Jun 27, 2024
bb466a3
Show errors when parsing task YAML
randomnetcat Jun 28, 2024
653d4fc
Fix handling of no search results in SelectMultiTypeahead
randomnetcat Jul 1, 2024
13e7df1
Use quickstart state directly
randomnetcat Jul 1, 2024
0f2f387
Fix quickstart metadata
randomnetcat Jul 1, 2024
c0b4cd9
Ensure Wizard always take up at least all height
randomnetcat Jul 1, 2024
b59fb7c
Wrap task error display
randomnetcat Jul 1, 2024
98d4286
Use useMemo in SelectMultiTypeahead
randomnetcat Jul 1, 2024
f7a5e3b
Use unleash directly in App
randomnetcat Jul 1, 2024
c0975b8
Make Creator its own independent app
randomnetcat Jul 1, 2024
79a7e98
Move creator preview to separate file
randomnetcat Jul 1, 2024
cec9309
Always show quickstart drawer
randomnetcat Jul 1, 2024
7a2aba6
Cleanup leftover context parts in Creator
randomnetcat Jul 1, 2024
ad495e6
Sync preview task to wizard step
randomnetcat Jul 1, 2024
a8a6ed8
Always use a string key in SelectMultiTypeahead
randomnetcat Jul 1, 2024
c80148c
Remove unused option id in SelectMultiTypeahead
randomnetcat Jul 1, 2024
ee837b4
Use an actually-unique ID in SelectMultiTypeahead
randomnetcat Jul 1, 2024
7afecb6
Add Data Driven Forms dependencies
randomnetcat Jul 8, 2024
ec33901
Remove commented-out code
randomnetcat Jul 8, 2024
9f448ed
Add isItemKind type guard
randomnetcat Jul 8, 2024
55df48b
Use basic data-driven form with overview page
randomnetcat Jul 8, 2024
ab96898
Add ALL_ITEM_KINDS
randomnetcat Jul 8, 2024
54e961c
Match type and details steps of original form
randomnetcat Jul 8, 2024
27d7d6e
Get tile preview working
randomnetcat Jul 8, 2024
c805132
Add basic panel editor
randomnetcat Jul 9, 2024
7c6fa87
Revert to uncontrolled panel preview
randomnetcat Jul 9, 2024
c92d667
Add field to show task YAML errors
randomnetcat Jul 9, 2024
af889e5
Ensure that task errors wrap
randomnetcat Jul 9, 2024
0c4271e
Add step to download files
randomnetcat Jul 9, 2024
5432f4d
Revert "Revert to uncontrolled panel preview"
randomnetcat Jul 9, 2024
c754628
Update task preview as moving through wizard
randomnetcat Jul 9, 2024
2029cf3
Remove missing content placeholder
randomnetcat Jul 9, 2024
0ed9957
Remove unused code
randomnetcat Jul 9, 2024
cbd7c4a
Fix "explicit use of any" error on FormValue
randomnetcat Jul 9, 2024
551c90e
Document the PropUpdater hack
randomnetcat Jul 9, 2024
2aeaa5d
Replace ugly hack with much cleaner hack
randomnetcat Jul 9, 2024
4304f44
Remove logging
randomnetcat Jul 9, 2024
fc95832
Don't use FormTemplate
randomnetcat Jul 10, 2024
7870ac7
Fix extra array around tags
randomnetcat Jul 10, 2024
ba7d837
Use WizardProps type for wizard schema
randomnetcat Jul 10, 2024
82e4401
Update Patternfly and tsc-transform-inputs in order to get automatic …
randomnetcat Jul 10, 2024
9ef92da
Use custom buttons for wizard footer
randomnetcat Jul 10, 2024
e66232d
Remove SelectMultiTypeahead
randomnetcat Jul 10, 2024
7787254
Update schema comments
randomnetcat Jul 10, 2024
9f2f2f2
Remove unused CSS
randomnetcat Jul 10, 2024
6d099f8
Remove unnecessary Viewer
randomnetcat Jul 10, 2024
6428cae
Rename App to Viewer
randomnetcat Jul 10, 2024
0a94fdb
Encapsulate uses of itemKindMeta
randomnetcat Jul 10, 2024
87b1577
Standardize on "kind" rather than "type"
randomnetcat Jul 10, 2024
12b72a6
Remove broken import
randomnetcat Jul 10, 2024
75cdc65
Further kind fixes
randomnetcat Jul 10, 2024
b1c4288
Fix button handling
randomnetcat Jul 10, 2024
3f3e5a5
Move CreatorPreview CSS to proper component
randomnetcat Jul 10, 2024
d6e2273
Remove CatalogSection CSS import
randomnetcat Jul 10, 2024
c43eecf
Sync react-code-editor
randomnetcat Jul 10, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions fec.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ module.exports = {
__dirname,
'./src/components/GlobalLearningResourcesPage/GlobalLearningResourcesPage'
),
'./Creator': path.resolve(__dirname, './src/Creator.tsx'),
},
exclude: ['react-router-dom'],
shared: [
Expand Down
468 changes: 413 additions & 55 deletions package-lock.json

Large diffs are not rendered by default.

12 changes: 8 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,11 @@
"postinstall": "ts-patch install"
},
"dependencies": {
"@patternfly/quickstarts": "5.2.0-prerelease.3",
"@patternfly/react-core": "^5.1.2",
"@data-driven-forms/pf4-component-mapper": "^3.23.0",
"@data-driven-forms/react-form-renderer": "^3.23.0",
"@patternfly/quickstarts": "^5.4.0-prerelease.1",
"@patternfly/react-code-editor": "^5.3.4",
"@patternfly/react-core": "^5.3.4",
"@patternfly/react-table": "^5.1.1",
"@redhat-cloud-services/frontend-components": "^4.2.9",
"@redhat-cloud-services/frontend-components-notifications": "^4.0.4",
Expand All @@ -31,12 +34,13 @@
"axios": "^1.6.7",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-router-dom": "^6.22.3"
"react-router-dom": "^6.22.3",
"yaml": "^2.4.5"
},
"devDependencies": {
"@redhat-cloud-services/eslint-config-redhat-cloud-services": "^2.0.3",
"@redhat-cloud-services/frontend-components-config": "^6.0.5",
"@redhat-cloud-services/tsc-transform-imports": "^1.0.4",
"@redhat-cloud-services/tsc-transform-imports": "^1.0.15",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^14.1.2",
"@types/react": "18.2.46",
Expand Down
4 changes: 2 additions & 2 deletions src/AppEntry.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import { App } from './App';
import { Viewer } from './Viewer';

const AppEntry = (props: { bundle: string }) => <App {...props} />;
const AppEntry = (props: { bundle: string }) => <Viewer {...props} />;

export default AppEntry;
240 changes: 240 additions & 0 deletions src/Creator.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
import React, { useMemo, useState } from 'react';
import YAML, { YAMLError } from 'yaml';
import {
Grid,
GridItem,
PageGroup,
PageSection,
Title,
} from '@patternfly/react-core';
import {
QuickStart,
QuickStartSpec,
QuickStartTask,
} from '@patternfly/quickstarts';
import CreatorWizard, { EMPTY_TASK } from './components/creator/CreatorWizard';
import { ItemKind, metaForKind } from './components/creator/meta';
import CreatorPreview from './components/creator/CreatorPreview';

export type CreatorErrors = {
taskErrors: Map<number, string>;
};

const BASE_METADATA = {
name: 'test-quickstart',
};

function makeDemoQuickStart(
kind: ItemKind | null,
baseQuickStart: QuickStart,
taskContents: string[]
): [QuickStart, CreatorErrors] {
const kindMeta = kind !== null ? metaForKind(kind) : null;

const [tasks, taskErrors] = (() => {
if (kindMeta?.hasTasks !== true) return [undefined, new Map()];

const out: QuickStartTask[] = [];
const errors: CreatorErrors['taskErrors'] = new Map();

if (baseQuickStart.spec.tasks !== undefined) {
for (let index = 0; index < baseQuickStart.spec.tasks.length; ++index) {
const task = baseQuickStart.spec.tasks[index];

try {
out.push({
...YAML.parse(taskContents[index]),
title: task.title,
});
} catch (e) {
if (!(e instanceof YAMLError)) throw e;

out.push({ ...EMPTY_TASK, title: task.title });
errors.set(index, e.message);
}
}
}

return [out, errors];
})();

return [
{
...baseQuickStart,
metadata: {
...baseQuickStart.metadata,
name: 'test-quickstart',
...(kindMeta?.extraMetadata ?? {}),
},
spec: {
...baseQuickStart.spec,
tasks: tasks,
},
},
{ taskErrors },
];
}

const Creator = () => {
const [rawKind, setRawKind] = useState<ItemKind | null>(null);

const [rawQuickStart, setRawQuickStart] = useState<QuickStart>({
metadata: {
name: 'test-quickstart',
},
spec: {
displayName: '',
icon: null,
description: '',
},
});

const selectedKind =
rawKind !== null ? { id: rawKind, meta: metaForKind(rawKind) } : null;

const [bundles, setBundles] = useState<string[]>([]);
const [taskContents, setTaskContents] = useState<string[]>([]);

const [currentTask, setCurrentTask] = useState<number | null>(null);

const updateSpec = (
updater: (old: QuickStartSpec) => Partial<QuickStartSpec>
) => {
setRawQuickStart((old) => ({
...old,
spec: {
...old.spec,
...updater(old.spec),
},
}));
};

const setKind = (newKind: ItemKind | null) => {
if (newKind !== null) {
const meta = metaForKind(newKind);

setRawQuickStart((old) => {
const updates: Partial<QuickStart> = {};

updates.spec = { ...old.spec };

updates.spec.type = {
text: meta.displayName,
color: meta.tagColor,
};

if (
meta.hasTasks &&
(old.spec.tasks === undefined || old.spec.tasks.length === 0)
) {
updates.spec.tasks = [EMPTY_TASK];
}

if (!meta.hasTasks) {
updates.spec.tasks = undefined;
updates.spec.introduction = undefined;
updates.spec.prerequisites = [];
}

if (!meta.fields.url) updates.spec.link = undefined;
if (!meta.fields.duration) updates.spec.durationMinutes = undefined;

updates.metadata = { ...BASE_METADATA, ...meta.extraMetadata };

return { ...old, ...updates };
});

if (meta.hasTasks) {
setTaskContents((old) => (old.length === 0 ? [''] : old));
} else if (!meta.hasTasks) {
setTaskContents([]);
}
}

setRawKind(newKind);
};

const [quickStart, errors] = useMemo(
() => makeDemoQuickStart(rawKind, rawQuickStart, taskContents),
[rawKind, rawQuickStart, taskContents]
);

const files = useMemo(() => {
const effectiveName = quickStart.spec.displayName
.toLowerCase()
.replaceAll(/\s/g, '-')
.replaceAll(/(^-+)|(-+$)/g, '');

const adjustedQuickstart = { ...quickStart };
adjustedQuickstart.spec = { ...adjustedQuickstart.spec };
adjustedQuickstart.metadata = {
...adjustedQuickstart.metadata,
name: effectiveName,
};

delete adjustedQuickstart.spec['icon'];

return [
{
name: 'metadata.yaml',
randomnetcat marked this conversation as resolved.
Show resolved Hide resolved
content: YAML.stringify({
kind: 'QuickStarts',
name: effectiveName,
tags: bundles
.toSorted()
.map((bundle) => ({ kind: 'bundle', value: bundle })),
}),
},
{
name: `${effectiveName}.yaml`,
content: YAML.stringify(adjustedQuickstart),
},
];
}, [quickStart, bundles]);

if ((quickStart.spec.tasks?.length ?? 0) != taskContents.length) {
throw new Error(
`Mismatch between quickstart tasks and task contents: ${quickStart.spec.tasks?.length} vs ${taskContents.length}`
);
}

return (
<PageGroup>
<PageSection variant="darker">
<Title headingLevel="h1" size="2xl">
Add new learning resources
</Title>

<p>Description</p>
</PageSection>

<PageSection isFilled>
<Grid hasGutter className="pf-v5-u-h-100 pf-v5-u-w-100">
<GridItem span={12} lg={6}>
<CreatorWizard
randomnetcat marked this conversation as resolved.
Show resolved Hide resolved
onChangeKind={setKind}
onChangeQuickStartSpec={(spec) => {
updateSpec(() => spec);
}}
onChangeBundles={setBundles}
onChangeTaskContents={setTaskContents}
onChangeCurrentTask={setCurrentTask}
errors={errors}
files={files}
/>
</GridItem>

<GridItem span={12} lg={6}>
<CreatorPreview
kindMeta={selectedKind?.meta ?? null}
quickStart={quickStart}
currentTask={currentTask}
/>
</GridItem>
</Grid>
</PageSection>
</PageGroup>
);
};

export default Creator;
File renamed without changes.
4 changes: 2 additions & 2 deletions src/App.tsx → src/Viewer.tsx
randomnetcat marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useEffect, useState } from 'react';
import './App.scss';
import './Viewer.scss';
import { useChrome } from '@redhat-cloud-services/frontend-components/useChrome';
import {
LoadingBox,
Expand All @@ -26,7 +26,7 @@ import { BookmarkIcon, OutlinedBookmarkIcon } from '@patternfly/react-icons';
import { useFlag } from '@unleash/proxy-client-react';
import useQuickStarts from './hooks/useQuickStarts';

export const App = ({ bundle }: { bundle: string }) => {
export const Viewer = ({ bundle }: { bundle: string }) => {
const chrome = useChrome();
const { activeQuickStartID, allQuickStartStates, setFilter, loading } =
React.useContext<QuickStartContextValues>(QuickStartContext);
Expand Down
15 changes: 0 additions & 15 deletions src/components/CatalogSection.scss
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,3 @@
margin-bottom: var(--pf-global--spacer--md);
}
}

.lr-c-quickstart_tile {
.pf-v5-c-card__header {
height: 0;
}
.pf-v5-c-title {
flex: 1;
}
>div {
height: 100%;
>a {
color: var(--pf-v5-global--palette--black-1000);
}
}
}
Loading