Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
*/

import { observer } from "mobx-react";
import { useTranslation } from "@plane/i18n";
import type { TQuickAddIssueForm } from "../root";

export const CalendarQuickAddIssueForm = observer(function CalendarQuickAddIssueForm(props: TQuickAddIssueForm) {
const { ref, isOpen, projectDetail, register, onSubmit, isEpic } = props;
const { t } = useTranslation();

return (
<div
Expand All @@ -28,6 +30,10 @@ export const CalendarQuickAddIssueForm = observer(function CalendarQuickAddIssue
placeholder={isEpic ? "Epic Title" : "Work item Title"}
{...register("name", {
required: `${isEpic ? "Epic" : "Work item"} title is required.`,
maxLength: {
value: 255,
message: t("title_should_be_less_than_255_characters"),
},
})}
className="w-full rounded-md bg-transparent py-1.5 pr-2 text-13 leading-5 font-medium text-secondary outline-none md:text-11"
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ export const GanttQuickAddIssueForm = observer(function GanttQuickAddIssueForm(p
placeholder={isEpic ? t("epic.title.label") : t("issue.title.label")}
{...register("name", {
required: isEpic ? t("epic.title.required") : t("issue.title.required"),
maxLength: {
value: 255,
message: t("title_should_be_less_than_255_characters"),
},
})}
className="w-full rounded-md bg-transparent px-2 py-3 text-13 leading-5 font-medium text-secondary outline-none"
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ export const KanbanQuickAddIssueForm = observer(function KanbanQuickAddIssueForm
placeholder={isEpic ? t("epic.title.label") : t("issue.title.label")}
{...register("name", {
required: isEpic ? t("epic.title.required") : t("issue.title.required"),
maxLength: {
value: 255,
message: t("title_should_be_less_than_255_characters"),
},
})}
className="w-full rounded-md bg-transparent px-2 py-1.5 pl-0 text-13 leading-5 font-medium text-secondary outline-none"
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ export const ListQuickAddIssueForm = observer(function ListQuickAddIssueForm(pro
placeholder={isEpic ? t("epic.title.label") : t("issue.title.label")}
{...register("name", {
required: isEpic ? t("epic.title.required") : t("issue.title.required"),
maxLength: {
value: 255,
message: t("title_should_be_less_than_255_characters"),
},
})}
className="w-full rounded-md bg-transparent px-2 py-3 text-13 leading-5 font-medium text-secondary outline-none"
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ export const SpreadsheetQuickAddIssueForm = observer(function SpreadsheetQuickAd
placeholder={isEpic ? t("epic.title.label") : t("issue.title.label")}
{...register("name", {
required: isEpic ? t("epic.title.required") : t("issue.title.required"),
maxLength: {
value: 255,
message: t("title_should_be_less_than_255_characters"),
},
})}
className="w-full rounded-md bg-transparent py-3 text-13 leading-5 text-secondary outline-none"
/>
Expand Down
45 changes: 32 additions & 13 deletions apps/web/core/components/issues/issue-layouts/quick-add/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,21 @@ export const QuickAddIssueRoot = observer(function QuickAddIssueRoot(props: TQui
},
error: {
title: t("common.error.label"),
message: (err) => err?.message || t("common.error.message"),
message: (err) => {
// Issue service throws response.data (field errors), not Error instances
if (typeof err === "string") return err;
if (err?.message && typeof err.message === "string") return err.message;
if (err?.name) {
return Array.isArray(err.name) ? err.name[0] : err.name;
}
if (err && typeof err === "object") {
for (const value of Object.values(err)) {
if (typeof value === "string") return value;
if (Array.isArray(value) && typeof value[0] === "string") return value[0];
}
}
return t("common.error.message");
},
},
});

Expand All @@ -144,18 +158,23 @@ export const QuickAddIssueRoot = observer(function QuickAddIssueRoot(props: TQui
)}
>
{isOpen ? (
<QuickAddIssueFormRoot
isOpen={isOpen}
layout={layout}
prePopulatedData={prePopulatedData}
projectId={projectId?.toString()}
hasError={errors && errors?.name && errors?.name?.message ? true : false}
setFocus={setFocus}
register={register}
onSubmit={handleSubmit(onSubmitHandler)}
onClose={() => handleIsOpen(false)}
isEpic={isEpic}
/>
<>
<QuickAddIssueFormRoot
isOpen={isOpen}
layout={layout}
prePopulatedData={prePopulatedData}
projectId={projectId?.toString()}
hasError={errors && errors?.name && errors?.name?.message ? true : false}
setFocus={setFocus}
register={register}
onSubmit={handleSubmit(onSubmitHandler)}
onClose={() => handleIsOpen(false)}
isEpic={isEpic}
/>
{errors?.name?.message && (
<p className="px-3 py-1 text-11 text-danger-primary">{errors.name.message}</p>
)}
</>
) : (
<>
{QuickAddButton && <QuickAddButton isEpic={isEpic} onClick={() => handleIsOpen(true)} />}
Expand Down
47 changes: 28 additions & 19 deletions apps/web/core/store/issue/helpers/base-issues.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -645,26 +645,35 @@ export abstract class BaseIssuesStore implements IBaseIssuesStore {
async issueQuickAdd(workspaceSlug: string, projectId: string, data: TIssue) {
// Add issue to store with a temporary Id
this.addIssue(data);
// call Create issue method
const response = await this.createIssue(workspaceSlug, projectId, data);
runInAction(() => {
this.removeIssueFromList(data.id);
this.rootIssueStore.issues.removeIssue(data.id);
});
const currentCycleId = data.cycle_id !== "" && data.cycle_id === "None" ? undefined : data.cycle_id;
const currentModuleIds =
data.module_ids && data.module_ids.length > 0 ? data.module_ids.filter((moduleId) => moduleId != "None") : [];
const promiseRequests = [];
if (currentCycleId) {
promiseRequests.push(this.addCycleToIssue(workspaceSlug, projectId, currentCycleId, response.id));
}
if (currentModuleIds.length > 0) {
promiseRequests.push(this.changeModulesInIssue(workspaceSlug, projectId, response.id, currentModuleIds, []));
}
if (promiseRequests && promiseRequests.length > 0) {
await Promise.all(promiseRequests);
try {
// call Create issue method
const response = await this.createIssue(workspaceSlug, projectId, data);
runInAction(() => {
this.removeIssueFromList(data.id);
this.rootIssueStore.issues.removeIssue(data.id);
});
const currentCycleId = data.cycle_id !== "" && data.cycle_id === "None" ? undefined : data.cycle_id;
const currentModuleIds =
data.module_ids && data.module_ids.length > 0 ? data.module_ids.filter((moduleId) => moduleId != "None") : [];
const promiseRequests = [];
if (currentCycleId) {
promiseRequests.push(this.addCycleToIssue(workspaceSlug, projectId, currentCycleId, response.id));
}
if (currentModuleIds.length > 0) {
promiseRequests.push(this.changeModulesInIssue(workspaceSlug, projectId, response.id, currentModuleIds, []));
}
if (promiseRequests && promiseRequests.length > 0) {
await Promise.all(promiseRequests);
}
return response;
} catch (error) {
// Roll back optimistic temp issue so the list does not keep a failed entry
runInAction(() => {
this.removeIssueFromList(data.id);
this.rootIssueStore.issues.removeIssue(data.id);
});
throw error;
}
return response;
}

/**
Expand Down