forked from github/plane
merge conflicts resolved
This commit is contained in:
commit
c55c021a37
@ -8,8 +8,8 @@ Before submitting a new issue, please search the [issues](https://github.com/mak
|
|||||||
|
|
||||||
While we want to fix all the [issues](https://github.com/makeplane/plane/issues), before fixing a bug we need to be able to reproduce and confirm it. Please provide us with a minimal reproduction scenario using a repository or [Gist](https://gist.github.com/). Having a live, reproducible scenario gives us the information without asking questions back & forth with additional questions like:
|
While we want to fix all the [issues](https://github.com/makeplane/plane/issues), before fixing a bug we need to be able to reproduce and confirm it. Please provide us with a minimal reproduction scenario using a repository or [Gist](https://gist.github.com/). Having a live, reproducible scenario gives us the information without asking questions back & forth with additional questions like:
|
||||||
|
|
||||||
- 3rd-party libraries being used and their versions
|
- 3rd-party libraries being used and their versions
|
||||||
- a use-case that fails
|
- a use-case that fails
|
||||||
|
|
||||||
Without said minimal reproduction, we won't be able to investigate all [issues](https://github.com/makeplane/plane/issues), and the issue might not be resolved.
|
Without said minimal reproduction, we won't be able to investigate all [issues](https://github.com/makeplane/plane/issues), and the issue might not be resolved.
|
||||||
|
|
||||||
@ -19,10 +19,10 @@ You can open a new issue with this [issue form](https://github.com/makeplane/pla
|
|||||||
|
|
||||||
### Requirements
|
### Requirements
|
||||||
|
|
||||||
- Node.js version v16.18.0
|
- Node.js version v16.18.0
|
||||||
- Python version 3.8+
|
- Python version 3.8+
|
||||||
- Postgres version v14
|
- Postgres version v14
|
||||||
- Redis version v6.2.7
|
- Redis version v6.2.7
|
||||||
|
|
||||||
### Setup the project
|
### Setup the project
|
||||||
|
|
||||||
@ -30,6 +30,48 @@ The project is a monorepo, with backend api and frontend in a single repo.
|
|||||||
|
|
||||||
The backend is a django project which is kept inside apiserver
|
The backend is a django project which is kept inside apiserver
|
||||||
|
|
||||||
|
1. Clone the repo
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/makeplane/plane
|
||||||
|
cd plane
|
||||||
|
chmod +x setup.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Run setup.sh
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./setup.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Define `NEXT_PUBLIC_API_BASE_URL=http://localhost` in **web/.env** and **space/.env** file
|
||||||
|
|
||||||
|
```bash
|
||||||
|
echo "\nNEXT_PUBLIC_API_BASE_URL=http://localhost\n" >> ./web/.env
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
echo "\nNEXT_PUBLIC_API_BASE_URL=http://localhost\n" >> ./space/.env
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Run Docker compose up
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
5. Install dependencies
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn install
|
||||||
|
```
|
||||||
|
|
||||||
|
6. Run the web app in development mode
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn dev
|
||||||
|
```
|
||||||
|
|
||||||
## Missing a Feature?
|
## Missing a Feature?
|
||||||
|
|
||||||
If a feature is missing, you can directly _request_ a new one [here](https://github.com/makeplane/plane/issues/new?assignees=&labels=feature&template=feature_request.yml&title=%F0%9F%9A%80+Feature%3A+). You also can do the same by choosing "🚀 Feature" when raising a [New Issue](https://github.com/makeplane/plane/issues/new/choose) on our GitHub Repository.
|
If a feature is missing, you can directly _request_ a new one [here](https://github.com/makeplane/plane/issues/new?assignees=&labels=feature&template=feature_request.yml&title=%F0%9F%9A%80+Feature%3A+). You also can do the same by choosing "🚀 Feature" when raising a [New Issue](https://github.com/makeplane/plane/issues/new/choose) on our GitHub Repository.
|
||||||
@ -39,8 +81,8 @@ If you would like to _implement_ it, an issue with your proposal must be submitt
|
|||||||
|
|
||||||
To ensure consistency throughout the source code, please keep these rules in mind as you are working:
|
To ensure consistency throughout the source code, please keep these rules in mind as you are working:
|
||||||
|
|
||||||
- All features or bug fixes must be tested by one or more specs (unit-tests).
|
- All features or bug fixes must be tested by one or more specs (unit-tests).
|
||||||
- We use [Eslint default rule guide](https://eslint.org/docs/rules/), with minor changes. An automated formatter is available using prettier.
|
- We use [Eslint default rule guide](https://eslint.org/docs/rules/), with minor changes. An automated formatter is available using prettier.
|
||||||
|
|
||||||
## Need help? Questions and suggestions
|
## Need help? Questions and suggestions
|
||||||
|
|
||||||
@ -48,11 +90,11 @@ Questions, suggestions, and thoughts are most welcome. We can also be reached in
|
|||||||
|
|
||||||
## Ways to contribute
|
## Ways to contribute
|
||||||
|
|
||||||
- Try Plane Cloud and the self hosting platform and give feedback
|
- Try Plane Cloud and the self hosting platform and give feedback
|
||||||
- Add new integrations
|
- Add new integrations
|
||||||
- Help with open [issues](https://github.com/makeplane/plane/issues) or [create your own](https://github.com/makeplane/plane/issues/new/choose)
|
- Help with open [issues](https://github.com/makeplane/plane/issues) or [create your own](https://github.com/makeplane/plane/issues/new/choose)
|
||||||
- Share your thoughts and suggestions with us
|
- Share your thoughts and suggestions with us
|
||||||
- Help create tutorials and blog posts
|
- Help create tutorials and blog posts
|
||||||
- Request a feature by submitting a proposal
|
- Request a feature by submitting a proposal
|
||||||
- Report a bug
|
- Report a bug
|
||||||
- **Improve documentation** - fix incomplete or missing [docs](https://docs.plane.so/), bad wording, examples or explanations.
|
- **Improve documentation** - fix incomplete or missing [docs](https://docs.plane.so/), bad wording, examples or explanations.
|
||||||
|
@ -93,7 +93,9 @@ export const IssuesFilterView: React.FC = () => {
|
|||||||
<Tooltip
|
<Tooltip
|
||||||
key={option.type}
|
key={option.type}
|
||||||
tooltipContent={
|
tooltipContent={
|
||||||
<span className="capitalize">{replaceUnderscoreIfSnakeCase(option.type)} Layout</span>
|
<span className="capitalize">
|
||||||
|
{replaceUnderscoreIfSnakeCase(option.type)} Layout
|
||||||
|
</span>
|
||||||
}
|
}
|
||||||
position="bottom"
|
position="bottom"
|
||||||
>
|
>
|
||||||
@ -318,7 +320,7 @@ export const IssuesFilterView: React.FC = () => {
|
|||||||
displayFilters.layout !== "spreadsheet" &&
|
displayFilters.layout !== "spreadsheet" &&
|
||||||
displayFilters.layout !== "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">Show empty states</h4>
|
<h4 className="text-custom-text-200">Show empty groups</h4>
|
||||||
<div className="w-28">
|
<div className="w-28">
|
||||||
<ToggleSwitch
|
<ToggleSwitch
|
||||||
value={displayFilters.show_empty_groups ?? true}
|
value={displayFilters.show_empty_groups ?? true}
|
||||||
|
@ -20,7 +20,7 @@ import { renderEmoji } from "helpers/emoji.helper";
|
|||||||
// types
|
// types
|
||||||
import { IIssueViewProps, IState, TIssuePriorities, TStateGroups } from "types";
|
import { IIssueViewProps, IState, TIssuePriorities, TStateGroups } from "types";
|
||||||
// fetch-keys
|
// fetch-keys
|
||||||
import { PROJECT_ISSUE_LABELS, PROJECT_MEMBERS } from "constants/fetch-keys";
|
import { PROJECT_ISSUE_LABELS, PROJECT_MEMBERS, WORKSPACE_LABELS } from "constants/fetch-keys";
|
||||||
// constants
|
// constants
|
||||||
import { STATE_GROUP_COLORS } from "constants/state";
|
import { STATE_GROUP_COLORS } from "constants/state";
|
||||||
|
|
||||||
@ -59,6 +59,15 @@ export const BoardHeader: React.FC<Props> = ({
|
|||||||
: null
|
: null
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { data: workspaceLabels } = useSWR(
|
||||||
|
workspaceSlug && displayFilters?.group_by === "labels"
|
||||||
|
? WORKSPACE_LABELS(workspaceSlug.toString())
|
||||||
|
: null,
|
||||||
|
workspaceSlug && displayFilters?.group_by === "labels"
|
||||||
|
? () => issuesService.getWorkspaceLabels(workspaceSlug.toString())
|
||||||
|
: null
|
||||||
|
);
|
||||||
|
|
||||||
const { data: members } = useSWR(
|
const { data: members } = useSWR(
|
||||||
workspaceSlug &&
|
workspaceSlug &&
|
||||||
projectId &&
|
projectId &&
|
||||||
@ -82,7 +91,10 @@ export const BoardHeader: React.FC<Props> = ({
|
|||||||
title = addSpaceIfCamelCase(currentState?.name ?? "");
|
title = addSpaceIfCamelCase(currentState?.name ?? "");
|
||||||
break;
|
break;
|
||||||
case "labels":
|
case "labels":
|
||||||
title = issueLabels?.find((label) => label.id === groupTitle)?.name ?? "None";
|
title =
|
||||||
|
[...(issueLabels ?? []), ...(workspaceLabels ?? [])]?.find(
|
||||||
|
(label) => label.id === groupTitle
|
||||||
|
)?.name ?? "None";
|
||||||
break;
|
break;
|
||||||
case "project":
|
case "project":
|
||||||
title = projects?.find((p) => p.id === groupTitle)?.name ?? "None";
|
title = projects?.find((p) => p.id === groupTitle)?.name ?? "None";
|
||||||
@ -137,7 +149,9 @@ export const BoardHeader: React.FC<Props> = ({
|
|||||||
break;
|
break;
|
||||||
case "labels":
|
case "labels":
|
||||||
const labelColor =
|
const labelColor =
|
||||||
issueLabels?.find((label) => label.id === groupTitle)?.color ?? "#000000";
|
[...(issueLabels ?? []), ...(workspaceLabels ?? [])]?.find(
|
||||||
|
(label) => label.id === groupTitle
|
||||||
|
)?.color ?? "#000000";
|
||||||
icon = (
|
icon = (
|
||||||
<span
|
<span
|
||||||
className="h-3.5 w-3.5 flex-shrink-0 rounded-full"
|
className="h-3.5 w-3.5 flex-shrink-0 rounded-full"
|
||||||
|
@ -266,7 +266,7 @@ export const ProfileIssuesViewOptions: React.FC = () => {
|
|||||||
displayFilters?.layout !== "spreadsheet" && (
|
displayFilters?.layout !== "spreadsheet" && (
|
||||||
<>
|
<>
|
||||||
<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 empty groups</h4>
|
||||||
<div className="w-28">
|
<div className="w-28">
|
||||||
<ToggleSwitch
|
<ToggleSwitch
|
||||||
value={displayFilters?.show_empty_groups ?? true}
|
value={displayFilters?.show_empty_groups ?? true}
|
||||||
|
@ -31,15 +31,53 @@ import { BoltOutlined, GridViewOutlined } from "@mui/icons-material";
|
|||||||
import emptyDashboard from "public/empty-state/dashboard.svg";
|
import emptyDashboard from "public/empty-state/dashboard.svg";
|
||||||
import githubBlackImage from "/public/logos/github-black.png";
|
import githubBlackImage from "/public/logos/github-black.png";
|
||||||
import githubWhiteImage from "/public/logos/github-white.png";
|
import githubWhiteImage from "/public/logos/github-white.png";
|
||||||
// helpers
|
|
||||||
import { render12HourFormatTime, renderShortDate } from "helpers/date-time.helper";
|
|
||||||
// types
|
// types
|
||||||
import { ICurrentUserResponse } from "types";
|
import { ICurrentUserResponse } from "types";
|
||||||
import type { NextPage } from "next";
|
import type { NextPage } from "next";
|
||||||
// fetch-keys
|
// fetch-keys
|
||||||
import { CURRENT_USER, USER_WORKSPACE_DASHBOARD } from "constants/fetch-keys";
|
import { CURRENT_USER, USER_WORKSPACE_DASHBOARD } from "constants/fetch-keys";
|
||||||
// constants
|
|
||||||
import { DAYS } from "constants/project";
|
const Greeting = ({ user }: { user: ICurrentUserResponse | undefined }) => {
|
||||||
|
const currentTime = new Date();
|
||||||
|
|
||||||
|
const hour = new Intl.DateTimeFormat("en-US", {
|
||||||
|
hour12: false,
|
||||||
|
hour: "numeric",
|
||||||
|
}).format(currentTime);
|
||||||
|
|
||||||
|
const date = new Intl.DateTimeFormat("en-US", {
|
||||||
|
month: "short",
|
||||||
|
day: "numeric",
|
||||||
|
}).format(currentTime);
|
||||||
|
|
||||||
|
const weekDay = new Intl.DateTimeFormat("en-US", {
|
||||||
|
weekday: "long",
|
||||||
|
}).format(currentTime);
|
||||||
|
|
||||||
|
const timeString = new Intl.DateTimeFormat("en-US", {
|
||||||
|
timeZone: user?.user_timezone,
|
||||||
|
hour12: false, // Use 24-hour format
|
||||||
|
hour: "2-digit",
|
||||||
|
minute: "2-digit",
|
||||||
|
}).format(currentTime);
|
||||||
|
|
||||||
|
const greeting =
|
||||||
|
parseInt(hour, 10) < 12 ? "morning" : parseInt(hour, 10) < 18 ? "afternoon" : "evening";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h3 className="text-2xl font-semibold">
|
||||||
|
Good {greeting}, {user?.first_name} {user?.last_name}
|
||||||
|
</h3>
|
||||||
|
<h6 className="text-custom-text-400 font-medium flex items-center gap-2">
|
||||||
|
<div>{greeting === "morning" ? "🌤️" : greeting === "afternoon" ? "🌥️" : "🌙️"}</div>
|
||||||
|
<div>
|
||||||
|
{weekDay}, {date} {timeString}
|
||||||
|
</div>
|
||||||
|
</h6>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const WorkspacePage: NextPage = () => {
|
const WorkspacePage: NextPage = () => {
|
||||||
const [month, setMonth] = useState(new Date().getMonth() + 1);
|
const [month, setMonth] = useState(new Date().getMonth() + 1);
|
||||||
@ -58,10 +96,6 @@ const WorkspacePage: NextPage = () => {
|
|||||||
workspaceSlug ? () => userService.userWorkspaceDashboard(workspaceSlug as string, month) : null
|
workspaceSlug ? () => userService.userWorkspaceDashboard(workspaceSlug as string, month) : null
|
||||||
);
|
);
|
||||||
|
|
||||||
const today = new Date();
|
|
||||||
const greeting =
|
|
||||||
today.getHours() < 12 ? "morning" : today.getHours() < 18 ? "afternoon" : "evening";
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!workspaceSlug) return;
|
if (!workspaceSlug) return;
|
||||||
|
|
||||||
@ -127,9 +161,11 @@ const WorkspacePage: NextPage = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{projects ? (
|
<div className="p-8 space-y-8">
|
||||||
projects.length > 0 ? (
|
<Greeting user={user} />
|
||||||
<div className="p-8">
|
|
||||||
|
{projects ? (
|
||||||
|
projects.length > 0 ? (
|
||||||
<div className="flex flex-col gap-8">
|
<div className="flex flex-col gap-8">
|
||||||
<IssuesStats data={workspaceDashboardData} />
|
<IssuesStats data={workspaceDashboardData} />
|
||||||
<div className="grid grid-cols-1 gap-8 lg:grid-cols-2">
|
<div className="grid grid-cols-1 gap-8 lg:grid-cols-2">
|
||||||
@ -143,40 +179,34 @@ const WorkspacePage: NextPage = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
) : (
|
||||||
) : (
|
<div className="p-8">
|
||||||
<div className="p-8">
|
<Greeting user={user} />
|
||||||
<h3 className="text-2xl font-semibold">
|
<div className="mt-7 bg-custom-primary-100/5 flex justify-between gap-5 md:gap-8">
|
||||||
Good {greeting}, {user?.first_name} {user?.last_name}
|
<div className="p-5 md:p-8 pr-0">
|
||||||
</h3>
|
<h5 className="text-xl font-semibold">Create a project</h5>
|
||||||
<h6 className="text-custom-text-400 font-medium">
|
<p className="mt-2 mb-5">
|
||||||
{greeting === "morning" ? "🌤️" : greeting === "afternoon" ? "🌥️" : "🌙️"}
|
Manage your projects by creating issues, cycles, modules, views and pages.
|
||||||
{DAYS[today.getDay()]}, {renderShortDate(today)} {render12HourFormatTime(today)}
|
</p>
|
||||||
</h6>
|
<PrimaryButton
|
||||||
<div className="mt-7 bg-custom-primary-100/5 flex justify-between gap-5 md:gap-8">
|
onClick={() => {
|
||||||
<div className="p-5 md:p-8 pr-0">
|
const e = new KeyboardEvent("keydown", {
|
||||||
<h5 className="text-xl font-semibold">Create a project</h5>
|
key: "p",
|
||||||
<p className="mt-2 mb-5">
|
});
|
||||||
Manage your projects by creating issues, cycles, modules, views and pages.
|
document.dispatchEvent(e);
|
||||||
</p>
|
}}
|
||||||
<PrimaryButton
|
>
|
||||||
onClick={() => {
|
Create Project
|
||||||
const e = new KeyboardEvent("keydown", {
|
</PrimaryButton>
|
||||||
key: "p",
|
</div>
|
||||||
});
|
<div className="hidden md:block self-end overflow-hidden pt-8">
|
||||||
document.dispatchEvent(e);
|
<Image src={emptyDashboard} alt="Empty Dashboard" />
|
||||||
}}
|
</div>
|
||||||
>
|
|
||||||
Create Project
|
|
||||||
</PrimaryButton>
|
|
||||||
</div>
|
|
||||||
<div className="hidden md:block self-end overflow-hidden pt-8">
|
|
||||||
<Image src={emptyDashboard} alt="Empty Dashboard" />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)
|
||||||
)
|
) : null}
|
||||||
) : null}
|
</div>
|
||||||
</WorkspaceAuthorizationLayout>
|
</WorkspaceAuthorizationLayout>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user