Skip to content

Commit

Permalink
feat(frontend): add Edit and View
Browse files Browse the repository at this point in the history
  • Loading branch information
remarkablemark committed Mar 12, 2024
1 parent 432f3e4 commit 5383f65
Show file tree
Hide file tree
Showing 26 changed files with 611 additions and 198 deletions.
71 changes: 40 additions & 31 deletions src/frontend/src/edit/Edit.tsx
Original file line number Diff line number Diff line change
@@ -1,42 +1,51 @@
import Button, { ButtonGroup } from '@atlaskit/button';
import Form, { Field } from '@atlaskit/form';
import TextField from '@atlaskit/textfield';
import ButtonGroup from '@atlaskit/button/button-group';
import LoadingButton from '@atlaskit/button/loading-button';
import Button from '@atlaskit/button/new';
import Form, { FormFooter } from '@atlaskit/form';
import { view } from '@forge/bridge';

import type { FormValues, View } from '../types';
import { log } from '../helpers';
import { useFormValues, useGetFormValues } from '../hooks';
import type { FormValues } from '../types';
import Formulas from './formulas';
import Variables from './variables';

interface Props {
formValues: FormValues;
view: View;
}
export default function Edit() {
const { formValues: oldFormValues } = useFormValues();
const formValues = useGetFormValues();

export default function Edit(props: Props) {
return (
<Form<FormValues> onSubmit={(formValues) => props.view.submit(formValues)}>
<Form<FormValues>
onSubmit={() => {
import.meta.env.DEV && log.info('submit:', formValues);
view.submit(formValues);
}}
>
{({ formProps, submitting }) => (
<form {...formProps}>
<Field
name="label"
label="Label"
defaultValue={props.formValues.label}
>
{({ fieldProps }) => <TextField {...fieldProps} />}
</Field>

<Field name="jql" label="JQL" defaultValue={props.formValues.jql}>
{({ fieldProps }) => <TextField {...fieldProps} />}
</Field>

<br />
<Variables />
<Formulas />

<ButtonGroup>
<Button appearance="primary" type="submit" isDisabled={submitting}>
Save
</Button>
<FormFooter align="start">
<ButtonGroup label="Form submit options">
<LoadingButton
type="submit"
appearance="primary"
isLoading={submitting}
>
Save
</LoadingButton>

<Button onClick={() => props.view.submit(props.formValues)}>
Cancel
</Button>
</ButtonGroup>
<Button
onClick={() => {
import.meta.env.DEV && log.info('cancel');
formValues && view.submit(oldFormValues);
}}
>
Cancel
</Button>
</ButtonGroup>
</FormFooter>
</form>
)}
</Form>
Expand Down
67 changes: 67 additions & 0 deletions src/frontend/src/edit/formulas/FormulaSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { Inline } from '@atlaskit/primitives';

import { useFormValuesStore } from '../../hooks';
import { DeleteButton, TextArea, TextField } from '../../shared';

interface Props {
index: number;
showLabel?: boolean;
}

export default function FormulaSection(props: Props) {
const formValues = useFormValuesStore();

return (
<Inline space="space.050">
<TextArea
name={`formula[${props.index}]`}
label={props.showLabel && 'Math Formula'}
value={formValues.formula[props.index]}
spellCheck={false}
onChange={(event) => {
formValues.updateFormValue(
'formula',
props.index,
event.target.value,
);
}}
style={{ flexGrow: 1, maxWidth: 400 }}
isRequired
/>

<TextArea
name={`label[${props.index}]`}
label={props.showLabel && 'Label'}
value={formValues.label[props.index]}
onChange={(event) => {
formValues.updateFormValue('label', props.index, event.target.value);
}}
style={{ flexGrow: 1, maxWidth: 300 }}
isRequired
/>

<TextField
name={`decimal[${props.index}]`}
label={props.showLabel && 'Decimals'}
value={formValues.decimal[props.index]}
onChange={(event) => {
formValues.updateFormValue(
'decimal',
props.index,
(event.target as HTMLInputElement).value,
);
}}
type="number"
min={0}
width={55}
isRequired
/>

<DeleteButton
label="Delete formula"
onClick={() => formValues.deleteFormula(props.index)}
offsetLabel={props.showLabel}
/>
</Inline>
);
}
33 changes: 33 additions & 0 deletions src/frontend/src/edit/formulas/Formulas.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Code } from '@atlaskit/code';
import { FormSection } from '@atlaskit/form';
import { Box } from '@atlaskit/primitives';

import { useFormValuesStore } from '../../hooks';
import { AddButton } from '../../shared';
import FormulaSection from './FormulaSection';

export default function Formulas() {
const { formula, addFormula } = useFormValuesStore();

return (
<>
<FormSection
title="Formulas"
description={
<>
Mathematical calculations using variables. For example:{' '}
<Code>a + b</Code> or <Code>var_1 / var_2 * 100</Code>.
</>
}
>
{formula.map((_, index) => (
<FormulaSection key={index} index={index} showLabel={!index} />
))}
</FormSection>

<Box padding="space.050" />

<AddButton label="Add formula" onClick={addFormula} />
</>
);
}
1 change: 1 addition & 0 deletions src/frontend/src/edit/formulas/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './Formulas';
7 changes: 3 additions & 4 deletions src/frontend/src/edit/index.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import Spinner from '@atlaskit/spinner';
import { view } from '@forge/bridge';

import { useFormValues } from '../hooks';
import Edit from './Edit';

export default function EditContext() {
const formValues = useFormValues();
const { isLoading } = useFormValues();

if (!formValues) {
if (isLoading) {
return <Spinner label="Loading" />;
}

return <Edit formValues={formValues} view={view} />;
return <Edit />;
}
46 changes: 46 additions & 0 deletions src/frontend/src/edit/variables/VariableField.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { ErrorMessage } from '@atlaskit/form';
import { useState } from 'react';

import { useFormValuesStore } from '../../hooks';
import { TextArea, type TextAreaProps } from '../../shared';

interface Props extends TextAreaProps {
index: number;
}

export default function VariableField(props: Props) {
const { index, ...restProps } = props;
const [error, setError] = useState('');
const formValues = useFormValuesStore();

function validate(value?: unknown) {
if (!value || typeof value !== 'string') {
setError('');
} else if (!/^[a-zA-Z]/.test(value)) {
setError('Variable must start with a letter');
} else if (/\s/.test(value)) {
setError('Variable must not contain whitespace');
} else if (!/^[a-zA-Z0-9_]+$/.test(value)) {
setError('Variable must not contain special characters');
} else {
setError('');
}
}

return (
<>
<TextArea
{...restProps}
spellCheck={false}
onChange={(event) => {
formValues.updateFormValue('variable', index, event.target.value);
validate(event.target.value);
}}
style={{ flexGrow: 1, maxWidth: 200 }}
isRequired
/>

{error && <ErrorMessage>{error}</ErrorMessage>}
</>
);
}
70 changes: 70 additions & 0 deletions src/frontend/src/edit/variables/VariableSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { Field } from '@atlaskit/form';
import { Inline } from '@atlaskit/primitives';
import Select from '@atlaskit/select';

import { useFormValuesStore } from '../../hooks';
import { DeleteButton, TextArea } from '../../shared';
import VariableField from './VariableField';

interface Props {
index: number;
showLabel?: boolean;
}

export default function VariableSection(props: Props) {
const formValues = useFormValuesStore();

return (
<Inline space="space.050">
<VariableField
name={`variable[${props.index}]`}
label={props.showLabel && 'Variable'}
value={formValues.variable[props.index]}
index={props.index}
/>

<Field<string, HTMLSelectElement>
name={`function[${props.index}]`}
label={props.showLabel && 'Function'}
>
{({ fieldProps }) => (
<Select
{...fieldProps}
options={[
{
label: 'COUNT',
value: 'COUNT',
},
]}
value={formValues.function[props.index]}
onChange={(event) => {
formValues.updateFormValue(
'function',
props.index,
event?.value || '',
);
}}
required
/>
)}
</Field>

<TextArea
name={`jql[${props.index}]`}
label={props.showLabel && 'JQL'}
value={formValues.jql[props.index]}
spellCheck={false}
onChange={(event) => {
formValues.updateFormValue('jql', props.index, event.target.value);
}}
style={{ flexGrow: 1, maxWidth: 800 }}
/>

<DeleteButton
label="Delete variable"
onClick={() => formValues.deleteVariable(props.index)}
offsetLabel={props.showLabel}
/>
</Inline>
);
}
33 changes: 33 additions & 0 deletions src/frontend/src/edit/variables/Variables.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Code } from '@atlaskit/code';
import { FormSection } from '@atlaskit/form';
import { Box } from '@atlaskit/primitives';

import { useFormValuesStore } from '../../hooks';
import { AddButton } from '../../shared';
import VariableSection from './VariableSection';

export default function Variables() {
const { variable, addVariable } = useFormValuesStore();

return (
<>
<FormSection
title="Variables"
description={
<>
Data used in formula calculations. For example: <Code>a</Code> or{' '}
<Code>var_1</Code>.
</>
}
>
{variable.map((_, index) => (
<VariableSection key={index} index={index} showLabel={!index} />
))}
</FormSection>

<Box padding="space.050" />

<AddButton label="Add variable" onClick={addVariable} />
</>
);
}
1 change: 1 addition & 0 deletions src/frontend/src/edit/variables/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './Variables';
3 changes: 2 additions & 1 deletion src/frontend/src/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export { useFormValuesStore } from '../store/formValuesStore';
export * from './useForgeContext';
export * from './useFormValues';
export * from './useId';
export * from './useGetFormValues';
export * from './useJiraSearch';
Loading

0 comments on commit 5383f65

Please sign in to comment.