Hello Atlassian Developer Community!
Disclaimer: I’m very new to both Forge and React.
I have created a Forge App using forge create
with the UI Kit template jira-custom-field
. When I edit it, I want to use a list to select the item that should be stored. I have been trying to get this to work using <Select />
and it does work - but it looks really bad since the Edit
modal only shows the two first items and then there’s a scroll bar that kind of (but not really) works.
The <Select />
has three items in the screenshot below and it is possible to use the arrow keys as well as some times get the scroll bar to work. But it’s not really something I would like to expose the end users to.
My manifest.yml
:
modules:
jira:customField:
- key: custom-item
name: Custom Item
description: A custom field for Custom Item.
type: object
formatter:
expression: "`[${value.id}] ${value.name}`"
schema:
properties:
id:
type: string
searchAlias: ID
name:
type: string
searchAlias: Name
required: ["id", "name"]
render: native
resource: main
edit:
resource: edit
render: native
resources:
- key: main
path: src/frontend/index.jsx
- key: edit
path: src/frontend/edit.jsx
app:
runtime:
name: nodejs18.x
id: ari:cloud:ecosystem::app/[some-uuid]
My src/frontend/index.jsx
:
import React, { useState, useEffect } from "react";
import ForgeReconciler, { Text } from "@forge/react";
import { view } from "@forge/bridge";
const View = () => {
const [fieldValue, setFieldValue] = useState(null);
useEffect(() => {
view.getContext().then((context) => {
setFieldValue(context.extension.fieldValue);
});
}, []);
if (!fieldValue) {
return `Empty...`;
}
const { id, name } = fieldValue;
if (!id && !name) {
return `Empty...`;
}
return (
<>
<Text>{`[${id}] ${name}`}</Text>
</>
);
};
ForgeReconciler.render(
<React.StrictMode>
<View />
</React.StrictMode>
);
My src/frontend/edit.jsx
:
import React, { useState, useEffect } from "react";
import ForgeReconciler, {
Form,
Label,
useForm,
FormSection,
FormFooter,
ButtonGroup,
LoadingButton,
Button,
Select,
} from "@forge/react";
import { view } from "@forge/bridge";
const Edit = () => {
const [renderContext, setRenderContext] = useState(null);
const [isLoading, setIsLoading] = useState(false);
const { handleSubmit, register, getFieldId, getValues } = useForm();
useEffect(() => {
view.getContext().then((context) => {
setRenderContext(context.extension.renderContext);
});
}, []);
const onSubmit = async (data) => {
setIsLoading(true);
try {
const { item } = data;
if (!item) {
throw new Error("Item is required");
}
const { value } = item;
if (!value) {
throw new Error("Item is required");
}
const { id, name } = value;
if (!id || !name) {
throw new Error("Item is required");
}
await view.submit({ id, name });
} catch (e) {
console.error(e);
} finally {
setIsLoading(false);
}
};
const items = [
{ id: "ID-001", name: "Foo" },
{ id: "ID-002", name: "Bar" },
{ id: "ID-003", name: "Baz" },
];
const itemOptions = items.map((item) => ({
label: `[${item.id}] ${item.name}`,
value: item,
}));
return renderContext === "issue-view" ? (
<Form onSubmit={handleSubmit(onSubmit)}>
<FormSection>
<Label labelFor={getFieldId("fieldName")}>Custom field value</Label>
<Select isSearchable options={itemOptions} {...register("item")} />
</FormSection>
<FormFooter>
<ButtonGroup>
<Button appearance="subtle" onClick={view.close}>
Close
</Button>
<LoadingButton
appearance="primary"
type="submit"
isLoading={isLoading}
>
Submit
</LoadingButton>
</ButtonGroup>
</FormFooter>
</Form>
) : (
<Form onSubmit={handleSubmit(onSubmit)}>
<Label labelFor={getFieldId("fieldName")}>Custom field value</Label>
<Select isSearchable {...register("item")} options={itemOptions} />
</Form>
);
};
ForgeReconciler.render(
<React.StrictMode>
<Edit />
</React.StrictMode>
);
Note: items
are supposed to be retreived using a resolver, but since the issue is UI related this is a simpler example.
As a reference, creating a new Issue looks just fine:
See reply below for screenshot
I would either like to get the modal to work correctly, or even better to get the <Select />
to work directly in the Issue (where it says Empty...
in the screenshot below).
See reply below for screenshot
Any assistance at this point would be greatly appriciated, since I’m not figuring it out. Sorry in advance if this is a really simple fix that I’ve just missed.