Skip to content

Commit

Permalink
feat: integrate with application workspace template
Browse files Browse the repository at this point in the history
Signed-off-by: Lin Wang <wonglam@amazon.com>
  • Loading branch information
wanglam committed Jun 12, 2023
1 parent d694a14 commit 27673ce
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 113 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,21 @@
import React from 'react';
import { EuiSpacer, EuiTitle } from '@elastic/eui';

import { useOpenSearchDashboards } from '../../../../../plugins/opensearch_dashboards_react/public';

import { WorkspaceForm } from './workspace_form';
import { defaultTemplates, defaultFeatureOrGroups } from './sample_data';

export const WorkspaceCreator = () => {
const {
services: { application },
} = useOpenSearchDashboards();
return (
<div>
<EuiTitle>
<h1>Create Workspace</h1>
</EuiTitle>
<EuiSpacer />
<WorkspaceForm templates={defaultTemplates} featureOrGroups={defaultFeatureOrGroups} />
{application && <WorkspaceForm application={application} />}
</div>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
* SPDX-License-Identifier: Apache-2.0
*/

import React, { useCallback, useState, FormEventHandler, useRef } from 'react';
import React, { useCallback, useState, FormEventHandler, useRef, useMemo } from 'react';
import { groupBy } from 'lodash';
import {
EuiPanel,
EuiSpacer,
Expand All @@ -27,18 +28,15 @@ import {
EuiCheckboxProps,
EuiFieldTextProps,
} from '@elastic/eui';
import { ApplicationStart } from 'opensearch-dashboards/public';

interface WorkspaceTemplate {
name: string;
image: string;
description: string;
keyFeatures: string[];
}
import { WorkspaceTemplate } from '../../../../../core/types';
import { useApplications, useWorkspaceTemplate } from '../../hooks';

interface WorkspaceFeature {
id: string;
name: string;
template: string[];
templates: WorkspaceTemplate[];
}

interface WorkspaceFeatureGroup {
Expand All @@ -61,22 +59,21 @@ const isWorkspaceFeatureGroup = (
const workspaceHtmlIdGenerator = htmlIdGenerator();

interface WorkspaceFormProps {
templates: WorkspaceTemplate[];
featureOrGroups: Array<WorkspaceFeature | WorkspaceFeatureGroup>;
application: ApplicationStart;
onSubmit?: (formData: WorkspaceFormData) => void;
defaultValues?: WorkspaceFormData;
}
export const WorkspaceForm = ({
templates,
featureOrGroups,
onSubmit,
defaultValues,
}: WorkspaceFormProps) => {
export const WorkspaceForm = ({ application, onSubmit, defaultValues }: WorkspaceFormProps) => {
const { workspaceTemplates, templateFeatureMap } = useWorkspaceTemplate(application);
const applications = useApplications(application);

const [name, setName] = useState(defaultValues?.name);
const [description, setDescription] = useState(defaultValues?.description);
const [selectedTemplateName, setSelectedTemplateName] = useState<string>();
const [selectedTemplateId, setSelectedTemplateId] = useState<string>();
const [selectedFeatureIds, setSelectedFeatureIds] = useState(defaultValues?.features || []);
const selectedTemplate = templates.find((template) => template.name === selectedTemplateName);
const selectedTemplate = workspaceTemplates.find(
(template) => template.id === selectedTemplateId
);
const [formErrors, setFormErrors] = useState<WorkspaceFormErrors>({});
const formIdRef = useRef<string>();
const getFormData = () => ({
Expand All @@ -87,20 +84,47 @@ export const WorkspaceForm = ({
const getFormDataRef = useRef(getFormData);
getFormDataRef.current = getFormData;

const featureOrGroups = useMemo(() => {
const category2Applications = groupBy(applications, 'category.label');
return Object.keys(category2Applications).reduce<
Array<WorkspaceFeature | WorkspaceFeatureGroup>
>((previousValue, currentKey) => {
if (currentKey === 'undefined') {
return previousValue;
}
const apps = category2Applications[currentKey];
const features = apps.map(({ id, title, workspaceTemplate }) => ({
id,
name: title,
templates: workspaceTemplate || [],
}));
if (features.length === 1) {
return [...previousValue, features[0]];
}
return [
...previousValue,
{
name: apps[0].category?.label || '',
features,
},
];
}, []);
}, [applications]);

if (!formIdRef.current) {
formIdRef.current = workspaceHtmlIdGenerator();
}

const handleTemplateCardChange = useCallback<EuiCheckableCardProps['onChange']>(
(e) => {
const templateName = e.target.value;
setSelectedTemplateName(templateName);
const templateId = e.target.value;
setSelectedTemplateId(templateId);
setSelectedFeatureIds(
featureOrGroups.reduce<string[]>(
(previousData, currentData) => [
...previousData,
...(isWorkspaceFeatureGroup(currentData) ? currentData.features : [currentData])
.filter(({ template }) => template.includes(templateName))
.filter(({ templates }) => !!templates.find((template) => template.id === templateId))
.map((feature) => feature.id),
],
[]
Expand Down Expand Up @@ -192,14 +216,14 @@ export const WorkspaceForm = ({
</EuiTitle>
<EuiSpacer />
<EuiFlexGrid columns={2}>
{templates.map((template) => (
<EuiFlexItem key={template.name}>
{workspaceTemplates.map((template) => (
<EuiFlexItem key={template.label}>
<EuiCheckableCard
id={workspaceHtmlIdGenerator()}
title={template.name}
label={template.name}
value={template.name}
checked={template.name === selectedTemplateName}
title={template.label}
label={template.label}
value={template.id}
checked={template.id === selectedTemplateId}
onChange={handleTemplateCardChange}
/>
</EuiFlexItem>
Expand All @@ -214,7 +238,9 @@ export const WorkspaceForm = ({
<EuiSpacer />
<EuiFlexGroup>
<EuiFlexItem>
<EuiImage src={selectedTemplate.image} alt={selectedTemplate.name} />
{selectedTemplate.coverImage && (
<EuiImage src={selectedTemplate.coverImage} alt={selectedTemplate.label} />
)}
</EuiFlexItem>
<EuiFlexItem>
<EuiText>{selectedTemplate.description}</EuiText>
Expand All @@ -223,8 +249,8 @@ export const WorkspaceForm = ({
</EuiTitle>
<EuiSpacer />
<EuiFlexGrid style={{ paddingLeft: 20, paddingRight: 100 }} columns={2}>
{selectedTemplate.keyFeatures.map((feature) => (
<EuiFlexItem key={feature}>{feature}</EuiFlexItem>
{templateFeatureMap.get(selectedTemplate.id)?.map((feature) => (
<EuiFlexItem key={feature.id}>{feature.title}</EuiFlexItem>
))}
</EuiFlexGrid>
</EuiFlexItem>
Expand Down
11 changes: 11 additions & 0 deletions src/plugins/workspace/public/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,17 @@ import { useObservable } from 'react-use';
import { useMemo } from 'react';
import { WorkspaceTemplate } from '../../../core/types';

export function useApplications(application: ApplicationStart) {
const applications = useObservable(application.applications$);
return useMemo(() => {
const apps: PublicAppInfo[] = [];
applications?.forEach((app) => {
apps.push(app);
});
return apps;
}, [applications]);
}

export function useWorkspaceTemplate(application: ApplicationStart) {
const applications = useObservable(application.applications$);

Expand Down

0 comments on commit 27673ce

Please sign in to comment.