mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
Merge branch 'preview' of github.com:makeplane/plane into develop
This commit is contained in:
commit
80761d3507
@ -1,82 +1,79 @@
|
|||||||
# 1-Click Self-Hosting
|
# One-click deploy
|
||||||
|
|
||||||
In this guide, we will walk you through the process of setting up a 1-click self-hosted environment. Self-hosting allows you to have full control over your applications and data. It's a great way to ensure privacy, control, and customization.
|
Deployment methods for Plane have improved significantly to make self-managing super-easy. One of those is a single-line-command installation of Plane.
|
||||||
|
|
||||||
Let's get started!
|
This short guide will guide you through the process, the background tasks that run with the command for the Community, One, and Enterprise editions, and the post-deployment configuration options available to you.
|
||||||
|
|
||||||
## Installing Plane
|
### Requirements
|
||||||
|
|
||||||
Installing Plane is a very easy and minimal step process.
|
- Operating systems: Debian, Ubuntu, CentOS
|
||||||
|
- Supported CPU architectures: AMD64, ARM64, x86_64, AArch64
|
||||||
|
|
||||||
### Prerequisite
|
### Download the latest stable release
|
||||||
|
|
||||||
- Operating System (latest): Debian / Ubuntu / Centos
|
Run ↓ on any CLI.
|
||||||
- Supported CPU Architechture: AMD64 / ARM64 / x86_64 / aarch64
|
|
||||||
|
|
||||||
### Downloading Latest Stable Release
|
|
||||||
|
|
||||||
```
|
```
|
||||||
curl -fsSL https://raw.githubusercontent.com/makeplane/plane/master/deploy/1-click/install.sh | sh -
|
curl -fsSL https://raw.githubusercontent.com/makeplane/plane/master/deploy/1-click/install.sh | sh -
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
<details>
|
### Download the Preview release
|
||||||
<summary>Downloading Preview Release</summary>
|
|
||||||
|
`Preview` builds do not support ARM64, AArch64 CPU architectures
|
||||||
|
|
||||||
|
Run ↓ on any CLI.
|
||||||
|
|
||||||
```
|
```
|
||||||
export BRANCH=preview
|
export BRANCH=preview
|
||||||
|
|
||||||
curl -fsSL https://raw.githubusercontent.com/makeplane/plane/preview/deploy/1-click/install.sh | sh -
|
curl -fsSL https://raw.githubusercontent.com/makeplane/plane/preview/deploy/1-click/install.sh | sh -
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
NOTE: `Preview` builds do not support ARM64/AARCH64 CPU architecture
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
Expect this after a successful install
|
|
||||||
|
|
||||||
![Install Output](images/install.png)
|
|
||||||
|
|
||||||
Access the application on a browser via http://server-ip-address
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Get Control of your Plane Server Setup
|
### Successful installation
|
||||||
|
|
||||||
Plane App is available via the command `plane-app`. Running the command `plane-app --help` helps you to manage Plane
|
You should see ↓ if there are no hitches. That output will also list the IP address you can use to access your Plane instance.
|
||||||
|
|
||||||
|
![Install Output](images/install.png)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Manage your Plane instance
|
||||||
|
|
||||||
|
Use `plane-app` [OPERATOR] to manage your Plane instance easily. Get a list of all operators with `plane-app ---help`.
|
||||||
|
|
||||||
![Plane Help](images/help.png)
|
![Plane Help](images/help.png)
|
||||||
|
|
||||||
<ins>Basic Operations</ins>:
|
1. Basic operators
|
||||||
|
|
||||||
1. Start Server using `plane-app start`
|
1. `plane-app start` starts the Plane server.
|
||||||
1. Stop Server using `plane-app stop`
|
2. `plane-app restart` restarts the Plane server.
|
||||||
1. Restart Server using `plane-app restart`
|
3. `plane-app stop` stops the Plane server.
|
||||||
|
|
||||||
<ins>Advanced Operations</ins>:
|
2. Advanced operators
|
||||||
|
|
||||||
1. Configure Plane using `plane-app --configure`. This will give you options to modify
|
`plane-app --configure` will show advanced configurators.
|
||||||
|
|
||||||
- NGINX Port (default 80)
|
- Change your proxy or listening port
|
||||||
- Domain Name (default is the local server public IP address)
|
<br>Default: 80
|
||||||
- File Upload Size (default 5MB)
|
- Change your domain name
|
||||||
- External Postgres DB Url (optional - default empty)
|
<br>Default: Deployed server's public IP address
|
||||||
- External Redis URL (optional - default empty)
|
- File upload size
|
||||||
- AWS S3 Bucket (optional - to be configured only in case the user wants to use an S3 Bucket)
|
<br>Default: 5MB
|
||||||
|
- Specify external database address when using an external database
|
||||||
|
<br>Default: `Empty`
|
||||||
|
<br>`Default folder: /opt/plane/data/postgres`
|
||||||
|
- Specify external Redis URL when using external Redis
|
||||||
|
<br>Default: `Empty`
|
||||||
|
<br>`Default folder: /opt/plane/data/redis`
|
||||||
|
- Configure AWS S3 bucket
|
||||||
|
<br>Use only when you or your users want to use S3
|
||||||
|
<br>`Default folder: /opt/plane/data/minio`
|
||||||
|
|
||||||
1. Upgrade Plane using `plane-app --upgrade`. This will get the latest stable version of Plane files (docker-compose.yaml, .env, and docker images)
|
3. Version operators
|
||||||
|
|
||||||
1. Updating Plane App installer using `plane-app --update-installer` will update the `plane-app` utility.
|
1. `plane-app --upgrade` gets the latest stable version of `docker-compose.yaml`, `.env`, and Docker images
|
||||||
|
2. `plane-app --update-installer` updates the installer and the `plane-app` utility.
|
||||||
1. Uninstall Plane using `plane-app --uninstall`. This will uninstall the Plane application from the server and all docker containers but do not remove the data stored in Postgres, Redis, and Minio.
|
3. `plane-app --uninstall` uninstalls the Plane application and all Docker containers from the server but leaves the data stored in
|
||||||
|
Postgres, Redis, and Minio alone.
|
||||||
1. Plane App can be reinstalled using `plane-app --install`.
|
4. `plane-app --install` installs the Plane app again.
|
||||||
|
|
||||||
<ins>Application Data is stored in the mentioned folders</ins>:
|
|
||||||
|
|
||||||
1. DB Data: /opt/plane/data/postgres
|
|
||||||
1. Redis Data: /opt/plane/data/redis
|
|
||||||
1. Minio Data: /opt/plane/data/minio
|
|
||||||
|
@ -58,6 +58,7 @@ export interface IGroupByKanBan {
|
|||||||
scrollableContainerRef?: MutableRefObject<HTMLDivElement | null>;
|
scrollableContainerRef?: MutableRefObject<HTMLDivElement | null>;
|
||||||
isDragStarted?: boolean;
|
isDragStarted?: boolean;
|
||||||
showEmptyGroup?: boolean;
|
showEmptyGroup?: boolean;
|
||||||
|
subGroupIssueHeaderCount?: (listId: string) => number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const GroupByKanBan: React.FC<IGroupByKanBan> = observer((props) => {
|
const GroupByKanBan: React.FC<IGroupByKanBan> = observer((props) => {
|
||||||
@ -83,6 +84,7 @@ const GroupByKanBan: React.FC<IGroupByKanBan> = observer((props) => {
|
|||||||
scrollableContainerRef,
|
scrollableContainerRef,
|
||||||
isDragStarted,
|
isDragStarted,
|
||||||
showEmptyGroup = true,
|
showEmptyGroup = true,
|
||||||
|
subGroupIssueHeaderCount,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const member = useMember();
|
const member = useMember();
|
||||||
@ -105,44 +107,57 @@ const GroupByKanBan: React.FC<IGroupByKanBan> = observer((props) => {
|
|||||||
|
|
||||||
if (!list) return null;
|
if (!list) return null;
|
||||||
|
|
||||||
const groupWithIssues = list.filter((_list) => (issueIds as TGroupedIssues)?.[_list.id]?.length > 0);
|
const visibilityGroupBy = (_list: IGroupByColumn): { showGroup: boolean; showIssues: boolean } => {
|
||||||
|
|
||||||
const groupList = showEmptyGroup ? list : groupWithIssues;
|
|
||||||
|
|
||||||
const visibilityGroupBy = (_list: IGroupByColumn) => {
|
|
||||||
if (sub_group_by) {
|
if (sub_group_by) {
|
||||||
if (kanbanFilters?.sub_group_by.includes(_list.id)) return true;
|
const groupVisibility = {
|
||||||
return false;
|
showGroup: true,
|
||||||
|
showIssues: true,
|
||||||
|
};
|
||||||
|
if (!showEmptyGroup) {
|
||||||
|
groupVisibility.showGroup = subGroupIssueHeaderCount ? subGroupIssueHeaderCount(_list.id) > 0 : true;
|
||||||
|
}
|
||||||
|
return groupVisibility;
|
||||||
} else {
|
} else {
|
||||||
if (kanbanFilters?.group_by.includes(_list.id)) return true;
|
const groupVisibility = {
|
||||||
return false;
|
showGroup: true,
|
||||||
|
showIssues: true,
|
||||||
|
};
|
||||||
|
if (!showEmptyGroup) {
|
||||||
|
if ((issueIds as TGroupedIssues)?.[_list.id]?.length > 0) groupVisibility.showGroup = true;
|
||||||
|
else groupVisibility.showGroup = false;
|
||||||
|
}
|
||||||
|
if (kanbanFilters?.group_by.includes(_list.id)) groupVisibility.showIssues = false;
|
||||||
|
return groupVisibility;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const isGroupByCreatedBy = group_by === "created_by";
|
const isGroupByCreatedBy = group_by === "created_by";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`relative flex w-full gap-2 ${sub_group_by ? "h-full" : "h-full"}`}>
|
<div className={`relative w-full flex gap-2 ${sub_group_by ? "h-full" : "h-full"}`}>
|
||||||
{groupList &&
|
{list &&
|
||||||
groupList.length > 0 &&
|
list.length > 0 &&
|
||||||
groupList.map((_list: IGroupByColumn) => {
|
list.map((subList: IGroupByColumn) => {
|
||||||
const groupByVisibilityToggle = visibilityGroupBy(_list);
|
const groupByVisibilityToggle = visibilityGroupBy(subList);
|
||||||
|
|
||||||
|
if (groupByVisibilityToggle.showGroup === false) return <></>;
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={_list.id}
|
key={subList.id}
|
||||||
className={`group relative flex flex-shrink-0 flex-col ${groupByVisibilityToggle ? `` : `w-[350px]`}`}
|
className={`relative flex flex-shrink-0 flex-col group ${
|
||||||
|
groupByVisibilityToggle.showIssues ? `w-[350px]` : ``
|
||||||
|
} `}
|
||||||
>
|
>
|
||||||
{sub_group_by === null && (
|
{sub_group_by === null && (
|
||||||
<div className="sticky top-0 z-[2] w-full flex-shrink-0 bg-custom-background-90 py-1">
|
<div className="sticky top-0 z-[2] w-full flex-shrink-0 bg-custom-background-90 py-1">
|
||||||
<HeaderGroupByCard
|
<HeaderGroupByCard
|
||||||
sub_group_by={sub_group_by}
|
sub_group_by={sub_group_by}
|
||||||
group_by={group_by}
|
group_by={group_by}
|
||||||
column_id={_list.id}
|
column_id={subList.id}
|
||||||
icon={_list.icon}
|
icon={subList.icon}
|
||||||
title={_list.name}
|
title={subList.name}
|
||||||
count={(issueIds as TGroupedIssues)?.[_list.id]?.length || 0}
|
count={(issueIds as TGroupedIssues)?.[subList.id]?.length || 0}
|
||||||
issuePayload={_list.payload}
|
issuePayload={subList.payload}
|
||||||
disableIssueCreation={disableIssueCreation || isGroupByCreatedBy}
|
disableIssueCreation={disableIssueCreation || isGroupByCreatedBy}
|
||||||
storeType={storeType}
|
storeType={storeType}
|
||||||
addIssuesToView={addIssuesToView}
|
addIssuesToView={addIssuesToView}
|
||||||
@ -152,9 +167,9 @@ const GroupByKanBan: React.FC<IGroupByKanBan> = observer((props) => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{!groupByVisibilityToggle && (
|
{groupByVisibilityToggle.showIssues && (
|
||||||
<KanbanGroup
|
<KanbanGroup
|
||||||
groupId={_list.id}
|
groupId={subList.id}
|
||||||
issuesMap={issuesMap}
|
issuesMap={issuesMap}
|
||||||
issueIds={issueIds}
|
issueIds={issueIds}
|
||||||
peekIssueId={peekIssue?.issueId ?? ""}
|
peekIssueId={peekIssue?.issueId ?? ""}
|
||||||
@ -170,7 +185,6 @@ const GroupByKanBan: React.FC<IGroupByKanBan> = observer((props) => {
|
|||||||
viewId={viewId}
|
viewId={viewId}
|
||||||
disableIssueCreation={disableIssueCreation}
|
disableIssueCreation={disableIssueCreation}
|
||||||
canEditProperties={canEditProperties}
|
canEditProperties={canEditProperties}
|
||||||
groupByVisibilityToggle={groupByVisibilityToggle}
|
|
||||||
scrollableContainerRef={scrollableContainerRef}
|
scrollableContainerRef={scrollableContainerRef}
|
||||||
isDragStarted={isDragStarted}
|
isDragStarted={isDragStarted}
|
||||||
/>
|
/>
|
||||||
@ -208,6 +222,7 @@ export interface IKanBan {
|
|||||||
canEditProperties: (projectId: string | undefined) => boolean;
|
canEditProperties: (projectId: string | undefined) => boolean;
|
||||||
scrollableContainerRef?: MutableRefObject<HTMLDivElement | null>;
|
scrollableContainerRef?: MutableRefObject<HTMLDivElement | null>;
|
||||||
isDragStarted?: boolean;
|
isDragStarted?: boolean;
|
||||||
|
subGroupIssueHeaderCount?: (listId: string) => number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const KanBan: React.FC<IKanBan> = observer((props) => {
|
export const KanBan: React.FC<IKanBan> = observer((props) => {
|
||||||
@ -232,6 +247,7 @@ export const KanBan: React.FC<IKanBan> = observer((props) => {
|
|||||||
scrollableContainerRef,
|
scrollableContainerRef,
|
||||||
isDragStarted,
|
isDragStarted,
|
||||||
showEmptyGroup,
|
showEmptyGroup,
|
||||||
|
subGroupIssueHeaderCount,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const issueKanBanView = useKanbanView();
|
const issueKanBanView = useKanbanView();
|
||||||
@ -259,6 +275,7 @@ export const KanBan: React.FC<IKanBan> = observer((props) => {
|
|||||||
scrollableContainerRef={scrollableContainerRef}
|
scrollableContainerRef={scrollableContainerRef}
|
||||||
isDragStarted={isDragStarted}
|
isDragStarted={isDragStarted}
|
||||||
showEmptyGroup={showEmptyGroup}
|
showEmptyGroup={showEmptyGroup}
|
||||||
|
subGroupIssueHeaderCount={subGroupIssueHeaderCount}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -36,7 +36,7 @@ interface IKanbanGroup {
|
|||||||
viewId?: string;
|
viewId?: string;
|
||||||
disableIssueCreation?: boolean;
|
disableIssueCreation?: boolean;
|
||||||
canEditProperties: (projectId: string | undefined) => boolean;
|
canEditProperties: (projectId: string | undefined) => boolean;
|
||||||
groupByVisibilityToggle: boolean;
|
groupByVisibilityToggle?: boolean;
|
||||||
scrollableContainerRef?: MutableRefObject<HTMLDivElement | null>;
|
scrollableContainerRef?: MutableRefObject<HTMLDivElement | null>;
|
||||||
isDragStarted?: boolean;
|
isDragStarted?: boolean;
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ interface ISubGroupSwimlaneHeader {
|
|||||||
kanbanFilters: TIssueKanbanFilters;
|
kanbanFilters: TIssueKanbanFilters;
|
||||||
handleKanbanFilters: (toggle: "group_by" | "sub_group_by", value: string) => void;
|
handleKanbanFilters: (toggle: "group_by" | "sub_group_by", value: string) => void;
|
||||||
storeType: KanbanStoreType;
|
storeType: KanbanStoreType;
|
||||||
|
showEmptyGroup: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const getSubGroupHeaderIssuesCount = (issueIds: TSubGroupedIssues, groupById: string) => {
|
const getSubGroupHeaderIssuesCount = (issueIds: TSubGroupedIssues, groupById: string) => {
|
||||||
@ -39,6 +40,22 @@ const getSubGroupHeaderIssuesCount = (issueIds: TSubGroupedIssues, groupById: st
|
|||||||
return headerCount;
|
return headerCount;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const visibilitySubGroupByGroupCount = (
|
||||||
|
issueIds: TSubGroupedIssues,
|
||||||
|
_list: IGroupByColumn,
|
||||||
|
showEmptyGroup: boolean
|
||||||
|
): boolean => {
|
||||||
|
let subGroupHeaderVisibility = true;
|
||||||
|
|
||||||
|
if (showEmptyGroup) subGroupHeaderVisibility = true;
|
||||||
|
else {
|
||||||
|
if (getSubGroupHeaderIssuesCount(issueIds, _list.id) > 0) subGroupHeaderVisibility = true;
|
||||||
|
else subGroupHeaderVisibility = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return subGroupHeaderVisibility;
|
||||||
|
};
|
||||||
|
|
||||||
const SubGroupSwimlaneHeader: React.FC<ISubGroupSwimlaneHeader> = ({
|
const SubGroupSwimlaneHeader: React.FC<ISubGroupSwimlaneHeader> = ({
|
||||||
issueIds,
|
issueIds,
|
||||||
sub_group_by,
|
sub_group_by,
|
||||||
@ -47,26 +64,37 @@ const SubGroupSwimlaneHeader: React.FC<ISubGroupSwimlaneHeader> = ({
|
|||||||
list,
|
list,
|
||||||
kanbanFilters,
|
kanbanFilters,
|
||||||
handleKanbanFilters,
|
handleKanbanFilters,
|
||||||
|
showEmptyGroup,
|
||||||
}) => (
|
}) => (
|
||||||
<div className="relative flex h-max min-h-full w-full items-center gap-2">
|
<div className="relative flex h-max min-h-full w-full items-center gap-2">
|
||||||
{list &&
|
{list &&
|
||||||
list.length > 0 &&
|
list.length > 0 &&
|
||||||
list.map((_list: IGroupByColumn) => (
|
list.map((_list: IGroupByColumn) => {
|
||||||
<div key={`${sub_group_by}_${_list.id}`} className="flex w-[350px] flex-shrink-0 flex-col">
|
const subGroupByVisibilityToggle = visibilitySubGroupByGroupCount(
|
||||||
<HeaderGroupByCard
|
issueIds as TSubGroupedIssues,
|
||||||
sub_group_by={sub_group_by}
|
_list,
|
||||||
group_by={group_by}
|
showEmptyGroup
|
||||||
column_id={_list.id}
|
);
|
||||||
icon={_list.icon}
|
|
||||||
title={_list.name}
|
if (subGroupByVisibilityToggle === false) return <></>;
|
||||||
count={getSubGroupHeaderIssuesCount(issueIds as TSubGroupedIssues, _list?.id)}
|
|
||||||
kanbanFilters={kanbanFilters}
|
return (
|
||||||
handleKanbanFilters={handleKanbanFilters}
|
<div key={`${sub_group_by}_${_list.id}`} className="flex w-[350px] flex-shrink-0 flex-col">
|
||||||
issuePayload={_list.payload}
|
<HeaderGroupByCard
|
||||||
storeType={storeType}
|
sub_group_by={sub_group_by}
|
||||||
/>
|
group_by={group_by}
|
||||||
</div>
|
column_id={_list.id}
|
||||||
))}
|
icon={_list.icon}
|
||||||
|
title={_list.name}
|
||||||
|
count={getSubGroupHeaderIssuesCount(issueIds as TSubGroupedIssues, _list?.id)}
|
||||||
|
kanbanFilters={kanbanFilters}
|
||||||
|
handleKanbanFilters={handleKanbanFilters}
|
||||||
|
issuePayload={_list.payload}
|
||||||
|
storeType={storeType}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -127,53 +155,74 @@ const SubGroupSwimlane: React.FC<ISubGroupSwimlane> = observer((props) => {
|
|||||||
return issueCount;
|
return issueCount;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const visibilitySubGroupBy = (_list: IGroupByColumn): { showGroup: boolean; showIssues: boolean } => {
|
||||||
|
const subGroupVisibility = {
|
||||||
|
showGroup: true,
|
||||||
|
showIssues: true,
|
||||||
|
};
|
||||||
|
if (showEmptyGroup) subGroupVisibility.showGroup = true;
|
||||||
|
else {
|
||||||
|
if (calculateIssueCount(_list.id) > 0) subGroupVisibility.showGroup = true;
|
||||||
|
else subGroupVisibility.showGroup = false;
|
||||||
|
}
|
||||||
|
if (kanbanFilters?.sub_group_by.includes(_list.id)) subGroupVisibility.showIssues = false;
|
||||||
|
return subGroupVisibility;
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative h-max min-h-full w-full">
|
<div className="relative h-max min-h-full w-full">
|
||||||
{list &&
|
{list &&
|
||||||
list.length > 0 &&
|
list.length > 0 &&
|
||||||
list.map((_list: any) => (
|
list.map((_list: any) => {
|
||||||
<div key={_list.id} className="flex flex-shrink-0 flex-col">
|
const subGroupByVisibilityToggle = visibilitySubGroupBy(_list);
|
||||||
<div className="sticky top-[50px] z-[1] flex w-full items-center bg-custom-background-90 py-1">
|
if (subGroupByVisibilityToggle.showGroup === false) return <></>;
|
||||||
<div className="sticky left-0 flex-shrink-0 bg-custom-background-90 pr-2">
|
return (
|
||||||
<HeaderSubGroupByCard
|
<div key={_list.id} className="flex flex-shrink-0 flex-col">
|
||||||
column_id={_list.id}
|
<div className="sticky top-[50px] z-[1] flex w-full items-center bg-custom-background-90 py-1">
|
||||||
icon={_list.Icon}
|
<div className="sticky left-0 flex-shrink-0 bg-custom-background-90 pr-2">
|
||||||
title={_list.name || ""}
|
<HeaderSubGroupByCard
|
||||||
count={calculateIssueCount(_list.id)}
|
column_id={_list.id}
|
||||||
kanbanFilters={kanbanFilters}
|
icon={_list.Icon}
|
||||||
handleKanbanFilters={handleKanbanFilters}
|
title={_list.name || ""}
|
||||||
/>
|
count={calculateIssueCount(_list.id)}
|
||||||
|
kanbanFilters={kanbanFilters}
|
||||||
|
handleKanbanFilters={handleKanbanFilters}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="w-full border-b border-dashed border-custom-border-400" />
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full border-b border-dashed border-custom-border-400" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{!kanbanFilters?.sub_group_by.includes(_list.id) && (
|
{subGroupByVisibilityToggle.showIssues && (
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<KanBan
|
<KanBan
|
||||||
issuesMap={issuesMap}
|
issuesMap={issuesMap}
|
||||||
issueIds={(issueIds as TSubGroupedIssues)?.[_list.id]}
|
issueIds={(issueIds as TSubGroupedIssues)?.[_list.id]}
|
||||||
displayProperties={displayProperties}
|
displayProperties={displayProperties}
|
||||||
sub_group_by={sub_group_by}
|
sub_group_by={sub_group_by}
|
||||||
group_by={group_by}
|
group_by={group_by}
|
||||||
sub_group_id={_list.id}
|
sub_group_id={_list.id}
|
||||||
updateIssue={updateIssue}
|
storeType={storeType}
|
||||||
quickActions={quickActions}
|
updateIssue={updateIssue}
|
||||||
kanbanFilters={kanbanFilters}
|
quickActions={quickActions}
|
||||||
handleKanbanFilters={handleKanbanFilters}
|
kanbanFilters={kanbanFilters}
|
||||||
showEmptyGroup={showEmptyGroup}
|
handleKanbanFilters={handleKanbanFilters}
|
||||||
enableQuickIssueCreate={enableQuickIssueCreate}
|
showEmptyGroup={showEmptyGroup}
|
||||||
canEditProperties={canEditProperties}
|
enableQuickIssueCreate={enableQuickIssueCreate}
|
||||||
addIssuesToView={addIssuesToView}
|
canEditProperties={canEditProperties}
|
||||||
quickAddCallback={quickAddCallback}
|
addIssuesToView={addIssuesToView}
|
||||||
viewId={viewId}
|
quickAddCallback={quickAddCallback}
|
||||||
scrollableContainerRef={scrollableContainerRef}
|
viewId={viewId}
|
||||||
isDragStarted={isDragStarted}
|
scrollableContainerRef={scrollableContainerRef}
|
||||||
storeType={storeType}
|
isDragStarted={isDragStarted}
|
||||||
/>
|
subGroupIssueHeaderCount={(groupByListId: string) =>
|
||||||
</div>
|
getSubGroupHeaderIssuesCount(issueIds as TSubGroupedIssues, groupByListId)
|
||||||
)}
|
}
|
||||||
</div>
|
/>
|
||||||
))}
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -267,6 +316,7 @@ export const KanBanSwimLanes: React.FC<IKanBanSwimLanes> = observer((props) => {
|
|||||||
handleKanbanFilters={handleKanbanFilters}
|
handleKanbanFilters={handleKanbanFilters}
|
||||||
list={groupByList}
|
list={groupByList}
|
||||||
storeType={storeType}
|
storeType={storeType}
|
||||||
|
showEmptyGroup={showEmptyGroup}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user