diff --git a/.github/workflows/build-branch.yml b/.github/workflows/build-branch.yml index a3ca1d688..47bbb94c0 100644 --- a/.github/workflows/build-branch.yml +++ b/.github/workflows/build-branch.yml @@ -15,7 +15,7 @@ env: TARGET_BRANCH: ${{ github.event.pull_request.base.ref }} jobs: - branch_build_and_push: + branch_build_setup: if: ${{ (github.event_name == 'pull_request' && github.event.action =='closed' && github.event.pull_request.merged == true) }} name: Build-Push Web/Space/API/Proxy Docker Image runs-on: ubuntu-20.04 @@ -59,18 +59,18 @@ jobs: branch_build_push_frontend: runs-on: ubuntu-20.04 - needs: [branch_build_and_push] + needs: [branch_build_setup] env: - FRONTEND_TAG: ${{ secrets.DOCKERHUB_USERNAME }}/plane-frontend-private:${{ needs.branch_build_and_push.outputs.gh_branch_name }} + FRONTEND_TAG: ${{ secrets.DOCKERHUB_USERNAME }}/plane-frontend-private:${{ needs.branch_build_setup.outputs.gh_branch_name }} steps: - name: Set Frontend Docker Tag run: | - if [ "${{ needs.branch_build_and_push.outputs.gh_branch_name }}" = "master" ]; then - TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-frontend-private:latest" - elif [ "${{ needs.branch_build_and_push.outputs.gh_branch_name }}" = "release" ] || [ "${{ needs.branch_build_and_push.outputs.gh_branch_name }}" = "preview" ]; then - TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-frontend-private:preview,${{ secrets.DOCKERHUB_USERNAME }}/plane-frontend:preview" + if [ "${{ needs.branch_build_setup.outputs.gh_branch_name }}" == "master" ]; then + TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-frontend-private:latest + elif [ "${{ needs.branch_build_setup.outputs.gh_branch_name }}" == "release" ] || [ "${{ needs.branch_build_setup.outputs.gh_branch_name }}" == "preview" ]; then + TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-frontend-private:preview,${{ secrets.DOCKERHUB_USERNAME }}/plane-frontend:preview else - TAG=${{ env.FRONTEND_TAG }}" + TAG=${{ env.FRONTEND_TAG }} fi echo "FRONTEND_TAG=${TAG}" >> $GITHUB_ENV - name: Set up Docker Buildx @@ -101,18 +101,18 @@ jobs: branch_build_push_space: runs-on: ubuntu-20.04 - needs: [branch_build_and_push] + needs: [branch_build_setup] env: - SPACE_TAG: ${{ secrets.DOCKERHUB_USERNAME }}/plane-space-private:${{ needs.branch_build_and_push.outputs.gh_branch_name }} + SPACE_TAG: ${{ secrets.DOCKERHUB_USERNAME }}/plane-space-private:${{ needs.branch_build_setup.outputs.gh_branch_name }} steps: - name: Set Space Docker Tag run: | - if [ "${{ needs.branch_build_and_push.outputs.gh_branch_name }}" = "master" ]; then - TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-space:latest" - elif [ "${{ needs.branch_build_and_push.outputs.gh_branch_name }}" = "release" ] || [ "${{ needs.branch_build_and_push.outputs.gh_branch_name }}" = "preview" ]; then - TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-space-private:preview,${{ secrets.DOCKERHUB_USERNAME }}/plane-space:preview" + if [ "${{ needs.branch_build_setup.outputs.gh_branch_name }}" == "master" ]; then + TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-space:latest + elif [ "${{ needs.branch_build_setup.outputs.gh_branch_name }}" == "release" ] || [ "${{ needs.branch_build_setup.outputs.gh_branch_name }}" == "preview" ]; then + TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-space-private:preview,${{ secrets.DOCKERHUB_USERNAME }}/plane-space:preview else - TAG=${{ env.SPACE_TAG }}" + TAG=${{ env.SPACE_TAG }} fi echo "SPACE_TAG=${TAG}" >> $GITHUB_ENV - name: Set up Docker Buildx @@ -143,16 +143,16 @@ jobs: branch_build_push_backend: runs-on: ubuntu-20.04 - needs: [branch_build_and_push] + needs: [branch_build_setup] env: - BACKEND_TAG: ${{ secrets.DOCKERHUB_USERNAME }}/plane-backend-private:${{ needs.branch_build_and_push.outputs.gh_branch_name }} + BACKEND_TAG: ${{ secrets.DOCKERHUB_USERNAME }}/plane-backend-private:${{ needs.branch_build_setup.outputs.gh_branch_name }} steps: - name: Set Backend Docker Tag run: | - if [ "${{ needs.branch_build_and_push.outputs.gh_branch_name }}" = "master" ]; then - TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-backend-private:latest" - elif [ "${{ needs.branch_build_and_push.outputs.gh_branch_name }}" = "release" ] || [ "${{ needs.branch_build_and_push.outputs.gh_branch_name }}" = "preview" ]; then - TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-backend-private:preview",${{ secrets.DOCKERHUB_USERNAME }}/plane-backend:preview" + if [ "${{ needs.branch_build_setup.outputs.gh_branch_name }}" == "master" ]; then + TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-backend-private:latest + elif [ "${{ needs.branch_build_setup.outputs.gh_branch_name }}" == "release" ] || [ "${{ needs.branch_build_setup.outputs.gh_branch_name }}" == "preview" ]; then + TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-backend-private:preview,${{ secrets.DOCKERHUB_USERNAME }}/plane-backend:preview else TAG=${{ env.BACKEND_TAG }} fi @@ -185,16 +185,16 @@ jobs: branch_build_push_proxy: runs-on: ubuntu-20.04 - needs: [branch_build_and_push] + needs: [branch_build_setup] env: - PROXY_TAG: ${{ secrets.DOCKERHUB_USERNAME }}/plane-proxy-private:${{ needs.branch_build_and_push.outputs.gh_branch_name }} + PROXY_TAG: ${{ secrets.DOCKERHUB_USERNAME }}/plane-proxy-private:${{ needs.branch_build_setup.outputs.gh_branch_name }} steps: - name: Set Proxy Docker Tag run: | - if [ "${{ needs.branch_build_and_push.outputs.gh_branch_name }}" = "master" ]; then - TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-proxy-private:latest" - elif [ "${{ needs.branch_build_and_push.outputs.gh_branch_name }}" = "release" ] || [ "${{ needs.branch_build_and_push.outputs.gh_branch_name }}" = "preview" ]; then - TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-proxy-private:preview,${{ secrets.DOCKERHUB_USERNAME }}/plane-proxy:preview" + if [ "${{ needs.branch_build_setup.outputs.gh_branch_name }}" == "master" ]; then + TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-proxy-private:latest + elif [ "${{ needs.branch_build_setup.outputs.gh_branch_name }}" == "release" ] || [ "${{ needs.branch_build_setup.outputs.gh_branch_name }}" == "preview" ]; then + TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-proxy-private:preview,${{ secrets.DOCKERHUB_USERNAME }}/plane-proxy:preview else TAG=${{ env.PROXY_TAG }} fi diff --git a/ENV_SETUP.md b/ENV_SETUP.md index f1cc7cb1e..3e03244c6 100644 --- a/ENV_SETUP.md +++ b/ENV_SETUP.md @@ -76,7 +76,6 @@ NEXT_PUBLIC_ENABLE_OAUTH=0 # Backend # Debug value for api server use it as 0 for production use DEBUG=0 -DJANGO_SETTINGS_MODULE="plane.settings.selfhosted" # deprecated ​ # Error logs SENTRY_DSN="" diff --git a/deploy/coolify/coolify-docker-compose.yml b/deploy/coolify/coolify-docker-compose.yml index 4d3516b16..2a21c61a8 100644 --- a/deploy/coolify/coolify-docker-compose.yml +++ b/deploy/coolify/coolify-docker-compose.yml @@ -35,7 +35,6 @@ services: command: ./bin/takeoff environment: - DEBUG=${DEBUG:-0} - - DJANGO_SETTINGS_MODULE=${DJANGO_SETTINGS_MODULE:-plane.settings.selfhosted} - SENTRY_DSN=${SENTRY_DSN:-""} - PGUSER=${PGUSER:-plane} - PGPASSWORD=${PGPASSWORD:-plane} @@ -84,7 +83,6 @@ services: command: ./bin/worker environment: - DEBUG=${DEBUG:-0} - - DJANGO_SETTINGS_MODULE=${DJANGO_SETTINGS_MODULE:-plane.settings.selfhosted} - SENTRY_DSN=${SENTRY_DSN:-""} - PGUSER=${PGUSER:-plane} - PGPASSWORD=${PGPASSWORD:-plane} @@ -131,7 +129,6 @@ services: command: ./bin/beat environment: - DEBUG=${DEBUG:-0} - - DJANGO_SETTINGS_MODULE=${DJANGO_SETTINGS_MODULE:-plane.settings.selfhosted} - SENTRY_DSN=${SENTRY_DSN:-""} - PGUSER=${PGUSER:-plane} - PGPASSWORD=${PGPASSWORD:-plane} diff --git a/deploy/selfhost/variables.env b/deploy/selfhost/variables.env index b822b7ed1..6be9ca2f4 100644 --- a/deploy/selfhost/variables.env +++ b/deploy/selfhost/variables.env @@ -7,7 +7,6 @@ API_REPLICAS=1 NGINX_PORT=80 WEB_URL=http://localhost DEBUG=0 -DJANGO_SETTINGS_MODULE=plane.settings.selfhosted # deprecated NEXT_PUBLIC_ENABLE_OAUTH=0 NEXT_PUBLIC_DEPLOY_URL=http://localhost/spaces SENTRY_DSN="" diff --git a/space/components/accounts/email-reset-password-form.tsx b/space/components/accounts/email-reset-password-form.tsx index ee71890ec..e7752a00f 100644 --- a/space/components/accounts/email-reset-password-form.tsx +++ b/space/components/accounts/email-reset-password-form.tsx @@ -1,11 +1,5 @@ import React from "react"; - -// react hook form import { useForm } from "react-hook-form"; -// services -import userService from "services/user.service"; -// hooks -// import useToast from "hooks/use-toast"; // ui import { Input } from "components/ui"; import { Button } from "@plane/ui"; @@ -30,10 +24,9 @@ export const EmailResetPasswordForm: React.FC = ({ setIsResettingPassword }); const forgotPassword = async (formData: any) => { - const payload = { - email: formData.email, - }; - + // const payload = { + // email: formData.email, + // }; // await userService // .forgotPassword(payload) // .then(() => @@ -60,7 +53,7 @@ export const EmailResetPasswordForm: React.FC = ({ setIsResettingPassword }; return ( -
+
= ({ setIsResettingPassword ) || "Email address is not valid", })} placeholder="Enter registered email address.." - className="border-custom-border-300 h-[46px]" + className="h-[46px] border-custom-border-300" /> {errors.email &&
{errors.email.message}
}
-
+
diff --git a/space/components/issues/filters-render/state/filter-state-block.tsx b/space/components/issues/filters-render/state/filter-state-block.tsx index 9b6447cb6..b9c8ed4ec 100644 --- a/space/components/issues/filters-render/state/filter-state-block.tsx +++ b/space/components/issues/filters-render/state/filter-state-block.tsx @@ -1,19 +1,10 @@ -import { useRouter } from "next/router"; -// mobx react lite import { observer } from "mobx-react-lite"; -// mobx hook -import { useMobxStore } from "lib/mobx/store-provider"; // interfaces import { IIssueState } from "types/issue"; // constants import { issueGroupFilter } from "constants/data"; export const RenderIssueState = observer(({ state }: { state: IIssueState }) => { - const store = useMobxStore(); - - const router = useRouter(); - const { workspace_slug, project_slug } = router.query as { workspace_slug: string; project_slug: string }; - const stateGroup = issueGroupFilter(state.group); const removeStateFromFilter = () => { @@ -28,12 +19,12 @@ export const RenderIssueState = observer(({ state }: { state: IIssueState }) => if (stateGroup === null) return <>; return (
-
+
{/* */}
-
{state?.name}
+
{state?.name}
close diff --git a/space/components/issues/navbar/index.tsx b/space/components/issues/navbar/index.tsx index 8cc25090a..220991bd9 100644 --- a/space/components/issues/navbar/index.tsx +++ b/space/components/issues/navbar/index.tsx @@ -7,7 +7,7 @@ import { useRouter } from "next/router"; // mobx import { observer } from "mobx-react-lite"; // components -import { NavbarSearch } from "./search"; +// import { NavbarSearch } from "./search"; import { NavbarIssueBoardView } from "./issue-board-view"; import { NavbarTheme } from "./theme"; // ui @@ -83,45 +83,43 @@ const IssueNavbar = observer(() => { }, [board, workspace_slug, project_slug, router, projectStore, projectStore?.deploySettings]); return ( -
+
{/* project detail */} -
-
+
+
{projectStore?.project && projectStore?.project?.emoji ? ( renderEmoji(projectStore?.project?.emoji) ) : ( - plane logo + plane logo )}
-
+
{projectStore?.project?.name || `...`}
{/* issue search bar */} -
- -
+
{/* */}
{/* issue views */} -
+
{/* theming */} -
+
{user ? ( -
+
{user.avatar && user.avatar !== "" ? (
{/* eslint-disable-next-line @next/next/no-img-element */} {user.display_name
) : ( -
+
{(user.display_name ?? "A")[0]}
)} diff --git a/space/components/issues/navbar/issue-board-view.tsx b/space/components/issues/navbar/issue-board-view.tsx index 0ae71e8ee..16b09229a 100644 --- a/space/components/issues/navbar/issue-board-view.tsx +++ b/space/components/issues/navbar/issue-board-view.tsx @@ -7,28 +7,30 @@ import { useMobxStore } from "lib/mobx/store-provider"; import { RootStore } from "store/root"; export const NavbarIssueBoardView = observer(() => { - const { project: projectStore, issue: issueStore }: RootStore = useMobxStore(); - + const { + project: { viewOptions, setActiveBoard, activeBoard }, + }: RootStore = useMobxStore(); + // router const router = useRouter(); const { workspace_slug, project_slug } = router.query as { workspace_slug: string; project_slug: string }; const handleCurrentBoardView = (boardView: string) => { - projectStore.setActiveBoard(boardView); + setActiveBoard(boardView); router.push(`/${workspace_slug}/${project_slug}?board=${boardView}`); }; return ( <> - {projectStore?.viewOptions && - Object.keys(projectStore?.viewOptions).map((viewKey: string) => { - if (projectStore?.viewOptions[viewKey]) { + {viewOptions && + Object.keys(viewOptions).map((viewKey: string) => { + if (viewOptions[viewKey]) { return (
handleCurrentBoardView(viewKey)} title={viewKey} diff --git a/space/components/issues/navbar/issue-view.tsx b/space/components/issues/navbar/issue-view.tsx deleted file mode 100644 index 0a8f5c860..000000000 --- a/space/components/issues/navbar/issue-view.tsx +++ /dev/null @@ -1,13 +0,0 @@ -"use client"; - -// mobx react lite -import { observer } from "mobx-react-lite"; -// mobx -import { useMobxStore } from "lib/mobx/store-provider"; -import { RootStore } from "store/root"; - -export const NavbarIssueView = observer(() => { - const store: RootStore = useMobxStore(); - - return
View
; -}); diff --git a/space/components/issues/navbar/search.tsx b/space/components/issues/navbar/search.tsx deleted file mode 100644 index d1cafea6a..000000000 --- a/space/components/issues/navbar/search.tsx +++ /dev/null @@ -1,13 +0,0 @@ -"use client"; - -// mobx react lite -import { observer } from "mobx-react-lite"; -// mobx -import { useMobxStore } from "lib/mobx/store-provider"; -import { RootStore } from "store/root"; - -export const NavbarSearch = observer(() => { - const store: RootStore = useMobxStore(); - - return
; -}); diff --git a/space/components/issues/peek-overview/full-screen-peek-view.tsx b/space/components/issues/peek-overview/full-screen-peek-view.tsx index a40e6b16a..3a66c9abe 100644 --- a/space/components/issues/peek-overview/full-screen-peek-view.tsx +++ b/space/components/issues/peek-overview/full-screen-peek-view.tsx @@ -1,7 +1,4 @@ -import { useEffect } from "react"; import { observer } from "mobx-react-lite"; -// lib -import { useMobxStore } from "lib/mobx/store-provider"; // components import { PeekOverviewHeader, @@ -22,19 +19,19 @@ export const FullScreenPeekView: React.FC = observer((props) => { const { handleClose, issueDetails } = props; return ( -
-
+
+
{issueDetails ? ( -
+
{/* issue title and description */}
{/* divider */} -
+
{/* issue activity/comments */}
@@ -43,7 +40,7 @@ export const FullScreenPeekView: React.FC = observer((props) => { ) : ( -
+
diff --git a/space/components/issues/peek-overview/issue-activity.tsx b/space/components/issues/peek-overview/issue-activity.tsx index 5bb846214..2d173487c 100644 --- a/space/components/issues/peek-overview/issue-activity.tsx +++ b/space/components/issues/peek-overview/issue-activity.tsx @@ -18,16 +18,18 @@ type Props = { issueDetails: IIssue; }; -export const PeekOverviewIssueActivity: React.FC = observer((props) => { +export const PeekOverviewIssueActivity: React.FC = observer(() => { + // router const router = useRouter(); const { workspace_slug } = router.query; - - const { issueDetails: issueDetailStore, project: projectStore, user: userStore } = useMobxStore(); - + // store + const { + issueDetails: issueDetailStore, + project: projectStore, + user: { currentUser }, + } = useMobxStore(); const comments = issueDetailStore.details[issueDetailStore.peekId || ""]?.comments || []; - const user = userStore?.currentUser; - return (

Activity

@@ -38,17 +40,17 @@ export const PeekOverviewIssueActivity: React.FC = observer((props) => { ))}
- {user ? ( + {currentUser ? ( <> {projectStore.deploySettings?.comments && (
- +
)} ) : ( -
-

+

+

Sign in to add your comment

diff --git a/space/components/issues/peek-overview/layout.tsx b/space/components/issues/peek-overview/layout.tsx index a3d7386eb..121bb9164 100644 --- a/space/components/issues/peek-overview/layout.tsx +++ b/space/components/issues/peek-overview/layout.tsx @@ -13,16 +13,15 @@ import { useMobxStore } from "lib/mobx/store-provider"; type Props = {}; -export const IssuePeekOverview: React.FC = observer((props) => { +export const IssuePeekOverview: React.FC = observer(() => { + // states const [isSidePeekOpen, setIsSidePeekOpen] = useState(false); const [isModalPeekOpen, setIsModalPeekOpen] = useState(false); - // router const router = useRouter(); const { workspace_slug, project_slug, peekId, board } = router.query; // store const { issueDetails: issueDetailStore, issue: issueStore } = useMobxStore(); - const issueDetails = issueDetailStore.peekId && peekId ? issueDetailStore.details[peekId.toString()] : undefined; useEffect(() => { @@ -75,7 +74,7 @@ export const IssuePeekOverview: React.FC = observer((props) => { leaveFrom="translate-x-0" leaveTo="translate-x-full" > - + @@ -105,7 +104,7 @@ export const IssuePeekOverview: React.FC = observer((props) => { >
diff --git a/space/components/ui/tooltip.tsx b/space/components/ui/tooltip.tsx index 994c0f32a..64876ffc0 100644 --- a/space/components/ui/tooltip.tsx +++ b/space/components/ui/tooltip.tsx @@ -1,5 +1,4 @@ import React from "react"; - // next-themes import { useTheme } from "next-themes"; // tooltip2 @@ -50,9 +49,9 @@ export const Tooltip: React.FC = ({ hoverCloseDelay={closeDelay} content={
{tooltipHeading && (
diff --git a/space/components/views/login.tsx b/space/components/views/login.tsx index 406d6be98..2f4d0946c 100644 --- a/space/components/views/login.tsx +++ b/space/components/views/login.tsx @@ -10,7 +10,7 @@ export const LoginView = observer(() => { return ( <> {userStore?.loader ? ( -
Loading
+
Loading
// TODO: Add spinner instead ) : ( <>{userStore.currentUser ? : } )} diff --git a/space/components/views/project-details.tsx b/space/components/views/project-details.tsx index 1c9c6ddc9..cd2658279 100644 --- a/space/components/views/project-details.tsx +++ b/space/components/views/project-details.tsx @@ -1,9 +1,6 @@ import { useEffect } from "react"; - import Image from "next/image"; import { useRouter } from "next/router"; - -// mobx import { observer } from "mobx-react-lite"; // components import { IssueListView } from "components/issues/board-views/list"; @@ -20,7 +17,7 @@ import SomethingWentWrongImage from "public/something-went-wrong.svg"; export const ProjectDetailsView = observer(() => { const router = useRouter(); - const { workspace_slug, project_slug, states, labels, priorities, board, peekId } = router.query; + const { workspace_slug, project_slug, states, labels, priorities, peekId } = router.query; const { issue: issueStore, @@ -53,22 +50,22 @@ export const ProjectDetailsView = observer(() => { }, [peekId, issueDetailStore, project_slug, workspace_slug]); return ( -
+
{workspace_slug && } {issueStore?.loader && !issueStore.issues ? ( -
Loading...
+
Loading...
) : ( <> {issueStore?.error ? ( -
+
-
-
+
+
Oops! Something went wrong
-

Oops! Something went wrong.

+

Oops! Something went wrong.

The public board does not exist. Please check the URL.

@@ -76,12 +73,12 @@ export const ProjectDetailsView = observer(() => { projectStore?.activeBoard && ( <> {projectStore?.activeBoard === "list" && ( -
+
)} {projectStore?.activeBoard === "kanban" && ( -
+
)} diff --git a/space/lib/mobx/store-init.tsx b/space/lib/mobx/store-init.tsx index 4fc761ad1..50bf1a853 100644 --- a/space/lib/mobx/store-init.tsx +++ b/space/lib/mobx/store-init.tsx @@ -1,5 +1,3 @@ -"use client"; - import { useEffect } from "react"; // next imports import { useRouter } from "next/router"; @@ -15,12 +13,6 @@ const MobxStoreInit = () => { const router = useRouter(); const { states, labels, priorities } = router.query as { states: string[]; labels: string[]; priorities: string[] }; - // useEffect(() => { - // store.issue.userSelectedLabels = labels || []; - // store.issue.userSelectedPriorities = priorities || []; - // store.issue.userSelectedStates = states || []; - // }, [store.issue]); - useEffect(() => { const authToken = Cookie.get("accessToken") || null; if (authToken) userStore.fetchCurrentUser(); diff --git a/space/package.json b/space/package.json index 9d2521e01..8ea815c58 100644 --- a/space/package.json +++ b/space/package.json @@ -17,10 +17,10 @@ "@emotion/styled": "^11.11.0", "@headlessui/react": "^1.7.13", "@mui/material": "^5.14.1", + "@plane/document-editor": "*", "@plane/lite-text-editor": "*", "@plane/rich-text-editor": "*", "@plane/ui": "*", - "@plane/document-editor": "*", "axios": "^1.3.4", "clsx": "^2.0.0", "js-cookie": "^3.0.1", @@ -28,7 +28,7 @@ "lucide-react": "^0.293.0", "mobx": "^6.10.0", "mobx-react-lite": "^4.0.3", - "next": "12.3.2", + "next": "^14.0.3", "next-images": "^1.8.5", "next-themes": "^0.2.1", "nprogress": "^0.2.0", diff --git a/space/pages/_app.tsx b/space/pages/_app.tsx index 7e00f4d8c..c5b66ca07 100644 --- a/space/pages/_app.tsx +++ b/space/pages/_app.tsx @@ -5,7 +5,6 @@ import { ThemeProvider } from "next-themes"; import "styles/globals.css"; import "styles/editor.css"; import "styles/table.css"; - // contexts import { ToastContextProvider } from "contexts/toast.context"; // mobx store provider diff --git a/space/pages/_document.tsx b/space/pages/_document.tsx index ca023f4a4..bf83a722c 100644 --- a/space/pages/_document.tsx +++ b/space/pages/_document.tsx @@ -5,7 +5,7 @@ class MyDocument extends Document { return ( - +
diff --git a/web/components/account/sign-in-forms/create-password.tsx b/web/components/account/sign-in-forms/create-password.tsx index 9494d1518..bc8fb300c 100644 --- a/web/components/account/sign-in-forms/create-password.tsx +++ b/web/components/account/sign-in-forms/create-password.tsx @@ -1,4 +1,5 @@ import React from "react"; +import Link from "next/link"; import { Controller, useForm } from "react-hook-form"; // services import { AuthService } from "services/auth.service"; @@ -74,7 +75,7 @@ export const CreatePasswordForm: React.FC = (props) => { return ( <> -

+

Let{"'"}s get a new password

@@ -117,16 +118,23 @@ export const CreatePasswordForm: React.FC = (props) => { hasError={Boolean(errors.password)} placeholder="Create password" className="w-full h-[46px] placeholder:text-onboarding-text-400 border border-onboarding-border-100 pr-12" + minLength={8} /> )} /> -

+

Whatever you choose now will be your account{"'"}s password until you change it.

+

+ When you click the button above, you agree with our{" "} + + terms and conditions of service. + +

); diff --git a/web/components/account/sign-in-forms/email-form.tsx b/web/components/account/sign-in-forms/email-form.tsx index c8e138a49..f704d4134 100644 --- a/web/components/account/sign-in-forms/email-form.tsx +++ b/web/components/account/sign-in-forms/email-form.tsx @@ -83,10 +83,10 @@ export const EmailForm: React.FC = (props) => { return ( <> -

+

Get on your flight deck!

-

+

Sign in with the email you used to sign up for Plane

diff --git a/web/components/account/sign-in-forms/optional-set-password.tsx b/web/components/account/sign-in-forms/optional-set-password.tsx index 372dc3947..57161054b 100644 --- a/web/components/account/sign-in-forms/optional-set-password.tsx +++ b/web/components/account/sign-in-forms/optional-set-password.tsx @@ -1,4 +1,5 @@ import React, { useState } from "react"; +import Link from "next/link"; import { Controller, useForm } from "react-hook-form"; // ui import { Button, Input } from "@plane/ui"; @@ -37,12 +38,12 @@ export const OptionalSetPasswordForm: React.FC = (props) => { return ( <> -

Set a password

+

Set a password

- If you{"'"}d to do away with codes, set a password here. + If you{"'"}d to do away with codes, set a password here

-
+ = (props) => { /> )} /> -
+
+

+ When you click Go to workspace above, you agree with our{" "} + + terms and conditions of service. + +

); diff --git a/web/components/account/sign-in-forms/password.tsx b/web/components/account/sign-in-forms/password.tsx index bdaa34b22..547f59e9d 100644 --- a/web/components/account/sign-in-forms/password.tsx +++ b/web/components/account/sign-in-forms/password.tsx @@ -1,4 +1,5 @@ import React from "react"; +import Link from "next/link"; import { Controller, useForm } from "react-hook-form"; import { XCircle } from "lucide-react"; // services @@ -184,17 +185,25 @@ export const PasswordForm: React.FC = (props) => { /> )} /> - +
+ +
+

+ When you click the button above, you agree with our{" "} + + terms and conditions of service. + +

); diff --git a/web/components/account/sign-in-forms/root.tsx b/web/components/account/sign-in-forms/root.tsx index d2d6ef753..9797c8573 100644 --- a/web/components/account/sign-in-forms/root.tsx +++ b/web/components/account/sign-in-forms/root.tsx @@ -23,6 +23,8 @@ type Props = { handleSignInRedirection: () => Promise; }; +const OAUTH_HIDDEN_STEPS = [ESignInSteps.OPTIONAL_SET_PASSWORD, ESignInSteps.CREATE_PASSWORD]; + export const SignInRoot: React.FC = (props) => { const { handleSignInRedirection } = props; // states @@ -72,7 +74,7 @@ export const SignInRoot: React.FC = (props) => { /> )}
- {signInStep !== ESignInSteps.OPTIONAL_SET_PASSWORD && ( + {!OAUTH_HIDDEN_STEPS.includes(signInStep) && ( setEmail(newEmail)} handleStepChange={(step: ESignInSteps) => setSignInStep(step)} diff --git a/web/components/account/sign-in-forms/set-password-link.tsx b/web/components/account/sign-in-forms/set-password-link.tsx index 34e643b92..f683a26fc 100644 --- a/web/components/account/sign-in-forms/set-password-link.tsx +++ b/web/components/account/sign-in-forms/set-password-link.tsx @@ -1,4 +1,5 @@ import React, { useState } from "react"; +import Link from "next/link"; import { Controller, useForm } from "react-hook-form"; import { XCircle } from "lucide-react"; // services @@ -48,6 +49,13 @@ export const SetPasswordLink: React.FC = (props) => { await authService .emailCheck(payload) + .then(() => + setToastAlert({ + type: "success", + title: "Success!", + message: "We have sent a new link to your email.", + }) + ) .catch((err) => setToastAlert({ type: "error", @@ -60,15 +68,15 @@ export const SetPasswordLink: React.FC = (props) => { return ( <> -

- Get on your flight deck! +

+ Get on your flight deck

- We have sent a link to {email}, so you can set a + We have sent a link to {email}, so you can set a password

-
+
= (props) => { )} />
-
- -
+ +

+ When you click the button above, you agree with our{" "} + + terms and conditions of service. + +

); diff --git a/web/components/account/sign-in-forms/unique-code.tsx b/web/components/account/sign-in-forms/unique-code.tsx index 71ed93f0c..43e183fd5 100644 --- a/web/components/account/sign-in-forms/unique-code.tsx +++ b/web/components/account/sign-in-forms/unique-code.tsx @@ -1,4 +1,5 @@ import React, { useState } from "react"; +import Link from "next/link"; import { Controller, useForm } from "react-hook-form"; import { CornerDownLeft, XCircle } from "lucide-react"; // services @@ -44,7 +45,7 @@ export const UniqueCodeForm: React.FC = (props) => { // toast alert const { setToastAlert } = useToast(); // timer - const { timer: resendTimerCode, setTimer: setResendCodeTimer } = useTimer(); + const { timer: resendTimerCode, setTimer: setResendCodeTimer } = useTimer(30); // form info const { control, @@ -131,11 +132,9 @@ export const UniqueCodeForm: React.FC = (props) => { return ( <> -

- Moving to the runway -

-

- Paste the code you got at {email} below. +

Moving to the runway

+

+ Paste the code you got at {email} below

@@ -196,25 +195,29 @@ export const UniqueCodeForm: React.FC = (props) => { value={value} onChange={onChange} hasError={Boolean(errors.token)} - placeholder="gets-sets-fays" + placeholder="gets-sets-flys" className="w-full h-[46px] placeholder:text-onboarding-text-400 border border-onboarding-border-100 pr-12" /> )} /> - +
+ +
+

+ When you click Confirm above, you agree with our{" "} + + terms and conditions of service. + +

); diff --git a/web/components/command-palette/command-pallette.tsx b/web/components/command-palette/command-pallette.tsx index a4f5279a2..6891279b1 100644 --- a/web/components/command-palette/command-pallette.tsx +++ b/web/components/command-palette/command-pallette.tsx @@ -55,22 +55,10 @@ export const CommandPalette: FC = observer(() => { toggleBulkDeleteIssueModal, isDeleteIssueModalOpen, toggleDeleteIssueModal, - + isAnyModalOpen, createIssueStoreType, } = commandPalette; - const isAnyModalOpen = Boolean( - isCreateIssueModalOpen || - isCreateCycleModalOpen || - isCreatePageModalOpen || - isCreateProjectModalOpen || - isCreateModuleModalOpen || - isCreateViewModalOpen || - isShortcutModalOpen || - isBulkDeleteIssueModalOpen || - isDeleteIssueModalOpen - ); - const { setToastAlert } = useToast(); const { data: issueDetails } = useSWR( diff --git a/web/components/common/latest-feature-block.tsx b/web/components/common/latest-feature-block.tsx index 46309f6da..bade52d62 100644 --- a/web/components/common/latest-feature-block.tsx +++ b/web/components/common/latest-feature-block.tsx @@ -1,34 +1,35 @@ import Image from "next/image"; +import Link from "next/link"; import { useTheme } from "next-themes"; // icons import { Lightbulb } from "lucide-react"; // images -import signInIssues from "public/onboarding/onboarding-issues.svg"; +import latestFeatures from "public/onboarding/onboarding-pages.svg"; export const LatestFeatureBlock = () => { const { resolvedTheme } = useTheme(); return ( <> -
+
-

- Try the latest features, like Tiptap editor, to write compelling responses.{" "} - {}}> - See new features - +

+ Pages gets a facelift! Write anything and use Galileo to help you start.{" "} + + Learn more +

-
- Plane Issues +
+
+ Plane Issues +
); diff --git a/web/components/common/new-empty-state.tsx b/web/components/common/new-empty-state.tsx index d11604d37..b1f769ef7 100644 --- a/web/components/common/new-empty-state.tsx +++ b/web/components/common/new-empty-state.tsx @@ -46,7 +46,7 @@ export const NewEmptyState: React.FC = ({

{title}

{description &&

{description}

}
- {primaryButton?.text + {primaryButton?.text
diff --git a/web/components/cycles/cycles-board-card.tsx b/web/components/cycles/cycles-board-card.tsx index 8a74565d5..22b59fc5f 100644 --- a/web/components/cycles/cycles-board-card.tsx +++ b/web/components/cycles/cycles-board-card.tsx @@ -33,7 +33,10 @@ export interface ICyclesBoardCard { export const CyclesBoardCard: FC = (props) => { const { cycle, workspaceSlug, projectId } = props; // store - const { cycle: cycleStore, trackEvent: { setTrackElement } } = useMobxStore(); + const { + cycle: cycleStore, + trackEvent: { setTrackElement }, + } = useMobxStore(); // toast const { setToastAlert } = useToast(); // states @@ -152,7 +155,7 @@ export const CyclesBoardCard: FC = (props) => { /> - +
@@ -268,7 +271,7 @@ export const CyclesBoardCard: FC = (props) => {
-
+
); diff --git a/web/components/cycles/cycles-list-item.tsx b/web/components/cycles/cycles-list-item.tsx index 531a637aa..30fcda221 100644 --- a/web/components/cycles/cycles-list-item.tsx +++ b/web/components/cycles/cycles-list-item.tsx @@ -153,7 +153,7 @@ export const CyclesListItem: FC = (props) => { projectId={projectId} /> - +
@@ -262,7 +262,7 @@ export const CyclesListItem: FC = (props) => {
- +
); diff --git a/web/components/headers/global-issues.tsx b/web/components/headers/global-issues.tsx index bb692b4f4..964e14c8b 100644 --- a/web/components/headers/global-issues.tsx +++ b/web/components/headers/global-issues.tsx @@ -2,8 +2,6 @@ import { useCallback, useState } from "react"; import Link from "next/link"; import { useRouter } from "next/router"; import { observer } from "mobx-react-lite"; -import useSWR from "swr"; - // mobx store import { useMobxStore } from "lib/mobx/store-provider"; // components @@ -17,6 +15,7 @@ import { List, PlusIcon, Sheet } from "lucide-react"; import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions, TStaticViewTypes } from "types"; // constants import { ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "constants/issue"; +import { EFilterType } from "store/issues/types"; const GLOBAL_VIEW_LAYOUTS = [ { key: "list", title: "List", link: "/workspace-views", icon: List }, @@ -27,73 +26,55 @@ type Props = { activeLayout: "list" | "spreadsheet"; }; -const STATIC_VIEW_TYPES: TStaticViewTypes[] = ["all-issues", "assigned", "created", "subscribed"]; - export const GlobalIssuesHeader: React.FC = observer((props) => { const { activeLayout } = props; const [createViewModal, setCreateViewModal] = useState(false); const router = useRouter(); - const { workspaceSlug, globalViewId } = router.query; + const { workspaceSlug } = router.query as { workspaceSlug: string }; const { - globalViewFilters: globalViewFiltersStore, - workspaceFilter: workspaceFilterStore, - workspace: workspaceStore, + workspace: { workspaceLabels }, workspaceMember: { workspaceMembers }, - project: projectStore, - } = useMobxStore(); + project: { workspaceProjects }, - const storedFilters = globalViewId ? globalViewFiltersStore.storedFilters[globalViewId.toString()] : undefined; + workspaceGlobalIssuesFilter: { issueFilters, updateFilters }, + } = useMobxStore(); const handleFiltersUpdate = useCallback( (key: keyof IIssueFilterOptions, value: string | string[]) => { - if (!workspaceSlug || !globalViewId) return; - - const newValues = storedFilters?.[key] ?? []; + if (!workspaceSlug) return; + const newValues = issueFilters?.filters?.[key] ?? []; if (Array.isArray(value)) { value.forEach((val) => { if (!newValues.includes(val)) newValues.push(val); }); } else { - if (storedFilters?.[key]?.includes(value)) newValues.splice(newValues.indexOf(value), 1); + if (issueFilters?.filters?.[key]?.includes(value)) newValues.splice(newValues.indexOf(value), 1); else newValues.push(value); } - globalViewFiltersStore.updateStoredFilters(globalViewId.toString(), { - [key]: newValues, - }); + updateFilters(workspaceSlug, EFilterType.FILTERS, { [key]: newValues }); }, - [globalViewId, globalViewFiltersStore, storedFilters, workspaceSlug] + [workspaceSlug, issueFilters, updateFilters] ); - const handleDisplayFiltersUpdate = useCallback( + const handleDisplayFilters = useCallback( (updatedDisplayFilter: Partial) => { if (!workspaceSlug) return; - - workspaceFilterStore.updateWorkspaceFilters(workspaceSlug.toString(), { - display_filters: updatedDisplayFilter, - }); + updateFilters(workspaceSlug, EFilterType.DISPLAY_FILTERS, updatedDisplayFilter); }, - [workspaceFilterStore, workspaceSlug] + [workspaceSlug, updateFilters] ); - const handleDisplayPropertiesUpdate = useCallback( + const handleDisplayProperties = useCallback( (property: Partial) => { if (!workspaceSlug) return; - - workspaceFilterStore.updateWorkspaceFilters(workspaceSlug.toString(), { - display_properties: property, - }); + updateFilters(workspaceSlug, EFilterType.DISPLAY_PROPERTIES, property); }, - [workspaceFilterStore, workspaceSlug] - ); - - useSWR( - workspaceSlug ? "USER_WORKSPACE_DISPLAY_FILTERS" : null, - workspaceSlug ? () => workspaceFilterStore.fetchUserWorkspaceFilters(workspaceSlug.toString()) : null + [workspaceSlug, updateFilters] ); return ( @@ -137,32 +118,31 @@ export const GlobalIssuesHeader: React.FC = observer((props) => { ))}
+ {activeLayout === "spreadsheet" && ( <> - {!STATIC_VIEW_TYPES.some((word) => router.pathname.includes(word)) && ( - - m.member) ?? undefined} - projects={workspaceSlug ? projectStore.projects[workspaceSlug.toString()] : undefined} - /> - - )} - + + m.member)} + projects={workspaceProjects ?? undefined} + /> + )} + diff --git a/web/components/headers/project-views.tsx b/web/components/headers/project-views.tsx index 66e320872..92e876557 100644 --- a/web/components/headers/project-views.tsx +++ b/web/components/headers/project-views.tsx @@ -1,4 +1,3 @@ -import { useState } from "react"; import { useRouter } from "next/router"; import { observer } from "mobx-react-lite"; import { Plus } from "lucide-react"; @@ -15,18 +14,16 @@ export const ProjectViewsHeader: React.FC = observer(() => { // router const router = useRouter(); const { workspaceSlug, projectId } = router.query; - // states - const [createViewModal, setCreateViewModal] = useState(false); - const { project: projectStore } = useMobxStore(); + const { project: projectStore, commandPalette } = useMobxStore(); const { currentProjectDetails } = projectStore; return ( <> {workspaceSlug && projectId && ( setCreateViewModal(false)} + isOpen={commandPalette.isCreateViewModalOpen} + onClose={() => commandPalette.toggleCreateViewModal(false)} workspaceSlug={workspaceSlug.toString()} projectId={projectId.toString()} /> @@ -69,7 +66,7 @@ export const ProjectViewsHeader: React.FC = observer(() => { variant="primary" size="sm" prependIcon={} - onClick={() => setCreateViewModal(true)} + onClick={() => commandPalette.toggleCreateViewModal(true)} > Create View diff --git a/web/components/inbox/issue-card.tsx b/web/components/inbox/issue-card.tsx index abf82208e..24f267506 100644 --- a/web/components/inbox/issue-card.tsx +++ b/web/components/inbox/issue-card.tsx @@ -27,71 +27,69 @@ export const InboxIssueCard: React.FC = (props) => { return ( - -
-
-

- {issue.project_detail?.identifier}-{issue.sequence_id} -

-
{issue.name}
-
-
- - - - -
- - {renderShortDateWithYearFormat(issue.created_at ?? "")} -
-
-
-
s.value === issueStatus)?.textColor - }`} - > - {issueStatus === -2 ? ( - <> - - Pending - - ) : issueStatus === -1 ? ( - <> - - Declined - - ) : issueStatus === 0 ? ( - <> - - - {new Date(issue.issue_inbox[0].snoozed_till ?? "") < new Date() ? "Snoozed date passed" : "Snoozed"} - - - ) : issueStatus === 1 ? ( - <> - - Accepted - - ) : ( - <> - - Duplicate - - )} -
+
+
+

+ {issue.project_detail?.identifier}-{issue.sequence_id} +

+
{issue.name}
- +
+ + + + +
+ + {renderShortDateWithYearFormat(issue.created_at ?? "")} +
+
+
+
s.value === issueStatus)?.textColor + }`} + > + {issueStatus === -2 ? ( + <> + + Pending + + ) : issueStatus === -1 ? ( + <> + + Declined + + ) : issueStatus === 0 ? ( + <> + + + {new Date(issue.issue_inbox[0].snoozed_till ?? "") < new Date() ? "Snoozed date passed" : "Snoozed"} + + + ) : issueStatus === 1 ? ( + <> + + Accepted + + ) : ( + <> + + Duplicate + + )} +
+
); }; diff --git a/web/components/instance/help-section.tsx b/web/components/instance/help-section.tsx index f880688f4..5d1e48c9c 100644 --- a/web/components/instance/help-section.tsx +++ b/web/components/instance/help-section.tsx @@ -98,12 +98,12 @@ export const InstanceHelpSection: FC = () => { if (href) return ( - +
{name} - +
); else diff --git a/web/components/instance/instance-admin-restriction.tsx b/web/components/instance/instance-admin-restriction.tsx index c1e8a47db..5551c0786 100644 --- a/web/components/instance/instance-admin-restriction.tsx +++ b/web/components/instance/instance-admin-restriction.tsx @@ -67,12 +67,10 @@ export const InstanceAdminRestriction: FC = ({ re
- - - +
diff --git a/web/components/instance/not-ready-view.tsx b/web/components/instance/not-ready-view.tsx index 501ab4d41..1333d65a6 100644 --- a/web/components/instance/not-ready-view.tsx +++ b/web/components/instance/not-ready-view.tsx @@ -1,29 +1,29 @@ import React from "react"; import Image from "next/image"; import { useTheme } from "next-themes"; -// image +// images import instanceNotReady from "public/instance/plane-instance-not-ready.webp"; import PlaneWhiteLogo from "public/plane-logos/white-horizontal-with-blue-logo.svg"; -import PlaneDarkLogo from "public/plane-logos/black-horizontal-with-blue-logo.svg"; +import PlaneBlackLogo from "public/plane-logos/black-horizontal-with-blue-logo.svg"; export const InstanceNotReady = () => { const { resolvedTheme } = useTheme(); - const planeLogo = resolvedTheme === "dark" ? PlaneWhiteLogo : PlaneDarkLogo; + const planeLogo = resolvedTheme === "dark" ? PlaneWhiteLogo : PlaneBlackLogo; return (
-
-
-
+
+
+
- image + Plane logo
- image + Instance not ready
-

Your Plane instance isn’t ready yet

+

Your Plane instance isn{"'"}t ready yet

Ask your Instance Admin to complete set-up first.

diff --git a/web/components/instance/setup-done-view.tsx b/web/components/instance/setup-done-view.tsx index 4885e006a..4eab4013f 100644 --- a/web/components/instance/setup-done-view.tsx +++ b/web/components/instance/setup-done-view.tsx @@ -1,43 +1,66 @@ -import React from "react"; +import React, { useState } from "react"; import Image from "next/image"; - +import { useTheme } from "next-themes"; // ui import { Button } from "@plane/ui"; import { UserCog2 } from "lucide-react"; -// image +// images import instanceSetupDone from "public/instance-setup-done.svg"; -import PlaneLogo from "public/plane-logos/blue-without-text.png"; +import PlaneBlackLogo from "public/plane-logos/black-horizontal-with-blue-logo.svg"; +import PlaneWhiteLogo from "public/plane-logos/white-horizontal-with-blue-logo.svg"; +import { useMobxStore } from "lib/mobx/store-provider"; -export const InstanceSetupDone = () => ( -
-
-
-
-
- image - To the stratosphere now! -
+export const InstanceSetupDone = () => { + // states + const [isRedirecting, setIsRedirecting] = useState(false); + // next-themes + const { resolvedTheme } = useTheme(); + // mobx store + const { + instance: { fetchInstanceInfo }, + } = useMobxStore(); -
- image -
+ const planeLogo = resolvedTheme === "dark" ? PlaneWhiteLogo : PlaneBlackLogo; -
- - Your instance is now ready for more security, more controls, and more intelligence. - - + const redirectToGodMode = async () => { + setIsRedirecting(true); -
- Use this wisely. Remember, with great power comes great responsibility.🕷️ + await fetchInstanceInfo().finally(() => setIsRedirecting(false)); + }; + + return ( +
+
+
+
+
+
+ Plane logo +
+
+ +
+
+ image +
+
+ +
+
+
+ Your instance is now ready for more security, more controls, and more intelligence. +
+

+ Use this wisely. Remember, with great power comes great responsibility. +

+
+
-
-); + ); +}; diff --git a/web/components/instance/setup-form/email-code-form.tsx b/web/components/instance/setup-form/email-code-form.tsx index 6264ba20f..24643d833 100644 --- a/web/components/instance/setup-form/email-code-form.tsx +++ b/web/components/instance/setup-form/email-code-form.tsx @@ -1,4 +1,4 @@ -import { FC } from "react"; +import { FC, useState } from "react"; import { useForm, Controller } from "react-hook-form"; // ui import { Input, Button } from "@plane/ui"; @@ -24,6 +24,8 @@ export interface IInstanceSetupEmailCodeForm { export const InstanceSetupEmailCodeForm: FC = (props) => { const { handleNextStep, email, moveBack } = props; + // states + const [isResendingCode, setIsResendingCode] = useState(false); // form info const { control, @@ -40,10 +42,10 @@ export const InstanceSetupEmailCodeForm: FC = (prop const { setToastAlert } = useToast(); const { timer, setTimer } = useTimer(30); // computed - const isResendDisabled = timer > 0 || isSubmitting; + const isResendDisabled = timer > 0 || isResendingCode; - const handleEmailCodeFormSubmit = (formValues: InstanceSetupEmailCodeFormValues) => - authService + const handleEmailCodeFormSubmit = async (formValues: InstanceSetupEmailCodeFormValues) => + await authService .instanceMagicSignIn({ key: `magic_${formValues.email}`, token: formValues.token }) .then(() => { reset(); @@ -51,42 +53,40 @@ export const InstanceSetupEmailCodeForm: FC = (prop }) .catch((err) => { setToastAlert({ - title: "Oops!", type: "error", - message: err?.error, + title: "Error!", + message: err?.error ?? "Something went wrong. Please try again.", }); }); - const resendMagicCode = () => { - setTimer(30); - authService + const resendMagicCode = async () => { + setIsResendingCode(true); + + await authService .instanceAdminEmailCode({ email }) - .then(() => { - // setCodeResending(false); - setTimer(30); - }) + .then(() => setTimer(30)) .catch((err) => { setToastAlert({ - title: "Oops!", type: "error", - message: err?.error, + title: "Error!", + message: err?.error ?? "Something went wrong. Please try again.", }); - }); + }) + .finally(() => setIsResendingCode(false)); }; return (
-
-

- Let’s secure your instance -

-
-

Paste the code you got at

- {email} - below. -
- -
+

+ Let{"'"}s secure your instance +

+

+ Paste the code you got at +
+ {email} below. +

+
+
= (prop ) || "Email address is not valid", }} render={({ field: { value, onChange } }) => ( -
+
= (prop
)} /> -
- {timer > 0 ? ( - Request new code in {timer}s - ) : isSubmitting ? ( - "Sending new code..." - ) : ( -
- -
- )} +
+
- ( -
- -
- )} - /> - -
+ ( +
+ +
+ )} + /> +
); diff --git a/web/components/instance/setup-form/email-form.tsx b/web/components/instance/setup-form/email-form.tsx index b2c336695..7305095a9 100644 --- a/web/components/instance/setup-form/email-form.tsx +++ b/web/components/instance/setup-form/email-form.tsx @@ -44,61 +44,59 @@ export const InstanceSetupEmailForm: FC = (props) => { }) .catch((err) => { setToastAlert({ - title: "Oops!", type: "error", - message: err?.error, + title: "Error!", + message: err?.error ?? "Something went wrong. Please try again.", }); }); return (
-
-

- Let’s secure your instance -

-

- Explore privacy options. Get AI features. Secure access.
Takes 2 minutes. -

- -
- - /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test( - value - ) || "Email address is not valid", - }} - render={({ field: { value, onChange } }) => ( -
- + Let{"'"}s secure your instance +
+

+ Explore privacy options. Get AI features. Secure access. +
+ Takes 2 minutes. +

+
+ + /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test( + value + ) || "Email address is not valid", + }} + render={({ field: { value, onChange } }) => ( +
+ + {value.length > 0 && ( + setValue("email", "")} /> - {value.length > 0 && ( - setValue("email", "")} - /> - )} -
- )} - /> -

- Use your email address if you are the instance admin.
Use your admin’s e-mail if you are not. -

- - -
+ )} +
+ )} + /> +

+ Use your email address if you are the instance admin.
Use your admin’s e-mail if you are not. +

+
); diff --git a/web/components/instance/setup-form/password-form.tsx b/web/components/instance/setup-form/password-form.tsx index f963b960e..86053cfd7 100644 --- a/web/components/instance/setup-form/password-form.tsx +++ b/web/components/instance/setup-form/password-form.tsx @@ -1,4 +1,5 @@ import React from "react"; +import Link from "next/link"; import { useForm, Controller } from "react-hook-form"; // ui import { Input, Button } from "@plane/ui"; @@ -43,14 +44,14 @@ export const InstanceSetupPasswordForm: React.FC = ( return (
-

+

Moving to the runway

- {"Let's set a password so you can do away with codes."} + Let{"'"}s set a password so you can do away with codes.

-
+
= (
)} /> - -
+
= (
)} /> +

+ Whatever you choose now will be your account{"'"}s password +

-

- {"Whatever you choose now will be your account's password"} -

+

+ When you click the button above, you agree with our{" "} + + terms and conditions of service. + +

diff --git a/web/components/instance/setup-form/root.tsx b/web/components/instance/setup-form/root.tsx index ebc6c5649..46f5493ba 100644 --- a/web/components/instance/setup-form/root.tsx +++ b/web/components/instance/setup-form/root.tsx @@ -21,13 +21,11 @@ export const InstanceSetupFormRoot = () => { return ( <> {setupStep === EInstanceSetupSteps.DONE ? ( -
- -
+ ) : ( -
-
-
+
+
+
{setupStep === EInstanceSetupSteps.EMAIL && ( { diff --git a/web/components/instance/setup-view.tsx b/web/components/instance/setup-view.tsx index 07d4455dd..e79f6321e 100644 --- a/web/components/instance/setup-view.tsx +++ b/web/components/instance/setup-view.tsx @@ -24,7 +24,7 @@ export const InstanceSetupView = observer(() => { return ( <> -
+
Plane Logo diff --git a/web/components/instance/sidebar-menu.tsx b/web/components/instance/sidebar-menu.tsx index 8feaa44c2..54a04529f 100644 --- a/web/components/instance/sidebar-menu.tsx +++ b/web/components/instance/sidebar-menu.tsx @@ -54,7 +54,7 @@ export const InstanceAdminSidebarMenu = () => { return ( - +
{ )}
- +
); })} diff --git a/web/components/issues/attachment/attachments.tsx b/web/components/issues/attachment/attachments.tsx index d2f592f2e..86cafd7a9 100644 --- a/web/components/issues/attachment/attachments.tsx +++ b/web/components/issues/attachment/attachments.tsx @@ -59,33 +59,31 @@ export const IssueAttachments = () => { key={file.id} className="flex h-[60px] items-center justify-between gap-1 rounded-md border-[2px] border-custom-border-200 bg-custom-background-100 px-4 py-2 text-sm" > - - -
-
{getFileIcon(getFileExtension(file.asset))}
-
-
- - {truncateText(`${getFileName(file.attributes.name)}`, 10)} - - person.member.id === file.updated_by)?.member.display_name ?? "" - } uploaded on ${renderLongDateFormat(file.updated_at)}`} - > - - - - -
+ +
+
{getFileIcon(getFileExtension(file.asset))}
+
+
+ + {truncateText(`${getFileName(file.attributes.name)}`, 10)} + + person.member.id === file.updated_by)?.member.display_name ?? "" + } uploaded on ${renderLongDateFormat(file.updated_at)}`} + > + + + + +
-
- {getFileExtension(file.asset).toUpperCase()} - {convertBytesToSize(file.attributes.size)} -
+
+ {getFileExtension(file.asset).toUpperCase()} + {convertBytesToSize(file.attributes.size)}
- +
- )} + )} */}
); }); diff --git a/web/components/issues/issue-layouts/index.ts b/web/components/issues/issue-layouts/index.ts index aa82dc686..3a8a2baac 100644 --- a/web/components/issues/issue-layouts/index.ts +++ b/web/components/issues/issue-layouts/index.ts @@ -3,6 +3,9 @@ export * from "./filters"; export * from "./empty-states"; export * from "./quick-action-dropdowns"; +// roots +export * from "./roots"; + // layouts export * from "./list"; export * from "./calendar"; @@ -10,6 +13,5 @@ export * from "./gantt"; export * from "./kanban"; export * from "./spreadsheet"; +// properties export * from "./properties"; - -export * from "./roots"; diff --git a/web/components/issues/issue-layouts/kanban/base-kanban-root.tsx b/web/components/issues/issue-layouts/kanban/base-kanban-root.tsx index aa3ba503e..e63b6e745 100644 --- a/web/components/issues/issue-layouts/kanban/base-kanban-root.tsx +++ b/web/components/issues/issue-layouts/kanban/base-kanban-root.tsx @@ -267,6 +267,7 @@ export const BaseKanBanRoot: React.FC = observer((props: IBas enableQuickIssueCreate={enableQuickAdd} isReadOnly={!enableInlineEditing || !isEditingAllowed} currentStore={currentStore} + quickAddCallback={issueStore?.quickAddIssue} addIssuesToView={(issues) => { console.log("kanban existingIds", issues); diff --git a/web/components/issues/issue-layouts/kanban/properties.tsx b/web/components/issues/issue-layouts/kanban/properties.tsx index c3c677208..929311f31 100644 --- a/web/components/issues/issue-layouts/kanban/properties.tsx +++ b/web/components/issues/issue-layouts/kanban/properties.tsx @@ -89,6 +89,7 @@ export const KanBanProperties: React.FC = observer((props) => = observer((props) => = observer((props) => Promise; } const SubGroupSwimlane: React.FC = observer((props) => { const { @@ -118,6 +124,7 @@ const SubGroupSwimlane: React.FC = observer((props) => { enableQuickIssueCreate, isReadOnly, addIssuesToView, + quickAddCallback, } = props; const calculateIssueCount = (column_id: string) => { @@ -176,6 +183,7 @@ const SubGroupSwimlane: React.FC = observer((props) => { isDragStarted={isDragStarted} isReadOnly={isReadOnly} addIssuesToView={addIssuesToView} + quickAddCallback={quickAddCallback} />
)} @@ -208,6 +216,12 @@ export interface IKanBanSwimLanes { currentStore?: EProjectStore; addIssuesToView?: (issueIds: string[]) => Promise; enableQuickIssueCreate: boolean; + quickAddCallback?: ( + workspaceSlug: string, + projectId: string, + data: IIssue, + viewId?: string + ) => Promise; isReadOnly: boolean; } @@ -236,6 +250,7 @@ export const KanBanSwimLanes: React.FC = observer((props) => { isReadOnly, currentStore, addIssuesToView, + quickAddCallback, } = props; return ( @@ -378,6 +393,7 @@ export const KanBanSwimLanes: React.FC = observer((props) => { disableIssueCreation={disableIssueCreation} enableQuickIssueCreate={enableQuickIssueCreate} isReadOnly={isReadOnly} + quickAddCallback={quickAddCallback} /> )} @@ -406,6 +422,7 @@ export const KanBanSwimLanes: React.FC = observer((props) => { disableIssueCreation={disableIssueCreation} enableQuickIssueCreate={enableQuickIssueCreate} isReadOnly={isReadOnly} + quickAddCallback={quickAddCallback} /> )} @@ -434,6 +451,7 @@ export const KanBanSwimLanes: React.FC = observer((props) => { disableIssueCreation={disableIssueCreation} enableQuickIssueCreate={enableQuickIssueCreate} isReadOnly={isReadOnly} + quickAddCallback={quickAddCallback} /> )} @@ -462,6 +480,7 @@ export const KanBanSwimLanes: React.FC = observer((props) => { disableIssueCreation={disableIssueCreation} enableQuickIssueCreate={enableQuickIssueCreate} isReadOnly={isReadOnly} + quickAddCallback={quickAddCallback} /> )} @@ -490,6 +509,7 @@ export const KanBanSwimLanes: React.FC = observer((props) => { disableIssueCreation={disableIssueCreation} enableQuickIssueCreate={enableQuickIssueCreate} isReadOnly={isReadOnly} + quickAddCallback={quickAddCallback} /> )} @@ -518,6 +538,7 @@ export const KanBanSwimLanes: React.FC = observer((props) => { disableIssueCreation={disableIssueCreation} enableQuickIssueCreate={enableQuickIssueCreate} isReadOnly={isReadOnly} + quickAddCallback={quickAddCallback} /> )} @@ -546,6 +567,7 @@ export const KanBanSwimLanes: React.FC = observer((props) => { disableIssueCreation={disableIssueCreation} enableQuickIssueCreate={enableQuickIssueCreate} isReadOnly={isReadOnly} + quickAddCallback={quickAddCallback} /> )} @@ -574,6 +596,7 @@ export const KanBanSwimLanes: React.FC = observer((props) => { disableIssueCreation={disableIssueCreation} enableQuickIssueCreate={enableQuickIssueCreate} isReadOnly={isReadOnly} + quickAddCallback={quickAddCallback} /> )}
diff --git a/web/components/issues/issue-layouts/list/properties.tsx b/web/components/issues/issue-layouts/list/properties.tsx index ef6e6981b..a1ce45313 100644 --- a/web/components/issues/issue-layouts/list/properties.tsx +++ b/web/components/issues/issue-layouts/list/properties.tsx @@ -60,6 +60,7 @@ export const ListProperties: FC = observer((props) => { = observer((props) => { = observer((props) => { void; disabled?: boolean; hideDropdownArrow?: boolean; @@ -27,6 +29,7 @@ export const IssuePropertyAssignee: React.FC = observer( const { projectId, value, + defaultOptions = [], onChange, disabled = false, hideDropdownArrow = false, @@ -40,8 +43,7 @@ export const IssuePropertyAssignee: React.FC = observer( // store const { workspace: workspaceStore, - project: projectStore, - workspaceMember: { workspaceMembers, fetchWorkspaceMembers }, + projectMember: { projectMembers: _projectMembers, fetchProjectMembers }, } = useMobxStore(); const workspaceSlug = workspaceStore?.workspaceSlug; // states @@ -50,20 +52,16 @@ export const IssuePropertyAssignee: React.FC = observer( const [popperElement, setPopperElement] = useState(null); const [isLoading, setIsLoading] = useState(false); - // const fetchProjectMembers = () => { - // setIsLoading(true); - // if (workspaceSlug && projectId) - // workspaceSlug && - // projectId && - // projectStore.fetchProjectMembers(workspaceSlug, projectId).then(() => setIsLoading(false)); - // }; - const getWorkspaceMembers = () => { setIsLoading(true); - if (workspaceSlug) workspaceSlug && fetchWorkspaceMembers(workspaceSlug).then(() => setIsLoading(false)); + if (workspaceSlug && projectId) fetchProjectMembers(workspaceSlug, projectId).then(() => setIsLoading(false)); }; - const options = (workspaceMembers ?? [])?.map((member) => ({ + const updatedDefaultOptions: IProjectMember[] = + defaultOptions.map((member: any) => ({ member: { ...member } })) ?? []; + const projectMembers = _projectMembers ?? updatedDefaultOptions; + + const options = projectMembers?.map((member) => ({ value: member.member.id, query: member.member.display_name, content: ( @@ -82,7 +80,7 @@ export const IssuePropertyAssignee: React.FC = observer( // if multiple assignees if (Array.isArray(value)) { - const assignees = workspaceMembers?.filter((m) => value.includes(m.member.id)); + const assignees = projectMembers?.filter((m) => value.includes(m.member.id)); if (!assignees || assignees.length === 0) return "No Assignee"; @@ -93,7 +91,7 @@ export const IssuePropertyAssignee: React.FC = observer( } // if single assignee - const assignee = workspaceMembers?.find((m) => m.member.id === value)?.member; + const assignee = projectMembers?.find((m) => m.member.id === value)?.member; if (!assignee) return "No Assignee"; @@ -107,7 +105,7 @@ export const IssuePropertyAssignee: React.FC = observer( {value && value.length > 0 && Array.isArray(value) ? ( {value.map((assigneeId) => { - const member = workspaceMembers?.find((m) => m.member.id === assigneeId)?.member; + const member = projectMembers?.find((m) => m.member.id === assigneeId)?.member; if (!member) return null; return ; })} @@ -149,7 +147,7 @@ export const IssuePropertyAssignee: React.FC = observer( className={`flex items-center justify-between gap-1 w-full text-xs ${ disabled ? "cursor-not-allowed text-custom-text-200" : "cursor-pointer hover:bg-custom-background-80" } ${buttonClassName}`} - onClick={() => !workspaceMembers && getWorkspaceMembers()} + onClick={() => !projectMembers && getWorkspaceMembers()} > {label} {!hideDropdownArrow && !disabled &&