Skip to content

Commit

Permalink
Use editor component in the description field of a workshop (#694)
Browse files Browse the repository at this point in the history
* Use editor component in the description field of a workshop

* fixup! Use editor component in the description field of a workshop

* Increase hash size to avoid collisions
  • Loading branch information
aleixhub authored Nov 15, 2022
1 parent a54b657 commit dca7a68
Show file tree
Hide file tree
Showing 8 changed files with 55 additions and 21 deletions.
25 changes: 17 additions & 8 deletions catalog/ui/src/app/Catalog/CatalogItemForm.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { useEffect, useMemo, useReducer, useState } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import parseDuration from 'parse-duration';
import { EditorState } from 'lexical/LexicalEditorState';
import {
ActionList,
ActionListItem,
Expand All @@ -19,7 +20,6 @@ import {
SelectOption,
SelectVariant,
Switch,
TextArea,
TextInput,
Title,
Tooltip,
Expand All @@ -43,6 +43,7 @@ import { CatalogItem } from '@app/types';
import { ErrorBoundary } from 'react-error-boundary';
import { displayName, isLabDeveloper, randomString } from '@app/util';
import DateTimePicker from '@app/components/DateTimePicker';
import Editor from '@app/components/Editor/Editor';
import useSession from '@app/utils/useSession';
import useDebounce from '@app/utils/useDebounce';
import PatientNumberInput from '@app/components/PatientNumberInput';
Expand Down Expand Up @@ -418,16 +419,24 @@ const CatalogItemFormData: React.FC<{ namespace: string; catalogItemName: string
</FormGroup>
<FormGroup fieldId="workshopDescription" label="Description">
<div className="catalog-item-form__group-control--single">
<TextArea
onChange={(v) =>
dispatchFormState({ type: 'workshop', workshop: { ...formState.workshop, description: v } })
}
value={formState.workshop.description}
<Editor
onChange={(state: EditorState) => {
const editorState = state.toJSON();
dispatchFormState({
type: 'workshop',
workshop: { ...formState.workshop, description: JSON.stringify(editorState) },
});
}}
placeholder="Add description"
aria-label="Description"
defaultValue={formState.workshop.description}
/>
<Tooltip position="right" content={<p>Description shown in the workshop user interface.</p>}>
<Tooltip
position="right"
content={<p>Description text visible after the user accesses the Workshop.</p>}
>
<OutlinedQuestionCircleIcon
aria-label="Description shown in the workshop user interface"
aria-label="Description text visible after the user accesses the Workshop."
className="tooltip-icon-only"
/>
</Tooltip>
Expand Down
2 changes: 1 addition & 1 deletion catalog/ui/src/app/Services/service-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export function getAutoTimes(resourceClaim: ResourceClaim): { startTime: number;
function getSpecResourceByName(name: string): ResourceClaimSpecResource {
return specResources.find((s) => s.name === name);
}
if (!resources) return null;
if (!resources) return { startTime: null, stopTime: null };
// The start time for a multi-component service is the earliest start time of all components and the stop time is the latest stop time
const stopTimes = [];
const startTimes = [];
Expand Down
4 changes: 2 additions & 2 deletions catalog/ui/src/app/Workshops/WorkshopsItemDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,9 @@ const WorkshopsItemDetails: React.FC<{
<DescriptionListGroup>
<DescriptionListTerm>
Description{' '}
<Tooltip position="right" content={<p>Custom details visible after the user accesses the Workshop.</p>}>
<Tooltip position="right" content={<p>Description text visible after the user accesses the Workshop.</p>}>
<OutlinedQuestionCircleIcon
aria-label="Custom details visible after the user accesses the Workshop."
aria-label="Description text visible after the user accesses the Workshop."
className="tooltip-icon-only"
/>
</Tooltip>
Expand Down
2 changes: 1 addition & 1 deletion catalog/ui/src/app/Workshops/WorkshopsItemServices.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ const WorkshopsItemServices: React.FC<{
<SelectableTable
key="table"
columns={['Name', 'GUID', 'Status', 'Created', 'Actions']}
onSelectAll={(isSelected) => {
onSelectAll={(isSelected: boolean) => {
if (isSelected) {
setSelectedUids(resourceClaims.map((resourceClaim) => resourceClaim.metadata.uid));
} else {
Expand Down
18 changes: 15 additions & 3 deletions catalog/ui/src/app/components/Editor/Editor.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import { EditorState, LexicalEditor } from 'lexical';
import { LexicalComposer } from '@lexical/react/LexicalComposer';
import { $createParagraphNode, $createTextNode, $getRoot, EditorState, LexicalEditor } from 'lexical';
import { InitialEditorStateType, LexicalComposer } from '@lexical/react/LexicalComposer';
import { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin';
import { ContentEditable } from '@lexical/react/LexicalContentEditable';
import { OnChangePlugin } from '@lexical/react/LexicalOnChangePlugin';
Expand All @@ -26,12 +26,24 @@ const Editor: React.FC<{
placeholder: string;
defaultValue?: string;
}> = ({ onChange, placeholder, defaultValue }) => {
let _defaultValue: InitialEditorStateType = defaultValue;
try {
JSON.parse(defaultValue);
} catch {
_defaultValue = () => {
const root = $getRoot();
root.clear();
const p = $createParagraphNode();
p.append($createTextNode(defaultValue));
root.append(p);
};
}
return (
<div className="editor">
<LexicalComposer
initialConfig={{
namespace: 'editor',
editorState: defaultValue,
editorState: _defaultValue,
theme: Theme,
nodes: [
HeadingNode,
Expand Down
17 changes: 15 additions & 2 deletions catalog/ui/src/app/components/Editor/EditorViewer.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from 'react';
import { LexicalComposer } from '@lexical/react/LexicalComposer';
import { $createParagraphNode, $createTextNode, $getRoot } from 'lexical';
import { InitialEditorStateType, LexicalComposer } from '@lexical/react/LexicalComposer';
import { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin';
import { ContentEditable } from '@lexical/react/LexicalContentEditable';
import LexicalErrorBoundary from '@lexical/react/LexicalErrorBoundary';
Expand All @@ -15,13 +16,25 @@ import './editor.css';
const EditorViewer: React.FC<{
value?: string;
}> = ({ value }) => {
let _defaultValue: InitialEditorStateType = value;
try {
JSON.parse(value);
} catch {
_defaultValue = () => {
const root = $getRoot();
root.clear();
const p = $createParagraphNode();
p.append($createTextNode(value));
root.append(p);
};
}
return (
<div className="editor editor-viewer">
<LexicalComposer
initialConfig={{
editable: false,
namespace: 'editor',
editorState: value,
editorState: _defaultValue,
theme: Theme,
nodes: [
HeadingNode,
Expand Down
4 changes: 2 additions & 2 deletions catalog/ui/webpack.common.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ module.exports = () => {
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[contenthash:4].bundle.js',
chunkFilename: '[name].[contenthash:4].bundle.js',
filename: '[name].[contenthash:8].bundle.js',
chunkFilename: '[name].[contenthash:8].bundle.js',
publicPath: ASSET_PATH,
},
plugins: [
Expand Down
4 changes: 2 additions & 2 deletions catalog/ui/webpack.prod.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ module.exports = merge(common('production'), {
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].[contenthash:4].css',
chunkFilename: '[name].[contenthash:4].bundle.css',
filename: '[name].[contenthash:8].css',
chunkFilename: '[name].[contenthash:8].bundle.css',
ignoreOrder: true,
}),
],
Expand Down

0 comments on commit dca7a68

Please sign in to comment.