forked from github/plane
chore: created new issue peek overview component and implemented in project issues list view (#2481)
* chore: created new issue peek overview component and implemented in project issues list view * build: default project props in project, cycles, modules and view layout
This commit is contained in:
parent
704fe155af
commit
9b96e297b3
@ -9,11 +9,14 @@ import { KanBan } from "./default";
|
|||||||
// store
|
// store
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
import { RootStore } from "store/root";
|
import { RootStore } from "store/root";
|
||||||
|
// constants
|
||||||
|
import { ISSUE_STATE_GROUPS, ISSUE_PRIORITIES } from "constants/issue";
|
||||||
|
|
||||||
export interface ICycleKanBanLayout {}
|
export interface ICycleKanBanLayout {}
|
||||||
|
|
||||||
export const CycleKanBanLayout: React.FC = observer(() => {
|
export const CycleKanBanLayout: React.FC = observer(() => {
|
||||||
const {
|
const {
|
||||||
|
project: projectStore,
|
||||||
cycleIssue: cycleIssueStore,
|
cycleIssue: cycleIssueStore,
|
||||||
issueFilter: issueFilterStore,
|
issueFilter: issueFilterStore,
|
||||||
cycleIssueKanBanView: cycleIssueKanBanViewStore,
|
cycleIssueKanBanView: cycleIssueKanBanViewStore,
|
||||||
@ -55,6 +58,14 @@ export const CycleKanBanLayout: React.FC = observer(() => {
|
|||||||
cycleIssueKanBanViewStore.handleKanBanToggle(toggle, value);
|
cycleIssueKanBanViewStore.handleKanBanToggle(toggle, value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const states = projectStore?.projectStates || null;
|
||||||
|
const priorities = ISSUE_PRIORITIES || null;
|
||||||
|
const labels = projectStore?.projectLabels || null;
|
||||||
|
const members = projectStore?.projectMembers || null;
|
||||||
|
const stateGroups = ISSUE_STATE_GROUPS || null;
|
||||||
|
const projects = projectStore?.projectStates || null;
|
||||||
|
const estimates = null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`relative min-w-full w-max min-h-full h-max bg-custom-background-90 px-3`}>
|
<div className={`relative min-w-full w-max min-h-full h-max bg-custom-background-90 px-3`}>
|
||||||
<DragDropContext onDragEnd={onDragEnd}>
|
<DragDropContext onDragEnd={onDragEnd}>
|
||||||
@ -67,6 +78,13 @@ export const CycleKanBanLayout: React.FC = observer(() => {
|
|||||||
display_properties={display_properties}
|
display_properties={display_properties}
|
||||||
kanBanToggle={cycleIssueKanBanViewStore?.kanBanToggle}
|
kanBanToggle={cycleIssueKanBanViewStore?.kanBanToggle}
|
||||||
handleKanBanToggle={handleKanBanToggle}
|
handleKanBanToggle={handleKanBanToggle}
|
||||||
|
states={states}
|
||||||
|
stateGroups={stateGroups}
|
||||||
|
priorities={priorities}
|
||||||
|
labels={labels}
|
||||||
|
members={members}
|
||||||
|
projects={projects}
|
||||||
|
estimates={estimates}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<KanBanSwimLanes
|
<KanBanSwimLanes
|
||||||
@ -77,6 +95,13 @@ export const CycleKanBanLayout: React.FC = observer(() => {
|
|||||||
display_properties={display_properties}
|
display_properties={display_properties}
|
||||||
kanBanToggle={cycleIssueKanBanViewStore?.kanBanToggle}
|
kanBanToggle={cycleIssueKanBanViewStore?.kanBanToggle}
|
||||||
handleKanBanToggle={handleKanBanToggle}
|
handleKanBanToggle={handleKanBanToggle}
|
||||||
|
states={states}
|
||||||
|
stateGroups={stateGroups}
|
||||||
|
priorities={priorities}
|
||||||
|
labels={labels}
|
||||||
|
members={members}
|
||||||
|
projects={projects}
|
||||||
|
estimates={estimates}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</DragDropContext>
|
</DragDropContext>
|
||||||
|
@ -114,10 +114,18 @@ export interface IKanBan {
|
|||||||
display_properties: any;
|
display_properties: any;
|
||||||
kanBanToggle: any;
|
kanBanToggle: any;
|
||||||
handleKanBanToggle: any;
|
handleKanBanToggle: any;
|
||||||
|
|
||||||
|
states: any;
|
||||||
|
stateGroups: any;
|
||||||
|
priorities: any;
|
||||||
|
labels: any;
|
||||||
|
members: any;
|
||||||
|
projects: any;
|
||||||
|
estimates: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const KanBan: React.FC<IKanBan> = observer(
|
export const KanBan: React.FC<IKanBan> = observer((props) => {
|
||||||
({
|
const {
|
||||||
issues,
|
issues,
|
||||||
sub_group_by,
|
sub_group_by,
|
||||||
group_by,
|
group_by,
|
||||||
@ -126,107 +134,114 @@ export const KanBan: React.FC<IKanBan> = observer(
|
|||||||
display_properties,
|
display_properties,
|
||||||
kanBanToggle,
|
kanBanToggle,
|
||||||
handleKanBanToggle,
|
handleKanBanToggle,
|
||||||
}) => {
|
states,
|
||||||
const { project: projectStore, issueKanBanView: issueKanBanViewStore }: RootStore = useMobxStore();
|
stateGroups,
|
||||||
|
priorities,
|
||||||
|
labels,
|
||||||
|
members,
|
||||||
|
projects,
|
||||||
|
estimates,
|
||||||
|
} = props;
|
||||||
|
|
||||||
return (
|
const { project: projectStore, issueKanBanView: issueKanBanViewStore }: RootStore = useMobxStore();
|
||||||
<div className="relative w-full h-full">
|
|
||||||
{group_by && group_by === "state" && (
|
|
||||||
<GroupByKanBan
|
|
||||||
issues={issues}
|
|
||||||
group_by={group_by}
|
|
||||||
sub_group_by={sub_group_by}
|
|
||||||
sub_group_id={sub_group_id}
|
|
||||||
list={projectStore?.projectStates}
|
|
||||||
listKey={`id`}
|
|
||||||
isDragDisabled={!issueKanBanViewStore?.canUserDragDrop}
|
|
||||||
handleIssues={handleIssues}
|
|
||||||
display_properties={display_properties}
|
|
||||||
kanBanToggle={kanBanToggle}
|
|
||||||
handleKanBanToggle={handleKanBanToggle}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{group_by && group_by === "state_detail.group" && (
|
return (
|
||||||
<GroupByKanBan
|
<div className="relative w-full h-full">
|
||||||
issues={issues}
|
{group_by && group_by === "state" && (
|
||||||
group_by={group_by}
|
<GroupByKanBan
|
||||||
sub_group_by={sub_group_by}
|
issues={issues}
|
||||||
sub_group_id={sub_group_id}
|
group_by={group_by}
|
||||||
list={ISSUE_STATE_GROUPS}
|
sub_group_by={sub_group_by}
|
||||||
listKey={`key`}
|
sub_group_id={sub_group_id}
|
||||||
isDragDisabled={!issueKanBanViewStore?.canUserDragDrop}
|
list={projectStore?.projectStates}
|
||||||
handleIssues={handleIssues}
|
listKey={`id`}
|
||||||
display_properties={display_properties}
|
isDragDisabled={!issueKanBanViewStore?.canUserDragDrop}
|
||||||
kanBanToggle={kanBanToggle}
|
handleIssues={handleIssues}
|
||||||
handleKanBanToggle={handleKanBanToggle}
|
display_properties={display_properties}
|
||||||
/>
|
kanBanToggle={kanBanToggle}
|
||||||
)}
|
handleKanBanToggle={handleKanBanToggle}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
{group_by && group_by === "priority" && (
|
{group_by && group_by === "state_detail.group" && (
|
||||||
<GroupByKanBan
|
<GroupByKanBan
|
||||||
issues={issues}
|
issues={issues}
|
||||||
group_by={group_by}
|
group_by={group_by}
|
||||||
sub_group_by={sub_group_by}
|
sub_group_by={sub_group_by}
|
||||||
sub_group_id={sub_group_id}
|
sub_group_id={sub_group_id}
|
||||||
list={ISSUE_PRIORITIES}
|
list={ISSUE_STATE_GROUPS}
|
||||||
listKey={`key`}
|
listKey={`key`}
|
||||||
isDragDisabled={!issueKanBanViewStore?.canUserDragDrop}
|
isDragDisabled={!issueKanBanViewStore?.canUserDragDrop}
|
||||||
handleIssues={handleIssues}
|
handleIssues={handleIssues}
|
||||||
display_properties={display_properties}
|
display_properties={display_properties}
|
||||||
kanBanToggle={kanBanToggle}
|
kanBanToggle={kanBanToggle}
|
||||||
handleKanBanToggle={handleKanBanToggle}
|
handleKanBanToggle={handleKanBanToggle}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{group_by && group_by === "labels" && (
|
{group_by && group_by === "priority" && (
|
||||||
<GroupByKanBan
|
<GroupByKanBan
|
||||||
issues={issues}
|
issues={issues}
|
||||||
group_by={group_by}
|
group_by={group_by}
|
||||||
sub_group_by={sub_group_by}
|
sub_group_by={sub_group_by}
|
||||||
sub_group_id={sub_group_id}
|
sub_group_id={sub_group_id}
|
||||||
list={projectStore?.projectLabels}
|
list={ISSUE_PRIORITIES}
|
||||||
listKey={`id`}
|
listKey={`key`}
|
||||||
isDragDisabled={!issueKanBanViewStore?.canUserDragDrop}
|
isDragDisabled={!issueKanBanViewStore?.canUserDragDrop}
|
||||||
handleIssues={handleIssues}
|
handleIssues={handleIssues}
|
||||||
display_properties={display_properties}
|
display_properties={display_properties}
|
||||||
kanBanToggle={kanBanToggle}
|
kanBanToggle={kanBanToggle}
|
||||||
handleKanBanToggle={handleKanBanToggle}
|
handleKanBanToggle={handleKanBanToggle}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{group_by && group_by === "assignees" && (
|
{group_by && group_by === "labels" && (
|
||||||
<GroupByKanBan
|
<GroupByKanBan
|
||||||
issues={issues}
|
issues={issues}
|
||||||
group_by={group_by}
|
group_by={group_by}
|
||||||
sub_group_by={sub_group_by}
|
sub_group_by={sub_group_by}
|
||||||
sub_group_id={sub_group_id}
|
sub_group_id={sub_group_id}
|
||||||
list={projectStore?.projectMembers}
|
list={projectStore?.projectLabels}
|
||||||
listKey={`member.id`}
|
listKey={`id`}
|
||||||
isDragDisabled={!issueKanBanViewStore?.canUserDragDrop}
|
isDragDisabled={!issueKanBanViewStore?.canUserDragDrop}
|
||||||
handleIssues={handleIssues}
|
handleIssues={handleIssues}
|
||||||
display_properties={display_properties}
|
display_properties={display_properties}
|
||||||
kanBanToggle={kanBanToggle}
|
kanBanToggle={kanBanToggle}
|
||||||
handleKanBanToggle={handleKanBanToggle}
|
handleKanBanToggle={handleKanBanToggle}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{group_by && group_by === "created_by" && (
|
{group_by && group_by === "assignees" && (
|
||||||
<GroupByKanBan
|
<GroupByKanBan
|
||||||
issues={issues}
|
issues={issues}
|
||||||
group_by={group_by}
|
group_by={group_by}
|
||||||
sub_group_by={sub_group_by}
|
sub_group_by={sub_group_by}
|
||||||
sub_group_id={sub_group_id}
|
sub_group_id={sub_group_id}
|
||||||
list={projectStore?.projectMembers}
|
list={projectStore?.projectMembers}
|
||||||
listKey={`member.id`}
|
listKey={`member.id`}
|
||||||
isDragDisabled={!issueKanBanViewStore?.canUserDragDrop}
|
isDragDisabled={!issueKanBanViewStore?.canUserDragDrop}
|
||||||
handleIssues={handleIssues}
|
handleIssues={handleIssues}
|
||||||
display_properties={display_properties}
|
display_properties={display_properties}
|
||||||
kanBanToggle={kanBanToggle}
|
kanBanToggle={kanBanToggle}
|
||||||
handleKanBanToggle={handleKanBanToggle}
|
handleKanBanToggle={handleKanBanToggle}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
|
||||||
);
|
{group_by && group_by === "created_by" && (
|
||||||
}
|
<GroupByKanBan
|
||||||
);
|
issues={issues}
|
||||||
|
group_by={group_by}
|
||||||
|
sub_group_by={sub_group_by}
|
||||||
|
sub_group_id={sub_group_id}
|
||||||
|
list={projectStore?.projectMembers}
|
||||||
|
listKey={`member.id`}
|
||||||
|
isDragDisabled={!issueKanBanViewStore?.canUserDragDrop}
|
||||||
|
handleIssues={handleIssues}
|
||||||
|
display_properties={display_properties}
|
||||||
|
kanBanToggle={kanBanToggle}
|
||||||
|
handleKanBanToggle={handleKanBanToggle}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
@ -9,11 +9,14 @@ import { KanBan } from "./default";
|
|||||||
// store
|
// store
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
import { RootStore } from "store/root";
|
import { RootStore } from "store/root";
|
||||||
|
// constants
|
||||||
|
import { ISSUE_STATE_GROUPS, ISSUE_PRIORITIES } from "constants/issue";
|
||||||
|
|
||||||
export interface IModuleKanBanLayout {}
|
export interface IModuleKanBanLayout {}
|
||||||
|
|
||||||
export const ModuleKanBanLayout: React.FC = observer(() => {
|
export const ModuleKanBanLayout: React.FC = observer(() => {
|
||||||
const {
|
const {
|
||||||
|
project: projectStore,
|
||||||
moduleIssue: moduleIssueStore,
|
moduleIssue: moduleIssueStore,
|
||||||
issueFilter: issueFilterStore,
|
issueFilter: issueFilterStore,
|
||||||
moduleIssueKanBanView: moduleIssueKanBanViewStore,
|
moduleIssueKanBanView: moduleIssueKanBanViewStore,
|
||||||
@ -55,6 +58,14 @@ export const ModuleKanBanLayout: React.FC = observer(() => {
|
|||||||
moduleIssueKanBanViewStore.handleKanBanToggle(toggle, value);
|
moduleIssueKanBanViewStore.handleKanBanToggle(toggle, value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const states = projectStore?.projectStates || null;
|
||||||
|
const priorities = ISSUE_PRIORITIES || null;
|
||||||
|
const labels = projectStore?.projectLabels || null;
|
||||||
|
const members = projectStore?.projectMembers || null;
|
||||||
|
const stateGroups = ISSUE_STATE_GROUPS || null;
|
||||||
|
const projects = projectStore?.projectStates || null;
|
||||||
|
const estimates = null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`relative min-w-full w-max min-h-full h-max bg-custom-background-90 px-3`}>
|
<div className={`relative min-w-full w-max min-h-full h-max bg-custom-background-90 px-3`}>
|
||||||
<DragDropContext onDragEnd={onDragEnd}>
|
<DragDropContext onDragEnd={onDragEnd}>
|
||||||
@ -67,6 +78,13 @@ export const ModuleKanBanLayout: React.FC = observer(() => {
|
|||||||
display_properties={display_properties}
|
display_properties={display_properties}
|
||||||
kanBanToggle={moduleIssueKanBanViewStore?.kanBanToggle}
|
kanBanToggle={moduleIssueKanBanViewStore?.kanBanToggle}
|
||||||
handleKanBanToggle={handleKanBanToggle}
|
handleKanBanToggle={handleKanBanToggle}
|
||||||
|
states={states}
|
||||||
|
stateGroups={stateGroups}
|
||||||
|
priorities={priorities}
|
||||||
|
labels={labels}
|
||||||
|
members={members}
|
||||||
|
projects={projects}
|
||||||
|
estimates={estimates}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<KanBanSwimLanes
|
<KanBanSwimLanes
|
||||||
@ -77,6 +95,13 @@ export const ModuleKanBanLayout: React.FC = observer(() => {
|
|||||||
display_properties={display_properties}
|
display_properties={display_properties}
|
||||||
kanBanToggle={moduleIssueKanBanViewStore?.kanBanToggle}
|
kanBanToggle={moduleIssueKanBanViewStore?.kanBanToggle}
|
||||||
handleKanBanToggle={handleKanBanToggle}
|
handleKanBanToggle={handleKanBanToggle}
|
||||||
|
states={states}
|
||||||
|
stateGroups={stateGroups}
|
||||||
|
priorities={priorities}
|
||||||
|
labels={labels}
|
||||||
|
members={members}
|
||||||
|
projects={projects}
|
||||||
|
estimates={estimates}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</DragDropContext>
|
</DragDropContext>
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import React from "react";
|
import { FC } from "react";
|
||||||
// react beautiful dnd
|
|
||||||
import { DragDropContext } from "@hello-pangea/dnd";
|
import { DragDropContext } from "@hello-pangea/dnd";
|
||||||
// mobx
|
// mobx
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
@ -9,11 +8,15 @@ import { KanBan } from "./default";
|
|||||||
// store
|
// store
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
import { RootStore } from "store/root";
|
import { RootStore } from "store/root";
|
||||||
|
// constants
|
||||||
|
import { ISSUE_STATE_GROUPS, ISSUE_PRIORITIES } from "constants/issue";
|
||||||
|
|
||||||
export interface IProfileIssuesKanBanLayout {}
|
export interface IProfileIssuesKanBanLayout {}
|
||||||
|
|
||||||
export const ProfileIssuesKanBanLayout: React.FC = observer(() => {
|
export const ProfileIssuesKanBanLayout: FC = observer(() => {
|
||||||
const {
|
const {
|
||||||
|
workspace: workspaceStore,
|
||||||
|
project: projectStore,
|
||||||
profileIssues: profileIssuesStore,
|
profileIssues: profileIssuesStore,
|
||||||
profileIssueFilters: profileIssueFiltersStore,
|
profileIssueFilters: profileIssueFiltersStore,
|
||||||
issueKanBanView: issueKanBanViewStore,
|
issueKanBanView: issueKanBanViewStore,
|
||||||
@ -55,6 +58,14 @@ export const ProfileIssuesKanBanLayout: React.FC = observer(() => {
|
|||||||
issueKanBanViewStore.handleKanBanToggle(toggle, value);
|
issueKanBanViewStore.handleKanBanToggle(toggle, value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const states = projectStore?.projectStates || null;
|
||||||
|
const priorities = ISSUE_PRIORITIES || null;
|
||||||
|
const labels = workspaceStore.workspaceLabels || null;
|
||||||
|
const members = projectStore?.projectMembers || null;
|
||||||
|
const stateGroups = ISSUE_STATE_GROUPS || null;
|
||||||
|
const projects = projectStore?.workspaceProjects || null;
|
||||||
|
const estimates = null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`relative min-w-full w-max min-h-full h-max bg-custom-background-90 px-3`}>
|
<div className={`relative min-w-full w-max min-h-full h-max bg-custom-background-90 px-3`}>
|
||||||
<DragDropContext onDragEnd={onDragEnd}>
|
<DragDropContext onDragEnd={onDragEnd}>
|
||||||
@ -67,6 +78,13 @@ export const ProfileIssuesKanBanLayout: React.FC = observer(() => {
|
|||||||
display_properties={display_properties}
|
display_properties={display_properties}
|
||||||
kanBanToggle={issueKanBanViewStore?.kanBanToggle}
|
kanBanToggle={issueKanBanViewStore?.kanBanToggle}
|
||||||
handleKanBanToggle={handleKanBanToggle}
|
handleKanBanToggle={handleKanBanToggle}
|
||||||
|
states={states}
|
||||||
|
stateGroups={stateGroups}
|
||||||
|
priorities={priorities}
|
||||||
|
labels={labels}
|
||||||
|
members={members}
|
||||||
|
projects={projects}
|
||||||
|
estimates={estimates}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<KanBanSwimLanes
|
<KanBanSwimLanes
|
||||||
@ -77,6 +95,13 @@ export const ProfileIssuesKanBanLayout: React.FC = observer(() => {
|
|||||||
display_properties={display_properties}
|
display_properties={display_properties}
|
||||||
kanBanToggle={issueKanBanViewStore?.kanBanToggle}
|
kanBanToggle={issueKanBanViewStore?.kanBanToggle}
|
||||||
handleKanBanToggle={handleKanBanToggle}
|
handleKanBanToggle={handleKanBanToggle}
|
||||||
|
states={states}
|
||||||
|
stateGroups={stateGroups}
|
||||||
|
priorities={priorities}
|
||||||
|
labels={labels}
|
||||||
|
members={members}
|
||||||
|
projects={projects}
|
||||||
|
estimates={estimates}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</DragDropContext>
|
</DragDropContext>
|
||||||
|
@ -76,13 +76,13 @@ export const KanBanLayout: FC = observer(() => {
|
|||||||
display_properties={display_properties}
|
display_properties={display_properties}
|
||||||
kanBanToggle={issueKanBanViewStore?.kanBanToggle}
|
kanBanToggle={issueKanBanViewStore?.kanBanToggle}
|
||||||
handleKanBanToggle={handleKanBanToggle}
|
handleKanBanToggle={handleKanBanToggle}
|
||||||
// states={states}
|
states={states}
|
||||||
// stateGroups={stateGroups}
|
stateGroups={stateGroups}
|
||||||
// priorities={priorities}
|
priorities={priorities}
|
||||||
// labels={labels}
|
labels={labels}
|
||||||
// members={members}
|
members={members}
|
||||||
// projects={projects}
|
projects={projects}
|
||||||
// estimates={estimates}
|
estimates={estimates}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<KanBanSwimLanes
|
<KanBanSwimLanes
|
||||||
@ -93,13 +93,13 @@ export const KanBanLayout: FC = observer(() => {
|
|||||||
display_properties={display_properties}
|
display_properties={display_properties}
|
||||||
kanBanToggle={issueKanBanViewStore?.kanBanToggle}
|
kanBanToggle={issueKanBanViewStore?.kanBanToggle}
|
||||||
handleKanBanToggle={handleKanBanToggle}
|
handleKanBanToggle={handleKanBanToggle}
|
||||||
// states={states}
|
states={states}
|
||||||
// stateGroups={stateGroups}
|
stateGroups={stateGroups}
|
||||||
// priorities={priorities}
|
priorities={priorities}
|
||||||
// labels={labels}
|
labels={labels}
|
||||||
// members={members}
|
members={members}
|
||||||
// projects={projects}
|
projects={projects}
|
||||||
// estimates={estimates}
|
estimates={estimates}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</DragDropContext>
|
</DragDropContext>
|
||||||
|
@ -64,9 +64,16 @@ interface ISubGroupSwimlane extends ISubGroupSwimlaneHeader {
|
|||||||
display_properties: any;
|
display_properties: any;
|
||||||
kanBanToggle: any;
|
kanBanToggle: any;
|
||||||
handleKanBanToggle: any;
|
handleKanBanToggle: any;
|
||||||
|
states: any;
|
||||||
|
stateGroups: any;
|
||||||
|
priorities: any;
|
||||||
|
labels: any;
|
||||||
|
members: any;
|
||||||
|
projects: any;
|
||||||
|
estimates: any;
|
||||||
}
|
}
|
||||||
const SubGroupSwimlane: React.FC<ISubGroupSwimlane> = observer(
|
const SubGroupSwimlane: React.FC<ISubGroupSwimlane> = observer((props) => {
|
||||||
({
|
const {
|
||||||
issues,
|
issues,
|
||||||
sub_group_by,
|
sub_group_by,
|
||||||
group_by,
|
group_by,
|
||||||
@ -76,55 +83,69 @@ const SubGroupSwimlane: React.FC<ISubGroupSwimlane> = observer(
|
|||||||
display_properties,
|
display_properties,
|
||||||
kanBanToggle,
|
kanBanToggle,
|
||||||
handleKanBanToggle,
|
handleKanBanToggle,
|
||||||
}) => {
|
states,
|
||||||
const calculateIssueCount = (column_id: string) => {
|
stateGroups,
|
||||||
let issueCount = 0;
|
priorities,
|
||||||
issues?.[column_id] &&
|
labels,
|
||||||
Object.keys(issues?.[column_id])?.forEach((_list: any) => {
|
members,
|
||||||
issueCount += issues?.[column_id]?.[_list]?.length || 0;
|
projects,
|
||||||
});
|
estimates,
|
||||||
return issueCount;
|
} = props;
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
const calculateIssueCount = (column_id: string) => {
|
||||||
<div className="relative w-full min-h-full h-max">
|
let issueCount = 0;
|
||||||
{list &&
|
issues?.[column_id] &&
|
||||||
list.length > 0 &&
|
Object.keys(issues?.[column_id])?.forEach((_list: any) => {
|
||||||
list.map((_list: any) => (
|
issueCount += issues?.[column_id]?.[_list]?.length || 0;
|
||||||
<div className="flex-shrink-0 flex flex-col">
|
});
|
||||||
<div className="sticky top-[50px] w-full z-[1] bg-custom-background-90 flex items-center py-1">
|
return issueCount;
|
||||||
<div className="flex-shrink-0 sticky left-0 bg-custom-background-90 pr-2">
|
};
|
||||||
<KanBanSubGroupByHeaderRoot
|
|
||||||
column_id={getValueFromObject(_list, listKey) as string}
|
return (
|
||||||
sub_group_by={sub_group_by}
|
<div className="relative w-full min-h-full h-max">
|
||||||
group_by={group_by}
|
{list &&
|
||||||
issues_count={calculateIssueCount(getValueFromObject(_list, listKey) as string)}
|
list.length > 0 &&
|
||||||
kanBanToggle={kanBanToggle}
|
list.map((_list: any) => (
|
||||||
handleKanBanToggle={handleKanBanToggle}
|
<div className="flex-shrink-0 flex flex-col">
|
||||||
/>
|
<div className="sticky top-[50px] w-full z-[1] bg-custom-background-90 flex items-center py-1">
|
||||||
</div>
|
<div className="flex-shrink-0 sticky left-0 bg-custom-background-90 pr-2">
|
||||||
<div className="w-full border-b border-custom-border-400 border-dashed" />
|
<KanBanSubGroupByHeaderRoot
|
||||||
|
column_id={getValueFromObject(_list, listKey) as string}
|
||||||
|
sub_group_by={sub_group_by}
|
||||||
|
group_by={group_by}
|
||||||
|
issues_count={calculateIssueCount(getValueFromObject(_list, listKey) as string)}
|
||||||
|
kanBanToggle={kanBanToggle}
|
||||||
|
handleKanBanToggle={handleKanBanToggle}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
{!kanBanToggle?.subgroupByIssuesVisibility.includes(getValueFromObject(_list, listKey) as string) && (
|
<div className="w-full border-b border-custom-border-400 border-dashed" />
|
||||||
<div className="relative">
|
|
||||||
<KanBan
|
|
||||||
issues={issues?.[getValueFromObject(_list, listKey) as string]}
|
|
||||||
sub_group_by={sub_group_by}
|
|
||||||
group_by={group_by}
|
|
||||||
sub_group_id={getValueFromObject(_list, listKey) as string}
|
|
||||||
handleIssues={handleIssues}
|
|
||||||
display_properties={display_properties}
|
|
||||||
kanBanToggle={kanBanToggle}
|
|
||||||
handleKanBanToggle={handleKanBanToggle}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
))}
|
{!kanBanToggle?.subgroupByIssuesVisibility.includes(getValueFromObject(_list, listKey) as string) && (
|
||||||
</div>
|
<div className="relative">
|
||||||
);
|
<KanBan
|
||||||
}
|
issues={issues?.[getValueFromObject(_list, listKey) as string]}
|
||||||
);
|
sub_group_by={sub_group_by}
|
||||||
|
group_by={group_by}
|
||||||
|
sub_group_id={getValueFromObject(_list, listKey) as string}
|
||||||
|
handleIssues={handleIssues}
|
||||||
|
display_properties={display_properties}
|
||||||
|
kanBanToggle={kanBanToggle}
|
||||||
|
handleKanBanToggle={handleKanBanToggle}
|
||||||
|
states={states}
|
||||||
|
stateGroups={stateGroups}
|
||||||
|
priorities={priorities}
|
||||||
|
labels={labels}
|
||||||
|
members={members}
|
||||||
|
projects={projects}
|
||||||
|
estimates={estimates}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
export interface IKanBanSwimLanes {
|
export interface IKanBanSwimLanes {
|
||||||
issues: any;
|
issues: any;
|
||||||
@ -134,172 +155,236 @@ export interface IKanBanSwimLanes {
|
|||||||
display_properties: any;
|
display_properties: any;
|
||||||
kanBanToggle: any;
|
kanBanToggle: any;
|
||||||
handleKanBanToggle: any;
|
handleKanBanToggle: any;
|
||||||
|
states: any;
|
||||||
|
stateGroups: any;
|
||||||
|
priorities: any;
|
||||||
|
labels: any;
|
||||||
|
members: any;
|
||||||
|
projects: any;
|
||||||
|
estimates: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const KanBanSwimLanes: React.FC<IKanBanSwimLanes> = observer(
|
export const KanBanSwimLanes: React.FC<IKanBanSwimLanes> = observer((props) => {
|
||||||
({ issues, sub_group_by, group_by, handleIssues, display_properties, kanBanToggle, handleKanBanToggle }) => {
|
const {
|
||||||
const { project: projectStore }: RootStore = useMobxStore();
|
issues,
|
||||||
|
sub_group_by,
|
||||||
|
group_by,
|
||||||
|
handleIssues,
|
||||||
|
display_properties,
|
||||||
|
kanBanToggle,
|
||||||
|
handleKanBanToggle,
|
||||||
|
states,
|
||||||
|
stateGroups,
|
||||||
|
priorities,
|
||||||
|
labels,
|
||||||
|
members,
|
||||||
|
projects,
|
||||||
|
estimates,
|
||||||
|
} = props;
|
||||||
|
|
||||||
return (
|
const { project: projectStore }: RootStore = useMobxStore();
|
||||||
<div className="relative">
|
|
||||||
<div className="sticky top-0 z-[2] bg-custom-background-90 h-[50px]">
|
|
||||||
{group_by && group_by === "state" && (
|
|
||||||
<SubGroupSwimlaneHeader
|
|
||||||
issues={issues}
|
|
||||||
sub_group_by={sub_group_by}
|
|
||||||
group_by={group_by}
|
|
||||||
list={projectStore?.projectStates}
|
|
||||||
listKey={`id`}
|
|
||||||
kanBanToggle={kanBanToggle}
|
|
||||||
handleKanBanToggle={handleKanBanToggle}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{group_by && group_by === "state_detail.group" && (
|
return (
|
||||||
<SubGroupSwimlaneHeader
|
<div className="relative">
|
||||||
issues={issues}
|
<div className="sticky top-0 z-[2] bg-custom-background-90 h-[50px]">
|
||||||
sub_group_by={sub_group_by}
|
{group_by && group_by === "state" && (
|
||||||
group_by={group_by}
|
<SubGroupSwimlaneHeader
|
||||||
list={ISSUE_STATE_GROUPS}
|
|
||||||
listKey={`key`}
|
|
||||||
kanBanToggle={kanBanToggle}
|
|
||||||
handleKanBanToggle={handleKanBanToggle}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{group_by && group_by === "priority" && (
|
|
||||||
<SubGroupSwimlaneHeader
|
|
||||||
issues={issues}
|
|
||||||
sub_group_by={sub_group_by}
|
|
||||||
group_by={group_by}
|
|
||||||
list={ISSUE_PRIORITIES}
|
|
||||||
listKey={`key`}
|
|
||||||
kanBanToggle={kanBanToggle}
|
|
||||||
handleKanBanToggle={handleKanBanToggle}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{group_by && group_by === "labels" && (
|
|
||||||
<SubGroupSwimlaneHeader
|
|
||||||
issues={issues}
|
|
||||||
sub_group_by={sub_group_by}
|
|
||||||
group_by={group_by}
|
|
||||||
list={projectStore?.projectLabels}
|
|
||||||
listKey={`id`}
|
|
||||||
kanBanToggle={kanBanToggle}
|
|
||||||
handleKanBanToggle={handleKanBanToggle}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{group_by && group_by === "assignees" && (
|
|
||||||
<SubGroupSwimlaneHeader
|
|
||||||
issues={issues}
|
|
||||||
sub_group_by={sub_group_by}
|
|
||||||
group_by={group_by}
|
|
||||||
list={projectStore?.projectMembers}
|
|
||||||
listKey={`member.id`}
|
|
||||||
kanBanToggle={kanBanToggle}
|
|
||||||
handleKanBanToggle={handleKanBanToggle}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{group_by && group_by === "created_by" && (
|
|
||||||
<SubGroupSwimlaneHeader
|
|
||||||
issues={issues}
|
|
||||||
sub_group_by={sub_group_by}
|
|
||||||
group_by={group_by}
|
|
||||||
list={projectStore?.projectMembers}
|
|
||||||
listKey={`member.id`}
|
|
||||||
kanBanToggle={kanBanToggle}
|
|
||||||
handleKanBanToggle={handleKanBanToggle}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{sub_group_by && sub_group_by === "state" && (
|
|
||||||
<SubGroupSwimlane
|
|
||||||
issues={issues}
|
issues={issues}
|
||||||
sub_group_by={sub_group_by}
|
sub_group_by={sub_group_by}
|
||||||
group_by={group_by}
|
group_by={group_by}
|
||||||
list={projectStore?.projectStates}
|
list={projectStore?.projectStates}
|
||||||
listKey={`id`}
|
listKey={`id`}
|
||||||
handleIssues={handleIssues}
|
|
||||||
display_properties={display_properties}
|
|
||||||
kanBanToggle={kanBanToggle}
|
kanBanToggle={kanBanToggle}
|
||||||
handleKanBanToggle={handleKanBanToggle}
|
handleKanBanToggle={handleKanBanToggle}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{sub_group_by && sub_group_by === "state_detail.group" && (
|
{group_by && group_by === "state_detail.group" && (
|
||||||
<SubGroupSwimlane
|
<SubGroupSwimlaneHeader
|
||||||
issues={issues}
|
issues={issues}
|
||||||
sub_group_by={sub_group_by}
|
sub_group_by={sub_group_by}
|
||||||
group_by={group_by}
|
group_by={group_by}
|
||||||
list={ISSUE_STATE_GROUPS}
|
list={ISSUE_STATE_GROUPS}
|
||||||
listKey={`key`}
|
listKey={`key`}
|
||||||
handleIssues={handleIssues}
|
|
||||||
display_properties={display_properties}
|
|
||||||
kanBanToggle={kanBanToggle}
|
kanBanToggle={kanBanToggle}
|
||||||
handleKanBanToggle={handleKanBanToggle}
|
handleKanBanToggle={handleKanBanToggle}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{sub_group_by && sub_group_by === "priority" && (
|
{group_by && group_by === "priority" && (
|
||||||
<SubGroupSwimlane
|
<SubGroupSwimlaneHeader
|
||||||
issues={issues}
|
issues={issues}
|
||||||
sub_group_by={sub_group_by}
|
sub_group_by={sub_group_by}
|
||||||
group_by={group_by}
|
group_by={group_by}
|
||||||
list={ISSUE_PRIORITIES}
|
list={ISSUE_PRIORITIES}
|
||||||
listKey={`key`}
|
listKey={`key`}
|
||||||
handleIssues={handleIssues}
|
|
||||||
display_properties={display_properties}
|
|
||||||
kanBanToggle={kanBanToggle}
|
kanBanToggle={kanBanToggle}
|
||||||
handleKanBanToggle={handleKanBanToggle}
|
handleKanBanToggle={handleKanBanToggle}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{sub_group_by && sub_group_by === "labels" && (
|
{group_by && group_by === "labels" && (
|
||||||
<SubGroupSwimlane
|
<SubGroupSwimlaneHeader
|
||||||
issues={issues}
|
issues={issues}
|
||||||
sub_group_by={sub_group_by}
|
sub_group_by={sub_group_by}
|
||||||
group_by={group_by}
|
group_by={group_by}
|
||||||
list={projectStore?.projectLabels}
|
list={projectStore?.projectLabels}
|
||||||
listKey={`id`}
|
listKey={`id`}
|
||||||
handleIssues={handleIssues}
|
|
||||||
display_properties={display_properties}
|
|
||||||
kanBanToggle={kanBanToggle}
|
kanBanToggle={kanBanToggle}
|
||||||
handleKanBanToggle={handleKanBanToggle}
|
handleKanBanToggle={handleKanBanToggle}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{sub_group_by && sub_group_by === "assignees" && (
|
{group_by && group_by === "assignees" && (
|
||||||
<SubGroupSwimlane
|
<SubGroupSwimlaneHeader
|
||||||
issues={issues}
|
issues={issues}
|
||||||
sub_group_by={sub_group_by}
|
sub_group_by={sub_group_by}
|
||||||
group_by={group_by}
|
group_by={group_by}
|
||||||
list={projectStore?.projectMembers}
|
list={projectStore?.projectMembers}
|
||||||
listKey={`member.id`}
|
listKey={`member.id`}
|
||||||
handleIssues={handleIssues}
|
|
||||||
display_properties={display_properties}
|
|
||||||
kanBanToggle={kanBanToggle}
|
kanBanToggle={kanBanToggle}
|
||||||
handleKanBanToggle={handleKanBanToggle}
|
handleKanBanToggle={handleKanBanToggle}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{sub_group_by && sub_group_by === "created_by" && (
|
{group_by && group_by === "created_by" && (
|
||||||
<SubGroupSwimlane
|
<SubGroupSwimlaneHeader
|
||||||
issues={issues}
|
issues={issues}
|
||||||
sub_group_by={sub_group_by}
|
sub_group_by={sub_group_by}
|
||||||
group_by={group_by}
|
group_by={group_by}
|
||||||
list={projectStore?.projectMembers}
|
list={projectStore?.projectMembers}
|
||||||
listKey={`member.id`}
|
listKey={`member.id`}
|
||||||
handleIssues={handleIssues}
|
|
||||||
display_properties={display_properties}
|
|
||||||
kanBanToggle={kanBanToggle}
|
kanBanToggle={kanBanToggle}
|
||||||
handleKanBanToggle={handleKanBanToggle}
|
handleKanBanToggle={handleKanBanToggle}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
|
||||||
}
|
{sub_group_by && sub_group_by === "state" && (
|
||||||
);
|
<SubGroupSwimlane
|
||||||
|
issues={issues}
|
||||||
|
sub_group_by={sub_group_by}
|
||||||
|
group_by={group_by}
|
||||||
|
list={projectStore?.projectStates}
|
||||||
|
listKey={`id`}
|
||||||
|
handleIssues={handleIssues}
|
||||||
|
display_properties={display_properties}
|
||||||
|
kanBanToggle={kanBanToggle}
|
||||||
|
handleKanBanToggle={handleKanBanToggle}
|
||||||
|
states={states}
|
||||||
|
stateGroups={stateGroups}
|
||||||
|
priorities={priorities}
|
||||||
|
labels={labels}
|
||||||
|
members={members}
|
||||||
|
projects={projects}
|
||||||
|
estimates={estimates}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{sub_group_by && sub_group_by === "state_detail.group" && (
|
||||||
|
<SubGroupSwimlane
|
||||||
|
issues={issues}
|
||||||
|
sub_group_by={sub_group_by}
|
||||||
|
group_by={group_by}
|
||||||
|
list={ISSUE_STATE_GROUPS}
|
||||||
|
listKey={`key`}
|
||||||
|
handleIssues={handleIssues}
|
||||||
|
display_properties={display_properties}
|
||||||
|
kanBanToggle={kanBanToggle}
|
||||||
|
handleKanBanToggle={handleKanBanToggle}
|
||||||
|
states={states}
|
||||||
|
stateGroups={stateGroups}
|
||||||
|
priorities={priorities}
|
||||||
|
labels={labels}
|
||||||
|
members={members}
|
||||||
|
projects={projects}
|
||||||
|
estimates={estimates}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{sub_group_by && sub_group_by === "priority" && (
|
||||||
|
<SubGroupSwimlane
|
||||||
|
issues={issues}
|
||||||
|
sub_group_by={sub_group_by}
|
||||||
|
group_by={group_by}
|
||||||
|
list={ISSUE_PRIORITIES}
|
||||||
|
listKey={`key`}
|
||||||
|
handleIssues={handleIssues}
|
||||||
|
display_properties={display_properties}
|
||||||
|
kanBanToggle={kanBanToggle}
|
||||||
|
handleKanBanToggle={handleKanBanToggle}
|
||||||
|
states={states}
|
||||||
|
stateGroups={stateGroups}
|
||||||
|
priorities={priorities}
|
||||||
|
labels={labels}
|
||||||
|
members={members}
|
||||||
|
projects={projects}
|
||||||
|
estimates={estimates}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{sub_group_by && sub_group_by === "labels" && (
|
||||||
|
<SubGroupSwimlane
|
||||||
|
issues={issues}
|
||||||
|
sub_group_by={sub_group_by}
|
||||||
|
group_by={group_by}
|
||||||
|
list={projectStore?.projectLabels}
|
||||||
|
listKey={`id`}
|
||||||
|
handleIssues={handleIssues}
|
||||||
|
display_properties={display_properties}
|
||||||
|
kanBanToggle={kanBanToggle}
|
||||||
|
handleKanBanToggle={handleKanBanToggle}
|
||||||
|
states={states}
|
||||||
|
stateGroups={stateGroups}
|
||||||
|
priorities={priorities}
|
||||||
|
labels={labels}
|
||||||
|
members={members}
|
||||||
|
projects={projects}
|
||||||
|
estimates={estimates}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{sub_group_by && sub_group_by === "assignees" && (
|
||||||
|
<SubGroupSwimlane
|
||||||
|
issues={issues}
|
||||||
|
sub_group_by={sub_group_by}
|
||||||
|
group_by={group_by}
|
||||||
|
list={projectStore?.projectMembers}
|
||||||
|
listKey={`member.id`}
|
||||||
|
handleIssues={handleIssues}
|
||||||
|
display_properties={display_properties}
|
||||||
|
kanBanToggle={kanBanToggle}
|
||||||
|
handleKanBanToggle={handleKanBanToggle}
|
||||||
|
states={states}
|
||||||
|
stateGroups={stateGroups}
|
||||||
|
priorities={priorities}
|
||||||
|
labels={labels}
|
||||||
|
members={members}
|
||||||
|
projects={projects}
|
||||||
|
estimates={estimates}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{sub_group_by && sub_group_by === "created_by" && (
|
||||||
|
<SubGroupSwimlane
|
||||||
|
issues={issues}
|
||||||
|
sub_group_by={sub_group_by}
|
||||||
|
group_by={group_by}
|
||||||
|
list={projectStore?.projectMembers}
|
||||||
|
listKey={`member.id`}
|
||||||
|
handleIssues={handleIssues}
|
||||||
|
display_properties={display_properties}
|
||||||
|
kanBanToggle={kanBanToggle}
|
||||||
|
handleKanBanToggle={handleKanBanToggle}
|
||||||
|
states={states}
|
||||||
|
stateGroups={stateGroups}
|
||||||
|
priorities={priorities}
|
||||||
|
labels={labels}
|
||||||
|
members={members}
|
||||||
|
projects={projects}
|
||||||
|
estimates={estimates}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
@ -9,11 +9,14 @@ import { KanBan } from "./default";
|
|||||||
// store
|
// store
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
import { RootStore } from "store/root";
|
import { RootStore } from "store/root";
|
||||||
|
// constants
|
||||||
|
import { ISSUE_STATE_GROUPS, ISSUE_PRIORITIES } from "constants/issue";
|
||||||
|
|
||||||
export interface IViewKanBanLayout {}
|
export interface IViewKanBanLayout {}
|
||||||
|
|
||||||
export const ViewKanBanLayout: React.FC = observer(() => {
|
export const ViewKanBanLayout: React.FC = observer(() => {
|
||||||
const {
|
const {
|
||||||
|
project: projectStore,
|
||||||
issue: issueStore,
|
issue: issueStore,
|
||||||
issueFilter: issueFilterStore,
|
issueFilter: issueFilterStore,
|
||||||
issueKanBanView: issueKanBanViewStore,
|
issueKanBanView: issueKanBanViewStore,
|
||||||
@ -51,6 +54,14 @@ export const ViewKanBanLayout: React.FC = observer(() => {
|
|||||||
issueStore.updateIssueStructure(group_by, sub_group_by, issue);
|
issueStore.updateIssueStructure(group_by, sub_group_by, issue);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const states = projectStore?.projectStates || null;
|
||||||
|
const priorities = ISSUE_PRIORITIES || null;
|
||||||
|
const labels = projectStore?.projectLabels || null;
|
||||||
|
const members = projectStore?.projectMembers || null;
|
||||||
|
const stateGroups = ISSUE_STATE_GROUPS || null;
|
||||||
|
const projects = projectStore?.projectStates || null;
|
||||||
|
const estimates = null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`relative min-w-full w-max min-h-full h-max bg-custom-background-90 px-3`}>
|
<div className={`relative min-w-full w-max min-h-full h-max bg-custom-background-90 px-3`}>
|
||||||
<DragDropContext onDragEnd={onDragEnd}>
|
<DragDropContext onDragEnd={onDragEnd}>
|
||||||
@ -63,6 +74,13 @@ export const ViewKanBanLayout: React.FC = observer(() => {
|
|||||||
display_properties={display_properties}
|
display_properties={display_properties}
|
||||||
kanBanToggle={() => {}}
|
kanBanToggle={() => {}}
|
||||||
handleKanBanToggle={() => {}}
|
handleKanBanToggle={() => {}}
|
||||||
|
states={states}
|
||||||
|
stateGroups={stateGroups}
|
||||||
|
priorities={priorities}
|
||||||
|
labels={labels}
|
||||||
|
members={members}
|
||||||
|
projects={projects}
|
||||||
|
estimates={estimates}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<KanBanSwimLanes
|
<KanBanSwimLanes
|
||||||
@ -73,6 +91,13 @@ export const ViewKanBanLayout: React.FC = observer(() => {
|
|||||||
display_properties={display_properties}
|
display_properties={display_properties}
|
||||||
kanBanToggle={() => {}}
|
kanBanToggle={() => {}}
|
||||||
handleKanBanToggle={() => {}}
|
handleKanBanToggle={() => {}}
|
||||||
|
states={states}
|
||||||
|
stateGroups={stateGroups}
|
||||||
|
priorities={priorities}
|
||||||
|
labels={labels}
|
||||||
|
members={members}
|
||||||
|
projects={projects}
|
||||||
|
estimates={estimates}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</DragDropContext>
|
</DragDropContext>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { FC } from "react";
|
import { FC } from "react";
|
||||||
// components
|
// components
|
||||||
import { KanBanProperties } from "./properties";
|
import { KanBanProperties } from "./properties";
|
||||||
|
import { IssuePeekOverview } from "components/issues/issue-peek-overview";
|
||||||
// ui
|
// ui
|
||||||
import { Tooltip } from "@plane/ui";
|
import { Tooltip } from "@plane/ui";
|
||||||
|
|
||||||
@ -18,6 +19,10 @@ interface IssueBlockProps {
|
|||||||
export const IssueBlock: FC<IssueBlockProps> = (props) => {
|
export const IssueBlock: FC<IssueBlockProps> = (props) => {
|
||||||
const { columnId, issues, handleIssues, display_properties, states, labels, members, priorities } = props;
|
const { columnId, issues, handleIssues, display_properties, states, labels, members, priorities } = props;
|
||||||
|
|
||||||
|
const handleIssue = (_issue: any) => {
|
||||||
|
if (_issue && handleIssues) handleIssues(!columnId && columnId === "null" ? null : columnId, _issue);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{issues &&
|
{issues &&
|
||||||
@ -25,14 +30,25 @@ export const IssueBlock: FC<IssueBlockProps> = (props) => {
|
|||||||
issues.map((issue: any, index: any) => (
|
issues.map((issue: any, index: any) => (
|
||||||
<div
|
<div
|
||||||
key={index}
|
key={index}
|
||||||
className={`text-sm p-3 shadow-custom-shadow-2xs transition-all bg-custom-background-100 flex items-center gap-3 border-b border-custom-border-200`}
|
className={`text-sm p-3 shadow-custom-shadow-2xs bg-custom-background-100 flex items-center gap-3 border-b border-custom-border-200 hover:bg-custom-background-80`}
|
||||||
>
|
>
|
||||||
{display_properties && display_properties?.key && (
|
{display_properties && display_properties?.key && (
|
||||||
<div className="flex-shrink-0 text-xs text-custom-text-300">ONE-{issue.sequence_id}</div>
|
<div className="flex-shrink-0 text-xs text-custom-text-300">
|
||||||
|
{issue?.project_detail?.identifier}-{issue.sequence_id}
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
<Tooltip tooltipHeading="Title" tooltipContent={issue.name}>
|
|
||||||
<div className="line-clamp-1 text-sm font-medium text-custom-text-100">{issue.name}</div>
|
<IssuePeekOverview
|
||||||
</Tooltip>
|
workspaceSlug={issue?.workspace_detail?.slug}
|
||||||
|
projectId={issue?.project_detail?.id}
|
||||||
|
issueId={issue?.id}
|
||||||
|
handleIssue={handleIssue}
|
||||||
|
>
|
||||||
|
<Tooltip tooltipHeading="Title" tooltipContent={issue.name}>
|
||||||
|
<div className="line-clamp-1 text-sm font-medium text-custom-text-100 w-full">{issue.name}</div>
|
||||||
|
</Tooltip>
|
||||||
|
</IssuePeekOverview>
|
||||||
|
|
||||||
<div className="ml-auto flex-shrink-0">
|
<div className="ml-auto flex-shrink-0">
|
||||||
<KanBanProperties
|
<KanBanProperties
|
||||||
columnId={columnId}
|
columnId={columnId}
|
||||||
|
@ -2,7 +2,6 @@ import React from "react";
|
|||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
|
|
||||||
// mobx store
|
// mobx store
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
// components
|
// components
|
||||||
|
1
web/components/issues/issue-peek-overview/index.ts
Normal file
1
web/components/issues/issue-peek-overview/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from "./root";
|
45
web/components/issues/issue-peek-overview/issue-detail.tsx
Normal file
45
web/components/issues/issue-peek-overview/issue-detail.tsx
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import { FC } from "react";
|
||||||
|
// packages
|
||||||
|
import { RichTextEditor } from "@plane/rich-text-editor";
|
||||||
|
// hooks
|
||||||
|
import { useDebouncedCallback } from "use-debounce";
|
||||||
|
// types
|
||||||
|
import { IIssue } from "types";
|
||||||
|
// services
|
||||||
|
import { FileService } from "services/file.service";
|
||||||
|
|
||||||
|
const fileService = new FileService();
|
||||||
|
|
||||||
|
interface IPeekOverviewIssueDetails {
|
||||||
|
workspaceSlug: string;
|
||||||
|
issue: IIssue;
|
||||||
|
issueUpdate: (issue: Partial<IIssue>) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const PeekOverviewIssueDetails: FC<IPeekOverviewIssueDetails> = (props) => {
|
||||||
|
const { workspaceSlug, issue, issueUpdate } = props;
|
||||||
|
|
||||||
|
const debouncedIssueDescription = useDebouncedCallback(async (_data: any) => {
|
||||||
|
issueUpdate({ ...issue, description_html: _data });
|
||||||
|
}, 1500);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-2">
|
||||||
|
<div className="font-medium text-sm text-custom-text-200">
|
||||||
|
{issue?.project_detail?.identifier}-{issue?.sequence_id}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="font-medium text-xl">{issue?.name}</div>
|
||||||
|
|
||||||
|
<RichTextEditor
|
||||||
|
uploadFile={fileService.getUploadFileFunction(workspaceSlug)}
|
||||||
|
deleteFile={fileService.deleteImage}
|
||||||
|
value={issue?.description_html}
|
||||||
|
debouncedUpdatesEnabled={false}
|
||||||
|
onChange={(description: Object, description_html: string) => {
|
||||||
|
debouncedIssueDescription(description_html);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
141
web/components/issues/issue-peek-overview/properties.tsx
Normal file
141
web/components/issues/issue-peek-overview/properties.tsx
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
import { FC } from "react";
|
||||||
|
// ui icons
|
||||||
|
import { DoubleCircleIcon, UserGroupIcon } from "@plane/ui";
|
||||||
|
import { CalendarDays, Signal } from "lucide-react";
|
||||||
|
// components
|
||||||
|
import { IssuePropertyState } from "components/issues/issue-layouts/properties/state";
|
||||||
|
import { IssuePropertyPriority } from "components/issues/issue-layouts/properties/priority";
|
||||||
|
import { IssuePropertyAssignee } from "components/issues/issue-layouts/properties/assignee";
|
||||||
|
import { IssuePropertyDate } from "components/issues/issue-layouts/properties/date";
|
||||||
|
// types
|
||||||
|
import { IIssue } from "types";
|
||||||
|
|
||||||
|
interface IPeekOverviewProperties {
|
||||||
|
issue: IIssue;
|
||||||
|
issueUpdate: (issue: Partial<IIssue>) => void;
|
||||||
|
|
||||||
|
states: any;
|
||||||
|
members: any;
|
||||||
|
priorities: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const PeekOverviewProperties: FC<IPeekOverviewProperties> = (props) => {
|
||||||
|
const { issue, issueUpdate, states, members, priorities } = props;
|
||||||
|
|
||||||
|
const handleState = (_state: string) => {
|
||||||
|
if (issueUpdate) issueUpdate({ ...issue, state: _state });
|
||||||
|
};
|
||||||
|
|
||||||
|
const handlePriority = (_priority: any) => {
|
||||||
|
if (issueUpdate) issueUpdate({ ...issue, priority: _priority });
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleAssignee = (_assignees: string[]) => {
|
||||||
|
if (issueUpdate) issueUpdate({ ...issue, assignees: _assignees });
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleStartDate = (_startDate: string) => {
|
||||||
|
if (issueUpdate) issueUpdate({ ...issue, start_date: _startDate });
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTargetDate = (_targetDate: string) => {
|
||||||
|
if (issueUpdate) issueUpdate({ ...issue, target_date: _targetDate });
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-4">
|
||||||
|
{/* state */}
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<div className="flex-shrink-0 flex items-center gap-2 w-48 whitespace-nowrap">
|
||||||
|
<div className="w-4 h-4 flex justify-center items-center overflow-hidden">
|
||||||
|
<DoubleCircleIcon className="h-3.5 w-3.5 flex-shrink-0" />
|
||||||
|
</div>
|
||||||
|
<div className="font-medium text-custom-text-200 line-clamp-1">State</div>
|
||||||
|
</div>
|
||||||
|
<div className="w-full">
|
||||||
|
<IssuePropertyState
|
||||||
|
value={issue?.state || null}
|
||||||
|
dropdownArrow={false}
|
||||||
|
onChange={(id: string) => handleState(id)}
|
||||||
|
disabled={false}
|
||||||
|
list={states}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* assignees */}
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<div className="flex-shrink-0 flex items-center gap-2 w-48 whitespace-nowrap">
|
||||||
|
<div className="w-4 h-4 flex justify-center items-center overflow-hidden">
|
||||||
|
<UserGroupIcon className="h-3.5 w-3.5" />
|
||||||
|
</div>
|
||||||
|
<div className="font-medium text-custom-text-200 line-clamp-1">Assignees</div>
|
||||||
|
</div>
|
||||||
|
<div className="w-full">
|
||||||
|
<IssuePropertyAssignee
|
||||||
|
value={issue?.assignees || null}
|
||||||
|
dropdownArrow={false}
|
||||||
|
onChange={(ids: string[]) => handleAssignee(ids)}
|
||||||
|
disabled={false}
|
||||||
|
list={members}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* priority */}
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<div className="flex-shrink-0 flex items-center gap-2 w-48 whitespace-nowrap">
|
||||||
|
<div className="w-4 h-4 flex justify-center items-center overflow-hidden">
|
||||||
|
<Signal className="h-3.5 w-3.5" />
|
||||||
|
</div>
|
||||||
|
<div className="font-medium text-custom-text-200 line-clamp-1">Priority</div>
|
||||||
|
</div>
|
||||||
|
<div className="w-full">
|
||||||
|
<IssuePropertyPriority
|
||||||
|
value={issue?.priority || null}
|
||||||
|
dropdownArrow={false}
|
||||||
|
onChange={(id: string) => handlePriority(id)}
|
||||||
|
disabled={false}
|
||||||
|
list={priorities}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* start_date */}
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<div className="flex-shrink-0 flex items-center gap-2 w-48 whitespace-nowrap">
|
||||||
|
<div className="w-4 h-4 flex justify-center items-center overflow-hidden">
|
||||||
|
<CalendarDays className="h-3.5 w-3.5" />
|
||||||
|
</div>
|
||||||
|
<div className="font-medium text-custom-text-200 line-clamp-1">Start date</div>
|
||||||
|
</div>
|
||||||
|
<div className="w-full">
|
||||||
|
<IssuePropertyDate
|
||||||
|
value={issue?.start_date || null}
|
||||||
|
onChange={(date: string) => handleStartDate(date)}
|
||||||
|
disabled={false}
|
||||||
|
placeHolder={`Start date`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* target_date */}
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<div className="flex-shrink-0 flex items-center gap-2 w-48 whitespace-nowrap">
|
||||||
|
<div className="w-4 h-4 flex justify-center items-center overflow-hidden">
|
||||||
|
<CalendarDays className="h-3.5 w-3.5" />
|
||||||
|
</div>
|
||||||
|
<div className="font-medium text-custom-text-200 line-clamp-1">Target date</div>
|
||||||
|
</div>
|
||||||
|
<div className="w-full">
|
||||||
|
<IssuePropertyDate
|
||||||
|
value={issue?.target_date || null}
|
||||||
|
onChange={(date: string) => handleTargetDate(date)}
|
||||||
|
disabled={false}
|
||||||
|
placeHolder={`Target date`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
50
web/components/issues/issue-peek-overview/root.tsx
Normal file
50
web/components/issues/issue-peek-overview/root.tsx
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import { FC, ReactNode } from "react";
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
|
// components
|
||||||
|
import { IssueView } from "./view";
|
||||||
|
// hooks
|
||||||
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
|
// types
|
||||||
|
import { IIssue } from "types";
|
||||||
|
import { RootStore } from "store/root";
|
||||||
|
// constants
|
||||||
|
import { ISSUE_PRIORITIES } from "constants/issue";
|
||||||
|
|
||||||
|
interface IIssuePeekOverview {
|
||||||
|
workspaceSlug: string;
|
||||||
|
projectId: string;
|
||||||
|
issueId: string;
|
||||||
|
handleIssue: (issue: Partial<IIssue>) => void;
|
||||||
|
children: ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const IssuePeekOverview: FC<IIssuePeekOverview> = observer((props) => {
|
||||||
|
const { workspaceSlug, projectId, issueId, handleIssue, children } = props;
|
||||||
|
|
||||||
|
const { project: projectStore, issueDetail: issueDetailStore }: RootStore = useMobxStore();
|
||||||
|
|
||||||
|
const states = projectStore?.projectStates || undefined;
|
||||||
|
const members = projectStore?.projectMembers || undefined;
|
||||||
|
const priorities = ISSUE_PRIORITIES || undefined;
|
||||||
|
|
||||||
|
const issueUpdate = (_data: Partial<IIssue>) => {
|
||||||
|
if (handleIssue) {
|
||||||
|
handleIssue(_data);
|
||||||
|
issueDetailStore.updateIssue(workspaceSlug, projectId, issueId, _data, undefined);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<IssueView
|
||||||
|
workspaceSlug={workspaceSlug}
|
||||||
|
projectId={projectId}
|
||||||
|
issueId={issueId}
|
||||||
|
states={states}
|
||||||
|
members={members}
|
||||||
|
priorities={priorities}
|
||||||
|
issueUpdate={issueUpdate}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</IssueView>
|
||||||
|
);
|
||||||
|
});
|
206
web/components/issues/issue-peek-overview/view.tsx
Normal file
206
web/components/issues/issue-peek-overview/view.tsx
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
import { FC, ReactNode, useEffect, useState } from "react";
|
||||||
|
import { useRouter } from "next/router";
|
||||||
|
import { Maximize2, ArrowRight, Link, Trash, PanelRightOpen, Square, SquareCode } from "lucide-react";
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
|
// components
|
||||||
|
import { PeekOverviewIssueDetails } from "./issue-detail";
|
||||||
|
import { PeekOverviewProperties } from "./properties";
|
||||||
|
// types
|
||||||
|
import { IIssue } from "types";
|
||||||
|
import { RootStore } from "store/root";
|
||||||
|
// hooks
|
||||||
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
|
|
||||||
|
interface IIssueView {
|
||||||
|
workspaceSlug: string;
|
||||||
|
projectId: string;
|
||||||
|
issueId: string;
|
||||||
|
issueUpdate: (issue: Partial<IIssue>) => void;
|
||||||
|
states: any;
|
||||||
|
members: any;
|
||||||
|
priorities: any;
|
||||||
|
children: ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
type TPeekModes = "side-peek" | "modal" | "full-screen";
|
||||||
|
|
||||||
|
const peekOptions: { key: TPeekModes; icon: any; title: string }[] = [
|
||||||
|
{
|
||||||
|
key: "side-peek",
|
||||||
|
icon: PanelRightOpen,
|
||||||
|
title: "Side Peek",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "modal",
|
||||||
|
icon: Square,
|
||||||
|
title: "Modal",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "full-screen",
|
||||||
|
icon: SquareCode,
|
||||||
|
title: "Full Screen",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const IssueView: FC<IIssueView> = observer((props) => {
|
||||||
|
const { workspaceSlug, projectId, issueId, issueUpdate, states, members, priorities, children } = props;
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
const { peekIssueId } = router.query as { peekIssueId: string };
|
||||||
|
|
||||||
|
const { issueDetail: issueDetailStore }: RootStore = useMobxStore();
|
||||||
|
|
||||||
|
const [peekMode, setPeekMode] = useState<TPeekModes>("side-peek");
|
||||||
|
const handlePeekMode = (_peek: TPeekModes) => {
|
||||||
|
if (peekMode != _peek) setPeekMode(_peek);
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateRoutePeekId = () => {
|
||||||
|
if (issueId != peekIssueId) {
|
||||||
|
const { query } = router;
|
||||||
|
router.push({
|
||||||
|
pathname: router.pathname,
|
||||||
|
query: { ...query, peekIssueId: issueId },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const removeRoutePeekId = () => {
|
||||||
|
const { query } = router;
|
||||||
|
if (query.peekIssueId) {
|
||||||
|
delete query.peekIssueId;
|
||||||
|
router.push({
|
||||||
|
pathname: router.pathname,
|
||||||
|
query: { ...query },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const redirectToIssueDetail = () => {
|
||||||
|
router.push({
|
||||||
|
pathname: `/${workspaceSlug}/projects/${projectId}/issues/${issueId}`,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (workspaceSlug && projectId && issueId && peekIssueId && issueId === peekIssueId)
|
||||||
|
issueDetailStore.fetchIssueDetails(workspaceSlug, projectId, issueId);
|
||||||
|
}, [workspaceSlug, projectId, issueId, peekIssueId, issueDetailStore]);
|
||||||
|
|
||||||
|
const issue = issueDetailStore.getIssue;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="w-full !text-base">
|
||||||
|
<div onClick={updateRoutePeekId} className="w-full cursor-pointer">
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{issueId === peekIssueId && (
|
||||||
|
<div
|
||||||
|
className={`fixed z-50 overflow-hidden bg-custom-background-80 flex flex-col transition-all duration-200 border border-custom-border-200 rounded shadow-custom-shadow-2xl
|
||||||
|
${peekMode === "side-peek" ? `w-full md:w-[50%] top-0 right-0 bottom-0` : ``}
|
||||||
|
${peekMode === "modal" ? `top-[50%] left-[50%] -translate-x-[50%] -translate-y-[50%] w-5/6 h-5/6` : ``}
|
||||||
|
${peekMode === "full-screen" ? `top-0 right-0 bottom-0 left-0 m-4` : ``}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
{/* header */}
|
||||||
|
<div className="flex-shrink-0 w-full p-3 py-2.5 relative flex items-center gap-2 border-b border-custom-border-200">
|
||||||
|
<div
|
||||||
|
className="flex-shrink-0 overflow-hidden w-6 h-6 flex justify-center items-center rounded-sm transition-all duration-100 border border-custom-border-200 cursor-pointer hover:bg-custom-background-100"
|
||||||
|
onClick={removeRoutePeekId}
|
||||||
|
>
|
||||||
|
<ArrowRight width={12} strokeWidth={2} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
className="flex-shrink-0 overflow-hidden w-6 h-6 flex justify-center items-center rounded-sm transition-all duration-100 border border-custom-border-200 cursor-pointer hover:bg-custom-background-100"
|
||||||
|
onClick={redirectToIssueDetail}
|
||||||
|
>
|
||||||
|
<Maximize2 width={12} strokeWidth={2} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex-shrink-0 flex items-center gap-2">
|
||||||
|
{peekOptions.map((_option) => (
|
||||||
|
<div
|
||||||
|
key={_option?.key}
|
||||||
|
className={`px-1.5 min-w-6 h-6 flex justify-center items-center gap-1 rounded-sm transition-all duration-100 border border-custom-border-200 cursor-pointer hover:bg-custom-background-100
|
||||||
|
${peekMode === _option?.key ? `bg-custom-background-100` : ``}
|
||||||
|
`}
|
||||||
|
onClick={() => handlePeekMode(_option?.key)}
|
||||||
|
>
|
||||||
|
<_option.icon width={14} strokeWidth={2} />
|
||||||
|
<div className="text-xs font-medium">{_option?.title}</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="w-full flex justify-end items-center gap-2">
|
||||||
|
<div className="px-1.5 min-w-6 h-6 text-xs font-medium flex justify-center items-center rounded-sm transition-all duration-100 border border-custom-border-200 cursor-pointer hover:bg-custom-background-100">
|
||||||
|
Subscribe
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="overflow-hidden w-6 h-6 flex justify-center items-center rounded-sm transition-all duration-100 border border-custom-border-200 cursor-pointer hover:bg-custom-background-100">
|
||||||
|
<Link width={12} strokeWidth={2} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="overflow-hidden w-6 h-6 flex justify-center items-center rounded-sm transition-all duration-100 border border-custom-border-200 cursor-pointer hover:bg-custom-background-100">
|
||||||
|
<Trash width={12} strokeWidth={2} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* content */}
|
||||||
|
<div className="w-full h-full overflow-hidden overflow-y-auto">
|
||||||
|
{issueDetailStore?.loader && !issue ? (
|
||||||
|
<div className="text-center py-10">Loading...</div>
|
||||||
|
) : (
|
||||||
|
issue && (
|
||||||
|
<>
|
||||||
|
{["side-peek", "modal"].includes(peekMode) ? (
|
||||||
|
<div className="space-y-8 p-3 py-5">
|
||||||
|
<PeekOverviewIssueDetails workspaceSlug={workspaceSlug} issue={issue} issueUpdate={issueUpdate} />
|
||||||
|
|
||||||
|
{/* reactions */}
|
||||||
|
|
||||||
|
<PeekOverviewProperties
|
||||||
|
issue={issue}
|
||||||
|
issueUpdate={issueUpdate}
|
||||||
|
states={states}
|
||||||
|
members={members}
|
||||||
|
priorities={priorities}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* activity */}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="w-full h-full flex">
|
||||||
|
<div className="w-full h-full space-y-8 p-3 py-5">
|
||||||
|
<PeekOverviewIssueDetails
|
||||||
|
workspaceSlug={workspaceSlug}
|
||||||
|
issue={issue}
|
||||||
|
issueUpdate={issueUpdate}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* reactions */}
|
||||||
|
|
||||||
|
{/* activity */}
|
||||||
|
</div>
|
||||||
|
<div className="flex-shrink-0 !w-[400px] h-full border-l border-custom-border-200 p-3 py-5">
|
||||||
|
<PeekOverviewProperties
|
||||||
|
issue={issue}
|
||||||
|
issueUpdate={issueUpdate}
|
||||||
|
states={states}
|
||||||
|
members={members}
|
||||||
|
priorities={priorities}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
@ -1,4 +1,4 @@
|
|||||||
import { observable, action, makeObservable, runInAction } from "mobx";
|
import { observable, action, makeObservable, runInAction, computed } from "mobx";
|
||||||
// services
|
// services
|
||||||
import { IssueService } from "services/issue";
|
import { IssueService } from "services/issue";
|
||||||
// types
|
// types
|
||||||
@ -20,12 +20,22 @@ export interface IIssueDetailStore {
|
|||||||
|
|
||||||
setPeekId: (issueId: string | null) => void;
|
setPeekId: (issueId: string | null) => void;
|
||||||
setPeekMode: (issueId: IPeekMode | null) => void;
|
setPeekMode: (issueId: IPeekMode | null) => void;
|
||||||
|
|
||||||
|
// computed
|
||||||
|
getIssue: IIssue | null;
|
||||||
|
|
||||||
// fetch issue details
|
// fetch issue details
|
||||||
fetchIssueDetails: (workspaceSlug: string, projectId: string, issueId: string) => void;
|
fetchIssueDetails: (workspaceSlug: string, projectId: string, issueId: string) => void;
|
||||||
// creating issue
|
// creating issue
|
||||||
createIssue: (workspaceSlug: string, projectId: string, data: Partial<IIssue>, user: IUser) => void;
|
createIssue: (workspaceSlug: string, projectId: string, data: Partial<IIssue>, user: IUser) => void;
|
||||||
// updating issue
|
// updating issue
|
||||||
updateIssue: (workspaceSlug: string, projectId: string, issueId: string, data: Partial<IIssue>, user: IUser) => void;
|
updateIssue: (
|
||||||
|
workspaceId: string,
|
||||||
|
projectId: string,
|
||||||
|
issueId: string,
|
||||||
|
data: Partial<IIssue>,
|
||||||
|
user: IUser | undefined
|
||||||
|
) => void;
|
||||||
// deleting issue
|
// deleting issue
|
||||||
deleteIssue: (workspaceSlug: string, projectId: string, issueId: string, user: IUser) => void;
|
deleteIssue: (workspaceSlug: string, projectId: string, issueId: string, user: IUser) => void;
|
||||||
}
|
}
|
||||||
@ -57,6 +67,8 @@ export class IssueDetailStore implements IIssueDetailStore {
|
|||||||
|
|
||||||
issues: observable.ref,
|
issues: observable.ref,
|
||||||
|
|
||||||
|
getIssue: computed,
|
||||||
|
|
||||||
setPeekId: action,
|
setPeekId: action,
|
||||||
setPeekMode: action,
|
setPeekMode: action,
|
||||||
|
|
||||||
@ -70,6 +82,12 @@ export class IssueDetailStore implements IIssueDetailStore {
|
|||||||
this.issueService = new IssueService();
|
this.issueService = new IssueService();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get getIssue() {
|
||||||
|
if (!this.peekId) return null;
|
||||||
|
const _issue = this.issues[this.peekId];
|
||||||
|
return _issue || null;
|
||||||
|
}
|
||||||
|
|
||||||
setPeekId = (issueId: string | null) => (this.peekId = issueId);
|
setPeekId = (issueId: string | null) => (this.peekId = issueId);
|
||||||
|
|
||||||
setPeekMode = (mode: IPeekMode | null) => (this.peekMode = mode);
|
setPeekMode = (mode: IPeekMode | null) => (this.peekMode = mode);
|
||||||
@ -78,6 +96,7 @@ export class IssueDetailStore implements IIssueDetailStore {
|
|||||||
try {
|
try {
|
||||||
this.loader = true;
|
this.loader = true;
|
||||||
this.error = null;
|
this.error = null;
|
||||||
|
this.peekId = issueId;
|
||||||
|
|
||||||
const issueDetailsResponse = await this.issueService.retrieve(workspaceSlug, projectId, issueId);
|
const issueDetailsResponse = await this.issueService.retrieve(workspaceSlug, projectId, issueId);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user