forked from github/plane
refactor: view props structure (#2159)
* chore: update view_props types * refactor: view props structure
This commit is contained in:
parent
cdb888c23e
commit
8e9a4dca78
@ -58,16 +58,8 @@ export const IssuesFilterView: React.FC = () => {
|
|||||||
const isArchivedIssues = router.pathname.includes("archived-issues");
|
const isArchivedIssues = router.pathname.includes("archived-issues");
|
||||||
|
|
||||||
const {
|
const {
|
||||||
issueView,
|
displayFilters,
|
||||||
setIssueView,
|
setDisplayFilters,
|
||||||
groupByProperty,
|
|
||||||
setGroupByProperty,
|
|
||||||
orderBy,
|
|
||||||
setOrderBy,
|
|
||||||
showEmptyGroups,
|
|
||||||
showSubIssues,
|
|
||||||
setShowSubIssues,
|
|
||||||
setShowEmptyGroups,
|
|
||||||
filters,
|
filters,
|
||||||
setFilters,
|
setFilters,
|
||||||
resetFilterToDefault,
|
resetFilterToDefault,
|
||||||
@ -96,11 +88,11 @@ export const IssuesFilterView: React.FC = () => {
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className={`grid h-7 w-7 place-items-center rounded p-1 outline-none hover:bg-custom-sidebar-background-80 duration-300 ${
|
className={`grid h-7 w-7 place-items-center rounded p-1 outline-none hover:bg-custom-sidebar-background-80 duration-300 ${
|
||||||
issueView === option.type
|
displayFilters.layout === option.type
|
||||||
? "bg-custom-sidebar-background-80"
|
? "bg-custom-sidebar-background-80"
|
||||||
: "text-custom-sidebar-text-200"
|
: "text-custom-sidebar-text-200"
|
||||||
}`}
|
}`}
|
||||||
onClick={() => setIssueView(option.type)}
|
onClick={() => setDisplayFilters({ layout: option.type })}
|
||||||
>
|
>
|
||||||
<option.Icon
|
<option.Icon
|
||||||
sx={{
|
sx={{
|
||||||
@ -174,28 +166,30 @@ export const IssuesFilterView: React.FC = () => {
|
|||||||
<Popover.Panel className="absolute right-0 z-30 mt-1 w-screen max-w-xs transform rounded-lg border border-custom-border-200 bg-custom-background-90 p-3 shadow-lg">
|
<Popover.Panel className="absolute right-0 z-30 mt-1 w-screen max-w-xs transform rounded-lg border border-custom-border-200 bg-custom-background-90 p-3 shadow-lg">
|
||||||
<div className="relative divide-y-2 divide-custom-border-200">
|
<div className="relative divide-y-2 divide-custom-border-200">
|
||||||
<div className="space-y-4 pb-3 text-xs">
|
<div className="space-y-4 pb-3 text-xs">
|
||||||
{issueView !== "calendar" &&
|
{displayFilters.layout !== "calendar" &&
|
||||||
issueView !== "spreadsheet" &&
|
displayFilters.layout !== "spreadsheet" &&
|
||||||
issueView !== "gantt_chart" && (
|
displayFilters.layout !== "gantt_chart" && (
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<h4 className="text-custom-text-200">Group by</h4>
|
<h4 className="text-custom-text-200">Group by</h4>
|
||||||
<div className="w-28">
|
<div className="w-28">
|
||||||
<CustomMenu
|
<CustomMenu
|
||||||
label={
|
label={
|
||||||
GROUP_BY_OPTIONS.find((option) => option.key === groupByProperty)
|
GROUP_BY_OPTIONS.find(
|
||||||
?.name ?? "Select"
|
(option) => option.key === displayFilters.group_by
|
||||||
|
)?.name ?? "Select"
|
||||||
}
|
}
|
||||||
className="!w-full"
|
className="!w-full"
|
||||||
buttonClassName="w-full"
|
buttonClassName="w-full"
|
||||||
>
|
>
|
||||||
{GROUP_BY_OPTIONS.map((option) => {
|
{GROUP_BY_OPTIONS.map((option) => {
|
||||||
if (issueView === "kanban" && option.key === null) return null;
|
if (displayFilters.layout === "kanban" && option.key === null)
|
||||||
|
return null;
|
||||||
if (option.key === "project") return null;
|
if (option.key === "project") return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CustomMenu.MenuItem
|
<CustomMenu.MenuItem
|
||||||
key={option.key}
|
key={option.key}
|
||||||
onClick={() => setGroupByProperty(option.key)}
|
onClick={() => setDisplayFilters({ group_by: option.key })}
|
||||||
>
|
>
|
||||||
{option.name}
|
{option.name}
|
||||||
</CustomMenu.MenuItem>
|
</CustomMenu.MenuItem>
|
||||||
@ -205,41 +199,45 @@ export const IssuesFilterView: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{issueView !== "calendar" && issueView !== "spreadsheet" && (
|
{displayFilters.layout !== "calendar" &&
|
||||||
<div className="flex items-center justify-between">
|
displayFilters.layout !== "spreadsheet" && (
|
||||||
<h4 className="text-custom-text-200">Order by</h4>
|
<div className="flex items-center justify-between">
|
||||||
<div className="w-28">
|
<h4 className="text-custom-text-200">Order by</h4>
|
||||||
<CustomMenu
|
<div className="w-28">
|
||||||
label={
|
<CustomMenu
|
||||||
ORDER_BY_OPTIONS.find((option) => option.key === orderBy)?.name ??
|
label={
|
||||||
"Select"
|
ORDER_BY_OPTIONS.find(
|
||||||
}
|
(option) => option.key === displayFilters.order_by
|
||||||
className="!w-full"
|
)?.name ?? "Select"
|
||||||
buttonClassName="w-full"
|
}
|
||||||
>
|
className="!w-full"
|
||||||
{ORDER_BY_OPTIONS.map((option) =>
|
buttonClassName="w-full"
|
||||||
groupByProperty === "priority" && option.key === "priority" ? null : (
|
>
|
||||||
<CustomMenu.MenuItem
|
{ORDER_BY_OPTIONS.map((option) =>
|
||||||
key={option.key}
|
displayFilters.group_by === "priority" &&
|
||||||
onClick={() => {
|
option.key === "priority" ? null : (
|
||||||
setOrderBy(option.key);
|
<CustomMenu.MenuItem
|
||||||
}}
|
key={option.key}
|
||||||
>
|
onClick={() => {
|
||||||
{option.name}
|
setDisplayFilters({ order_by: option.key });
|
||||||
</CustomMenu.MenuItem>
|
}}
|
||||||
)
|
>
|
||||||
)}
|
{option.name}
|
||||||
</CustomMenu>
|
</CustomMenu.MenuItem>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</CustomMenu>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)}
|
||||||
)}
|
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<h4 className="text-custom-text-200">Issue type</h4>
|
<h4 className="text-custom-text-200">Issue type</h4>
|
||||||
<div className="w-28">
|
<div className="w-28">
|
||||||
<CustomMenu
|
<CustomMenu
|
||||||
label={
|
label={
|
||||||
FILTER_ISSUE_OPTIONS.find((option) => option.key === filters.type)
|
FILTER_ISSUE_OPTIONS.find(
|
||||||
?.name ?? "Select"
|
(option) => option.key === displayFilters.type
|
||||||
|
)?.name ?? "Select"
|
||||||
}
|
}
|
||||||
className="!w-full"
|
className="!w-full"
|
||||||
buttonClassName="w-full"
|
buttonClassName="w-full"
|
||||||
@ -248,7 +246,7 @@ export const IssuesFilterView: React.FC = () => {
|
|||||||
<CustomMenu.MenuItem
|
<CustomMenu.MenuItem
|
||||||
key={option.key}
|
key={option.key}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
setFilters({
|
setDisplayFilters({
|
||||||
type: option.key,
|
type: option.key,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -260,33 +258,40 @@ export const IssuesFilterView: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{issueView !== "calendar" && issueView !== "spreadsheet" && (
|
{displayFilters.layout !== "calendar" &&
|
||||||
<div className="flex items-center justify-between">
|
displayFilters.layout !== "spreadsheet" && (
|
||||||
<h4 className="text-custom-text-200">Show sub-issues</h4>
|
|
||||||
<div className="w-28">
|
|
||||||
<ToggleSwitch
|
|
||||||
value={showSubIssues}
|
|
||||||
onChange={() => setShowSubIssues(!showSubIssues)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{issueView !== "calendar" &&
|
|
||||||
issueView !== "spreadsheet" &&
|
|
||||||
issueView !== "gantt_chart" && (
|
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<h4 className="text-custom-text-200">Show empty states</h4>
|
<h4 className="text-custom-text-200">Show sub-issues</h4>
|
||||||
<div className="w-28">
|
<div className="w-28">
|
||||||
<ToggleSwitch
|
<ToggleSwitch
|
||||||
value={showEmptyGroups}
|
value={displayFilters.sub_issue ?? true}
|
||||||
onChange={() => setShowEmptyGroups(!showEmptyGroups)}
|
onChange={() =>
|
||||||
|
setDisplayFilters({ sub_issue: !displayFilters.sub_issue })
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{issueView !== "calendar" &&
|
{displayFilters.layout !== "calendar" &&
|
||||||
issueView !== "spreadsheet" &&
|
displayFilters.layout !== "spreadsheet" &&
|
||||||
issueView !== "gantt_chart" && (
|
displayFilters.layout !== "gantt_chart" && (
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<h4 className="text-custom-text-200">Show empty states</h4>
|
||||||
|
<div className="w-28">
|
||||||
|
<ToggleSwitch
|
||||||
|
value={displayFilters.show_empty_groups ?? true}
|
||||||
|
onChange={() =>
|
||||||
|
setDisplayFilters({
|
||||||
|
show_empty_groups: !displayFilters.show_empty_groups,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{displayFilters.layout !== "calendar" &&
|
||||||
|
displayFilters.layout !== "spreadsheet" &&
|
||||||
|
displayFilters.layout !== "gantt_chart" && (
|
||||||
<div className="relative flex justify-end gap-x-3">
|
<div className="relative flex justify-end gap-x-3">
|
||||||
<button type="button" onClick={() => resetFilterToDefault()}>
|
<button type="button" onClick={() => resetFilterToDefault()}>
|
||||||
Reset to default
|
Reset to default
|
||||||
@ -302,7 +307,7 @@ export const IssuesFilterView: React.FC = () => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{issueView !== "gantt_chart" && (
|
{displayFilters.layout !== "gantt_chart" && (
|
||||||
<div className="space-y-2 py-3">
|
<div className="space-y-2 py-3">
|
||||||
<h4 className="text-sm text-custom-text-200">Display Properties</h4>
|
<h4 className="text-sm text-custom-text-200">Display Properties</h4>
|
||||||
<div className="flex flex-wrap items-center gap-2 text-custom-text-200">
|
<div className="flex flex-wrap items-center gap-2 text-custom-text-200">
|
||||||
@ -310,7 +315,7 @@ export const IssuesFilterView: React.FC = () => {
|
|||||||
if (key === "estimate" && !isEstimateActive) return null;
|
if (key === "estimate" && !isEstimateActive) return null;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
issueView === "spreadsheet" &&
|
displayFilters.layout === "spreadsheet" &&
|
||||||
(key === "attachment_count" ||
|
(key === "attachment_count" ||
|
||||||
key === "link" ||
|
key === "link" ||
|
||||||
key === "sub_issue_count")
|
key === "sub_issue_count")
|
||||||
@ -318,7 +323,7 @@ export const IssuesFilterView: React.FC = () => {
|
|||||||
return null;
|
return null;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
issueView !== "spreadsheet" &&
|
displayFilters.layout !== "spreadsheet" &&
|
||||||
(key === "created_on" || key === "updated_on")
|
(key === "created_on" || key === "updated_on")
|
||||||
)
|
)
|
||||||
return null;
|
return null;
|
||||||
|
@ -58,7 +58,7 @@ export const BulkDeleteIssuesModal: React.FC<Props> = ({ isOpen, setIsOpen, user
|
|||||||
);
|
);
|
||||||
|
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
const { issueView, params } = useIssuesView();
|
const { displayFilters, params } = useIssuesView();
|
||||||
const { params: calendarParams } = useCalendarIssuesView();
|
const { params: calendarParams } = useCalendarIssuesView();
|
||||||
const { order_by, group_by, ...viewGanttParams } = params;
|
const { order_by, group_by, ...viewGanttParams } = params;
|
||||||
|
|
||||||
@ -126,8 +126,8 @@ export const BulkDeleteIssuesModal: React.FC<Props> = ({ isOpen, setIsOpen, user
|
|||||||
message: "Issues deleted successfully!",
|
message: "Issues deleted successfully!",
|
||||||
});
|
});
|
||||||
|
|
||||||
if (issueView === "calendar") mutate(calendarFetchKey);
|
if (displayFilters.layout === "calendar") mutate(calendarFetchKey);
|
||||||
else if (issueView === "gantt_chart") mutate(ganttFetchKey);
|
else if (displayFilters.layout === "gantt_chart") mutate(ganttFetchKey);
|
||||||
else {
|
else {
|
||||||
if (cycleId) {
|
if (cycleId) {
|
||||||
mutate(CYCLE_ISSUES_WITH_PARAMS(cycleId.toString(), params));
|
mutate(CYCLE_ISSUES_WITH_PARAMS(cycleId.toString(), params));
|
||||||
|
@ -80,7 +80,7 @@ export const AllViews: React.FC<Props> = ({
|
|||||||
const { user } = useUser();
|
const { user } = useUser();
|
||||||
const { memberRole } = useProjectMyMembership();
|
const { memberRole } = useProjectMyMembership();
|
||||||
|
|
||||||
const { groupedIssues, isEmpty, issueView } = viewProps;
|
const { groupedIssues, isEmpty, displayFilters } = viewProps;
|
||||||
|
|
||||||
const { data: stateGroups } = useSWR(
|
const { data: stateGroups } = useSWR(
|
||||||
workspaceSlug && projectId ? STATES_LIST(projectId as string) : null,
|
workspaceSlug && projectId ? STATES_LIST(projectId as string) : null,
|
||||||
@ -117,11 +117,11 @@ export const AllViews: React.FC<Props> = ({
|
|||||||
</StrictModeDroppable>
|
</StrictModeDroppable>
|
||||||
{groupedIssues ? (
|
{groupedIssues ? (
|
||||||
!isEmpty ||
|
!isEmpty ||
|
||||||
issueView === "kanban" ||
|
displayFilters?.layout === "kanban" ||
|
||||||
issueView === "calendar" ||
|
displayFilters?.layout === "calendar" ||
|
||||||
issueView === "gantt_chart" ? (
|
displayFilters?.layout === "gantt_chart" ? (
|
||||||
<>
|
<>
|
||||||
{issueView === "list" ? (
|
{displayFilters?.layout === "list" ? (
|
||||||
<AllLists
|
<AllLists
|
||||||
states={states}
|
states={states}
|
||||||
addIssueToGroup={addIssueToGroup}
|
addIssueToGroup={addIssueToGroup}
|
||||||
@ -134,7 +134,7 @@ export const AllViews: React.FC<Props> = ({
|
|||||||
userAuth={memberRole}
|
userAuth={memberRole}
|
||||||
viewProps={viewProps}
|
viewProps={viewProps}
|
||||||
/>
|
/>
|
||||||
) : issueView === "kanban" ? (
|
) : displayFilters?.layout === "kanban" ? (
|
||||||
<AllBoards
|
<AllBoards
|
||||||
addIssueToGroup={addIssueToGroup}
|
addIssueToGroup={addIssueToGroup}
|
||||||
disableUserActions={disableUserActions}
|
disableUserActions={disableUserActions}
|
||||||
@ -149,7 +149,7 @@ export const AllViews: React.FC<Props> = ({
|
|||||||
userAuth={memberRole}
|
userAuth={memberRole}
|
||||||
viewProps={viewProps}
|
viewProps={viewProps}
|
||||||
/>
|
/>
|
||||||
) : issueView === "calendar" ? (
|
) : displayFilters?.layout === "calendar" ? (
|
||||||
<CalendarView
|
<CalendarView
|
||||||
handleIssueAction={handleIssueAction}
|
handleIssueAction={handleIssueAction}
|
||||||
addIssueToDate={addIssueToDate}
|
addIssueToDate={addIssueToDate}
|
||||||
@ -157,7 +157,7 @@ export const AllViews: React.FC<Props> = ({
|
|||||||
user={user}
|
user={user}
|
||||||
userAuth={memberRole}
|
userAuth={memberRole}
|
||||||
/>
|
/>
|
||||||
) : issueView === "spreadsheet" ? (
|
) : displayFilters?.layout === "spreadsheet" ? (
|
||||||
<SpreadsheetView
|
<SpreadsheetView
|
||||||
handleIssueAction={handleIssueAction}
|
handleIssueAction={handleIssueAction}
|
||||||
openIssuesListModal={cycleId || moduleId ? openIssuesListModal : null}
|
openIssuesListModal={cycleId || moduleId ? openIssuesListModal : null}
|
||||||
@ -166,7 +166,7 @@ export const AllViews: React.FC<Props> = ({
|
|||||||
userAuth={memberRole}
|
userAuth={memberRole}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
issueView === "gantt_chart" && <GanttChartView />
|
displayFilters?.layout === "gantt_chart" && <GanttChartView />
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
) : router.pathname.includes("archived-issues") ? (
|
) : router.pathname.includes("archived-issues") ? (
|
||||||
|
@ -36,7 +36,7 @@ export const AllBoards: React.FC<Props> = ({
|
|||||||
userAuth,
|
userAuth,
|
||||||
viewProps,
|
viewProps,
|
||||||
}) => {
|
}) => {
|
||||||
const { groupByProperty: selectedGroup, groupedIssues, showEmptyGroups } = viewProps;
|
const { displayFilters, groupedIssues } = viewProps;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -44,9 +44,12 @@ export const AllBoards: React.FC<Props> = ({
|
|||||||
<div className="horizontal-scroll-enable flex h-full gap-x-4 p-8">
|
<div className="horizontal-scroll-enable flex h-full gap-x-4 p-8">
|
||||||
{Object.keys(groupedIssues).map((singleGroup, index) => {
|
{Object.keys(groupedIssues).map((singleGroup, index) => {
|
||||||
const currentState =
|
const currentState =
|
||||||
selectedGroup === "state" ? states?.find((s) => s.id === singleGroup) : null;
|
displayFilters?.group_by === "state"
|
||||||
|
? states?.find((s) => s.id === singleGroup)
|
||||||
|
: null;
|
||||||
|
|
||||||
if (!showEmptyGroups && groupedIssues[singleGroup].length === 0) return null;
|
if (!displayFilters?.show_empty_groups && groupedIssues[singleGroup].length === 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SingleBoard
|
<SingleBoard
|
||||||
@ -67,13 +70,15 @@ export const AllBoards: React.FC<Props> = ({
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
{!showEmptyGroups && (
|
{!displayFilters?.show_empty_groups && (
|
||||||
<div className="h-full w-96 flex-shrink-0 space-y-2 p-1">
|
<div className="h-full w-96 flex-shrink-0 space-y-2 p-1">
|
||||||
<h2 className="text-lg font-semibold">Hidden groups</h2>
|
<h2 className="text-lg font-semibold">Hidden groups</h2>
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
{Object.keys(groupedIssues).map((singleGroup, index) => {
|
{Object.keys(groupedIssues).map((singleGroup, index) => {
|
||||||
const currentState =
|
const currentState =
|
||||||
selectedGroup === "state" ? states?.find((s) => s.id === singleGroup) : null;
|
displayFilters?.group_by === "state"
|
||||||
|
? states?.find((s) => s.id === singleGroup)
|
||||||
|
: null;
|
||||||
|
|
||||||
if (groupedIssues[singleGroup].length === 0)
|
if (groupedIssues[singleGroup].length === 0)
|
||||||
return (
|
return (
|
||||||
@ -91,7 +96,7 @@ export const AllBoards: React.FC<Props> = ({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<h4 className="text-sm capitalize">
|
<h4 className="text-sm capitalize">
|
||||||
{selectedGroup === "state"
|
{displayFilters?.group_by === "state"
|
||||||
? addSpaceIfCamelCase(currentState?.name ?? "")
|
? addSpaceIfCamelCase(currentState?.name ?? "")
|
||||||
: addSpaceIfCamelCase(singleGroup)}
|
: addSpaceIfCamelCase(singleGroup)}
|
||||||
</h4>
|
</h4>
|
||||||
|
@ -48,22 +48,28 @@ export const BoardHeader: React.FC<Props> = ({
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId } = router.query;
|
const { workspaceSlug, projectId } = router.query;
|
||||||
|
|
||||||
const { groupedIssues, groupByProperty: selectedGroup } = viewProps;
|
const { displayFilters, groupedIssues } = viewProps;
|
||||||
|
|
||||||
|
console.log("dF", displayFilters);
|
||||||
|
|
||||||
const { data: issueLabels } = useSWR(
|
const { data: issueLabels } = useSWR(
|
||||||
workspaceSlug && projectId && selectedGroup === "labels"
|
workspaceSlug && projectId && displayFilters?.group_by === "labels"
|
||||||
? PROJECT_ISSUE_LABELS(projectId.toString())
|
? PROJECT_ISSUE_LABELS(projectId.toString())
|
||||||
: null,
|
: null,
|
||||||
workspaceSlug && projectId && selectedGroup === "labels"
|
workspaceSlug && projectId && displayFilters?.group_by === "labels"
|
||||||
? () => issuesService.getIssueLabels(workspaceSlug.toString(), projectId.toString())
|
? () => issuesService.getIssueLabels(workspaceSlug.toString(), projectId.toString())
|
||||||
: null
|
: null
|
||||||
);
|
);
|
||||||
|
|
||||||
const { data: members } = useSWR(
|
const { data: members } = useSWR(
|
||||||
workspaceSlug && projectId && (selectedGroup === "created_by" || selectedGroup === "assignees")
|
workspaceSlug &&
|
||||||
|
projectId &&
|
||||||
|
(displayFilters?.group_by === "created_by" || displayFilters?.group_by === "assignees")
|
||||||
? PROJECT_MEMBERS(projectId.toString())
|
? PROJECT_MEMBERS(projectId.toString())
|
||||||
: null,
|
: null,
|
||||||
workspaceSlug && projectId && (selectedGroup === "created_by" || selectedGroup === "assignees")
|
workspaceSlug &&
|
||||||
|
projectId &&
|
||||||
|
(displayFilters?.group_by === "created_by" || displayFilters?.group_by === "assignees")
|
||||||
? () => projectService.projectMembers(workspaceSlug.toString(), projectId.toString())
|
? () => projectService.projectMembers(workspaceSlug.toString(), projectId.toString())
|
||||||
: null
|
: null
|
||||||
);
|
);
|
||||||
@ -73,7 +79,7 @@ export const BoardHeader: React.FC<Props> = ({
|
|||||||
const getGroupTitle = () => {
|
const getGroupTitle = () => {
|
||||||
let title = addSpaceIfCamelCase(groupTitle);
|
let title = addSpaceIfCamelCase(groupTitle);
|
||||||
|
|
||||||
switch (selectedGroup) {
|
switch (displayFilters?.group_by) {
|
||||||
case "state":
|
case "state":
|
||||||
title = addSpaceIfCamelCase(currentState?.name ?? "");
|
title = addSpaceIfCamelCase(currentState?.name ?? "");
|
||||||
break;
|
break;
|
||||||
@ -97,7 +103,7 @@ export const BoardHeader: React.FC<Props> = ({
|
|||||||
const getGroupIcon = () => {
|
const getGroupIcon = () => {
|
||||||
let icon;
|
let icon;
|
||||||
|
|
||||||
switch (selectedGroup) {
|
switch (displayFilters?.group_by) {
|
||||||
case "state":
|
case "state":
|
||||||
icon = currentState && (
|
icon = currentState && (
|
||||||
<StateGroupIcon
|
<StateGroupIcon
|
||||||
@ -167,7 +173,7 @@ export const BoardHeader: React.FC<Props> = ({
|
|||||||
<span className="flex items-center">{getGroupIcon()}</span>
|
<span className="flex items-center">{getGroupIcon()}</span>
|
||||||
<h2
|
<h2
|
||||||
className={`text-lg font-semibold truncate ${
|
className={`text-lg font-semibold truncate ${
|
||||||
selectedGroup === "created_by" ? "" : "capitalize"
|
displayFilters?.group_by === "created_by" ? "" : "capitalize"
|
||||||
}`}
|
}`}
|
||||||
style={{
|
style={{
|
||||||
writingMode: isCollapsed ? "horizontal-tb" : "vertical-rl",
|
writingMode: isCollapsed ? "horizontal-tb" : "vertical-rl",
|
||||||
@ -198,7 +204,7 @@ export const BoardHeader: React.FC<Props> = ({
|
|||||||
<Icon iconName="open_in_full" className="text-base font-medium text-custom-text-900" />
|
<Icon iconName="open_in_full" className="text-base font-medium text-custom-text-900" />
|
||||||
)}
|
)}
|
||||||
</button>
|
</button>
|
||||||
{!disableAddIssue && !disableUserActions && selectedGroup !== "created_by" && (
|
{!disableAddIssue && !disableUserActions && displayFilters?.group_by !== "created_by" && (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="grid h-7 w-7 place-items-center rounded p-1 text-custom-text-200 outline-none duration-300 hover:bg-custom-background-80"
|
className="grid h-7 w-7 place-items-center rounded p-1 text-custom-text-200 outline-none duration-300 hover:bg-custom-background-80"
|
||||||
|
@ -50,7 +50,7 @@ export const SingleBoard: React.FC<Props> = ({
|
|||||||
// collapse/expand
|
// collapse/expand
|
||||||
const [isCollapsed, setIsCollapsed] = useState(true);
|
const [isCollapsed, setIsCollapsed] = useState(true);
|
||||||
|
|
||||||
const { groupedIssues, groupByProperty: selectedGroup, orderBy, properties } = viewProps;
|
const { displayFilters, groupedIssues, properties } = viewProps;
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { cycleId, moduleId } = router.query;
|
const { cycleId, moduleId } = router.query;
|
||||||
@ -80,14 +80,14 @@ export const SingleBoard: React.FC<Props> = ({
|
|||||||
{(provided, snapshot) => (
|
{(provided, snapshot) => (
|
||||||
<div
|
<div
|
||||||
className={`relative h-full ${
|
className={`relative h-full ${
|
||||||
orderBy !== "sort_order" && snapshot.isDraggingOver
|
displayFilters?.order_by !== "sort_order" && snapshot.isDraggingOver
|
||||||
? "bg-custom-background-100/20"
|
? "bg-custom-background-100/20"
|
||||||
: ""
|
: ""
|
||||||
} ${!isCollapsed ? "hidden" : "flex flex-col"}`}
|
} ${!isCollapsed ? "hidden" : "flex flex-col"}`}
|
||||||
ref={provided.innerRef}
|
ref={provided.innerRef}
|
||||||
{...provided.droppableProps}
|
{...provided.droppableProps}
|
||||||
>
|
>
|
||||||
{orderBy !== "sort_order" && (
|
{displayFilters?.order_by !== "sort_order" && (
|
||||||
<>
|
<>
|
||||||
<div
|
<div
|
||||||
className={`absolute ${
|
className={`absolute ${
|
||||||
@ -101,7 +101,11 @@ export const SingleBoard: React.FC<Props> = ({
|
|||||||
>
|
>
|
||||||
This board is ordered by{" "}
|
This board is ordered by{" "}
|
||||||
{replaceUnderscoreIfSnakeCase(
|
{replaceUnderscoreIfSnakeCase(
|
||||||
orderBy ? (orderBy[0] === "-" ? orderBy.slice(1) : orderBy) : "created_at"
|
displayFilters?.order_by
|
||||||
|
? displayFilters?.order_by[0] === "-"
|
||||||
|
? displayFilters?.order_by.slice(1)
|
||||||
|
: displayFilters?.order_by
|
||||||
|
: "created_at"
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
@ -145,13 +149,13 @@ export const SingleBoard: React.FC<Props> = ({
|
|||||||
))}
|
))}
|
||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
display: orderBy === "sort_order" ? "inline" : "none",
|
display: displayFilters?.order_by === "sort_order" ? "inline" : "none",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{provided.placeholder}
|
{provided.placeholder}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{selectedGroup !== "created_by" && (
|
{displayFilters?.group_by !== "created_by" && (
|
||||||
<div>
|
<div>
|
||||||
{type === "issue"
|
{type === "issue"
|
||||||
? !disableAddIssueOption && (
|
? !disableAddIssueOption && (
|
||||||
|
@ -93,7 +93,7 @@ export const SingleBoardIssue: React.FC<Props> = ({
|
|||||||
|
|
||||||
const actionSectionRef = useRef<HTMLDivElement | null>(null);
|
const actionSectionRef = useRef<HTMLDivElement | null>(null);
|
||||||
|
|
||||||
const { groupByProperty: selectedGroup, orderBy, properties, mutateIssues } = viewProps;
|
const { displayFilters, properties, mutateIssues } = viewProps;
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId, cycleId, moduleId } = router.query;
|
const { workspaceSlug, projectId, cycleId, moduleId } = router.query;
|
||||||
@ -131,9 +131,9 @@ export const SingleBoardIssue: React.FC<Props> = ({
|
|||||||
handleIssuesMutation(
|
handleIssuesMutation(
|
||||||
formData,
|
formData,
|
||||||
groupTitle ?? "",
|
groupTitle ?? "",
|
||||||
selectedGroup,
|
displayFilters?.group_by ?? null,
|
||||||
index,
|
index,
|
||||||
orderBy,
|
displayFilters?.order_by ?? "-created_at",
|
||||||
prevData
|
prevData
|
||||||
),
|
),
|
||||||
false
|
false
|
||||||
@ -149,24 +149,14 @@ export const SingleBoardIssue: React.FC<Props> = ({
|
|||||||
if (moduleId) mutate(MODULE_DETAILS(moduleId as string));
|
if (moduleId) mutate(MODULE_DETAILS(moduleId as string));
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[
|
[displayFilters, workspaceSlug, cycleId, moduleId, groupTitle, index, mutateIssues, user]
|
||||||
workspaceSlug,
|
|
||||||
cycleId,
|
|
||||||
moduleId,
|
|
||||||
groupTitle,
|
|
||||||
index,
|
|
||||||
selectedGroup,
|
|
||||||
mutateIssues,
|
|
||||||
orderBy,
|
|
||||||
user,
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const getStyle = (
|
const getStyle = (
|
||||||
style: DraggingStyle | NotDraggingStyle | undefined,
|
style: DraggingStyle | NotDraggingStyle | undefined,
|
||||||
snapshot: DraggableStateSnapshot
|
snapshot: DraggableStateSnapshot
|
||||||
) => {
|
) => {
|
||||||
if (orderBy === "sort_order") return style;
|
if (displayFilters?.order_by === "sort_order") return style;
|
||||||
if (!snapshot.isDragging) return {};
|
if (!snapshot.isDragging) return {};
|
||||||
if (!snapshot.isDropAnimating) return style;
|
if (!snapshot.isDropAnimating) return style;
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ export const CalendarView: React.FC<Props> = ({
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId, cycleId, moduleId, viewId } = router.query;
|
const { workspaceSlug, projectId, cycleId, moduleId, viewId } = router.query;
|
||||||
|
|
||||||
const { calendarIssues, params, setCalendarDateRange } = useCalendarIssuesView();
|
const { calendarIssues, params, setDisplayFilters } = useCalendarIssuesView();
|
||||||
|
|
||||||
const totalDate = eachDayOfInterval({
|
const totalDate = eachDayOfInterval({
|
||||||
start: calendarDates.startDate,
|
start: calendarDates.startDate,
|
||||||
@ -152,18 +152,20 @@ export const CalendarView: React.FC<Props> = ({
|
|||||||
endDate,
|
endDate,
|
||||||
});
|
});
|
||||||
|
|
||||||
setCalendarDateRange(
|
setDisplayFilters({
|
||||||
`${renderDateFormat(startDate)};after,${renderDateFormat(endDate)};before`
|
calendar_date_range: `${renderDateFormat(startDate)};after,${renderDateFormat(
|
||||||
);
|
endDate
|
||||||
|
)};before`,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setCalendarDateRange(
|
setDisplayFilters({
|
||||||
`${renderDateFormat(startOfWeek(currentDate))};after,${renderDateFormat(
|
calendar_date_range: `${renderDateFormat(startOfWeek(currentDate))};after,${renderDateFormat(
|
||||||
lastDayOfWeek(currentDate)
|
lastDayOfWeek(currentDate)
|
||||||
)};before`
|
)};before`,
|
||||||
);
|
});
|
||||||
}, [currentDate]);
|
}, [currentDate, setDisplayFilters]);
|
||||||
|
|
||||||
const isNotAllowed = userAuth.isGuest || userAuth.isViewer || disableUserActions;
|
const isNotAllowed = userAuth.isGuest || userAuth.isViewer || disableUserActions;
|
||||||
|
|
||||||
|
@ -77,18 +77,8 @@ export const IssuesView: React.FC<Props> = ({
|
|||||||
|
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
|
|
||||||
const {
|
const { groupedByIssues, mutateIssues, displayFilters, filters, isEmpty, setFilters, params } =
|
||||||
groupedByIssues,
|
useIssuesView();
|
||||||
mutateIssues,
|
|
||||||
issueView,
|
|
||||||
groupByProperty: selectedGroup,
|
|
||||||
orderBy,
|
|
||||||
filters,
|
|
||||||
isEmpty,
|
|
||||||
setFilters,
|
|
||||||
params,
|
|
||||||
showEmptyGroups,
|
|
||||||
} = useIssuesView();
|
|
||||||
const [properties] = useIssuesProperties(workspaceSlug as string, projectId as string);
|
const [properties] = useIssuesProperties(workspaceSlug as string, projectId as string);
|
||||||
|
|
||||||
const { data: stateGroups } = useSWR(
|
const { data: stateGroups } = useSWR(
|
||||||
@ -129,7 +119,7 @@ export const IssuesView: React.FC<Props> = ({
|
|||||||
if (destination.droppableId === "trashBox") {
|
if (destination.droppableId === "trashBox") {
|
||||||
handleDeleteIssue(draggedItem);
|
handleDeleteIssue(draggedItem);
|
||||||
} else {
|
} else {
|
||||||
if (orderBy === "sort_order") {
|
if (displayFilters.order_by === "sort_order") {
|
||||||
let newSortOrder = draggedItem.sort_order;
|
let newSortOrder = draggedItem.sort_order;
|
||||||
|
|
||||||
const destinationGroupArray = groupedByIssues[destination.droppableId];
|
const destinationGroupArray = groupedByIssues[destination.droppableId];
|
||||||
@ -177,16 +167,19 @@ export const IssuesView: React.FC<Props> = ({
|
|||||||
|
|
||||||
const destinationGroup = destination.droppableId; // destination group id
|
const destinationGroup = destination.droppableId; // destination group id
|
||||||
|
|
||||||
if (orderBy === "sort_order" || source.droppableId !== destination.droppableId) {
|
if (
|
||||||
|
displayFilters.order_by === "sort_order" ||
|
||||||
|
source.droppableId !== destination.droppableId
|
||||||
|
) {
|
||||||
// different group/column;
|
// different group/column;
|
||||||
|
|
||||||
// source.droppableId !== destination.droppableId -> even if order by is not sort_order,
|
// source.droppableId !== destination.droppableId -> even if order by is not sort_order,
|
||||||
// if the issue is moved to a different group, then we will change the group of the
|
// if the issue is moved to a different group, then we will change the group of the
|
||||||
// dragged item(or issue)
|
// dragged item(or issue)
|
||||||
|
|
||||||
if (selectedGroup === "priority")
|
if (displayFilters.group_by === "priority")
|
||||||
draggedItem.priority = destinationGroup as TIssuePriorities;
|
draggedItem.priority = destinationGroup as TIssuePriorities;
|
||||||
else if (selectedGroup === "state") {
|
else if (displayFilters.group_by === "state") {
|
||||||
draggedItem.state = destinationGroup;
|
draggedItem.state = destinationGroup;
|
||||||
draggedItem.state_detail = states?.find((s) => s.id === destinationGroup) as IState;
|
draggedItem.state_detail = states?.find((s) => s.id === destinationGroup) as IState;
|
||||||
}
|
}
|
||||||
@ -213,8 +206,14 @@ export const IssuesView: React.FC<Props> = ({
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
...prevData,
|
...prevData,
|
||||||
[sourceGroup]: orderArrayBy(sourceGroupArray, orderBy),
|
[sourceGroup]: orderArrayBy(
|
||||||
[destinationGroup]: orderArrayBy(destinationGroupArray, orderBy),
|
sourceGroupArray,
|
||||||
|
displayFilters.order_by ?? "-created_at"
|
||||||
|
),
|
||||||
|
[destinationGroup]: orderArrayBy(
|
||||||
|
destinationGroupArray,
|
||||||
|
displayFilters.order_by ?? "-created_at"
|
||||||
|
),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
false
|
false
|
||||||
@ -267,13 +266,13 @@ export const IssuesView: React.FC<Props> = ({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
|
displayFilters.group_by,
|
||||||
|
displayFilters.order_by,
|
||||||
workspaceSlug,
|
workspaceSlug,
|
||||||
cycleId,
|
cycleId,
|
||||||
moduleId,
|
moduleId,
|
||||||
groupedByIssues,
|
groupedByIssues,
|
||||||
projectId,
|
projectId,
|
||||||
selectedGroup,
|
|
||||||
orderBy,
|
|
||||||
handleDeleteIssue,
|
handleDeleteIssue,
|
||||||
params,
|
params,
|
||||||
states,
|
states,
|
||||||
@ -287,19 +286,19 @@ export const IssuesView: React.FC<Props> = ({
|
|||||||
|
|
||||||
let preloadedValue: string | string[] = groupTitle;
|
let preloadedValue: string | string[] = groupTitle;
|
||||||
|
|
||||||
if (selectedGroup === "labels") {
|
if (displayFilters.group_by === "labels") {
|
||||||
if (groupTitle === "None") preloadedValue = [];
|
if (groupTitle === "None") preloadedValue = [];
|
||||||
else preloadedValue = [groupTitle];
|
else preloadedValue = [groupTitle];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selectedGroup)
|
if (displayFilters.group_by)
|
||||||
setPreloadedData({
|
setPreloadedData({
|
||||||
[selectedGroup]: preloadedValue,
|
[displayFilters.group_by]: preloadedValue,
|
||||||
actionType: "createIssue",
|
actionType: "createIssue",
|
||||||
});
|
});
|
||||||
else setPreloadedData({ actionType: "createIssue" });
|
else setPreloadedData({ actionType: "createIssue" });
|
||||||
},
|
},
|
||||||
[setCreateIssueModal, setPreloadedData, selectedGroup]
|
[displayFilters.group_by, setCreateIssueModal, setPreloadedData]
|
||||||
);
|
);
|
||||||
|
|
||||||
const addIssueToDate = useCallback(
|
const addIssueToDate = useCallback(
|
||||||
@ -352,7 +351,7 @@ export const IssuesView: React.FC<Props> = ({
|
|||||||
CYCLE_ISSUES_WITH_PARAMS(cycleId as string, params),
|
CYCLE_ISSUES_WITH_PARAMS(cycleId as string, params),
|
||||||
(prevData: any) => {
|
(prevData: any) => {
|
||||||
if (!prevData) return prevData;
|
if (!prevData) return prevData;
|
||||||
if (selectedGroup) {
|
if (displayFilters.group_by) {
|
||||||
const filteredData: any = {};
|
const filteredData: any = {};
|
||||||
for (const key in prevData) {
|
for (const key in prevData) {
|
||||||
filteredData[key] = prevData[key].filter((item: any) => item.id !== issueId);
|
filteredData[key] = prevData[key].filter((item: any) => item.id !== issueId);
|
||||||
@ -384,7 +383,7 @@ export const IssuesView: React.FC<Props> = ({
|
|||||||
console.log(e);
|
console.log(e);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[workspaceSlug, projectId, cycleId, params, selectedGroup, setToastAlert]
|
[displayFilters.group_by, workspaceSlug, projectId, cycleId, params, setToastAlert]
|
||||||
);
|
);
|
||||||
|
|
||||||
const removeIssueFromModule = useCallback(
|
const removeIssueFromModule = useCallback(
|
||||||
@ -395,7 +394,7 @@ export const IssuesView: React.FC<Props> = ({
|
|||||||
MODULE_ISSUES_WITH_PARAMS(moduleId as string, params),
|
MODULE_ISSUES_WITH_PARAMS(moduleId as string, params),
|
||||||
(prevData: any) => {
|
(prevData: any) => {
|
||||||
if (!prevData) return prevData;
|
if (!prevData) return prevData;
|
||||||
if (selectedGroup) {
|
if (displayFilters.group_by) {
|
||||||
const filteredData: any = {};
|
const filteredData: any = {};
|
||||||
for (const key in prevData) {
|
for (const key in prevData) {
|
||||||
filteredData[key] = prevData[key].filter((item: any) => item.id !== issueId);
|
filteredData[key] = prevData[key].filter((item: any) => item.id !== issueId);
|
||||||
@ -427,7 +426,7 @@ export const IssuesView: React.FC<Props> = ({
|
|||||||
console.log(e);
|
console.log(e);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[workspaceSlug, projectId, moduleId, params, selectedGroup, setToastAlert]
|
[displayFilters.group_by, workspaceSlug, projectId, moduleId, params, setToastAlert]
|
||||||
);
|
);
|
||||||
|
|
||||||
const nullFilters = Object.keys(filters).filter(
|
const nullFilters = Object.keys(filters).filter(
|
||||||
@ -481,7 +480,6 @@ export const IssuesView: React.FC<Props> = ({
|
|||||||
state: null,
|
state: null,
|
||||||
start_date: null,
|
start_date: null,
|
||||||
target_date: null,
|
target_date: null,
|
||||||
type: null,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
@ -513,10 +511,10 @@ export const IssuesView: React.FC<Props> = ({
|
|||||||
addIssueToGroup={addIssueToGroup}
|
addIssueToGroup={addIssueToGroup}
|
||||||
disableUserActions={disableUserActions}
|
disableUserActions={disableUserActions}
|
||||||
dragDisabled={
|
dragDisabled={
|
||||||
selectedGroup === "created_by" ||
|
displayFilters.group_by === "created_by" ||
|
||||||
selectedGroup === "labels" ||
|
displayFilters.group_by === "labels" ||
|
||||||
selectedGroup === "state_detail.group" ||
|
displayFilters.group_by === "state_detail.group" ||
|
||||||
selectedGroup === "assignees"
|
displayFilters.group_by === "assignees"
|
||||||
}
|
}
|
||||||
emptyState={{
|
emptyState={{
|
||||||
title: cycleId
|
title: cycleId
|
||||||
@ -554,15 +552,12 @@ export const IssuesView: React.FC<Props> = ({
|
|||||||
trashBox={trashBox}
|
trashBox={trashBox}
|
||||||
setTrashBox={setTrashBox}
|
setTrashBox={setTrashBox}
|
||||||
viewProps={{
|
viewProps={{
|
||||||
groupByProperty: selectedGroup,
|
|
||||||
groupedIssues: groupedByIssues,
|
groupedIssues: groupedByIssues,
|
||||||
|
displayFilters,
|
||||||
isEmpty,
|
isEmpty,
|
||||||
issueView,
|
|
||||||
mutateIssues,
|
mutateIssues,
|
||||||
orderBy,
|
|
||||||
params,
|
params,
|
||||||
properties,
|
properties,
|
||||||
showEmptyGroups,
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
@ -29,7 +29,7 @@ export const AllLists: React.FC<Props> = ({
|
|||||||
userAuth,
|
userAuth,
|
||||||
viewProps,
|
viewProps,
|
||||||
}) => {
|
}) => {
|
||||||
const { groupByProperty: selectedGroup, groupedIssues, showEmptyGroups } = viewProps;
|
const { displayFilters, groupedIssues } = viewProps;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -37,9 +37,12 @@ export const AllLists: React.FC<Props> = ({
|
|||||||
<div className="h-full overflow-y-auto">
|
<div className="h-full overflow-y-auto">
|
||||||
{Object.keys(groupedIssues).map((singleGroup) => {
|
{Object.keys(groupedIssues).map((singleGroup) => {
|
||||||
const currentState =
|
const currentState =
|
||||||
selectedGroup === "state" ? states?.find((s) => s.id === singleGroup) : null;
|
displayFilters?.group_by === "state"
|
||||||
|
? states?.find((s) => s.id === singleGroup)
|
||||||
|
: null;
|
||||||
|
|
||||||
if (!showEmptyGroups && groupedIssues[singleGroup].length === 0) return null;
|
if (!displayFilters?.show_empty_groups && groupedIssues[singleGroup].length === 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SingleList
|
<SingleList
|
||||||
|
@ -91,7 +91,7 @@ export const SingleListIssue: React.FC<Props> = ({
|
|||||||
|
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
|
|
||||||
const { groupByProperty: selectedGroup, orderBy, properties, mutateIssues } = viewProps;
|
const { displayFilters, properties, mutateIssues } = viewProps;
|
||||||
|
|
||||||
const partialUpdateIssue = useCallback(
|
const partialUpdateIssue = useCallback(
|
||||||
(formData: Partial<IIssue>, issue: IIssue) => {
|
(formData: Partial<IIssue>, issue: IIssue) => {
|
||||||
@ -124,9 +124,9 @@ export const SingleListIssue: React.FC<Props> = ({
|
|||||||
handleIssuesMutation(
|
handleIssuesMutation(
|
||||||
formData,
|
formData,
|
||||||
groupTitle ?? "",
|
groupTitle ?? "",
|
||||||
selectedGroup,
|
displayFilters?.group_by ?? null,
|
||||||
index,
|
index,
|
||||||
orderBy,
|
displayFilters?.order_by ?? "-created_at",
|
||||||
prevData
|
prevData
|
||||||
),
|
),
|
||||||
false
|
false
|
||||||
@ -148,15 +148,14 @@ export const SingleListIssue: React.FC<Props> = ({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
|
displayFilters,
|
||||||
workspaceSlug,
|
workspaceSlug,
|
||||||
cycleId,
|
cycleId,
|
||||||
moduleId,
|
moduleId,
|
||||||
userId,
|
userId,
|
||||||
groupTitle,
|
groupTitle,
|
||||||
index,
|
index,
|
||||||
selectedGroup,
|
|
||||||
mutateIssues,
|
mutateIssues,
|
||||||
orderBy,
|
|
||||||
user,
|
user,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
@ -69,7 +69,7 @@ export const SingleList: React.FC<Props> = ({
|
|||||||
|
|
||||||
const type = cycleId ? "cycle" : moduleId ? "module" : "issue";
|
const type = cycleId ? "cycle" : moduleId ? "module" : "issue";
|
||||||
|
|
||||||
const { groupByProperty: selectedGroup, groupedIssues } = viewProps;
|
const { displayFilters, groupedIssues } = viewProps;
|
||||||
|
|
||||||
const { data: issueLabels } = useSWR<IIssueLabels[]>(
|
const { data: issueLabels } = useSWR<IIssueLabels[]>(
|
||||||
workspaceSlug && projectId ? PROJECT_ISSUE_LABELS(projectId as string) : null,
|
workspaceSlug && projectId ? PROJECT_ISSUE_LABELS(projectId as string) : null,
|
||||||
@ -90,7 +90,7 @@ export const SingleList: React.FC<Props> = ({
|
|||||||
const getGroupTitle = () => {
|
const getGroupTitle = () => {
|
||||||
let title = addSpaceIfCamelCase(groupTitle);
|
let title = addSpaceIfCamelCase(groupTitle);
|
||||||
|
|
||||||
switch (selectedGroup) {
|
switch (displayFilters?.group_by) {
|
||||||
case "state":
|
case "state":
|
||||||
title = addSpaceIfCamelCase(currentState?.name ?? "");
|
title = addSpaceIfCamelCase(currentState?.name ?? "");
|
||||||
break;
|
break;
|
||||||
@ -113,7 +113,7 @@ export const SingleList: React.FC<Props> = ({
|
|||||||
const getGroupIcon = () => {
|
const getGroupIcon = () => {
|
||||||
let icon;
|
let icon;
|
||||||
|
|
||||||
switch (selectedGroup) {
|
switch (displayFilters?.group_by) {
|
||||||
case "state":
|
case "state":
|
||||||
icon = currentState && (
|
icon = currentState && (
|
||||||
<StateGroupIcon
|
<StateGroupIcon
|
||||||
@ -177,13 +177,13 @@ export const SingleList: React.FC<Props> = ({
|
|||||||
<div className="flex items-center justify-between px-4 py-2.5 bg-custom-background-90">
|
<div className="flex items-center justify-between px-4 py-2.5 bg-custom-background-90">
|
||||||
<Disclosure.Button>
|
<Disclosure.Button>
|
||||||
<div className="flex items-center gap-x-3">
|
<div className="flex items-center gap-x-3">
|
||||||
{selectedGroup !== null && (
|
{displayFilters?.group_by !== null && (
|
||||||
<div className="flex items-center">{getGroupIcon()}</div>
|
<div className="flex items-center">{getGroupIcon()}</div>
|
||||||
)}
|
)}
|
||||||
{selectedGroup !== null ? (
|
{displayFilters?.group_by !== null ? (
|
||||||
<h2
|
<h2
|
||||||
className={`text-sm font-semibold leading-6 text-custom-text-100 ${
|
className={`text-sm font-semibold leading-6 text-custom-text-100 ${
|
||||||
selectedGroup === "created_by" ? "" : "capitalize"
|
displayFilters?.group_by === "created_by" ? "" : "capitalize"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{getGroupTitle()}
|
{getGroupTitle()}
|
||||||
|
@ -22,10 +22,10 @@ export const SpreadsheetColumns: React.FC<Props> = ({ columnData, gridTemplateCo
|
|||||||
const { storedValue: activeSortingProperty, setValue: setActiveSortingProperty } =
|
const { storedValue: activeSortingProperty, setValue: setActiveSortingProperty } =
|
||||||
useLocalStorage("spreadsheetViewActiveSortingProperty", "");
|
useLocalStorage("spreadsheetViewActiveSortingProperty", "");
|
||||||
|
|
||||||
const { orderBy, setOrderBy } = useSpreadsheetIssuesView();
|
const { displayFilters, setDisplayFilters } = useSpreadsheetIssuesView();
|
||||||
|
|
||||||
const handleOrderBy = (order: TIssueOrderByOptions, itemKey: string) => {
|
const handleOrderBy = (order: TIssueOrderByOptions, itemKey: string) => {
|
||||||
setOrderBy(order);
|
setDisplayFilters({ order_by: order });
|
||||||
setSelectedMenuItem(`${order}_${itemKey}`);
|
setSelectedMenuItem(`${order}_${itemKey}`);
|
||||||
setActiveSortingProperty(order === "-created_at" ? "" : itemKey);
|
setActiveSortingProperty(order === "-created_at" ? "" : itemKey);
|
||||||
};
|
};
|
||||||
@ -239,7 +239,7 @@ export const SpreadsheetColumns: React.FC<Props> = ({ columnData, gridTemplateCo
|
|||||||
</CustomMenu.MenuItem>
|
</CustomMenu.MenuItem>
|
||||||
{selectedMenuItem &&
|
{selectedMenuItem &&
|
||||||
selectedMenuItem !== "" &&
|
selectedMenuItem !== "" &&
|
||||||
orderBy !== "-created_at" &&
|
displayFilters?.order_by !== "-created_at" &&
|
||||||
selectedMenuItem.includes(col.propertyName) && (
|
selectedMenuItem.includes(col.propertyName) && (
|
||||||
<CustomMenu.MenuItem
|
<CustomMenu.MenuItem
|
||||||
className={`mt-0.5${
|
className={`mt-0.5${
|
||||||
|
@ -16,7 +16,7 @@ export const CycleIssuesGanttChartView = () => {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId, cycleId } = router.query;
|
const { workspaceSlug, projectId, cycleId } = router.query;
|
||||||
|
|
||||||
const { orderBy } = useIssuesView();
|
const { displayFilters } = useIssuesView();
|
||||||
|
|
||||||
const { user } = useUser();
|
const { user } = useUser();
|
||||||
const { projectDetails } = useProjectDetails();
|
const { projectDetails } = useProjectDetails();
|
||||||
@ -44,7 +44,7 @@ export const CycleIssuesGanttChartView = () => {
|
|||||||
enableBlockLeftResize={isAllowed}
|
enableBlockLeftResize={isAllowed}
|
||||||
enableBlockRightResize={isAllowed}
|
enableBlockRightResize={isAllowed}
|
||||||
enableBlockMove={isAllowed}
|
enableBlockMove={isAllowed}
|
||||||
enableReorder={orderBy === "sort_order" && isAllowed}
|
enableReorder={displayFilters.order_by === "sort_order" && isAllowed}
|
||||||
bottomSpacing
|
bottomSpacing
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -50,7 +50,7 @@ export const DeleteIssueModal: React.FC<Props> = ({
|
|||||||
const { workspaceSlug, projectId, cycleId, moduleId, viewId, issueId } = router.query;
|
const { workspaceSlug, projectId, cycleId, moduleId, viewId, issueId } = router.query;
|
||||||
const isArchivedIssues = router.pathname.includes("archived-issues");
|
const isArchivedIssues = router.pathname.includes("archived-issues");
|
||||||
|
|
||||||
const { issueView, params } = useIssuesView();
|
const { displayFilters, params } = useIssuesView();
|
||||||
const { params: calendarParams } = useCalendarIssuesView();
|
const { params: calendarParams } = useCalendarIssuesView();
|
||||||
const { params: spreadsheetParams } = useSpreadsheetIssuesView();
|
const { params: spreadsheetParams } = useSpreadsheetIssuesView();
|
||||||
|
|
||||||
@ -73,7 +73,7 @@ export const DeleteIssueModal: React.FC<Props> = ({
|
|||||||
await issueServices
|
await issueServices
|
||||||
.deleteIssue(workspaceSlug as string, data.project, data.id, user)
|
.deleteIssue(workspaceSlug as string, data.project, data.id, user)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
if (issueView === "calendar") {
|
if (displayFilters.layout === "calendar") {
|
||||||
const calendarFetchKey = cycleId
|
const calendarFetchKey = cycleId
|
||||||
? CYCLE_ISSUES_WITH_PARAMS(cycleId.toString(), calendarParams)
|
? CYCLE_ISSUES_WITH_PARAMS(cycleId.toString(), calendarParams)
|
||||||
: moduleId
|
: moduleId
|
||||||
@ -87,7 +87,7 @@ export const DeleteIssueModal: React.FC<Props> = ({
|
|||||||
(prevData) => (prevData ?? []).filter((p) => p.id !== data.id),
|
(prevData) => (prevData ?? []).filter((p) => p.id !== data.id),
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
} else if (issueView === "spreadsheet") {
|
} else if (displayFilters.layout === "spreadsheet") {
|
||||||
const spreadsheetFetchKey = cycleId
|
const spreadsheetFetchKey = cycleId
|
||||||
? CYCLE_ISSUES_WITH_PARAMS(cycleId.toString(), spreadsheetParams)
|
? CYCLE_ISSUES_WITH_PARAMS(cycleId.toString(), spreadsheetParams)
|
||||||
: moduleId
|
: moduleId
|
||||||
|
@ -16,7 +16,7 @@ export const IssueGanttChartView = () => {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId } = router.query;
|
const { workspaceSlug, projectId } = router.query;
|
||||||
|
|
||||||
const { orderBy } = useIssuesView();
|
const { displayFilters } = useIssuesView();
|
||||||
|
|
||||||
const { user } = useUser();
|
const { user } = useUser();
|
||||||
const { projectDetails } = useProjectDetails();
|
const { projectDetails } = useProjectDetails();
|
||||||
@ -43,7 +43,7 @@ export const IssueGanttChartView = () => {
|
|||||||
enableBlockLeftResize={isAllowed}
|
enableBlockLeftResize={isAllowed}
|
||||||
enableBlockRightResize={isAllowed}
|
enableBlockRightResize={isAllowed}
|
||||||
enableBlockMove={isAllowed}
|
enableBlockMove={isAllowed}
|
||||||
enableReorder={orderBy === "sort_order" && isAllowed}
|
enableReorder={displayFilters.order_by === "sort_order" && isAllowed}
|
||||||
bottomSpacing
|
bottomSpacing
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -78,7 +78,7 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = ({
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId, cycleId, moduleId, viewId, inboxId } = router.query;
|
const { workspaceSlug, projectId, cycleId, moduleId, viewId, inboxId } = router.query;
|
||||||
|
|
||||||
const { issueView, params } = useIssuesView();
|
const { displayFilters, params } = useIssuesView();
|
||||||
const { params: calendarParams } = useCalendarIssuesView();
|
const { params: calendarParams } = useCalendarIssuesView();
|
||||||
const { order_by, group_by, ...viewGanttParams } = params;
|
const { order_by, group_by, ...viewGanttParams } = params;
|
||||||
const { params: inboxParams } = useInboxView();
|
const { params: inboxParams } = useInboxView();
|
||||||
@ -247,13 +247,13 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = ({
|
|||||||
if (payload.module && payload.module !== "")
|
if (payload.module && payload.module !== "")
|
||||||
await addIssueToModule(res.id, payload.module);
|
await addIssueToModule(res.id, payload.module);
|
||||||
|
|
||||||
if (issueView === "calendar") mutate(calendarFetchKey);
|
if (displayFilters.layout === "calendar") mutate(calendarFetchKey);
|
||||||
if (issueView === "gantt_chart")
|
if (displayFilters.layout === "gantt_chart")
|
||||||
mutate(ganttFetchKey, {
|
mutate(ganttFetchKey, {
|
||||||
start_target_date: true,
|
start_target_date: true,
|
||||||
order_by: "sort_order",
|
order_by: "sort_order",
|
||||||
});
|
});
|
||||||
if (issueView === "spreadsheet") mutate(spreadsheetFetchKey);
|
if (displayFilters.layout === "spreadsheet") mutate(spreadsheetFetchKey);
|
||||||
if (groupedIssues) mutateMyIssues();
|
if (groupedIssues) mutateMyIssues();
|
||||||
|
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
@ -285,8 +285,8 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = ({
|
|||||||
if (isUpdatingSingleIssue) {
|
if (isUpdatingSingleIssue) {
|
||||||
mutate<IIssue>(PROJECT_ISSUES_DETAILS, (prevData) => ({ ...prevData, ...res }), false);
|
mutate<IIssue>(PROJECT_ISSUES_DETAILS, (prevData) => ({ ...prevData, ...res }), false);
|
||||||
} else {
|
} else {
|
||||||
if (issueView === "calendar") mutate(calendarFetchKey);
|
if (displayFilters.layout === "calendar") mutate(calendarFetchKey);
|
||||||
if (issueView === "spreadsheet") mutate(spreadsheetFetchKey);
|
if (displayFilters.layout === "spreadsheet") mutate(spreadsheetFetchKey);
|
||||||
if (payload.parent) mutate(SUB_ISSUES(payload.parent.toString()));
|
if (payload.parent) mutate(SUB_ISSUES(payload.parent.toString()));
|
||||||
mutate(PROJECT_ISSUES_LIST_WITH_PARAMS(activeProject ?? "", params));
|
mutate(PROJECT_ISSUES_LIST_WITH_PARAMS(activeProject ?? "", params));
|
||||||
}
|
}
|
||||||
|
@ -37,20 +37,8 @@ export const MyIssuesViewOptions: React.FC = () => {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug } = router.query;
|
||||||
|
|
||||||
const {
|
const { displayFilters, setDisplayFilters, properties, setProperty, filters, setFilters } =
|
||||||
issueView,
|
useMyIssuesFilters(workspaceSlug?.toString());
|
||||||
setIssueView,
|
|
||||||
groupBy,
|
|
||||||
setGroupBy,
|
|
||||||
orderBy,
|
|
||||||
setOrderBy,
|
|
||||||
showEmptyGroups,
|
|
||||||
setShowEmptyGroups,
|
|
||||||
properties,
|
|
||||||
setProperty,
|
|
||||||
filters,
|
|
||||||
setFilters,
|
|
||||||
} = useMyIssuesFilters(workspaceSlug?.toString());
|
|
||||||
|
|
||||||
const { isEstimateActive } = useEstimateOption();
|
const { isEstimateActive } = useEstimateOption();
|
||||||
|
|
||||||
@ -68,11 +56,11 @@ export const MyIssuesViewOptions: React.FC = () => {
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className={`grid h-7 w-7 place-items-center rounded p-1 outline-none hover:bg-custom-sidebar-background-80 duration-300 ${
|
className={`grid h-7 w-7 place-items-center rounded p-1 outline-none hover:bg-custom-sidebar-background-80 duration-300 ${
|
||||||
issueView === option.type
|
displayFilters?.layout === option.type
|
||||||
? "bg-custom-sidebar-background-80"
|
? "bg-custom-sidebar-background-80"
|
||||||
: "text-custom-sidebar-text-200"
|
: "text-custom-sidebar-text-200"
|
||||||
}`}
|
}`}
|
||||||
onClick={() => setIssueView(option.type)}
|
onClick={() => setDisplayFilters({ layout: option.type })}
|
||||||
>
|
>
|
||||||
<option.Icon
|
<option.Icon
|
||||||
sx={{
|
sx={{
|
||||||
@ -139,81 +127,89 @@ export const MyIssuesViewOptions: React.FC = () => {
|
|||||||
<Popover.Panel className="absolute right-0 z-30 mt-1 w-screen max-w-xs transform rounded-lg border border-custom-border-200 bg-custom-background-90 p-3 shadow-lg">
|
<Popover.Panel className="absolute right-0 z-30 mt-1 w-screen max-w-xs transform rounded-lg border border-custom-border-200 bg-custom-background-90 p-3 shadow-lg">
|
||||||
<div className="relative divide-y-2 divide-custom-border-200">
|
<div className="relative divide-y-2 divide-custom-border-200">
|
||||||
<div className="space-y-4 pb-3 text-xs">
|
<div className="space-y-4 pb-3 text-xs">
|
||||||
{issueView !== "calendar" && issueView !== "spreadsheet" && (
|
{displayFilters?.layout !== "calendar" &&
|
||||||
<>
|
displayFilters?.layout !== "spreadsheet" && (
|
||||||
<div className="flex items-center justify-between">
|
<>
|
||||||
<h4 className="text-custom-text-200">Group by</h4>
|
<div className="flex items-center justify-between">
|
||||||
<div className="w-28">
|
<h4 className="text-custom-text-200">Group by</h4>
|
||||||
<CustomMenu
|
<div className="w-28">
|
||||||
label={
|
<CustomMenu
|
||||||
groupBy === "project"
|
label={
|
||||||
? "Project"
|
displayFilters?.group_by === "project"
|
||||||
: GROUP_BY_OPTIONS.find((option) => option.key === groupBy)
|
? "Project"
|
||||||
?.name ?? "Select"
|
: GROUP_BY_OPTIONS.find(
|
||||||
}
|
(option) => option.key === displayFilters?.group_by
|
||||||
className="!w-full"
|
)?.name ?? "Select"
|
||||||
buttonClassName="w-full"
|
}
|
||||||
>
|
className="!w-full"
|
||||||
{GROUP_BY_OPTIONS.map((option) => {
|
buttonClassName="w-full"
|
||||||
if (issueView === "kanban" && option.key === null) return null;
|
>
|
||||||
if (
|
{GROUP_BY_OPTIONS.map((option) => {
|
||||||
option.key === "state" ||
|
if (displayFilters?.layout === "kanban" && option.key === null)
|
||||||
option.key === "created_by" ||
|
return null;
|
||||||
option.key === "assignees"
|
if (
|
||||||
)
|
option.key === "state" ||
|
||||||
return null;
|
option.key === "created_by" ||
|
||||||
|
option.key === "assignees"
|
||||||
|
)
|
||||||
|
return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CustomMenu.MenuItem
|
<CustomMenu.MenuItem
|
||||||
key={option.key}
|
key={option.key}
|
||||||
onClick={() => setGroupBy(option.key)}
|
onClick={() => setDisplayFilters({ group_by: option.key })}
|
||||||
>
|
>
|
||||||
{option.name}
|
{option.name}
|
||||||
</CustomMenu.MenuItem>
|
</CustomMenu.MenuItem>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</CustomMenu>
|
</CustomMenu>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div className="flex items-center justify-between">
|
||||||
<div className="flex items-center justify-between">
|
<h4 className="text-custom-text-200">Order by</h4>
|
||||||
<h4 className="text-custom-text-200">Order by</h4>
|
<div className="w-28">
|
||||||
<div className="w-28">
|
<CustomMenu
|
||||||
<CustomMenu
|
label={
|
||||||
label={
|
ORDER_BY_OPTIONS.find(
|
||||||
ORDER_BY_OPTIONS.find((option) => option.key === orderBy)?.name ??
|
(option) => option.key === displayFilters?.order_by
|
||||||
"Select"
|
)?.name ?? "Select"
|
||||||
}
|
}
|
||||||
className="!w-full"
|
className="!w-full"
|
||||||
buttonClassName="w-full"
|
buttonClassName="w-full"
|
||||||
>
|
>
|
||||||
{ORDER_BY_OPTIONS.map((option) => {
|
{ORDER_BY_OPTIONS.map((option) => {
|
||||||
if (groupBy === "priority" && option.key === "priority")
|
if (
|
||||||
return null;
|
displayFilters?.group_by === "priority" &&
|
||||||
if (option.key === "sort_order") return null;
|
option.key === "priority"
|
||||||
|
)
|
||||||
|
return null;
|
||||||
|
if (option.key === "sort_order") return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CustomMenu.MenuItem
|
<CustomMenu.MenuItem
|
||||||
key={option.key}
|
key={option.key}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setOrderBy(option.key);
|
setDisplayFilters({ order_by: option.key });
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{option.name}
|
{option.name}
|
||||||
</CustomMenu.MenuItem>
|
</CustomMenu.MenuItem>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</CustomMenu>
|
</CustomMenu>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</>
|
||||||
</>
|
)}
|
||||||
)}
|
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<h4 className="text-custom-text-200">Issue type</h4>
|
<h4 className="text-custom-text-200">Issue type</h4>
|
||||||
<div className="w-28">
|
<div className="w-28">
|
||||||
<CustomMenu
|
<CustomMenu
|
||||||
label={
|
label={
|
||||||
FILTER_ISSUE_OPTIONS.find((option) => option.key === filters?.type)
|
FILTER_ISSUE_OPTIONS.find(
|
||||||
?.name ?? "Select"
|
(option) => option.key === displayFilters?.type
|
||||||
|
)?.name ?? "Select"
|
||||||
}
|
}
|
||||||
className="!w-full"
|
className="!w-full"
|
||||||
buttonClassName="w-full"
|
buttonClassName="w-full"
|
||||||
@ -222,7 +218,7 @@ export const MyIssuesViewOptions: React.FC = () => {
|
|||||||
<CustomMenu.MenuItem
|
<CustomMenu.MenuItem
|
||||||
key={option.key}
|
key={option.key}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
setFilters({
|
setDisplayFilters({
|
||||||
type: option.key,
|
type: option.key,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -234,16 +230,24 @@ export const MyIssuesViewOptions: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{issueView !== "calendar" && issueView !== "spreadsheet" && (
|
{displayFilters?.layout !== "calendar" &&
|
||||||
<>
|
displayFilters?.layout !== "spreadsheet" && (
|
||||||
<div className="flex items-center justify-between">
|
<>
|
||||||
<h4 className="text-custom-text-200">Show empty states</h4>
|
<div className="flex items-center justify-between">
|
||||||
<div className="w-28">
|
<h4 className="text-custom-text-200">Show empty states</h4>
|
||||||
<ToggleSwitch value={showEmptyGroups} onChange={setShowEmptyGroups} />
|
<div className="w-28">
|
||||||
|
<ToggleSwitch
|
||||||
|
value={displayFilters?.show_empty_groups ?? true}
|
||||||
|
onChange={() =>
|
||||||
|
setDisplayFilters({
|
||||||
|
show_empty_groups: !displayFilters?.show_empty_groups,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</>
|
||||||
</>
|
)}
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-2 py-3">
|
<div className="space-y-2 py-3">
|
||||||
@ -253,7 +257,7 @@ export const MyIssuesViewOptions: React.FC = () => {
|
|||||||
if (key === "estimate" && !isEstimateActive) return null;
|
if (key === "estimate" && !isEstimateActive) return null;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
issueView === "spreadsheet" &&
|
displayFilters?.layout === "spreadsheet" &&
|
||||||
(key === "attachment_count" ||
|
(key === "attachment_count" ||
|
||||||
key === "link" ||
|
key === "link" ||
|
||||||
key === "sub_issue_count")
|
key === "sub_issue_count")
|
||||||
@ -261,7 +265,7 @@ export const MyIssuesViewOptions: React.FC = () => {
|
|||||||
return null;
|
return null;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
issueView !== "spreadsheet" &&
|
displayFilters?.layout !== "spreadsheet" &&
|
||||||
(key === "created_on" || key === "updated_on")
|
(key === "created_on" || key === "updated_on")
|
||||||
)
|
)
|
||||||
return null;
|
return null;
|
||||||
|
@ -57,8 +57,9 @@ export const MyIssuesView: React.FC<Props> = ({
|
|||||||
const { user } = useUserAuth();
|
const { user } = useUserAuth();
|
||||||
|
|
||||||
const { groupedIssues, mutateMyIssues, isEmpty, params } = useMyIssues(workspaceSlug?.toString());
|
const { groupedIssues, mutateMyIssues, isEmpty, params } = useMyIssues(workspaceSlug?.toString());
|
||||||
const { filters, setFilters, issueView, groupBy, orderBy, properties, showEmptyGroups } =
|
const { filters, setFilters, displayFilters, setDisplayFilters, properties } = useMyIssuesFilters(
|
||||||
useMyIssuesFilters(workspaceSlug?.toString());
|
workspaceSlug?.toString()
|
||||||
|
);
|
||||||
|
|
||||||
const { data: labels } = useSWR(
|
const { data: labels } = useSWR(
|
||||||
workspaceSlug && (filters?.labels ?? []).length > 0
|
workspaceSlug && (filters?.labels ?? []).length > 0
|
||||||
@ -81,7 +82,13 @@ export const MyIssuesView: React.FC<Props> = ({
|
|||||||
async (result: DropResult) => {
|
async (result: DropResult) => {
|
||||||
setTrashBox(false);
|
setTrashBox(false);
|
||||||
|
|
||||||
if (!result.destination || !workspaceSlug || !groupedIssues || groupBy !== "priority") return;
|
if (
|
||||||
|
!result.destination ||
|
||||||
|
!workspaceSlug ||
|
||||||
|
!groupedIssues ||
|
||||||
|
displayFilters?.group_by !== "priority"
|
||||||
|
)
|
||||||
|
return;
|
||||||
|
|
||||||
const { source, destination } = result;
|
const { source, destination } = result;
|
||||||
|
|
||||||
@ -96,7 +103,7 @@ export const MyIssuesView: React.FC<Props> = ({
|
|||||||
const sourceGroup = source.droppableId;
|
const sourceGroup = source.droppableId;
|
||||||
const destinationGroup = destination.droppableId;
|
const destinationGroup = destination.droppableId;
|
||||||
|
|
||||||
draggedItem[groupBy] = destinationGroup as TIssuePriorities;
|
draggedItem[displayFilters.group_by] = destinationGroup as TIssuePriorities;
|
||||||
|
|
||||||
mutate<{
|
mutate<{
|
||||||
[key: string]: IIssue[];
|
[key: string]: IIssue[];
|
||||||
@ -113,8 +120,14 @@ export const MyIssuesView: React.FC<Props> = ({
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
...prevData,
|
...prevData,
|
||||||
[sourceGroup]: orderArrayBy(sourceGroupArray, orderBy),
|
[sourceGroup]: orderArrayBy(
|
||||||
[destinationGroup]: orderArrayBy(destinationGroupArray, orderBy),
|
sourceGroupArray,
|
||||||
|
displayFilters.order_by ?? "-created_at"
|
||||||
|
),
|
||||||
|
[destinationGroup]: orderArrayBy(
|
||||||
|
destinationGroupArray,
|
||||||
|
displayFilters.order_by ?? "-created_at"
|
||||||
|
),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
false
|
false
|
||||||
@ -134,7 +147,7 @@ export const MyIssuesView: React.FC<Props> = ({
|
|||||||
.catch(() => mutate(USER_ISSUES(workspaceSlug.toString(), params)));
|
.catch(() => mutate(USER_ISSUES(workspaceSlug.toString(), params)));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[groupBy, groupedIssues, handleDeleteIssue, orderBy, params, user, workspaceSlug]
|
[displayFilters, groupedIssues, handleDeleteIssue, params, user, workspaceSlug]
|
||||||
);
|
);
|
||||||
|
|
||||||
const addIssueToGroup = useCallback(
|
const addIssueToGroup = useCallback(
|
||||||
@ -143,19 +156,19 @@ export const MyIssuesView: React.FC<Props> = ({
|
|||||||
|
|
||||||
let preloadedValue: string | string[] = groupTitle;
|
let preloadedValue: string | string[] = groupTitle;
|
||||||
|
|
||||||
if (groupBy === "labels") {
|
if (displayFilters?.group_by === "labels") {
|
||||||
if (groupTitle === "None") preloadedValue = [];
|
if (groupTitle === "None") preloadedValue = [];
|
||||||
else preloadedValue = [groupTitle];
|
else preloadedValue = [groupTitle];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (groupBy)
|
if (displayFilters?.group_by)
|
||||||
setPreloadedData({
|
setPreloadedData({
|
||||||
[groupBy]: preloadedValue,
|
[displayFilters?.group_by]: preloadedValue,
|
||||||
actionType: "createIssue",
|
actionType: "createIssue",
|
||||||
});
|
});
|
||||||
else setPreloadedData({ actionType: "createIssue" });
|
else setPreloadedData({ actionType: "createIssue" });
|
||||||
},
|
},
|
||||||
[setCreateIssueModal, setPreloadedData, groupBy]
|
[setCreateIssueModal, setPreloadedData, displayFilters?.group_by]
|
||||||
);
|
);
|
||||||
|
|
||||||
const addIssueToDate = useCallback(
|
const addIssueToDate = useCallback(
|
||||||
@ -263,7 +276,6 @@ export const MyIssuesView: React.FC<Props> = ({
|
|||||||
state_group: null,
|
state_group: null,
|
||||||
start_date: null,
|
start_date: null,
|
||||||
target_date: null,
|
target_date: null,
|
||||||
type: null,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
@ -275,7 +287,7 @@ export const MyIssuesView: React.FC<Props> = ({
|
|||||||
addIssueToDate={addIssueToDate}
|
addIssueToDate={addIssueToDate}
|
||||||
addIssueToGroup={addIssueToGroup}
|
addIssueToGroup={addIssueToGroup}
|
||||||
disableUserActions={disableUserActions}
|
disableUserActions={disableUserActions}
|
||||||
dragDisabled={groupBy !== "priority"}
|
dragDisabled={displayFilters?.group_by !== "priority"}
|
||||||
emptyState={{
|
emptyState={{
|
||||||
title: filters.assignees
|
title: filters.assignees
|
||||||
? "You don't have any issue assigned to you yet"
|
? "You don't have any issue assigned to you yet"
|
||||||
@ -304,15 +316,12 @@ export const MyIssuesView: React.FC<Props> = ({
|
|||||||
trashBox={trashBox}
|
trashBox={trashBox}
|
||||||
setTrashBox={setTrashBox}
|
setTrashBox={setTrashBox}
|
||||||
viewProps={{
|
viewProps={{
|
||||||
groupByProperty: groupBy,
|
displayFilters,
|
||||||
groupedIssues,
|
groupedIssues,
|
||||||
isEmpty,
|
isEmpty,
|
||||||
issueView,
|
|
||||||
mutateIssues: mutateMyIssues,
|
mutateIssues: mutateMyIssues,
|
||||||
orderBy,
|
|
||||||
params,
|
params,
|
||||||
properties,
|
properties,
|
||||||
showEmptyGroups,
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
@ -34,7 +34,7 @@ export const ViewDueDateSelect: React.FC<Props> = ({
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug } = router.query;
|
||||||
|
|
||||||
const { issueView } = useIssuesView();
|
const { displayFilters } = useIssuesView();
|
||||||
|
|
||||||
const minDate = issue.start_date ? new Date(issue.start_date) : null;
|
const minDate = issue.start_date ? new Date(issue.start_date) : null;
|
||||||
minDate?.setDate(minDate.getDate());
|
minDate?.setDate(minDate.getDate());
|
||||||
@ -80,7 +80,9 @@ export const ViewDueDateSelect: React.FC<Props> = ({
|
|||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
className={`${issue?.target_date ? "w-[6.5rem]" : "w-[5rem] text-center"} ${
|
className={`${issue?.target_date ? "w-[6.5rem]" : "w-[5rem] text-center"} ${
|
||||||
issueView === "kanban" ? "bg-custom-background-90" : "bg-custom-background-100"
|
displayFilters.layout === "kanban"
|
||||||
|
? "bg-custom-background-90"
|
||||||
|
: "bg-custom-background-100"
|
||||||
}`}
|
}`}
|
||||||
minDate={minDate ?? undefined}
|
minDate={minDate ?? undefined}
|
||||||
noBorder={noBorder}
|
noBorder={noBorder}
|
||||||
|
@ -34,7 +34,7 @@ export const ViewStartDateSelect: React.FC<Props> = ({
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug } = router.query;
|
||||||
|
|
||||||
const { issueView } = useIssuesView();
|
const { displayFilters } = useIssuesView();
|
||||||
|
|
||||||
const maxDate = issue.target_date ? new Date(issue.target_date) : null;
|
const maxDate = issue.target_date ? new Date(issue.target_date) : null;
|
||||||
maxDate?.setDate(maxDate.getDate());
|
maxDate?.setDate(maxDate.getDate());
|
||||||
@ -72,7 +72,9 @@ export const ViewStartDateSelect: React.FC<Props> = ({
|
|||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
className={`${issue?.start_date ? "w-[6.5rem]" : "w-[5rem] text-center"} ${
|
className={`${issue?.start_date ? "w-[6.5rem]" : "w-[5rem] text-center"} ${
|
||||||
issueView === "kanban" ? "bg-custom-background-90" : "bg-custom-background-100"
|
displayFilters.layout === "kanban"
|
||||||
|
? "bg-custom-background-90"
|
||||||
|
: "bg-custom-background-100"
|
||||||
}`}
|
}`}
|
||||||
maxDate={maxDate ?? undefined}
|
maxDate={maxDate ?? undefined}
|
||||||
noBorder={noBorder}
|
noBorder={noBorder}
|
||||||
|
@ -20,7 +20,7 @@ export const ModuleIssuesGanttChartView: FC<Props> = ({}) => {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId, moduleId } = router.query;
|
const { workspaceSlug, projectId, moduleId } = router.query;
|
||||||
|
|
||||||
const { orderBy } = useIssuesView();
|
const { displayFilters } = useIssuesView();
|
||||||
|
|
||||||
const { user } = useUser();
|
const { user } = useUser();
|
||||||
const { projectDetails } = useProjectDetails();
|
const { projectDetails } = useProjectDetails();
|
||||||
@ -48,7 +48,7 @@ export const ModuleIssuesGanttChartView: FC<Props> = ({}) => {
|
|||||||
enableBlockLeftResize={isAllowed}
|
enableBlockLeftResize={isAllowed}
|
||||||
enableBlockRightResize={isAllowed}
|
enableBlockRightResize={isAllowed}
|
||||||
enableBlockMove={isAllowed}
|
enableBlockMove={isAllowed}
|
||||||
enableReorder={orderBy === "sort_order" && isAllowed}
|
enableReorder={displayFilters.order_by === "sort_order" && isAllowed}
|
||||||
bottomSpacing
|
bottomSpacing
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -41,16 +41,10 @@ export const ProfileIssuesViewOptions: React.FC = () => {
|
|||||||
const { projects } = useProjects();
|
const { projects } = useProjects();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
issueView,
|
displayFilters,
|
||||||
setIssueView,
|
setDisplayFilters,
|
||||||
groupByProperty,
|
|
||||||
setGroupByProperty,
|
|
||||||
orderBy,
|
|
||||||
setOrderBy,
|
|
||||||
showEmptyGroups,
|
|
||||||
setShowEmptyGroups,
|
|
||||||
filters,
|
filters,
|
||||||
properties,
|
displayProperties,
|
||||||
setProperties,
|
setProperties,
|
||||||
setFilters,
|
setFilters,
|
||||||
} = useProfileIssues(workspaceSlug?.toString(), userId?.toString());
|
} = useProfileIssues(workspaceSlug?.toString(), userId?.toString());
|
||||||
@ -94,11 +88,11 @@ export const ProfileIssuesViewOptions: React.FC = () => {
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className={`grid h-7 w-7 place-items-center rounded p-1 outline-none hover:bg-custom-sidebar-background-80 duration-300 ${
|
className={`grid h-7 w-7 place-items-center rounded p-1 outline-none hover:bg-custom-sidebar-background-80 duration-300 ${
|
||||||
issueView === option.type
|
displayFilters.layout === option.type
|
||||||
? "bg-custom-sidebar-background-80"
|
? "bg-custom-sidebar-background-80"
|
||||||
: "text-custom-sidebar-text-200"
|
: "text-custom-sidebar-text-200"
|
||||||
}`}
|
}`}
|
||||||
onClick={() => setIssueView(option.type)}
|
onClick={() => setDisplayFilters({ layout: option.type })}
|
||||||
>
|
>
|
||||||
<option.Icon
|
<option.Icon
|
||||||
sx={{
|
sx={{
|
||||||
@ -165,82 +159,89 @@ export const ProfileIssuesViewOptions: React.FC = () => {
|
|||||||
<Popover.Panel className="absolute right-0 z-30 mt-1 w-screen max-w-xs transform rounded-lg border border-custom-border-200 bg-custom-background-90 p-3 shadow-lg">
|
<Popover.Panel className="absolute right-0 z-30 mt-1 w-screen max-w-xs transform rounded-lg border border-custom-border-200 bg-custom-background-90 p-3 shadow-lg">
|
||||||
<div className="relative divide-y-2 divide-custom-border-200">
|
<div className="relative divide-y-2 divide-custom-border-200">
|
||||||
<div className="space-y-4 pb-3 text-xs">
|
<div className="space-y-4 pb-3 text-xs">
|
||||||
{issueView !== "calendar" && issueView !== "spreadsheet" && (
|
{displayFilters.layout !== "calendar" &&
|
||||||
<>
|
displayFilters.layout !== "spreadsheet" && (
|
||||||
<div className="flex items-center justify-between">
|
<>
|
||||||
<h4 className="text-custom-text-200">Group by</h4>
|
<div className="flex items-center justify-between">
|
||||||
<div className="w-28">
|
<h4 className="text-custom-text-200">Group by</h4>
|
||||||
<CustomMenu
|
<div className="w-28">
|
||||||
label={
|
<CustomMenu
|
||||||
groupByProperty === "project"
|
label={
|
||||||
? "Project"
|
displayFilters.group_by === "project"
|
||||||
: GROUP_BY_OPTIONS.find(
|
? "Project"
|
||||||
(option) => option.key === groupByProperty
|
: GROUP_BY_OPTIONS.find(
|
||||||
)?.name ?? "Select"
|
(option) => option.key === displayFilters.group_by
|
||||||
}
|
)?.name ?? "Select"
|
||||||
className="!w-full"
|
}
|
||||||
buttonClassName="w-full"
|
className="!w-full"
|
||||||
>
|
buttonClassName="w-full"
|
||||||
{GROUP_BY_OPTIONS.map((option) => {
|
>
|
||||||
if (issueView === "kanban" && option.key === null) return null;
|
{GROUP_BY_OPTIONS.map((option) => {
|
||||||
if (
|
if (displayFilters.layout === "kanban" && option.key === null)
|
||||||
option.key === "state" ||
|
return null;
|
||||||
option.key === "created_by" ||
|
if (
|
||||||
option.key === "assignees"
|
option.key === "state" ||
|
||||||
)
|
option.key === "created_by" ||
|
||||||
return null;
|
option.key === "assignees"
|
||||||
|
)
|
||||||
|
return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CustomMenu.MenuItem
|
<CustomMenu.MenuItem
|
||||||
key={option.key}
|
key={option.key}
|
||||||
onClick={() => setGroupByProperty(option.key)}
|
onClick={() => setDisplayFilters({ group_by: option.key })}
|
||||||
>
|
>
|
||||||
{option.name}
|
{option.name}
|
||||||
</CustomMenu.MenuItem>
|
</CustomMenu.MenuItem>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</CustomMenu>
|
</CustomMenu>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div className="flex items-center justify-between">
|
||||||
<div className="flex items-center justify-between">
|
<h4 className="text-custom-text-200">Order by</h4>
|
||||||
<h4 className="text-custom-text-200">Order by</h4>
|
<div className="w-28">
|
||||||
<div className="w-28">
|
<CustomMenu
|
||||||
<CustomMenu
|
label={
|
||||||
label={
|
ORDER_BY_OPTIONS.find(
|
||||||
ORDER_BY_OPTIONS.find((option) => option.key === orderBy)?.name ??
|
(option) => option.key === displayFilters.order_by
|
||||||
"Select"
|
)?.name ?? "Select"
|
||||||
}
|
}
|
||||||
className="!w-full"
|
className="!w-full"
|
||||||
buttonClassName="w-full"
|
buttonClassName="w-full"
|
||||||
>
|
>
|
||||||
{ORDER_BY_OPTIONS.map((option) => {
|
{ORDER_BY_OPTIONS.map((option) => {
|
||||||
if (groupByProperty === "priority" && option.key === "priority")
|
if (
|
||||||
return null;
|
displayFilters.group_by === "priority" &&
|
||||||
if (option.key === "sort_order") return null;
|
option.key === "priority"
|
||||||
|
)
|
||||||
|
return null;
|
||||||
|
if (option.key === "sort_order") return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CustomMenu.MenuItem
|
<CustomMenu.MenuItem
|
||||||
key={option.key}
|
key={option.key}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setOrderBy(option.key);
|
setDisplayFilters({ order_by: option.key });
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{option.name}
|
{option.name}
|
||||||
</CustomMenu.MenuItem>
|
</CustomMenu.MenuItem>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</CustomMenu>
|
</CustomMenu>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</>
|
||||||
</>
|
)}
|
||||||
)}
|
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<h4 className="text-custom-text-200">Issue type</h4>
|
<h4 className="text-custom-text-200">Issue type</h4>
|
||||||
<div className="w-28">
|
<div className="w-28">
|
||||||
<CustomMenu
|
<CustomMenu
|
||||||
label={
|
label={
|
||||||
FILTER_ISSUE_OPTIONS.find((option) => option.key === filters?.type)
|
FILTER_ISSUE_OPTIONS.find(
|
||||||
?.name ?? "Select"
|
(option) => option.key === displayFilters?.type
|
||||||
|
)?.name ?? "Select"
|
||||||
}
|
}
|
||||||
className="!w-full"
|
className="!w-full"
|
||||||
buttonClassName="w-full"
|
buttonClassName="w-full"
|
||||||
@ -249,7 +250,7 @@ export const ProfileIssuesViewOptions: React.FC = () => {
|
|||||||
<CustomMenu.MenuItem
|
<CustomMenu.MenuItem
|
||||||
key={option.key}
|
key={option.key}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
setFilters({
|
setDisplayFilters({
|
||||||
type: option.key,
|
type: option.key,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -261,26 +262,34 @@ export const ProfileIssuesViewOptions: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{issueView !== "calendar" && issueView !== "spreadsheet" && (
|
{displayFilters.layout !== "calendar" &&
|
||||||
<>
|
displayFilters.layout !== "spreadsheet" && (
|
||||||
<div className="flex items-center justify-between">
|
<>
|
||||||
<h4 className="text-custom-text-200">Show empty states</h4>
|
<div className="flex items-center justify-between">
|
||||||
<div className="w-28">
|
<h4 className="text-custom-text-200">Show empty states</h4>
|
||||||
<ToggleSwitch value={showEmptyGroups} onChange={setShowEmptyGroups} />
|
<div className="w-28">
|
||||||
|
<ToggleSwitch
|
||||||
|
value={displayFilters.show_empty_groups ?? true}
|
||||||
|
onChange={() =>
|
||||||
|
setDisplayFilters({
|
||||||
|
show_empty_groups: !displayFilters.show_empty_groups,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</>
|
||||||
</>
|
)}
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-2 py-3">
|
<div className="space-y-2 py-3">
|
||||||
<h4 className="text-sm text-custom-text-200">Display Properties</h4>
|
<h4 className="text-sm text-custom-text-200">Display Properties</h4>
|
||||||
<div className="flex flex-wrap items-center gap-2 text-custom-text-200">
|
<div className="flex flex-wrap items-center gap-2 text-custom-text-200">
|
||||||
{Object.keys(properties).map((key) => {
|
{Object.keys(displayProperties).map((key) => {
|
||||||
if (key === "estimate" && !isEstimateActive) return null;
|
if (key === "estimate" && !isEstimateActive) return null;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
issueView === "spreadsheet" &&
|
displayFilters.layout === "spreadsheet" &&
|
||||||
(key === "attachment_count" ||
|
(key === "attachment_count" ||
|
||||||
key === "link" ||
|
key === "link" ||
|
||||||
key === "sub_issue_count")
|
key === "sub_issue_count")
|
||||||
@ -288,7 +297,7 @@ export const ProfileIssuesViewOptions: React.FC = () => {
|
|||||||
return null;
|
return null;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
issueView !== "spreadsheet" &&
|
displayFilters.layout !== "spreadsheet" &&
|
||||||
(key === "created_on" || key === "updated_on")
|
(key === "created_on" || key === "updated_on")
|
||||||
)
|
)
|
||||||
return null;
|
return null;
|
||||||
@ -298,7 +307,7 @@ export const ProfileIssuesViewOptions: React.FC = () => {
|
|||||||
key={key}
|
key={key}
|
||||||
type="button"
|
type="button"
|
||||||
className={`rounded border px-2 py-1 text-xs capitalize ${
|
className={`rounded border px-2 py-1 text-xs capitalize ${
|
||||||
properties[key as keyof Properties]
|
displayProperties[key as keyof Properties]
|
||||||
? "border-custom-primary bg-custom-primary text-white"
|
? "border-custom-primary bg-custom-primary text-white"
|
||||||
: "border-custom-border-200"
|
: "border-custom-border-200"
|
||||||
}`}
|
}`}
|
||||||
|
@ -50,14 +50,12 @@ export const ProfileIssuesView = () => {
|
|||||||
const {
|
const {
|
||||||
groupedIssues,
|
groupedIssues,
|
||||||
mutateProfileIssues,
|
mutateProfileIssues,
|
||||||
issueView,
|
displayFilters,
|
||||||
groupByProperty,
|
setDisplayFilters,
|
||||||
orderBy,
|
|
||||||
isEmpty,
|
isEmpty,
|
||||||
showEmptyGroups,
|
|
||||||
filters,
|
filters,
|
||||||
setFilters,
|
setFilters,
|
||||||
properties,
|
displayProperties,
|
||||||
params,
|
params,
|
||||||
} = useProfileIssues(workspaceSlug?.toString(), userId?.toString());
|
} = useProfileIssues(workspaceSlug?.toString(), userId?.toString());
|
||||||
|
|
||||||
@ -92,7 +90,12 @@ export const ProfileIssuesView = () => {
|
|||||||
async (result: DropResult) => {
|
async (result: DropResult) => {
|
||||||
setTrashBox(false);
|
setTrashBox(false);
|
||||||
|
|
||||||
if (!result.destination || !workspaceSlug || !groupedIssues || groupByProperty !== "priority")
|
if (
|
||||||
|
!result.destination ||
|
||||||
|
!workspaceSlug ||
|
||||||
|
!groupedIssues ||
|
||||||
|
displayFilters.group_by !== "priority"
|
||||||
|
)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const { source, destination } = result;
|
const { source, destination } = result;
|
||||||
@ -108,7 +111,7 @@ export const ProfileIssuesView = () => {
|
|||||||
const sourceGroup = source.droppableId;
|
const sourceGroup = source.droppableId;
|
||||||
const destinationGroup = destination.droppableId;
|
const destinationGroup = destination.droppableId;
|
||||||
|
|
||||||
draggedItem[groupByProperty] = destinationGroup as TIssuePriorities;
|
draggedItem[displayFilters.group_by] = destinationGroup as TIssuePriorities;
|
||||||
|
|
||||||
mutateProfileIssues((prevData: any) => {
|
mutateProfileIssues((prevData: any) => {
|
||||||
if (!prevData) return prevData;
|
if (!prevData) return prevData;
|
||||||
@ -121,8 +124,11 @@ export const ProfileIssuesView = () => {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
...prevData,
|
...prevData,
|
||||||
[sourceGroup]: orderArrayBy(sourceGroupArray, orderBy),
|
[sourceGroup]: orderArrayBy(sourceGroupArray, displayFilters.order_by ?? "-created_at"),
|
||||||
[destinationGroup]: orderArrayBy(destinationGroupArray, orderBy),
|
[destinationGroup]: orderArrayBy(
|
||||||
|
destinationGroupArray,
|
||||||
|
displayFilters.order_by ?? "-created_at"
|
||||||
|
),
|
||||||
};
|
};
|
||||||
}, false);
|
}, false);
|
||||||
|
|
||||||
@ -140,15 +146,7 @@ export const ProfileIssuesView = () => {
|
|||||||
.catch(() => mutateProfileIssues());
|
.catch(() => mutateProfileIssues());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[
|
[displayFilters, groupedIssues, handleDeleteIssue, mutateProfileIssues, user, workspaceSlug]
|
||||||
groupByProperty,
|
|
||||||
groupedIssues,
|
|
||||||
handleDeleteIssue,
|
|
||||||
mutateProfileIssues,
|
|
||||||
orderBy,
|
|
||||||
user,
|
|
||||||
workspaceSlug,
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const addIssueToGroup = useCallback(
|
const addIssueToGroup = useCallback(
|
||||||
@ -157,19 +155,19 @@ export const ProfileIssuesView = () => {
|
|||||||
|
|
||||||
let preloadedValue: string | string[] = groupTitle;
|
let preloadedValue: string | string[] = groupTitle;
|
||||||
|
|
||||||
if (groupByProperty === "labels") {
|
if (displayFilters.group_by === "labels") {
|
||||||
if (groupTitle === "None") preloadedValue = [];
|
if (groupTitle === "None") preloadedValue = [];
|
||||||
else preloadedValue = [groupTitle];
|
else preloadedValue = [groupTitle];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (groupByProperty)
|
if (displayFilters.group_by)
|
||||||
setPreloadedData({
|
setPreloadedData({
|
||||||
[groupByProperty]: preloadedValue,
|
[displayFilters.group_by]: preloadedValue,
|
||||||
actionType: "createIssue",
|
actionType: "createIssue",
|
||||||
});
|
});
|
||||||
else setPreloadedData({ actionType: "createIssue" });
|
else setPreloadedData({ actionType: "createIssue" });
|
||||||
},
|
},
|
||||||
[setCreateIssueModal, setPreloadedData, groupByProperty]
|
[setCreateIssueModal, setPreloadedData, displayFilters.group_by]
|
||||||
);
|
);
|
||||||
|
|
||||||
const addIssueToDate = useCallback(
|
const addIssueToDate = useCallback(
|
||||||
@ -277,7 +275,6 @@ export const ProfileIssuesView = () => {
|
|||||||
state_group: null,
|
state_group: null,
|
||||||
start_date: null,
|
start_date: null,
|
||||||
target_date: null,
|
target_date: null,
|
||||||
type: null,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
@ -289,7 +286,7 @@ export const ProfileIssuesView = () => {
|
|||||||
addIssueToDate={addIssueToDate}
|
addIssueToDate={addIssueToDate}
|
||||||
addIssueToGroup={addIssueToGroup}
|
addIssueToGroup={addIssueToGroup}
|
||||||
disableUserActions={false}
|
disableUserActions={false}
|
||||||
dragDisabled={groupByProperty !== "priority"}
|
dragDisabled={displayFilters.group_by !== "priority"}
|
||||||
emptyState={{
|
emptyState={{
|
||||||
title: router.pathname.includes("assigned")
|
title: router.pathname.includes("assigned")
|
||||||
? `Issues assigned to ${profileData?.user_data.display_name} will appear here`
|
? `Issues assigned to ${profileData?.user_data.display_name} will appear here`
|
||||||
@ -305,15 +302,12 @@ export const ProfileIssuesView = () => {
|
|||||||
trashBox={trashBox}
|
trashBox={trashBox}
|
||||||
setTrashBox={setTrashBox}
|
setTrashBox={setTrashBox}
|
||||||
viewProps={{
|
viewProps={{
|
||||||
groupByProperty,
|
|
||||||
groupedIssues,
|
groupedIssues,
|
||||||
|
displayFilters,
|
||||||
isEmpty,
|
isEmpty,
|
||||||
issueView,
|
|
||||||
mutateIssues: mutateProfileIssues,
|
mutateIssues: mutateProfileIssues,
|
||||||
orderBy,
|
|
||||||
params,
|
params,
|
||||||
properties,
|
properties: displayProperties,
|
||||||
showEmptyGroups,
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
@ -11,14 +11,15 @@ import projectService from "services/project.service";
|
|||||||
import cyclesService from "services/cycles.service";
|
import cyclesService from "services/cycles.service";
|
||||||
import modulesService from "services/modules.service";
|
import modulesService from "services/modules.service";
|
||||||
import viewsService from "services/views.service";
|
import viewsService from "services/views.service";
|
||||||
|
// hooks
|
||||||
|
import useUserAuth from "hooks/use-user-auth";
|
||||||
// types
|
// types
|
||||||
import {
|
import {
|
||||||
IIssueFilterOptions,
|
IIssueFilterOptions,
|
||||||
TIssueViewOptions,
|
|
||||||
IProjectMember,
|
IProjectMember,
|
||||||
TIssueGroupByOptions,
|
|
||||||
TIssueOrderByOptions,
|
|
||||||
ICurrentUserResponse,
|
ICurrentUserResponse,
|
||||||
|
IIssueDisplayFilterOptions,
|
||||||
|
IProjectViewProps,
|
||||||
} from "types";
|
} from "types";
|
||||||
// fetch-keys
|
// fetch-keys
|
||||||
import {
|
import {
|
||||||
@ -27,66 +28,34 @@ import {
|
|||||||
USER_PROJECT_VIEW,
|
USER_PROJECT_VIEW,
|
||||||
VIEW_DETAILS,
|
VIEW_DETAILS,
|
||||||
} from "constants/fetch-keys";
|
} from "constants/fetch-keys";
|
||||||
import useUserAuth from "hooks/use-user-auth";
|
|
||||||
|
|
||||||
export const issueViewContext = createContext<ContextType>({} as ContextType);
|
export const issueViewContext = createContext<ContextType>({} as ContextType);
|
||||||
|
|
||||||
type IssueViewProps = {
|
|
||||||
issueView: TIssueViewOptions;
|
|
||||||
groupByProperty: TIssueGroupByOptions;
|
|
||||||
orderBy: TIssueOrderByOptions;
|
|
||||||
showEmptyGroups: boolean;
|
|
||||||
showSubIssues: boolean;
|
|
||||||
calendarDateRange: string;
|
|
||||||
filters: IIssueFilterOptions;
|
|
||||||
};
|
|
||||||
|
|
||||||
type ReducerActionType = {
|
type ReducerActionType = {
|
||||||
type:
|
type: "REHYDRATE_THEME" | "SET_DISPLAY_FILTERS" | "SET_FILTERS" | "RESET_TO_DEFAULT";
|
||||||
| "REHYDRATE_THEME"
|
payload?: Partial<IProjectViewProps>;
|
||||||
| "SET_ISSUE_VIEW"
|
|
||||||
| "SET_ORDER_BY_PROPERTY"
|
|
||||||
| "SET_SHOW_EMPTY_STATES"
|
|
||||||
| "SET_CALENDAR_DATE_RANGE"
|
|
||||||
| "SET_FILTERS"
|
|
||||||
| "SET_GROUP_BY_PROPERTY"
|
|
||||||
| "RESET_TO_DEFAULT"
|
|
||||||
| "SET_SHOW_SUB_ISSUES";
|
|
||||||
payload?: Partial<IssueViewProps>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type ContextType = IssueViewProps & {
|
type ContextType = IProjectViewProps & {
|
||||||
setGroupByProperty: (property: TIssueGroupByOptions) => void;
|
setDisplayFilters: (displayFilter: Partial<IIssueDisplayFilterOptions>) => void;
|
||||||
setOrderBy: (property: TIssueOrderByOptions) => void;
|
|
||||||
setShowEmptyGroups: (property: boolean) => void;
|
|
||||||
setShowSubIssues: (value: boolean) => void;
|
|
||||||
setCalendarDateRange: (property: string) => void;
|
|
||||||
setFilters: (filters: Partial<IIssueFilterOptions>, saveToServer?: boolean) => void;
|
setFilters: (filters: Partial<IIssueFilterOptions>, saveToServer?: boolean) => void;
|
||||||
resetFilterToDefault: () => void;
|
resetFilterToDefault: () => void;
|
||||||
setNewFilterDefaultView: () => void;
|
setNewFilterDefaultView: () => void;
|
||||||
setIssueView: (property: TIssueViewOptions) => void;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type StateType = {
|
type StateType = IProjectViewProps;
|
||||||
issueView: TIssueViewOptions;
|
|
||||||
groupByProperty: TIssueGroupByOptions;
|
|
||||||
orderBy: TIssueOrderByOptions;
|
|
||||||
showEmptyGroups: boolean;
|
|
||||||
showSubIssues: boolean;
|
|
||||||
calendarDateRange: string;
|
|
||||||
filters: IIssueFilterOptions;
|
|
||||||
};
|
|
||||||
type ReducerFunctionType = (state: StateType, action: ReducerActionType) => StateType;
|
type ReducerFunctionType = (state: StateType, action: ReducerActionType) => StateType;
|
||||||
|
|
||||||
export const initialState: StateType = {
|
export const initialState: StateType = {
|
||||||
issueView: "list",
|
display_filters: {
|
||||||
groupByProperty: null,
|
calendar_date_range: "",
|
||||||
orderBy: "-created_at",
|
group_by: null,
|
||||||
showEmptyGroups: true,
|
layout: "list",
|
||||||
showSubIssues: true,
|
order_by: "-created_at",
|
||||||
calendarDateRange: "",
|
show_empty_groups: true,
|
||||||
|
sub_issue: true,
|
||||||
|
},
|
||||||
filters: {
|
filters: {
|
||||||
type: null,
|
|
||||||
priority: null,
|
priority: null,
|
||||||
assignees: null,
|
assignees: null,
|
||||||
labels: null,
|
labels: null,
|
||||||
@ -110,70 +79,14 @@ export const reducer: ReducerFunctionType = (state, action) => {
|
|||||||
return { ...initialState, ...payload, collapsed };
|
return { ...initialState, ...payload, collapsed };
|
||||||
}
|
}
|
||||||
|
|
||||||
case "SET_ISSUE_VIEW": {
|
case "SET_DISPLAY_FILTERS": {
|
||||||
const newState = {
|
const newState = {
|
||||||
...state,
|
...state,
|
||||||
issueView: payload?.issueView || "list",
|
display_filters: {
|
||||||
};
|
...state.display_filters,
|
||||||
|
...payload,
|
||||||
return {
|
},
|
||||||
...state,
|
issueView: payload?.display_filters?.layout || "list",
|
||||||
...newState,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
case "SET_GROUP_BY_PROPERTY": {
|
|
||||||
const newState = {
|
|
||||||
...state,
|
|
||||||
groupByProperty: payload?.groupByProperty || null,
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
...newState,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
case "SET_ORDER_BY_PROPERTY": {
|
|
||||||
const newState = {
|
|
||||||
...state,
|
|
||||||
orderBy: payload?.orderBy || "-created_at",
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
...newState,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
case "SET_SHOW_EMPTY_STATES": {
|
|
||||||
const newState = {
|
|
||||||
...state,
|
|
||||||
showEmptyGroups: payload?.showEmptyGroups || true,
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
...newState,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
case "SET_SHOW_SUB_ISSUES": {
|
|
||||||
const newState = {
|
|
||||||
...state,
|
|
||||||
showSubIssues: payload?.showSubIssues || true,
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
...newState,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
case "SET_CALENDAR_DATE_RANGE": {
|
|
||||||
const newState = {
|
|
||||||
...state,
|
|
||||||
calendarDateRange: payload?.calendarDateRange || "",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -210,9 +123,13 @@ export const reducer: ReducerFunctionType = (state, action) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const saveDataToServer = async (workspaceSlug: string, projectID: string, state: any) => {
|
const saveDataToServer = async (
|
||||||
|
workspaceSlug: string,
|
||||||
|
projectId: string,
|
||||||
|
state: IProjectViewProps
|
||||||
|
) => {
|
||||||
mutate<IProjectMember>(
|
mutate<IProjectMember>(
|
||||||
workspaceSlug && projectID ? USER_PROJECT_VIEW(projectID as string) : null,
|
workspaceSlug && projectId ? USER_PROJECT_VIEW(projectId as string) : null,
|
||||||
(prevData) => {
|
(prevData) => {
|
||||||
if (!prevData) return prevData;
|
if (!prevData) return prevData;
|
||||||
|
|
||||||
@ -224,7 +141,7 @@ const saveDataToServer = async (workspaceSlug: string, projectID: string, state:
|
|||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
await projectService.setProjectView(workspaceSlug, projectID, {
|
await projectService.setProjectView(workspaceSlug, projectId, {
|
||||||
view_props: state,
|
view_props: state,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -354,44 +271,57 @@ export const IssueViewContextProvider: React.FC<{ children: React.ReactNode }> =
|
|||||||
: null
|
: null
|
||||||
);
|
);
|
||||||
|
|
||||||
const setIssueView = useCallback(
|
const setDisplayFilters = useCallback(
|
||||||
(property: TIssueViewOptions) => {
|
(displayFilter: Partial<IIssueDisplayFilterOptions>) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: "SET_ISSUE_VIEW",
|
type: "SET_DISPLAY_FILTERS",
|
||||||
payload: {
|
payload: {
|
||||||
issueView: property,
|
display_filters: {
|
||||||
|
...state.display_filters,
|
||||||
|
...displayFilter,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const additionalProperties = {
|
const additionalProperties: Partial<IIssueDisplayFilterOptions> = {
|
||||||
groupByProperty: state.groupByProperty,
|
group_by: displayFilter.group_by ?? state.display_filters?.group_by,
|
||||||
orderBy: state.orderBy,
|
order_by: displayFilter.order_by ?? state.display_filters?.order_by,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (property === "kanban" && state.groupByProperty === null) {
|
if (
|
||||||
additionalProperties.groupByProperty = "state";
|
displayFilter.layout &&
|
||||||
|
displayFilter.layout === "kanban" &&
|
||||||
|
state.display_filters?.group_by === null
|
||||||
|
) {
|
||||||
|
additionalProperties.group_by = "state";
|
||||||
dispatch({
|
dispatch({
|
||||||
type: "SET_GROUP_BY_PROPERTY",
|
type: "SET_DISPLAY_FILTERS",
|
||||||
payload: {
|
payload: {
|
||||||
groupByProperty: "state",
|
display_filters: {
|
||||||
|
group_by: "state",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (property === "calendar") {
|
if (displayFilter.layout && displayFilter.layout === "calendar") {
|
||||||
additionalProperties.groupByProperty = null;
|
additionalProperties.group_by = null;
|
||||||
dispatch({
|
dispatch({
|
||||||
type: "SET_GROUP_BY_PROPERTY",
|
type: "SET_DISPLAY_FILTERS",
|
||||||
payload: {
|
payload: {
|
||||||
groupByProperty: null,
|
display_filters: {
|
||||||
|
group_by: null,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (property === "gantt_chart") {
|
if (displayFilter.layout && displayFilter.layout === "gantt_chart") {
|
||||||
additionalProperties.orderBy = "sort_order";
|
additionalProperties.order_by = "sort_order";
|
||||||
dispatch({
|
dispatch({
|
||||||
type: "SET_ORDER_BY_PROPERTY",
|
type: "SET_DISPLAY_FILTERS",
|
||||||
payload: {
|
payload: {
|
||||||
orderBy: "sort_order",
|
display_filters: {
|
||||||
|
order_by: "sort_order",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -400,168 +330,16 @@ export const IssueViewContextProvider: React.FC<{ children: React.ReactNode }> =
|
|||||||
|
|
||||||
saveDataToServer(workspaceSlug as string, projectId as string, {
|
saveDataToServer(workspaceSlug as string, projectId as string, {
|
||||||
...state,
|
...state,
|
||||||
issueView: property,
|
display_filters: {
|
||||||
...additionalProperties,
|
...state.display_filters,
|
||||||
|
...displayFilter,
|
||||||
|
...additionalProperties,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[workspaceSlug, projectId, state]
|
[workspaceSlug, projectId, state]
|
||||||
);
|
);
|
||||||
|
|
||||||
const setGroupByProperty = useCallback(
|
|
||||||
(property: TIssueGroupByOptions) => {
|
|
||||||
dispatch({
|
|
||||||
type: "SET_GROUP_BY_PROPERTY",
|
|
||||||
payload: {
|
|
||||||
groupByProperty: property,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!workspaceSlug || !projectId) return;
|
|
||||||
|
|
||||||
mutateMyViewProps((prevData: any) => {
|
|
||||||
if (!prevData) return prevData;
|
|
||||||
|
|
||||||
return {
|
|
||||||
...prevData,
|
|
||||||
view_props: {
|
|
||||||
...state,
|
|
||||||
groupByProperty: property,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}, false);
|
|
||||||
|
|
||||||
saveDataToServer(workspaceSlug as string, projectId as string, {
|
|
||||||
...state,
|
|
||||||
groupByProperty: property,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
[projectId, workspaceSlug, state, mutateMyViewProps]
|
|
||||||
);
|
|
||||||
|
|
||||||
const setOrderBy = useCallback(
|
|
||||||
(property: TIssueOrderByOptions) => {
|
|
||||||
dispatch({
|
|
||||||
type: "SET_ORDER_BY_PROPERTY",
|
|
||||||
payload: {
|
|
||||||
orderBy: property,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!workspaceSlug || !projectId) return;
|
|
||||||
|
|
||||||
mutateMyViewProps((prevData: any) => {
|
|
||||||
if (!prevData) return prevData;
|
|
||||||
|
|
||||||
return {
|
|
||||||
...prevData,
|
|
||||||
view_props: {
|
|
||||||
...state,
|
|
||||||
orderBy: property,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}, false);
|
|
||||||
|
|
||||||
saveDataToServer(workspaceSlug as string, projectId as string, {
|
|
||||||
...state,
|
|
||||||
orderBy: property,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
[projectId, workspaceSlug, state, mutateMyViewProps]
|
|
||||||
);
|
|
||||||
|
|
||||||
const setShowEmptyGroups = useCallback(
|
|
||||||
(property: boolean) => {
|
|
||||||
dispatch({
|
|
||||||
type: "SET_SHOW_EMPTY_STATES",
|
|
||||||
payload: {
|
|
||||||
showEmptyGroups: property,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!workspaceSlug || !projectId) return;
|
|
||||||
|
|
||||||
mutateMyViewProps((prevData: any) => {
|
|
||||||
if (!prevData) return prevData;
|
|
||||||
|
|
||||||
return {
|
|
||||||
...prevData,
|
|
||||||
view_props: {
|
|
||||||
...state,
|
|
||||||
showEmptyGroups: property,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}, false);
|
|
||||||
|
|
||||||
saveDataToServer(workspaceSlug as string, projectId as string, {
|
|
||||||
...state,
|
|
||||||
showEmptyGroups: property,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
[projectId, workspaceSlug, state, mutateMyViewProps]
|
|
||||||
);
|
|
||||||
|
|
||||||
const setShowSubIssues = useCallback(
|
|
||||||
(property: boolean) => {
|
|
||||||
dispatch({
|
|
||||||
type: "SET_SHOW_SUB_ISSUES",
|
|
||||||
payload: {
|
|
||||||
showSubIssues: property,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!workspaceSlug || !projectId) return;
|
|
||||||
|
|
||||||
mutateMyViewProps((prevData: any) => {
|
|
||||||
if (!prevData) return prevData;
|
|
||||||
|
|
||||||
return {
|
|
||||||
...prevData,
|
|
||||||
view_props: {
|
|
||||||
...state,
|
|
||||||
showSubIssues: property,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}, false);
|
|
||||||
|
|
||||||
saveDataToServer(workspaceSlug as string, projectId as string, {
|
|
||||||
...state,
|
|
||||||
showSubIssues: property,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
[projectId, workspaceSlug, state, mutateMyViewProps]
|
|
||||||
);
|
|
||||||
|
|
||||||
const setCalendarDateRange = useCallback(
|
|
||||||
(value: string) => {
|
|
||||||
dispatch({
|
|
||||||
type: "SET_CALENDAR_DATE_RANGE",
|
|
||||||
payload: {
|
|
||||||
calendarDateRange: value,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!workspaceSlug || !projectId) return;
|
|
||||||
|
|
||||||
mutateMyViewProps((prevData: any) => {
|
|
||||||
if (!prevData) return prevData;
|
|
||||||
|
|
||||||
return {
|
|
||||||
...prevData,
|
|
||||||
view_props: {
|
|
||||||
...state,
|
|
||||||
calendarDateRange: value,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}, false);
|
|
||||||
|
|
||||||
saveDataToServer(workspaceSlug as string, projectId as string, {
|
|
||||||
...state,
|
|
||||||
calendarDateRange: value,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
[projectId, workspaceSlug, state, mutateMyViewProps]
|
|
||||||
);
|
|
||||||
|
|
||||||
const setFilters = useCallback(
|
const setFilters = useCallback(
|
||||||
(property: Partial<IIssueFilterOptions>, saveToServer = true) => {
|
(property: Partial<IIssueFilterOptions>, saveToServer = true) => {
|
||||||
Object.keys(property).forEach((key) => {
|
Object.keys(property).forEach((key) => {
|
||||||
@ -717,12 +495,13 @@ export const IssueViewContextProvider: React.FC<{ children: React.ReactNode }> =
|
|||||||
payload: myViewProps?.default_props,
|
payload: myViewProps?.default_props,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!workspaceSlug || !projectId) return;
|
if (!workspaceSlug || !projectId || !myViewProps) return;
|
||||||
|
|
||||||
saveDataToServer(workspaceSlug as string, projectId as string, myViewProps?.default_props);
|
saveDataToServer(workspaceSlug as string, projectId as string, myViewProps.default_props);
|
||||||
}, [projectId, workspaceSlug, myViewProps]);
|
}, [projectId, workspaceSlug, myViewProps]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
console.log("running");
|
||||||
dispatch({
|
dispatch({
|
||||||
type: "REHYDRATE_THEME",
|
type: "REHYDRATE_THEME",
|
||||||
payload: {
|
payload: {
|
||||||
@ -743,22 +522,12 @@ export const IssueViewContextProvider: React.FC<{ children: React.ReactNode }> =
|
|||||||
return (
|
return (
|
||||||
<issueViewContext.Provider
|
<issueViewContext.Provider
|
||||||
value={{
|
value={{
|
||||||
issueView: state.issueView,
|
display_filters: state.display_filters,
|
||||||
groupByProperty: state.groupByProperty,
|
setDisplayFilters,
|
||||||
setGroupByProperty,
|
|
||||||
orderBy: state.orderBy,
|
|
||||||
showEmptyGroups: state.showEmptyGroups,
|
|
||||||
showSubIssues: state.showSubIssues,
|
|
||||||
calendarDateRange: state.calendarDateRange,
|
|
||||||
setCalendarDateRange,
|
|
||||||
setOrderBy,
|
|
||||||
setShowEmptyGroups,
|
|
||||||
setShowSubIssues,
|
|
||||||
filters: state.filters,
|
filters: state.filters,
|
||||||
setFilters,
|
setFilters,
|
||||||
resetFilterToDefault: resetToDefault,
|
resetFilterToDefault: resetToDefault,
|
||||||
setNewFilterDefaultView: setNewDefaultView,
|
setNewFilterDefaultView: setNewDefaultView,
|
||||||
setIssueView,
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ToastAlert />
|
<ToastAlert />
|
||||||
|
@ -5,66 +5,36 @@ import ToastAlert from "components/toast-alert";
|
|||||||
// types
|
// types
|
||||||
import {
|
import {
|
||||||
IIssueFilterOptions,
|
IIssueFilterOptions,
|
||||||
TIssueViewOptions,
|
|
||||||
TIssueGroupByOptions,
|
|
||||||
TIssueOrderByOptions,
|
|
||||||
Properties,
|
Properties,
|
||||||
|
IWorkspaceViewProps,
|
||||||
|
IIssueDisplayFilterOptions,
|
||||||
} from "types";
|
} from "types";
|
||||||
|
|
||||||
export const profileIssuesContext = createContext<ContextType>({} as ContextType);
|
export const profileIssuesContext = createContext<ContextType>({} as ContextType);
|
||||||
|
|
||||||
type IssueViewProps = {
|
|
||||||
issueView: TIssueViewOptions;
|
|
||||||
groupByProperty: TIssueGroupByOptions;
|
|
||||||
orderBy: TIssueOrderByOptions;
|
|
||||||
showEmptyGroups: boolean;
|
|
||||||
showSubIssues: boolean;
|
|
||||||
filters: IIssueFilterOptions;
|
|
||||||
properties: Properties;
|
|
||||||
};
|
|
||||||
|
|
||||||
type ReducerActionType = {
|
type ReducerActionType = {
|
||||||
type:
|
type: "SET_DISPLAY_FILTERS" | "SET_FILTERS" | "SET_PROPERTIES" | "RESET_TO_DEFAULT";
|
||||||
| "SET_ISSUE_VIEW"
|
payload?: Partial<IWorkspaceViewProps>;
|
||||||
| "SET_ORDER_BY_PROPERTY"
|
|
||||||
| "SET_SHOW_EMPTY_STATES"
|
|
||||||
| "SET_FILTERS"
|
|
||||||
| "SET_PROPERTIES"
|
|
||||||
| "SET_GROUP_BY_PROPERTY"
|
|
||||||
| "RESET_TO_DEFAULT"
|
|
||||||
| "SET_SHOW_SUB_ISSUES";
|
|
||||||
payload?: Partial<IssueViewProps>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type ContextType = IssueViewProps & {
|
type ContextType = IWorkspaceViewProps & {
|
||||||
setGroupByProperty: (property: TIssueGroupByOptions) => void;
|
setDisplayFilters: (displayFilter: Partial<IIssueDisplayFilterOptions>) => void;
|
||||||
setOrderBy: (property: TIssueOrderByOptions) => void;
|
|
||||||
setShowEmptyGroups: (property: boolean) => void;
|
|
||||||
setShowSubIssues: (value: boolean) => void;
|
|
||||||
setFilters: (filters: Partial<IIssueFilterOptions>) => void;
|
setFilters: (filters: Partial<IIssueFilterOptions>) => void;
|
||||||
setProperties: (key: keyof Properties) => void;
|
setProperties: (key: keyof Properties) => void;
|
||||||
setIssueView: (property: TIssueViewOptions) => void;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type StateType = {
|
type StateType = IWorkspaceViewProps;
|
||||||
issueView: TIssueViewOptions;
|
|
||||||
groupByProperty: TIssueGroupByOptions;
|
|
||||||
orderBy: TIssueOrderByOptions;
|
|
||||||
showEmptyGroups: boolean;
|
|
||||||
showSubIssues: boolean;
|
|
||||||
filters: IIssueFilterOptions;
|
|
||||||
properties: Properties;
|
|
||||||
};
|
|
||||||
type ReducerFunctionType = (state: StateType, action: ReducerActionType) => StateType;
|
type ReducerFunctionType = (state: StateType, action: ReducerActionType) => StateType;
|
||||||
|
|
||||||
export const initialState: StateType = {
|
export const initialState: StateType = {
|
||||||
issueView: "list",
|
display_filters: {
|
||||||
groupByProperty: null,
|
group_by: null,
|
||||||
orderBy: "-created_at",
|
layout: "list",
|
||||||
showEmptyGroups: true,
|
order_by: "-created_at",
|
||||||
showSubIssues: true,
|
show_empty_groups: true,
|
||||||
|
sub_issue: true,
|
||||||
|
},
|
||||||
filters: {
|
filters: {
|
||||||
type: null,
|
|
||||||
priority: null,
|
priority: null,
|
||||||
assignees: null,
|
assignees: null,
|
||||||
labels: null,
|
labels: null,
|
||||||
@ -75,7 +45,7 @@ export const initialState: StateType = {
|
|||||||
start_date: null,
|
start_date: null,
|
||||||
target_date: null,
|
target_date: null,
|
||||||
},
|
},
|
||||||
properties: {
|
display_properties: {
|
||||||
assignee: true,
|
assignee: true,
|
||||||
start_date: true,
|
start_date: true,
|
||||||
due_date: true,
|
due_date: true,
|
||||||
@ -96,58 +66,14 @@ export const reducer: ReducerFunctionType = (state, action) => {
|
|||||||
const { type, payload } = action;
|
const { type, payload } = action;
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "SET_ISSUE_VIEW": {
|
case "SET_DISPLAY_FILTERS": {
|
||||||
const newState = {
|
const newState = {
|
||||||
...state,
|
...state,
|
||||||
issueView: payload?.issueView || "list",
|
display_filters: {
|
||||||
};
|
...state.display_filters,
|
||||||
|
...payload,
|
||||||
return {
|
},
|
||||||
...state,
|
issueView: payload?.display_filters?.layout || "list",
|
||||||
...newState,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
case "SET_GROUP_BY_PROPERTY": {
|
|
||||||
const newState = {
|
|
||||||
...state,
|
|
||||||
groupByProperty: payload?.groupByProperty || null,
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
...newState,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
case "SET_ORDER_BY_PROPERTY": {
|
|
||||||
const newState = {
|
|
||||||
...state,
|
|
||||||
orderBy: payload?.orderBy || "-created_at",
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
...newState,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
case "SET_SHOW_EMPTY_STATES": {
|
|
||||||
const newState = {
|
|
||||||
...state,
|
|
||||||
showEmptyGroups: payload?.showEmptyGroups || true,
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
...newState,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
case "SET_SHOW_SUB_ISSUES": {
|
|
||||||
const newState = {
|
|
||||||
...state,
|
|
||||||
showSubIssues: payload?.showSubIssues || true,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -175,8 +101,8 @@ export const reducer: ReducerFunctionType = (state, action) => {
|
|||||||
const newState = {
|
const newState = {
|
||||||
...state,
|
...state,
|
||||||
properties: {
|
properties: {
|
||||||
...state.properties,
|
...state.display_properties,
|
||||||
...payload?.properties,
|
...payload?.display_properties,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -197,20 +123,29 @@ export const ProfileIssuesContextProvider: React.FC<{ children: React.ReactNode
|
|||||||
}) => {
|
}) => {
|
||||||
const [state, dispatch] = useReducer(reducer, initialState);
|
const [state, dispatch] = useReducer(reducer, initialState);
|
||||||
|
|
||||||
const setIssueView = useCallback(
|
const setDisplayFilters = useCallback(
|
||||||
(property: TIssueViewOptions) => {
|
(displayFilter: Partial<IIssueDisplayFilterOptions>) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: "SET_ISSUE_VIEW",
|
type: "SET_DISPLAY_FILTERS",
|
||||||
payload: {
|
payload: {
|
||||||
issueView: property,
|
display_filters: {
|
||||||
|
...state.display_filters,
|
||||||
|
...displayFilter,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (property === "kanban" && state.groupByProperty === null) {
|
if (
|
||||||
|
displayFilter.layout &&
|
||||||
|
displayFilter.layout === "kanban" &&
|
||||||
|
state.display_filters.group_by === null
|
||||||
|
) {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: "SET_GROUP_BY_PROPERTY",
|
type: "SET_DISPLAY_FILTERS",
|
||||||
payload: {
|
payload: {
|
||||||
groupByProperty: "state_detail.group",
|
display_filters: {
|
||||||
|
group_by: "state_detail.group",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -218,42 +153,6 @@ export const ProfileIssuesContextProvider: React.FC<{ children: React.ReactNode
|
|||||||
[state]
|
[state]
|
||||||
);
|
);
|
||||||
|
|
||||||
const setGroupByProperty = useCallback((property: TIssueGroupByOptions) => {
|
|
||||||
dispatch({
|
|
||||||
type: "SET_GROUP_BY_PROPERTY",
|
|
||||||
payload: {
|
|
||||||
groupByProperty: property,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const setOrderBy = useCallback((property: TIssueOrderByOptions) => {
|
|
||||||
dispatch({
|
|
||||||
type: "SET_ORDER_BY_PROPERTY",
|
|
||||||
payload: {
|
|
||||||
orderBy: property,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const setShowEmptyGroups = useCallback((property: boolean) => {
|
|
||||||
dispatch({
|
|
||||||
type: "SET_SHOW_EMPTY_STATES",
|
|
||||||
payload: {
|
|
||||||
showEmptyGroups: property,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const setShowSubIssues = useCallback((property: boolean) => {
|
|
||||||
dispatch({
|
|
||||||
type: "SET_SHOW_SUB_ISSUES",
|
|
||||||
payload: {
|
|
||||||
showSubIssues: property,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const setFilters = useCallback(
|
const setFilters = useCallback(
|
||||||
(property: Partial<IIssueFilterOptions>) => {
|
(property: Partial<IIssueFilterOptions>) => {
|
||||||
Object.keys(property).forEach((key) => {
|
Object.keys(property).forEach((key) => {
|
||||||
@ -279,9 +178,9 @@ export const ProfileIssuesContextProvider: React.FC<{ children: React.ReactNode
|
|||||||
dispatch({
|
dispatch({
|
||||||
type: "SET_PROPERTIES",
|
type: "SET_PROPERTIES",
|
||||||
payload: {
|
payload: {
|
||||||
properties: {
|
display_properties: {
|
||||||
...state.properties,
|
...state.display_properties,
|
||||||
[key]: !state.properties[key],
|
[key]: !state.display_properties[key],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -292,19 +191,11 @@ export const ProfileIssuesContextProvider: React.FC<{ children: React.ReactNode
|
|||||||
return (
|
return (
|
||||||
<profileIssuesContext.Provider
|
<profileIssuesContext.Provider
|
||||||
value={{
|
value={{
|
||||||
issueView: state.issueView,
|
display_filters: state.display_filters,
|
||||||
setIssueView,
|
setDisplayFilters,
|
||||||
groupByProperty: state.groupByProperty,
|
|
||||||
setGroupByProperty,
|
|
||||||
orderBy: state.orderBy,
|
|
||||||
setOrderBy,
|
|
||||||
showEmptyGroups: state.showEmptyGroups,
|
|
||||||
setShowEmptyGroups,
|
|
||||||
showSubIssues: state.showSubIssues,
|
|
||||||
setShowSubIssues,
|
|
||||||
filters: state.filters,
|
filters: state.filters,
|
||||||
setFilters,
|
setFilters,
|
||||||
properties: state.properties,
|
display_properties: state.display_properties,
|
||||||
setProperties,
|
setProperties,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -12,12 +12,12 @@ const useGanttChartCycleIssues = (
|
|||||||
projectId: string | undefined,
|
projectId: string | undefined,
|
||||||
cycleId: string | undefined
|
cycleId: string | undefined
|
||||||
) => {
|
) => {
|
||||||
const { orderBy, filters, showSubIssues } = useIssuesView();
|
const { displayFilters, filters } = useIssuesView();
|
||||||
|
|
||||||
const params: any = {
|
const params: any = {
|
||||||
order_by: orderBy,
|
order_by: displayFilters.order_by,
|
||||||
type: filters?.type ? filters?.type : undefined,
|
type: displayFilters?.type ? displayFilters?.type : undefined,
|
||||||
sub_issue: showSubIssues,
|
sub_issue: displayFilters.sub_issue,
|
||||||
assignees: filters?.assignees ? filters?.assignees.join(",") : undefined,
|
assignees: filters?.assignees ? filters?.assignees.join(",") : undefined,
|
||||||
state: filters?.state ? filters?.state.join(",") : undefined,
|
state: filters?.state ? filters?.state.join(",") : undefined,
|
||||||
priority: filters?.priority ? filters?.priority.join(",") : undefined,
|
priority: filters?.priority ? filters?.priority.join(",") : undefined,
|
||||||
|
@ -8,12 +8,12 @@ import useIssuesView from "hooks/use-issues-view";
|
|||||||
import { PROJECT_ISSUES_LIST_WITH_PARAMS } from "constants/fetch-keys";
|
import { PROJECT_ISSUES_LIST_WITH_PARAMS } from "constants/fetch-keys";
|
||||||
|
|
||||||
const useGanttChartIssues = (workspaceSlug: string | undefined, projectId: string | undefined) => {
|
const useGanttChartIssues = (workspaceSlug: string | undefined, projectId: string | undefined) => {
|
||||||
const { orderBy, filters, showSubIssues } = useIssuesView();
|
const { displayFilters, filters } = useIssuesView();
|
||||||
|
|
||||||
const params: any = {
|
const params: any = {
|
||||||
order_by: orderBy,
|
order_by: displayFilters.order_by,
|
||||||
type: filters?.type ? filters?.type : undefined,
|
type: displayFilters?.type ? displayFilters?.type : undefined,
|
||||||
sub_issue: showSubIssues,
|
sub_issue: displayFilters.sub_issue,
|
||||||
assignees: filters?.assignees ? filters?.assignees.join(",") : undefined,
|
assignees: filters?.assignees ? filters?.assignees.join(",") : undefined,
|
||||||
state: filters?.state ? filters?.state.join(",") : undefined,
|
state: filters?.state ? filters?.state.join(",") : undefined,
|
||||||
priority: filters?.priority ? filters?.priority.join(",") : undefined,
|
priority: filters?.priority ? filters?.priority.join(",") : undefined,
|
||||||
|
@ -12,12 +12,12 @@ const useGanttChartModuleIssues = (
|
|||||||
projectId: string | undefined,
|
projectId: string | undefined,
|
||||||
moduleId: string | undefined
|
moduleId: string | undefined
|
||||||
) => {
|
) => {
|
||||||
const { orderBy, filters, showSubIssues } = useIssuesView();
|
const { displayFilters, filters } = useIssuesView();
|
||||||
|
|
||||||
const params: any = {
|
const params: any = {
|
||||||
order_by: orderBy,
|
order_by: displayFilters.order_by,
|
||||||
type: filters?.type ? filters?.type : undefined,
|
type: displayFilters?.type ? displayFilters?.type : undefined,
|
||||||
sub_issue: showSubIssues,
|
sub_issue: displayFilters.sub_issue,
|
||||||
assignees: filters?.assignees ? filters?.assignees.join(",") : undefined,
|
assignees: filters?.assignees ? filters?.assignees.join(",") : undefined,
|
||||||
state: filters?.state ? filters?.state.join(",") : undefined,
|
state: filters?.state ? filters?.state.join(",") : undefined,
|
||||||
priority: filters?.priority ? filters?.priority.join(",") : undefined,
|
priority: filters?.priority ? filters?.priority.join(",") : undefined,
|
||||||
|
@ -6,33 +6,25 @@ import useSWR, { mutate } from "swr";
|
|||||||
import workspaceService from "services/workspace.service";
|
import workspaceService from "services/workspace.service";
|
||||||
// types
|
// types
|
||||||
import {
|
import {
|
||||||
|
IIssueDisplayFilterOptions,
|
||||||
IIssueFilterOptions,
|
IIssueFilterOptions,
|
||||||
IWorkspaceMember,
|
IWorkspaceMember,
|
||||||
IWorkspaceViewProps,
|
IWorkspaceViewProps,
|
||||||
Properties,
|
Properties,
|
||||||
TIssueGroupByOptions,
|
|
||||||
TIssueOrderByOptions,
|
|
||||||
TIssueViewOptions,
|
|
||||||
} from "types";
|
} from "types";
|
||||||
// fetch-keys
|
// fetch-keys
|
||||||
import { WORKSPACE_MEMBERS_ME } from "constants/fetch-keys";
|
import { WORKSPACE_MEMBERS_ME } from "constants/fetch-keys";
|
||||||
|
|
||||||
const initialValues: IWorkspaceViewProps = {
|
const initialValues: IWorkspaceViewProps = {
|
||||||
issueView: "list",
|
display_filters: {
|
||||||
filters: {
|
group_by: null,
|
||||||
assignees: null,
|
layout: "list",
|
||||||
created_by: null,
|
order_by: "-created_at",
|
||||||
labels: null,
|
show_empty_groups: true,
|
||||||
priority: null,
|
sub_issue: true,
|
||||||
state_group: null,
|
|
||||||
subscriber: null,
|
|
||||||
start_date: null,
|
|
||||||
target_date: null,
|
|
||||||
type: null,
|
type: null,
|
||||||
},
|
},
|
||||||
groupByProperty: null,
|
display_properties: {
|
||||||
orderBy: "-created_at",
|
|
||||||
properties: {
|
|
||||||
assignee: true,
|
assignee: true,
|
||||||
start_date: true,
|
start_date: true,
|
||||||
due_date: true,
|
due_date: true,
|
||||||
@ -47,7 +39,16 @@ const initialValues: IWorkspaceViewProps = {
|
|||||||
created_on: true,
|
created_on: true,
|
||||||
updated_on: true,
|
updated_on: true,
|
||||||
},
|
},
|
||||||
showEmptyGroups: true,
|
filters: {
|
||||||
|
assignees: null,
|
||||||
|
created_by: null,
|
||||||
|
labels: null,
|
||||||
|
priority: null,
|
||||||
|
state_group: null,
|
||||||
|
subscriber: null,
|
||||||
|
start_date: null,
|
||||||
|
target_date: null,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const useMyIssuesFilters = (workspaceSlug: string | undefined) => {
|
const useMyIssuesFilters = (workspaceSlug: string | undefined) => {
|
||||||
@ -90,59 +91,39 @@ const useMyIssuesFilters = (workspaceSlug: string | undefined) => {
|
|||||||
[myWorkspace, workspaceSlug]
|
[myWorkspace, workspaceSlug]
|
||||||
);
|
);
|
||||||
|
|
||||||
const issueView = (myWorkspace?.view_props ?? initialValues).issueView;
|
const groupBy = (myWorkspace?.view_props ?? initialValues).display_filters.group_by;
|
||||||
const groupBy = (myWorkspace?.view_props ?? initialValues).groupByProperty;
|
|
||||||
const orderBy = (myWorkspace?.view_props ?? initialValues).orderBy;
|
|
||||||
const showEmptyGroups = (myWorkspace?.view_props ?? initialValues).showEmptyGroups;
|
|
||||||
const filters = (myWorkspace?.view_props ?? initialValues).filters;
|
const filters = (myWorkspace?.view_props ?? initialValues).filters;
|
||||||
|
|
||||||
const setIssueView = useCallback(
|
const setDisplayFilters = useCallback(
|
||||||
(newView: TIssueViewOptions) => {
|
(displayFilter: Partial<IIssueDisplayFilterOptions>) => {
|
||||||
const payload: Partial<IWorkspaceViewProps> = {
|
const payload: Partial<IWorkspaceViewProps> = {
|
||||||
issueView: newView,
|
display_filters: {
|
||||||
|
...myWorkspace?.view_props?.display_filters,
|
||||||
|
...displayFilter,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
if (newView === "kanban" && groupBy === null) payload.groupByProperty = "state_detail.group";
|
if (
|
||||||
|
displayFilter.layout &&
|
||||||
|
displayFilter.layout === "kanban" &&
|
||||||
|
groupBy === null &&
|
||||||
|
payload.display_filters
|
||||||
|
)
|
||||||
|
payload.display_filters.group_by = "state_detail.group";
|
||||||
|
|
||||||
saveData(payload);
|
saveData(payload);
|
||||||
},
|
},
|
||||||
[groupBy, saveData]
|
[groupBy, myWorkspace?.view_props.display_filters, saveData]
|
||||||
);
|
);
|
||||||
|
|
||||||
const setGroupBy = useCallback(
|
|
||||||
(newGroup: TIssueGroupByOptions) => {
|
|
||||||
saveData({
|
|
||||||
groupByProperty: newGroup,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
[saveData]
|
|
||||||
);
|
|
||||||
|
|
||||||
const setOrderBy = useCallback(
|
|
||||||
(newOrderBy: TIssueOrderByOptions) => {
|
|
||||||
saveData({
|
|
||||||
orderBy: newOrderBy,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
[saveData]
|
|
||||||
);
|
|
||||||
|
|
||||||
const setShowEmptyGroups = useCallback(() => {
|
|
||||||
if (!myWorkspace) return;
|
|
||||||
|
|
||||||
saveData({
|
|
||||||
showEmptyGroups: !myWorkspace?.view_props?.showEmptyGroups,
|
|
||||||
});
|
|
||||||
}, [myWorkspace, saveData]);
|
|
||||||
|
|
||||||
const setProperty = useCallback(
|
const setProperty = useCallback(
|
||||||
(key: keyof Properties) => {
|
(key: keyof Properties) => {
|
||||||
if (!myWorkspace) return;
|
if (!myWorkspace) return;
|
||||||
|
|
||||||
saveData({
|
saveData({
|
||||||
properties: {
|
display_properties: {
|
||||||
...myWorkspace.view_props?.properties,
|
...myWorkspace.view_props?.display_properties,
|
||||||
[key]: !myWorkspace.view_props?.properties[key],
|
[key]: !myWorkspace.view_props?.display_properties[key],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -174,30 +155,24 @@ const useMyIssuesFilters = (workspaceSlug: string | undefined) => {
|
|||||||
}, [myWorkspace, workspaceSlug]);
|
}, [myWorkspace, workspaceSlug]);
|
||||||
|
|
||||||
const newProperties: Properties = {
|
const newProperties: Properties = {
|
||||||
assignee: myWorkspace?.view_props.properties.assignee ?? true,
|
assignee: myWorkspace?.view_props.display_properties.assignee ?? true,
|
||||||
start_date: myWorkspace?.view_props.properties.start_date ?? true,
|
start_date: myWorkspace?.view_props.display_properties.start_date ?? true,
|
||||||
due_date: myWorkspace?.view_props.properties.due_date ?? true,
|
due_date: myWorkspace?.view_props.display_properties.due_date ?? true,
|
||||||
key: myWorkspace?.view_props.properties.key ?? true,
|
key: myWorkspace?.view_props.display_properties.key ?? true,
|
||||||
labels: myWorkspace?.view_props.properties.labels ?? true,
|
labels: myWorkspace?.view_props.display_properties.labels ?? true,
|
||||||
priority: myWorkspace?.view_props.properties.priority ?? true,
|
priority: myWorkspace?.view_props.display_properties.priority ?? true,
|
||||||
state: myWorkspace?.view_props.properties.state ?? true,
|
state: myWorkspace?.view_props.display_properties.state ?? true,
|
||||||
sub_issue_count: myWorkspace?.view_props.properties.sub_issue_count ?? true,
|
sub_issue_count: myWorkspace?.view_props.display_properties.sub_issue_count ?? true,
|
||||||
attachment_count: myWorkspace?.view_props.properties.attachment_count ?? true,
|
attachment_count: myWorkspace?.view_props.display_properties.attachment_count ?? true,
|
||||||
link: myWorkspace?.view_props.properties.link ?? true,
|
link: myWorkspace?.view_props.display_properties.link ?? true,
|
||||||
estimate: myWorkspace?.view_props.properties.estimate ?? true,
|
estimate: myWorkspace?.view_props.display_properties.estimate ?? true,
|
||||||
created_on: myWorkspace?.view_props.properties.created_on ?? true,
|
created_on: myWorkspace?.view_props.display_properties.created_on ?? true,
|
||||||
updated_on: myWorkspace?.view_props.properties.updated_on ?? true,
|
updated_on: myWorkspace?.view_props.display_properties.updated_on ?? true,
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
issueView,
|
displayFilters: myWorkspace?.view_props?.display_filters,
|
||||||
setIssueView,
|
setDisplayFilters,
|
||||||
groupBy,
|
|
||||||
setGroupBy,
|
|
||||||
orderBy,
|
|
||||||
setOrderBy,
|
|
||||||
showEmptyGroups,
|
|
||||||
setShowEmptyGroups,
|
|
||||||
properties: newProperties,
|
properties: newProperties,
|
||||||
setProperty,
|
setProperty,
|
||||||
filters,
|
filters,
|
||||||
|
@ -16,20 +16,20 @@ import { USER_ISSUES } from "constants/fetch-keys";
|
|||||||
const useMyIssues = (workspaceSlug: string | undefined) => {
|
const useMyIssues = (workspaceSlug: string | undefined) => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const { filters, groupBy, orderBy } = useMyIssuesFilters(workspaceSlug);
|
const { filters, displayFilters } = useMyIssuesFilters(workspaceSlug);
|
||||||
|
|
||||||
const params: any = {
|
const params: any = {
|
||||||
assignees: filters?.assignees ? filters?.assignees.join(",") : undefined,
|
assignees: filters?.assignees ? filters?.assignees.join(",") : undefined,
|
||||||
created_by: filters?.created_by ? filters?.created_by.join(",") : undefined,
|
created_by: filters?.created_by ? filters?.created_by.join(",") : undefined,
|
||||||
group_by: groupBy,
|
group_by: displayFilters?.group_by,
|
||||||
labels: filters?.labels ? filters?.labels.join(",") : undefined,
|
labels: filters?.labels ? filters?.labels.join(",") : undefined,
|
||||||
order_by: orderBy,
|
order_by: displayFilters?.order_by,
|
||||||
priority: filters?.priority ? filters?.priority.join(",") : undefined,
|
priority: filters?.priority ? filters?.priority.join(",") : undefined,
|
||||||
state_group: filters?.state_group ? filters?.state_group.join(",") : undefined,
|
state_group: filters?.state_group ? filters?.state_group.join(",") : undefined,
|
||||||
subscriber: filters?.subscriber ? filters?.subscriber.join(",") : undefined,
|
subscriber: filters?.subscriber ? filters?.subscriber.join(",") : undefined,
|
||||||
start_date: filters?.start_date ? filters?.start_date.join(",") : undefined,
|
start_date: filters?.start_date ? filters?.start_date.join(",") : undefined,
|
||||||
target_date: filters?.target_date ? filters?.target_date.join(",") : undefined,
|
target_date: filters?.target_date ? filters?.target_date.join(",") : undefined,
|
||||||
type: filters?.type ? filters?.type : undefined,
|
type: displayFilters?.type,
|
||||||
};
|
};
|
||||||
|
|
||||||
const { data: myIssues, mutate: mutateMyIssues } = useSWR(
|
const { data: myIssues, mutate: mutateMyIssues } = useSWR(
|
||||||
@ -53,7 +53,7 @@ const useMyIssues = (workspaceSlug: string | undefined) => {
|
|||||||
allIssues: myIssues,
|
allIssues: myIssues,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (groupBy === "state_detail.group") {
|
if (displayFilters?.group_by === "state_detail.group") {
|
||||||
return myIssues
|
return myIssues
|
||||||
? Object.assign(
|
? Object.assign(
|
||||||
{
|
{
|
||||||
@ -69,7 +69,7 @@ const useMyIssues = (workspaceSlug: string | undefined) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return myIssues;
|
return myIssues;
|
||||||
}, [groupBy, myIssues]);
|
}, [displayFilters, myIssues]);
|
||||||
|
|
||||||
const isEmpty =
|
const isEmpty =
|
||||||
Object.values(groupedIssues ?? {}).every((group) => group.length === 0) ||
|
Object.values(groupedIssues ?? {}).every((group) => group.length === 0) ||
|
||||||
|
@ -22,14 +22,12 @@ import {
|
|||||||
|
|
||||||
const useCalendarIssuesView = () => {
|
const useCalendarIssuesView = () => {
|
||||||
const {
|
const {
|
||||||
issueView,
|
display_filters: displayFilters,
|
||||||
calendarDateRange,
|
setDisplayFilters,
|
||||||
setCalendarDateRange,
|
|
||||||
filters,
|
filters,
|
||||||
setFilters,
|
setFilters,
|
||||||
resetFilterToDefault,
|
resetFilterToDefault,
|
||||||
setNewFilterDefaultView,
|
setNewFilterDefaultView,
|
||||||
setIssueView,
|
|
||||||
} = useContext(issueViewContext);
|
} = useContext(issueViewContext);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@ -39,11 +37,11 @@ const useCalendarIssuesView = () => {
|
|||||||
assignees: filters?.assignees ? filters?.assignees.join(",") : undefined,
|
assignees: filters?.assignees ? filters?.assignees.join(",") : undefined,
|
||||||
state: filters?.state ? filters?.state.join(",") : undefined,
|
state: filters?.state ? filters?.state.join(",") : undefined,
|
||||||
priority: filters?.priority ? filters?.priority.join(",") : undefined,
|
priority: filters?.priority ? filters?.priority.join(",") : undefined,
|
||||||
type: filters?.type ? filters?.type : undefined,
|
type: displayFilters?.type ? displayFilters?.type : undefined,
|
||||||
labels: filters?.labels ? filters?.labels.join(",") : undefined,
|
labels: filters?.labels ? filters?.labels.join(",") : undefined,
|
||||||
created_by: filters?.created_by ? filters?.created_by.join(",") : undefined,
|
created_by: filters?.created_by ? filters?.created_by.join(",") : undefined,
|
||||||
start_date: filters?.start_date ? filters?.start_date.join(",") : undefined,
|
start_date: filters?.start_date ? filters?.start_date.join(",") : undefined,
|
||||||
target_date: calendarDateRange,
|
target_date: displayFilters?.calendar_date_range,
|
||||||
};
|
};
|
||||||
|
|
||||||
const { data: projectCalendarIssues } = useSWR(
|
const { data: projectCalendarIssues } = useSWR(
|
||||||
@ -103,16 +101,14 @@ const useCalendarIssuesView = () => {
|
|||||||
: (projectCalendarIssues as IIssue[]);
|
: (projectCalendarIssues as IIssue[]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
issueView,
|
displayFilters,
|
||||||
|
setDisplayFilters,
|
||||||
calendarIssues: calendarIssues ?? [],
|
calendarIssues: calendarIssues ?? [],
|
||||||
calendarDateRange,
|
|
||||||
setCalendarDateRange,
|
|
||||||
filters,
|
filters,
|
||||||
setFilters,
|
setFilters,
|
||||||
params,
|
params,
|
||||||
resetFilterToDefault,
|
resetFilterToDefault,
|
||||||
setNewFilterDefaultView,
|
setNewFilterDefaultView,
|
||||||
setIssueView,
|
|
||||||
} as const;
|
} as const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -27,22 +27,12 @@ import {
|
|||||||
|
|
||||||
const useIssuesView = () => {
|
const useIssuesView = () => {
|
||||||
const {
|
const {
|
||||||
issueView,
|
display_filters: displayFilters,
|
||||||
groupByProperty,
|
setDisplayFilters,
|
||||||
setGroupByProperty,
|
|
||||||
orderBy,
|
|
||||||
setOrderBy,
|
|
||||||
showEmptyGroups,
|
|
||||||
showSubIssues,
|
|
||||||
setShowEmptyGroups,
|
|
||||||
setShowSubIssues,
|
|
||||||
calendarDateRange,
|
|
||||||
setCalendarDateRange,
|
|
||||||
filters,
|
filters,
|
||||||
setFilters,
|
setFilters,
|
||||||
resetFilterToDefault,
|
resetFilterToDefault,
|
||||||
setNewFilterDefaultView,
|
setNewFilterDefaultView,
|
||||||
setIssueView,
|
|
||||||
} = useContext(issueViewContext);
|
} = useContext(issueViewContext);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@ -50,17 +40,17 @@ const useIssuesView = () => {
|
|||||||
const isArchivedIssues = router.pathname.includes("archived-issues");
|
const isArchivedIssues = router.pathname.includes("archived-issues");
|
||||||
|
|
||||||
const params: any = {
|
const params: any = {
|
||||||
order_by: orderBy,
|
order_by: displayFilters?.order_by,
|
||||||
group_by: groupByProperty,
|
group_by: displayFilters?.group_by,
|
||||||
assignees: filters?.assignees ? filters?.assignees.join(",") : undefined,
|
assignees: filters?.assignees ? filters?.assignees.join(",") : undefined,
|
||||||
state: filters?.state ? filters?.state.join(",") : undefined,
|
state: filters?.state ? filters?.state.join(",") : undefined,
|
||||||
priority: filters?.priority ? filters?.priority.join(",") : undefined,
|
priority: filters?.priority ? filters?.priority.join(",") : undefined,
|
||||||
type: filters?.type ? filters?.type : undefined,
|
type: displayFilters?.type ? displayFilters?.type : undefined,
|
||||||
labels: filters?.labels ? filters?.labels.join(",") : undefined,
|
labels: filters?.labels ? filters?.labels.join(",") : undefined,
|
||||||
created_by: filters?.created_by ? filters?.created_by.join(",") : undefined,
|
created_by: filters?.created_by ? filters?.created_by.join(",") : undefined,
|
||||||
start_date: filters?.start_date ? filters?.start_date.join(",") : undefined,
|
start_date: filters?.start_date ? filters?.start_date.join(",") : undefined,
|
||||||
target_date: filters?.target_date ? filters?.target_date.join(",") : undefined,
|
target_date: filters?.target_date ? filters?.target_date.join(",") : undefined,
|
||||||
sub_issue: showSubIssues,
|
sub_issue: displayFilters?.sub_issue,
|
||||||
};
|
};
|
||||||
|
|
||||||
const { data: projectIssues, mutate: mutateProjectIssues } = useSWR(
|
const { data: projectIssues, mutate: mutateProjectIssues } = useSWR(
|
||||||
@ -133,9 +123,9 @@ const useIssuesView = () => {
|
|||||||
const backlogStatesList = statesList?.filter((state) => state.group === "backlog");
|
const backlogStatesList = statesList?.filter((state) => state.group === "backlog");
|
||||||
|
|
||||||
const stateIds =
|
const stateIds =
|
||||||
filters && filters?.type === "active"
|
displayFilters && displayFilters?.type === "active"
|
||||||
? activeStatesList?.map((state) => state.id)
|
? activeStatesList?.map((state) => state.id)
|
||||||
: filters?.type === "backlog"
|
: displayFilters?.type === "backlog"
|
||||||
? backlogStatesList?.map((state) => state.id)
|
? backlogStatesList?.map((state) => state.id)
|
||||||
: statesList?.map((state) => state.id);
|
: statesList?.map((state) => state.id);
|
||||||
|
|
||||||
@ -164,17 +154,17 @@ const useIssuesView = () => {
|
|||||||
: projectIssues;
|
: projectIssues;
|
||||||
|
|
||||||
if (Array.isArray(issuesToGroup)) return { allIssues: issuesToGroup };
|
if (Array.isArray(issuesToGroup)) return { allIssues: issuesToGroup };
|
||||||
if (groupByProperty === "state")
|
if (displayFilters?.group_by === "state")
|
||||||
return issuesToGroup ? Object.assign(emptyStatesObject, issuesToGroup) : undefined;
|
return issuesToGroup ? Object.assign(emptyStatesObject, issuesToGroup) : undefined;
|
||||||
|
|
||||||
return issuesToGroup;
|
return issuesToGroup;
|
||||||
}, [
|
}, [
|
||||||
|
displayFilters?.group_by,
|
||||||
projectIssues,
|
projectIssues,
|
||||||
cycleIssues,
|
cycleIssues,
|
||||||
moduleIssues,
|
moduleIssues,
|
||||||
viewIssues,
|
viewIssues,
|
||||||
projectArchivedIssues,
|
projectArchivedIssues,
|
||||||
groupByProperty,
|
|
||||||
cycleId,
|
cycleId,
|
||||||
moduleId,
|
moduleId,
|
||||||
viewId,
|
viewId,
|
||||||
@ -187,6 +177,11 @@ const useIssuesView = () => {
|
|||||||
Object.keys(groupedByIssues ?? {}).length === 0;
|
Object.keys(groupedByIssues ?? {}).length === 0;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
displayFilters: {
|
||||||
|
...displayFilters,
|
||||||
|
layout: isArchivedIssues ? "list" : displayFilters?.layout,
|
||||||
|
},
|
||||||
|
setDisplayFilters,
|
||||||
groupedByIssues,
|
groupedByIssues,
|
||||||
mutateIssues: cycleId
|
mutateIssues: cycleId
|
||||||
? mutateCycleIssues
|
? mutateCycleIssues
|
||||||
@ -197,24 +192,12 @@ const useIssuesView = () => {
|
|||||||
: isArchivedIssues
|
: isArchivedIssues
|
||||||
? mutateProjectArchivedIssues
|
? mutateProjectArchivedIssues
|
||||||
: mutateProjectIssues,
|
: mutateProjectIssues,
|
||||||
issueView: isArchivedIssues ? "list" : issueView,
|
|
||||||
groupByProperty,
|
|
||||||
setGroupByProperty,
|
|
||||||
orderBy,
|
|
||||||
setOrderBy,
|
|
||||||
showEmptyGroups: isArchivedIssues ? false : showEmptyGroups,
|
|
||||||
showSubIssues,
|
|
||||||
setShowEmptyGroups,
|
|
||||||
setShowSubIssues,
|
|
||||||
calendarDateRange,
|
|
||||||
setCalendarDateRange,
|
|
||||||
filters,
|
filters,
|
||||||
setFilters,
|
setFilters,
|
||||||
params,
|
params,
|
||||||
isEmpty,
|
isEmpty,
|
||||||
resetFilterToDefault,
|
resetFilterToDefault,
|
||||||
setNewFilterDefaultView,
|
setNewFilterDefaultView,
|
||||||
setIssueView,
|
|
||||||
} as const;
|
} as const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -16,19 +16,11 @@ import { useWorkspaceMyMembership } from "contexts/workspace-member.context";
|
|||||||
|
|
||||||
const useProfileIssues = (workspaceSlug: string | undefined, userId: string | undefined) => {
|
const useProfileIssues = (workspaceSlug: string | undefined, userId: string | undefined) => {
|
||||||
const {
|
const {
|
||||||
issueView,
|
display_filters: displayFilters,
|
||||||
setIssueView,
|
setDisplayFilters,
|
||||||
groupByProperty,
|
|
||||||
setGroupByProperty,
|
|
||||||
orderBy,
|
|
||||||
setOrderBy,
|
|
||||||
showEmptyGroups,
|
|
||||||
setShowEmptyGroups,
|
|
||||||
showSubIssues,
|
|
||||||
setShowSubIssues,
|
|
||||||
filters,
|
filters,
|
||||||
setFilters,
|
setFilters,
|
||||||
properties,
|
display_properties: displayProperties,
|
||||||
setProperties,
|
setProperties,
|
||||||
} = useContext(profileIssuesContext);
|
} = useContext(profileIssuesContext);
|
||||||
|
|
||||||
@ -39,14 +31,14 @@ const useProfileIssues = (workspaceSlug: string | undefined, userId: string | un
|
|||||||
const params: any = {
|
const params: any = {
|
||||||
assignees: filters?.assignees ? filters?.assignees.join(",") : undefined,
|
assignees: filters?.assignees ? filters?.assignees.join(",") : undefined,
|
||||||
created_by: filters?.created_by ? filters?.created_by.join(",") : undefined,
|
created_by: filters?.created_by ? filters?.created_by.join(",") : undefined,
|
||||||
group_by: groupByProperty,
|
group_by: displayFilters.group_by,
|
||||||
labels: filters?.labels ? filters?.labels.join(",") : undefined,
|
labels: filters?.labels ? filters?.labels.join(",") : undefined,
|
||||||
order_by: orderBy,
|
order_by: displayFilters.order_by,
|
||||||
priority: filters?.priority ? filters?.priority.join(",") : undefined,
|
priority: filters?.priority ? filters?.priority.join(",") : undefined,
|
||||||
state_group: filters?.state_group ? filters?.state_group.join(",") : undefined,
|
state_group: filters?.state_group ? filters?.state_group.join(",") : undefined,
|
||||||
start_date: filters?.start_date ? filters?.start_date.join(",") : undefined,
|
start_date: filters?.start_date ? filters?.start_date.join(",") : undefined,
|
||||||
target_date: filters?.target_date ? filters?.target_date.join(",") : undefined,
|
target_date: filters?.target_date ? filters?.target_date.join(",") : undefined,
|
||||||
type: filters?.type ? filters?.type : undefined,
|
type: displayFilters?.type ? displayFilters?.type : undefined,
|
||||||
subscriber: filters?.subscriber ? filters?.subscriber.join(",") : undefined,
|
subscriber: filters?.subscriber ? filters?.subscriber.join(",") : undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -71,7 +63,7 @@ const useProfileIssues = (workspaceSlug: string | undefined, userId: string | un
|
|||||||
allIssues: userProfileIssues,
|
allIssues: userProfileIssues,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (groupByProperty === "state_detail.group") {
|
if (displayFilters.group_by === "state_detail.group") {
|
||||||
return userProfileIssues
|
return userProfileIssues
|
||||||
? Object.assign(
|
? Object.assign(
|
||||||
{
|
{
|
||||||
@ -87,7 +79,7 @@ const useProfileIssues = (workspaceSlug: string | undefined, userId: string | un
|
|||||||
}
|
}
|
||||||
|
|
||||||
return userProfileIssues;
|
return userProfileIssues;
|
||||||
}, [groupByProperty, userProfileIssues]);
|
}, [displayFilters.group_by, userProfileIssues]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!userId || !filters) return;
|
if (!userId || !filters) return;
|
||||||
@ -120,19 +112,11 @@ const useProfileIssues = (workspaceSlug: string | undefined, userId: string | un
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
groupedIssues,
|
groupedIssues,
|
||||||
issueView,
|
displayFilters,
|
||||||
setIssueView,
|
setDisplayFilters,
|
||||||
groupByProperty,
|
|
||||||
setGroupByProperty,
|
|
||||||
orderBy,
|
|
||||||
setOrderBy,
|
|
||||||
showEmptyGroups,
|
|
||||||
setShowEmptyGroups,
|
|
||||||
showSubIssues,
|
|
||||||
setShowSubIssues,
|
|
||||||
filters,
|
filters,
|
||||||
setFilters,
|
setFilters,
|
||||||
properties,
|
displayProperties,
|
||||||
setProperties,
|
setProperties,
|
||||||
isEmpty,
|
isEmpty,
|
||||||
mutateProfileIssues,
|
mutateProfileIssues,
|
||||||
|
@ -22,25 +22,23 @@ import {
|
|||||||
|
|
||||||
const useSpreadsheetIssuesView = () => {
|
const useSpreadsheetIssuesView = () => {
|
||||||
const {
|
const {
|
||||||
issueView,
|
display_filters: displayFilters,
|
||||||
orderBy,
|
setDisplayFilters,
|
||||||
setOrderBy,
|
|
||||||
filters,
|
filters,
|
||||||
setFilters,
|
setFilters,
|
||||||
resetFilterToDefault,
|
resetFilterToDefault,
|
||||||
setNewFilterDefaultView,
|
setNewFilterDefaultView,
|
||||||
setIssueView,
|
|
||||||
} = useContext(issueViewContext);
|
} = useContext(issueViewContext);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId, cycleId, moduleId, viewId } = router.query;
|
const { workspaceSlug, projectId, cycleId, moduleId, viewId } = router.query;
|
||||||
|
|
||||||
const params: any = {
|
const params: any = {
|
||||||
order_by: orderBy,
|
order_by: displayFilters?.order_by,
|
||||||
assignees: filters?.assignees ? filters?.assignees.join(",") : undefined,
|
assignees: filters?.assignees ? filters?.assignees.join(",") : undefined,
|
||||||
state: filters?.state ? filters?.state.join(",") : undefined,
|
state: filters?.state ? filters?.state.join(",") : undefined,
|
||||||
priority: filters?.priority ? filters?.priority.join(",") : undefined,
|
priority: filters?.priority ? filters?.priority.join(",") : undefined,
|
||||||
type: filters?.type ? filters?.type : undefined,
|
type: displayFilters?.type ? displayFilters?.type : undefined,
|
||||||
labels: filters?.labels ? filters?.labels.join(",") : undefined,
|
labels: filters?.labels ? filters?.labels.join(",") : undefined,
|
||||||
created_by: filters?.created_by ? filters?.created_by.join(",") : undefined,
|
created_by: filters?.created_by ? filters?.created_by.join(",") : undefined,
|
||||||
start_date: filters?.start_date ? filters?.start_date.join(",") : undefined,
|
start_date: filters?.start_date ? filters?.start_date.join(",") : undefined,
|
||||||
@ -105,7 +103,8 @@ const useSpreadsheetIssuesView = () => {
|
|||||||
: (projectSpreadsheetIssues as IIssue[]);
|
: (projectSpreadsheetIssues as IIssue[]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
issueView,
|
displayFilters,
|
||||||
|
setDisplayFilters,
|
||||||
mutateIssues: cycleId
|
mutateIssues: cycleId
|
||||||
? mutateCycleSpreadsheetIssues
|
? mutateCycleSpreadsheetIssues
|
||||||
: moduleId
|
: moduleId
|
||||||
@ -114,14 +113,11 @@ const useSpreadsheetIssuesView = () => {
|
|||||||
? mutateViewSpreadsheetIssues
|
? mutateViewSpreadsheetIssues
|
||||||
: mutateProjectSpreadsheetIssues,
|
: mutateProjectSpreadsheetIssues,
|
||||||
spreadsheetIssues: spreadsheetIssues ?? [],
|
spreadsheetIssues: spreadsheetIssues ?? [],
|
||||||
orderBy,
|
|
||||||
setOrderBy,
|
|
||||||
filters,
|
filters,
|
||||||
setFilters,
|
setFilters,
|
||||||
params,
|
params,
|
||||||
resetFilterToDefault,
|
resetFilterToDefault,
|
||||||
setNewFilterDefaultView,
|
setNewFilterDefaultView,
|
||||||
setIssueView,
|
|
||||||
} as const;
|
} as const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -7,7 +7,6 @@ import { PlusIcon } from "@heroicons/react/24/outline";
|
|||||||
// layouts
|
// layouts
|
||||||
import { WorkspaceAuthorizationLayout } from "layouts/auth-layout";
|
import { WorkspaceAuthorizationLayout } from "layouts/auth-layout";
|
||||||
// hooks
|
// hooks
|
||||||
import useProjects from "hooks/use-projects";
|
|
||||||
import useMyIssuesFilters from "hooks/my-issues/use-my-issues-filter";
|
import useMyIssuesFilters from "hooks/my-issues/use-my-issues-filter";
|
||||||
// components
|
// components
|
||||||
import { MyIssuesView, MyIssuesViewOptions } from "components/issues";
|
import { MyIssuesView, MyIssuesViewOptions } from "components/issues";
|
||||||
|
@ -4,8 +4,6 @@ import useSWR from "swr";
|
|||||||
|
|
||||||
// services
|
// services
|
||||||
import projectService from "services/project.service";
|
import projectService from "services/project.service";
|
||||||
// hooks
|
|
||||||
import useIssuesView from "hooks/use-issues-view";
|
|
||||||
// layouts
|
// layouts
|
||||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout";
|
import { ProjectAuthorizationWrapper } from "layouts/auth-layout";
|
||||||
// contexts
|
// contexts
|
||||||
@ -28,8 +26,6 @@ const ProjectArchivedIssues: NextPage = () => {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId } = router.query;
|
const { workspaceSlug, projectId } = router.query;
|
||||||
|
|
||||||
const { showEmptyGroups, setShowEmptyGroups } = useIssuesView();
|
|
||||||
|
|
||||||
const { data: projectDetails } = useSWR(
|
const { data: projectDetails } = useSWR(
|
||||||
workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null,
|
workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null,
|
||||||
workspaceSlug && projectId
|
workspaceSlug && projectId
|
||||||
|
@ -8,7 +8,6 @@ import type {
|
|||||||
IIssueActivity,
|
IIssueActivity,
|
||||||
IIssueComment,
|
IIssueComment,
|
||||||
IIssueLabels,
|
IIssueLabels,
|
||||||
IIssueViewOptions,
|
|
||||||
ISubIssueResponse,
|
ISubIssueResponse,
|
||||||
} from "types";
|
} from "types";
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ import APIService from "services/api.service";
|
|||||||
import trackEventServices from "./track-event.service";
|
import trackEventServices from "./track-event.service";
|
||||||
|
|
||||||
// types
|
// types
|
||||||
import type { IIssueViewOptions, IModule, IIssue, ICurrentUserResponse } from "types";
|
import type { IModule, IIssue, ICurrentUserResponse } from "types";
|
||||||
|
|
||||||
const { NEXT_PUBLIC_API_BASE_URL } = process.env;
|
const { NEXT_PUBLIC_API_BASE_URL } = process.env;
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ import type {
|
|||||||
IProjectMemberInvitation,
|
IProjectMemberInvitation,
|
||||||
ISearchIssueResponse,
|
ISearchIssueResponse,
|
||||||
ProjectPreferences,
|
ProjectPreferences,
|
||||||
ProjectViewTheme,
|
IProjectViewProps,
|
||||||
TProjectIssuesSearchParams,
|
TProjectIssuesSearchParams,
|
||||||
} from "types";
|
} from "types";
|
||||||
|
|
||||||
@ -297,8 +297,8 @@ export class ProjectServices extends APIService {
|
|||||||
workspaceSlug: string,
|
workspaceSlug: string,
|
||||||
projectId: string,
|
projectId: string,
|
||||||
data: {
|
data: {
|
||||||
view_props?: ProjectViewTheme;
|
view_props?: IProjectViewProps;
|
||||||
default_props?: ProjectViewTheme;
|
default_props?: IProjectViewProps;
|
||||||
preferences?: ProjectPreferences;
|
preferences?: ProjectPreferences;
|
||||||
sort_order?: number;
|
sort_order?: number;
|
||||||
}
|
}
|
||||||
|
1
web/types/index.d.ts
vendored
1
web/types/index.d.ts
vendored
@ -18,6 +18,7 @@ export * from "./calendar";
|
|||||||
export * from "./notifications";
|
export * from "./notifications";
|
||||||
export * from "./waitlist";
|
export * from "./waitlist";
|
||||||
export * from "./reaction";
|
export * from "./reaction";
|
||||||
|
export * from "./view-props";
|
||||||
|
|
||||||
export type NestedKeyOf<ObjectType extends object> = {
|
export type NestedKeyOf<ObjectType extends object> = {
|
||||||
[Key in keyof ObjectType & (string | number)]: ObjectType[Key] extends object
|
[Key in keyof ObjectType & (string | number)]: ObjectType[Key] extends object
|
||||||
|
59
web/types/issues.d.ts
vendored
59
web/types/issues.d.ts
vendored
@ -11,6 +11,11 @@ import type {
|
|||||||
IStateLite,
|
IStateLite,
|
||||||
TStateGroups,
|
TStateGroups,
|
||||||
Properties,
|
Properties,
|
||||||
|
IIssueFilterOptions,
|
||||||
|
TIssueGroupByOptions,
|
||||||
|
TIssueViewOptions,
|
||||||
|
TIssueOrderByOptions,
|
||||||
|
IIssueDisplayFilterOptions,
|
||||||
} from "types";
|
} from "types";
|
||||||
|
|
||||||
export interface IIssueCycle {
|
export interface IIssueCycle {
|
||||||
@ -213,55 +218,6 @@ export interface IIssueLite {
|
|||||||
workspace__slug: string;
|
workspace__slug: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IIssueFilterOptions {
|
|
||||||
type: "active" | "backlog" | null;
|
|
||||||
assignees: string[] | null;
|
|
||||||
start_date: string[] | null;
|
|
||||||
target_date: string[] | null;
|
|
||||||
state: string[] | null;
|
|
||||||
state_group: TStateGroups[] | null;
|
|
||||||
subscriber: string[] | null;
|
|
||||||
labels: string[] | null;
|
|
||||||
priority: string[] | null;
|
|
||||||
created_by: string[] | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type TIssueViewOptions = "list" | "kanban" | "calendar" | "spreadsheet" | "gantt_chart";
|
|
||||||
|
|
||||||
export type TIssueGroupByOptions =
|
|
||||||
| "state"
|
|
||||||
| "priority"
|
|
||||||
| "labels"
|
|
||||||
| "created_by"
|
|
||||||
| "state_detail.group"
|
|
||||||
| "project"
|
|
||||||
| "assignees"
|
|
||||||
| null;
|
|
||||||
|
|
||||||
export type TIssueOrderByOptions =
|
|
||||||
| "-created_at"
|
|
||||||
| "-updated_at"
|
|
||||||
| "priority"
|
|
||||||
| "sort_order"
|
|
||||||
| "state__name"
|
|
||||||
| "-state__name"
|
|
||||||
| "assignees__name"
|
|
||||||
| "-assignees__name"
|
|
||||||
| "labels__name"
|
|
||||||
| "-labels__name"
|
|
||||||
| "target_date"
|
|
||||||
| "-target_date"
|
|
||||||
| "estimate__point"
|
|
||||||
| "-estimate__point"
|
|
||||||
| "start_date"
|
|
||||||
| "-start_date";
|
|
||||||
|
|
||||||
export interface IIssueViewOptions {
|
|
||||||
group_by: TIssueGroupByOptions;
|
|
||||||
order_by: TIssueOrderByOptions;
|
|
||||||
filters: IIssueFilterOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IIssueAttachment {
|
export interface IIssueAttachment {
|
||||||
asset: string;
|
asset: string;
|
||||||
attributes: {
|
attributes: {
|
||||||
@ -280,19 +236,16 @@ export interface IIssueAttachment {
|
|||||||
|
|
||||||
export interface IIssueViewProps {
|
export interface IIssueViewProps {
|
||||||
groupedIssues: { [key: string]: IIssue[] } | undefined;
|
groupedIssues: { [key: string]: IIssue[] } | undefined;
|
||||||
groupByProperty: TIssueGroupByOptions;
|
displayFilters: IIssueDisplayFilterOptions | undefined;
|
||||||
isEmpty: boolean;
|
isEmpty: boolean;
|
||||||
issueView: TIssueViewOptions;
|
|
||||||
mutateIssues: KeyedMutator<
|
mutateIssues: KeyedMutator<
|
||||||
| IIssue[]
|
| IIssue[]
|
||||||
| {
|
| {
|
||||||
[key: string]: IIssue[];
|
[key: string]: IIssue[];
|
||||||
}
|
}
|
||||||
>;
|
>;
|
||||||
orderBy: TIssueOrderByOptions;
|
|
||||||
params: any;
|
params: any;
|
||||||
properties: Properties;
|
properties: Properties;
|
||||||
showEmptyGroups: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type TIssuePriorities = "urgent" | "high" | "medium" | "low" | null;
|
export type TIssuePriorities = "urgent" | "high" | "medium" | "low" | null;
|
||||||
|
13
web/types/projects.d.ts
vendored
13
web/types/projects.d.ts
vendored
@ -8,6 +8,7 @@ import type {
|
|||||||
TIssueOrderByOptions,
|
TIssueOrderByOptions,
|
||||||
TIssueViewOptions,
|
TIssueViewOptions,
|
||||||
TStateGroups,
|
TStateGroups,
|
||||||
|
IProjectViewProps,
|
||||||
} from ".";
|
} from ".";
|
||||||
|
|
||||||
export interface IProject {
|
export interface IProject {
|
||||||
@ -66,14 +67,6 @@ export interface IProjectLite {
|
|||||||
identifier: string;
|
identifier: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProjectViewTheme = {
|
|
||||||
issueView: TIssueViewOptions;
|
|
||||||
groupByProperty: TIssueGroupByOptions;
|
|
||||||
orderBy: TIssueOrderByOptions;
|
|
||||||
calendarDateRange: string;
|
|
||||||
filters: IIssueFilterOptions;
|
|
||||||
};
|
|
||||||
|
|
||||||
type ProjectPreferences = {
|
type ProjectPreferences = {
|
||||||
pages: {
|
pages: {
|
||||||
block_display: boolean;
|
block_display: boolean;
|
||||||
@ -90,8 +83,8 @@ export interface IProjectMember {
|
|||||||
|
|
||||||
preferences: ProjectPreferences;
|
preferences: ProjectPreferences;
|
||||||
|
|
||||||
view_props: ProjectViewTheme;
|
view_props: IProjectViewProps;
|
||||||
default_props: ProjectViewTheme;
|
default_props: IProjectViewProps;
|
||||||
|
|
||||||
created_at: Date;
|
created_at: Date;
|
||||||
updated_at: Date;
|
updated_at: Date;
|
||||||
|
63
web/types/view-props.d.ts
vendored
Normal file
63
web/types/view-props.d.ts
vendored
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
export type TIssueViewOptions = "list" | "kanban" | "calendar" | "spreadsheet" | "gantt_chart";
|
||||||
|
|
||||||
|
export type TIssueGroupByOptions =
|
||||||
|
| "state"
|
||||||
|
| "priority"
|
||||||
|
| "labels"
|
||||||
|
| "created_by"
|
||||||
|
| "state_detail.group"
|
||||||
|
| "project"
|
||||||
|
| "assignees"
|
||||||
|
| null;
|
||||||
|
|
||||||
|
export type TIssueOrderByOptions =
|
||||||
|
| "-created_at"
|
||||||
|
| "-updated_at"
|
||||||
|
| "priority"
|
||||||
|
| "sort_order"
|
||||||
|
| "state__name"
|
||||||
|
| "-state__name"
|
||||||
|
| "assignees__name"
|
||||||
|
| "-assignees__name"
|
||||||
|
| "labels__name"
|
||||||
|
| "-labels__name"
|
||||||
|
| "target_date"
|
||||||
|
| "-target_date"
|
||||||
|
| "estimate__point"
|
||||||
|
| "-estimate__point"
|
||||||
|
| "start_date"
|
||||||
|
| "-start_date";
|
||||||
|
|
||||||
|
export interface IIssueFilterOptions {
|
||||||
|
assignees?: string[] | null;
|
||||||
|
created_by?: string[] | null;
|
||||||
|
labels?: string[] | null;
|
||||||
|
priority?: string[] | null;
|
||||||
|
start_date?: string[] | null;
|
||||||
|
state?: string[] | null;
|
||||||
|
state_group?: TStateGroups[] | null;
|
||||||
|
subscriber?: string[] | null;
|
||||||
|
target_date?: string[] | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IIssueDisplayFilterOptions {
|
||||||
|
calendar_date_range?: string;
|
||||||
|
group_by?: TIssueGroupByOptions;
|
||||||
|
layout?: TIssueViewOptions;
|
||||||
|
order_by?: TIssueOrderByOptions;
|
||||||
|
show_empty_groups?: boolean;
|
||||||
|
start_target_date?: boolean;
|
||||||
|
sub_issue?: boolean;
|
||||||
|
type?: "active" | "backlog" | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IProjectViewProps {
|
||||||
|
display_filters: IIssueDisplayFilterOptions | undefined;
|
||||||
|
filters: IIssueFilterOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IWorkspaceViewProps {
|
||||||
|
display_filters: IIssueDisplayFilterOptions;
|
||||||
|
display_properties: Properties;
|
||||||
|
filters: IIssueFilterOptions;
|
||||||
|
}
|
10
web/types/workspace.d.ts
vendored
10
web/types/workspace.d.ts
vendored
@ -3,6 +3,7 @@ import type {
|
|||||||
IProjectMember,
|
IProjectMember,
|
||||||
IUser,
|
IUser,
|
||||||
IUserMemberLite,
|
IUserMemberLite,
|
||||||
|
IWorkspaceViewProps,
|
||||||
TIssueGroupByOptions,
|
TIssueGroupByOptions,
|
||||||
TIssueOrderByOptions,
|
TIssueOrderByOptions,
|
||||||
TIssueViewOptions,
|
TIssueViewOptions,
|
||||||
@ -63,15 +64,6 @@ export type Properties = {
|
|||||||
updated_on: boolean;
|
updated_on: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface IWorkspaceViewProps {
|
|
||||||
properties: Properties;
|
|
||||||
issueView: TIssueViewOptions;
|
|
||||||
groupByProperty: TIssueGroupByOptions;
|
|
||||||
orderBy: TIssueOrderByOptions;
|
|
||||||
filters: Partial<IIssueFilterOptions>;
|
|
||||||
showEmptyGroups: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IWorkspaceMember {
|
export interface IWorkspaceMember {
|
||||||
readonly id: string;
|
readonly id: string;
|
||||||
workspace: IWorkspace;
|
workspace: IWorkspace;
|
||||||
|
Loading…
Reference in New Issue
Block a user