From 216a7c8fda3482ba96482aa46e1f6e4a103b9c9a Mon Sep 17 00:00:00 2001 From: sriram veeraghanta Date: Wed, 20 Dec 2023 13:49:17 +0530 Subject: [PATCH 01/40] fix: adding additional headers to restrict iframe --- space/next.config.js | 14 ++++++++++++++ web/next.config.js | 8 ++++++++ 2 files changed, 22 insertions(+) diff --git a/space/next.config.js b/space/next.config.js index 16450199c..18b9275a1 100644 --- a/space/next.config.js +++ b/space/next.config.js @@ -3,10 +3,24 @@ require("dotenv").config({ path: ".env" }); const { withSentryConfig } = require("@sentry/nextjs"); const nextConfig = { + async headers() { + return [ + { + source: "/", + headers: [{ key: "X-Frame-Options", value: "SAMEORIGIN" }], + }, + ]; + }, basePath: process.env.NEXT_PUBLIC_DEPLOY_WITH_NGINX === "1" ? "/spaces" : "", reactStrictMode: false, swcMinify: true, images: { + remotePatterns: [ + { + protocol: "https", + hostname: "**", + }, + ], unoptimized: true, }, output: "standalone", diff --git a/web/next.config.js b/web/next.config.js index 29925a312..e018ea317 100644 --- a/web/next.config.js +++ b/web/next.config.js @@ -2,6 +2,14 @@ require("dotenv").config({ path: ".env" }); const { withSentryConfig } = require("@sentry/nextjs"); const nextConfig = { + async headers() { + return [ + { + source: "/(.*)?", + headers: [{ key: "X-Frame-Options", value: "SAMEORIGIN" }], + }, + ]; + }, reactStrictMode: false, swcMinify: true, images: { From 47d6b152a0898d4c058d59b896e6135559ee85fc Mon Sep 17 00:00:00 2001 From: Manish Gupta <59428681+mguptahub@users.noreply.github.com> Date: Wed, 20 Dec 2023 16:58:04 +0530 Subject: [PATCH 02/40] branch build custom docker repo with suffix (#3182) --- .github/workflows/build-branch.yml | 41 ++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/.github/workflows/build-branch.yml b/.github/workflows/build-branch.yml index d25154b15..14480fe44 100644 --- a/.github/workflows/build-branch.yml +++ b/.github/workflows/build-branch.yml @@ -9,6 +9,7 @@ on: - preview - qa - develop + - release-* release: types: [released, prereleased] @@ -62,14 +63,16 @@ jobs: runs-on: ubuntu-20.04 needs: [branch_build_setup] env: - FRONTEND_TAG: ${{ secrets.DOCKERHUB_USERNAME }}/plane-frontend:${{ needs.branch_build_setup.outputs.gh_branch_name }} + FRONTEND_TAG: ${{ secrets.DOCKERHUB_USERNAME }}/plane-frontend${{ secrets.DOCKER_REPO_SUFFIX || '' }}:${{ needs.branch_build_setup.outputs.gh_branch_name }} steps: - name: Set Frontend Docker Tag run: | - if [ "${{ needs.branch_build_setup.outputs.gh_branch_name }}" == "master" ] && [ "${{ github.event_name }}" == "release" ]; then - TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-frontend:latest,${{ secrets.DOCKERHUB_USERNAME }}/plane-frontend:${{ github.event.release.tag_name }} + if [[ ${{ needs.branch_build_setup.outputs.gh_branch_name }} == release-* ]]; then + TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-frontend${{ secrets.DOCKER_REPO_SUFFIX || '' }}-rel:${{ needs.branch_build_setup.outputs.gh_branch_name }} + elif [ "${{ needs.branch_build_setup.outputs.gh_branch_name }}" == "master" ] && [ "${{ github.event_name }}" == "release" ]; then + TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-frontend${{ secrets.DOCKER_REPO_SUFFIX || '' }}:latest,${{ secrets.DOCKERHUB_USERNAME }}/plane-frontend${{ secrets.DOCKER_REPO_SUFFIX || '' }}:${{ github.event.release.tag_name }} elif [ "${{ needs.branch_build_setup.outputs.gh_branch_name }}" == "master" ]; then - TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-frontend:stable + TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-frontend${{ secrets.DOCKER_REPO_SUFFIX || '' }}:stable else TAG=${{ env.FRONTEND_TAG }} fi @@ -104,14 +107,18 @@ jobs: runs-on: ubuntu-20.04 needs: [branch_build_setup] env: - SPACE_TAG: ${{ secrets.DOCKERHUB_USERNAME }}/plane-space:${{ needs.branch_build_setup.outputs.gh_branch_name }} + SPACE_TAG: ${{ secrets.DOCKERHUB_USERNAME }}/plane-space${{ secrets.DOCKER_REPO_SUFFIX || '' }}:${{ needs.branch_build_setup.outputs.gh_branch_name }} steps: - name: Set Space Docker Tag run: | + if [[ ${{ needs.branch_build_setup.outputs.gh_branch_name }} == release-* ]]; then + TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-space${{ secrets.DOCKER_REPO_SUFFIX || '' }}-rel:${{ needs.branch_build_setup.outputs.gh_branch_name }} + elif [[ ${{ needs.branch_build_setup.outputs.gh_branch_name }} == release-* ]]; then + TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-space${{ secrets.DOCKER_REPO_SUFFIX || '' }}-re:${{ needs.branch_build_setup.outputs.gh_branch_name }} if [ "${{ needs.branch_build_setup.outputs.gh_branch_name }}" == "master" ] && [ "${{ github.event_name }}" == "release" ]; then - TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-space:latest,${{ secrets.DOCKERHUB_USERNAME }}/plane-space:${{ github.event.release.tag_name }} + TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-space${{ secrets.DOCKER_REPO_SUFFIX || '' }}:latest,${{ secrets.DOCKERHUB_USERNAME }}/plane-space${{ secrets.DOCKER_REPO_SUFFIX || '' }}:${{ github.event.release.tag_name }} elif [ "${{ needs.branch_build_setup.outputs.gh_branch_name }}" == "master" ]; then - TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-space:stable + TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-space${{ secrets.DOCKER_REPO_SUFFIX || '' }}:stable else TAG=${{ env.SPACE_TAG }} fi @@ -146,14 +153,18 @@ jobs: runs-on: ubuntu-20.04 needs: [branch_build_setup] env: - BACKEND_TAG: ${{ secrets.DOCKERHUB_USERNAME }}/plane-backend:${{ needs.branch_build_setup.outputs.gh_branch_name }} + BACKEND_TAG: ${{ secrets.DOCKERHUB_USERNAME }}/plane-backend${{ secrets.DOCKER_REPO_SUFFIX || '' }}:${{ needs.branch_build_setup.outputs.gh_branch_name }} steps: - name: Set Backend Docker Tag run: | + if [[ ${{ needs.branch_build_setup.outputs.gh_branch_name }} == release-* ]]; then + TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-backend${{ secrets.DOCKER_REPO_SUFFIX || '' }}-rel:${{ needs.branch_build_setup.outputs.gh_branch_name }} + elif [[ ${{ needs.branch_build_setup.outputs.gh_branch_name }} == release-* ]]; then + TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-backend${{ secrets.DOCKER_REPO_SUFFIX || '' }}-re:${{ needs.branch_build_setup.outputs.gh_branch_name }} if [ "${{ needs.branch_build_setup.outputs.gh_branch_name }}" == "master" ] && [ "${{ github.event_name }}" == "release" ]; then - TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-backend:latest,${{ secrets.DOCKERHUB_USERNAME }}/plane-backend:${{ github.event.release.tag_name }} + TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-backend${{ secrets.DOCKER_REPO_SUFFIX || '' }}:latest,${{ secrets.DOCKERHUB_USERNAME }}/plane-backend${{ secrets.DOCKER_REPO_SUFFIX || '' }}:${{ github.event.release.tag_name }} elif [ "${{ needs.branch_build_setup.outputs.gh_branch_name }}" == "master" ]; then - TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-backend:stable + TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-backend${{ secrets.DOCKER_REPO_SUFFIX || '' }}:stable else TAG=${{ env.BACKEND_TAG }} fi @@ -188,14 +199,18 @@ jobs: runs-on: ubuntu-20.04 needs: [branch_build_setup] env: - PROXY_TAG: ${{ secrets.DOCKERHUB_USERNAME }}/plane-proxy:${{ needs.branch_build_setup.outputs.gh_branch_name }} + PROXY_TAG: ${{ secrets.DOCKERHUB_USERNAME }}/plane-proxy${{ secrets.DOCKER_REPO_SUFFIX || '' }}:${{ needs.branch_build_setup.outputs.gh_branch_name }} steps: - name: Set Proxy Docker Tag run: | + if [[ ${{ needs.branch_build_setup.outputs.gh_branch_name }} == release-* ]]; then + TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-proxy${{ secrets.DOCKER_REPO_SUFFIX || '' }}-rel:${{ needs.branch_build_setup.outputs.gh_branch_name }} + elif [[ ${{ needs.branch_build_setup.outputs.gh_branch_name }} == release-* ]]; then + TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-proxy${{ secrets.DOCKER_REPO_SUFFIX || '' }}-re:${{ needs.branch_build_setup.outputs.gh_branch_name }} if [ "${{ needs.branch_build_setup.outputs.gh_branch_name }}" == "master" ] && [ "${{ github.event_name }}" == "release" ]; then - TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-proxy:latest,${{ secrets.DOCKERHUB_USERNAME }}/plane-proxy:${{ github.event.release.tag_name }} + TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-proxy${{ secrets.DOCKER_REPO_SUFFIX || '' }}:latest,${{ secrets.DOCKERHUB_USERNAME }}/plane-proxy${{ secrets.DOCKER_REPO_SUFFIX || '' }}:${{ github.event.release.tag_name }} elif [ "${{ needs.branch_build_setup.outputs.gh_branch_name }}" == "master" ]; then - TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-proxy:stable + TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-proxy${{ secrets.DOCKER_REPO_SUFFIX || '' }}:stable else TAG=${{ env.PROXY_TAG }} fi From 40b8b0ac355fd7b0a04b9553270b5ae0e07964ba Mon Sep 17 00:00:00 2001 From: Lakhan Baheti <94619783+1akhanBaheti@users.noreply.github.com> Date: Wed, 20 Dec 2023 18:53:35 +0530 Subject: [PATCH 03/40] fix: role authorization for create project button in project empty state (#3204) --- web/components/page-views/workspace-dashboard.tsx | 3 +-- web/components/project/card-list.tsx | 5 ++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/web/components/page-views/workspace-dashboard.tsx b/web/components/page-views/workspace-dashboard.tsx index ff378e23d..299c35de9 100644 --- a/web/components/page-views/workspace-dashboard.tsx +++ b/web/components/page-views/workspace-dashboard.tsx @@ -37,8 +37,7 @@ export const WorkspaceDashboardView = observer(() => { workspaceSlug ? `USER_WORKSPACE_DASHBOARD_${workspaceSlug}_${month}` : null, workspaceSlug ? () => userStore.fetchUserDashboardInfo(workspaceSlug.toString(), month) : null ); - - const isEditingAllowed = !!userStore.currentProjectRole && userStore.currentProjectRole >= EUserWorkspaceRoles.MEMBER; + const isEditingAllowed = !!userStore.currentWorkspaceRole && userStore.currentWorkspaceRole >= EUserWorkspaceRoles.MEMBER; const handleTourCompleted = () => { userStore diff --git a/web/components/project/card-list.tsx b/web/components/project/card-list.tsx index 76f3112b6..3ccc403c1 100644 --- a/web/components/project/card-list.tsx +++ b/web/components/project/card-list.tsx @@ -23,12 +23,11 @@ export const ProjectCardList: FC = observer((props) => { project: projectStore, commandPalette: commandPaletteStore, trackEvent: { setTrackElement }, - user: { currentProjectRole }, + user: { currentWorkspaceRole }, } = useMobxStore(); const projects = workspaceSlug ? projectStore.projects[workspaceSlug.toString()] : null; - - const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER; + const isEditingAllowed = !!currentWorkspaceRole && currentWorkspaceRole >= EUserWorkspaceRoles.MEMBER; if (!projects) { return ( From e141091e99a59e03182856d0b89bd69972f3b101 Mon Sep 17 00:00:00 2001 From: "M. Palanikannan" <73993394+Palanikannan1437@users.noreply.github.com> Date: Wed, 20 Dec 2023 18:54:16 +0530 Subject: [PATCH 04/40] fix: Resolved page not saving/not copying contents bug (#3203) This commit adds a duplicate_page function to the PageDetailsPage component, which allows users to duplicate a page. If the current page does not have a description_html value, it will be set to the default value from the pageDetails object. The formData object is updated with the necessary values for duplication, including the new page name and description. Additionally, the handleSubmit dependency is included in the useEffect hook to ensure proper form submission. --- .../projects/[projectId]/pages/[pageId].tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/pages/[pageId].tsx b/web/pages/[workspaceSlug]/projects/[projectId]/pages/[pageId].tsx index a781cfd78..067d3e18f 100644 --- a/web/pages/[workspaceSlug]/projects/[projectId]/pages/[pageId].tsx +++ b/web/pages/[workspaceSlug]/projects/[projectId]/pages/[pageId].tsx @@ -246,6 +246,11 @@ const PageDetailsPage: NextPageWithLayout = observer(() => { // ================ Page Menu Actions ================== const duplicate_page = async () => { const currentPageValues = getValues(); + + if (!currentPageValues?.description_html) { + currentPageValues.description_html = pageDetails?.description_html as string; + } + const formData: Partial = { name: "Copy of " + pageDetails?.name, description_html: currentPageValues.description_html, @@ -336,7 +341,7 @@ const PageDetailsPage: NextPageWithLayout = observer(() => { debounce(async () => { handleSubmit(updatePage)().finally(() => setIsSubmitting("submitted")); }, 1500), - [handleSubmit] + [handleSubmit, pageDetails] ); if (error) From fe9519314afefa190d0fa82a368a57d0b9385b8e Mon Sep 17 00:00:00 2001 From: Ramesh Kumar Chandra <31303617+rameshkumarchandra@users.noreply.github.com> Date: Fri, 22 Dec 2023 14:05:17 +0530 Subject: [PATCH 05/40] fix: posthog events trigger in staging (#3220) * fix: posthog events trigger in staging * refactor: cleared comment lines for warnings, added dependancy values * refactor: removed unnecessary dependency --- web/lib/wrappers/posthog-wrapper.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/web/lib/wrappers/posthog-wrapper.tsx b/web/lib/wrappers/posthog-wrapper.tsx index 1e7c35c0d..9c17ee2bd 100644 --- a/web/lib/wrappers/posthog-wrapper.tsx +++ b/web/lib/wrappers/posthog-wrapper.tsx @@ -47,8 +47,7 @@ const PosthogWrapper: FC = (props) => { capture_pageview: false, // Disable automatic pageview capture, as we capture manually }); } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + }, [posthogAPIKey, posthogHost]); useEffect(() => { // Track page views @@ -60,7 +59,7 @@ const PosthogWrapper: FC = (props) => { return () => { router.events.off("routeChangeComplete", handleRouteChange); }; - // eslint-disable-next-line react-hooks/exhaustive-deps + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); if (posthogAPIKey) { From d76840ff6fcc130aa7f658a81a990a5e88910bd9 Mon Sep 17 00:00:00 2001 From: David Chiang <65947736+daveanthonyc@users.noreply.github.com> Date: Fri, 22 Dec 2023 22:54:02 +1100 Subject: [PATCH 06/40] Fix spelling error in setting-label-list.tsx (#3210) --- web/components/labels/project-setting-label-list.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/components/labels/project-setting-label-list.tsx b/web/components/labels/project-setting-label-list.tsx index 75fc40329..1dea90d01 100644 --- a/web/components/labels/project-setting-label-list.tsx +++ b/web/components/labels/project-setting-label-list.tsx @@ -217,7 +217,7 @@ export const ProjectSettingsLabelList: React.FC = observer(() => { {projectLabels && projectLabels.length === 0 && ( Date: Thu, 21 Dec 2023 13:52:38 +0530 Subject: [PATCH 07/40] fix: branch build fix (#3214) * branch build fix for release-* in case of space,backend,proxy * fixes --- .github/workflows/build-branch.yml | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/.github/workflows/build-branch.yml b/.github/workflows/build-branch.yml index 14480fe44..db65fbc2c 100644 --- a/.github/workflows/build-branch.yml +++ b/.github/workflows/build-branch.yml @@ -67,9 +67,7 @@ jobs: steps: - name: Set Frontend Docker Tag run: | - if [[ ${{ needs.branch_build_setup.outputs.gh_branch_name }} == release-* ]]; then - TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-frontend${{ secrets.DOCKER_REPO_SUFFIX || '' }}-rel:${{ needs.branch_build_setup.outputs.gh_branch_name }} - elif [ "${{ needs.branch_build_setup.outputs.gh_branch_name }}" == "master" ] && [ "${{ github.event_name }}" == "release" ]; then + if [ "${{ needs.branch_build_setup.outputs.gh_branch_name }}" == "master" ] && [ "${{ github.event_name }}" == "release" ]; then TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-frontend${{ secrets.DOCKER_REPO_SUFFIX || '' }}:latest,${{ secrets.DOCKERHUB_USERNAME }}/plane-frontend${{ secrets.DOCKER_REPO_SUFFIX || '' }}:${{ github.event.release.tag_name }} elif [ "${{ needs.branch_build_setup.outputs.gh_branch_name }}" == "master" ]; then TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-frontend${{ secrets.DOCKER_REPO_SUFFIX || '' }}:stable @@ -111,10 +109,6 @@ jobs: steps: - name: Set Space Docker Tag run: | - if [[ ${{ needs.branch_build_setup.outputs.gh_branch_name }} == release-* ]]; then - TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-space${{ secrets.DOCKER_REPO_SUFFIX || '' }}-rel:${{ needs.branch_build_setup.outputs.gh_branch_name }} - elif [[ ${{ needs.branch_build_setup.outputs.gh_branch_name }} == release-* ]]; then - TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-space${{ secrets.DOCKER_REPO_SUFFIX || '' }}-re:${{ needs.branch_build_setup.outputs.gh_branch_name }} if [ "${{ needs.branch_build_setup.outputs.gh_branch_name }}" == "master" ] && [ "${{ github.event_name }}" == "release" ]; then TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-space${{ secrets.DOCKER_REPO_SUFFIX || '' }}:latest,${{ secrets.DOCKERHUB_USERNAME }}/plane-space${{ secrets.DOCKER_REPO_SUFFIX || '' }}:${{ github.event.release.tag_name }} elif [ "${{ needs.branch_build_setup.outputs.gh_branch_name }}" == "master" ]; then @@ -157,10 +151,6 @@ jobs: steps: - name: Set Backend Docker Tag run: | - if [[ ${{ needs.branch_build_setup.outputs.gh_branch_name }} == release-* ]]; then - TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-backend${{ secrets.DOCKER_REPO_SUFFIX || '' }}-rel:${{ needs.branch_build_setup.outputs.gh_branch_name }} - elif [[ ${{ needs.branch_build_setup.outputs.gh_branch_name }} == release-* ]]; then - TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-backend${{ secrets.DOCKER_REPO_SUFFIX || '' }}-re:${{ needs.branch_build_setup.outputs.gh_branch_name }} if [ "${{ needs.branch_build_setup.outputs.gh_branch_name }}" == "master" ] && [ "${{ github.event_name }}" == "release" ]; then TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-backend${{ secrets.DOCKER_REPO_SUFFIX || '' }}:latest,${{ secrets.DOCKERHUB_USERNAME }}/plane-backend${{ secrets.DOCKER_REPO_SUFFIX || '' }}:${{ github.event.release.tag_name }} elif [ "${{ needs.branch_build_setup.outputs.gh_branch_name }}" == "master" ]; then @@ -203,10 +193,6 @@ jobs: steps: - name: Set Proxy Docker Tag run: | - if [[ ${{ needs.branch_build_setup.outputs.gh_branch_name }} == release-* ]]; then - TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-proxy${{ secrets.DOCKER_REPO_SUFFIX || '' }}-rel:${{ needs.branch_build_setup.outputs.gh_branch_name }} - elif [[ ${{ needs.branch_build_setup.outputs.gh_branch_name }} == release-* ]]; then - TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-proxy${{ secrets.DOCKER_REPO_SUFFIX || '' }}-re:${{ needs.branch_build_setup.outputs.gh_branch_name }} if [ "${{ needs.branch_build_setup.outputs.gh_branch_name }}" == "master" ] && [ "${{ github.event_name }}" == "release" ]; then TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-proxy${{ secrets.DOCKER_REPO_SUFFIX || '' }}:latest,${{ secrets.DOCKERHUB_USERNAME }}/plane-proxy${{ secrets.DOCKER_REPO_SUFFIX || '' }}:${{ github.event.release.tag_name }} elif [ "${{ needs.branch_build_setup.outputs.gh_branch_name }}" == "master" ]; then From 9c65657a6668c674d70966bd4b2a9a5fa7ef799f Mon Sep 17 00:00:00 2001 From: Hoang Luan Date: Thu, 21 Dec 2023 15:56:44 +0700 Subject: [PATCH 08/40] fix - file size limit not work on plane.settings.production (#3160) * fix - file size limit not work on plane.settings.production * fix - file size limit not work on plane.settings.production * fix - file size limit not work on plane.settings.production, move to common.py --------- Co-authored-by: luanduongtel4vn Co-authored-by: sriram veeraghanta --- apiserver/plane/settings/common.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apiserver/plane/settings/common.py b/apiserver/plane/settings/common.py index 76528176b..971ed5543 100644 --- a/apiserver/plane/settings/common.py +++ b/apiserver/plane/settings/common.py @@ -291,7 +291,9 @@ CELERY_IMPORTS = ( # Sentry Settings # Enable Sentry Settings -if bool(os.environ.get("SENTRY_DSN", False)) and os.environ.get("SENTRY_DSN").startswith("https://"): +if bool(os.environ.get("SENTRY_DSN", False)) and os.environ.get( + "SENTRY_DSN" +).startswith("https://"): sentry_sdk.init( dsn=os.environ.get("SENTRY_DSN", ""), integrations=[ @@ -334,3 +336,5 @@ INSTANCE_KEY = os.environ.get( # Skip environment variable configuration SKIP_ENV_VAR = os.environ.get("SKIP_ENV_VAR", "1") == "1" + +DATA_UPLOAD_MAX_MEMORY_SIZE = int(os.environ.get("FILE_SIZE_LIMIT", 5242880)) From 5f681973a01c1fd53e108acd46dd6e320ccc9413 Mon Sep 17 00:00:00 2001 From: Prateek Shourya Date: Thu, 21 Dec 2023 14:37:26 +0530 Subject: [PATCH 09/40] style: instance admin email settings ui & ux update. (#3186) --- web/components/instance/email-form.tsx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/web/components/instance/email-form.tsx b/web/components/instance/email-form.tsx index 82da7553e..9d23f398f 100644 --- a/web/components/instance/email-form.tsx +++ b/web/components/instance/email-form.tsx @@ -67,7 +67,7 @@ export const InstanceEmailForm: FC = (props) => { return ( <> -
+

Host

= (props) => { />
-
+

Username

= (props) => {
-
+

From address

= (props) => { )} />

- You will have to verify your email address to being sending emails. + This is the email address your users will see when getting emails from this instance. You will need to + verify this address.

-
+
From 0a41eff43567de297feb403bdb630fa9312f5cb4 Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com> Date: Thu, 21 Dec 2023 15:56:02 +0530 Subject: [PATCH 10/40] chore: bug fixes & improvement (#3218) * chore: draft issue validation added to prevent saving empty or whitespace title * chore: resolve scrolling issue in page empty state * chore: kanban layout quick add issue improvement --- web/components/common/new-empty-state.tsx | 120 +++++++++--------- .../kanban/quick-add-issue-form.tsx | 2 +- web/components/issues/modal.tsx | 2 +- 3 files changed, 63 insertions(+), 61 deletions(-) diff --git a/web/components/common/new-empty-state.tsx b/web/components/common/new-empty-state.tsx index 508d2e5da..7bad18734 100644 --- a/web/components/common/new-empty-state.tsx +++ b/web/components/common/new-empty-state.tsx @@ -41,69 +41,71 @@ export const NewEmptyState: React.FC = ({ setIsHovered(false); }; return ( -
-
-

{title}

- {description &&

{description}

} -
- {primaryButton?.text -
+
+
+
+

{title}

+ {description &&

{description}

} +
+ {primaryButton?.text +
-
- {primaryButton && ( - - )} - {comicBox && - isHovered && - (comicBox.direction === "right" ? ( -
+ {primaryButton && ( + + )} + {comicBox && + isHovered && + (comicBox.direction === "right" ? ( +
+
+
+
+
+

+

{comicBox?.title}

+

{comicBox?.description}

+ +
-
-

-

{comicBox?.title}

-

{comicBox?.description}

- + ) : ( +
+
+
+
+
+

+

{comicBox?.title}

+

{comicBox?.description}

+ +
-
- ) : ( -
-
-
-
-
-

-

{comicBox?.title}

-

{comicBox?.description}

- -
-
- ))} + ))} +
diff --git a/web/components/issues/issue-layouts/kanban/quick-add-issue-form.tsx b/web/components/issues/issue-layouts/kanban/quick-add-issue-form.tsx index 0120e02f6..9c4406f7d 100644 --- a/web/components/issues/issue-layouts/kanban/quick-add-issue-form.tsx +++ b/web/components/issues/issue-layouts/kanban/quick-add-issue-form.tsx @@ -22,7 +22,7 @@ const Inputs = (props: any) => { }, [setFocus]); return ( -
+

{projectDetail?.identifier ?? "..."}

= observer((prop */ const onDiscardClose = () => { - if (formDirtyState !== null) { + if (formDirtyState !== null && formDirtyState.name.trim() !== "") { setShowConfirmDiscard(true); } else { handleClose(); From aceee7d2e2bb3388832de20ff2c55996d137e072 Mon Sep 17 00:00:00 2001 From: Lakhan Baheti <94619783+1akhanBaheti@users.noreply.github.com> Date: Thu, 21 Dec 2023 15:59:21 +0530 Subject: [PATCH 11/40] fix: bugs & improvements (#3189) * fix: workspace invitation modal form values reset * fix: profile sidebar avatar letter --- web/components/profile/sidebar.tsx | 8 ++++---- .../workspace/send-workspace-invitation-modal.tsx | 8 +++++++- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/web/components/profile/sidebar.tsx b/web/components/profile/sidebar.tsx index 6c01db9f7..79cc96b5a 100644 --- a/web/components/profile/sidebar.tsx +++ b/web/components/profile/sidebar.tsx @@ -89,8 +89,8 @@ export const ProfileSidebar = () => { className="h-full w-full rounded object-cover" /> ) : ( -
- {userProjectsData.user_data.display_name?.[0]} +
+ {userProjectsData.user_data.first_name?.[0]}
)}
@@ -149,8 +149,8 @@ export const ProfileSidebar = () => { completedIssuePercentage <= 35 ? "bg-red-500/10 text-red-500" : completedIssuePercentage <= 70 - ? "bg-yellow-500/10 text-yellow-500" - : "bg-green-500/10 text-green-500" + ? "bg-yellow-500/10 text-yellow-500" + : "bg-green-500/10 text-green-500" }`} > {completedIssuePercentage}% diff --git a/web/components/workspace/send-workspace-invitation-modal.tsx b/web/components/workspace/send-workspace-invitation-modal.tsx index a720e31f5..43609d1c5 100644 --- a/web/components/workspace/send-workspace-invitation-modal.tsx +++ b/web/components/workspace/send-workspace-invitation-modal.tsx @@ -68,6 +68,12 @@ export const SendWorkspaceInvitationModal: React.FC = observer((props) => append({ email: "", role: 15 }); }; + const onSubmitForm = async (data: FormValues) => { + await onSubmit(data)?.then(() => { + reset(defaultValues); + }); + }; + useEffect(() => { if (fields.length === 0) append([{ email: "", role: 15 }]); }, [fields, append]); @@ -100,7 +106,7 @@ export const SendWorkspaceInvitationModal: React.FC = observer((props) => >
{ if (e.code === "Enter") e.preventDefault(); }} From 0b1efb173fbeba26f8a9ac311576889740d5c476 Mon Sep 17 00:00:00 2001 From: "M. Palanikannan" <73993394+Palanikannan1437@users.noreply.github.com> Date: Thu, 21 Dec 2023 16:01:38 +0530 Subject: [PATCH 12/40] [refactor] Editor code refactoring (#3194) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * removed relative imports from editor core * Update issue widget file paths and imports to use kebab case instead of camel case, to align with coding conventions and improve consistency. * Update Tiptap core and extensions versions to 2.1.13 and Tiptap React version to 2.1.13. Update Tiptap table imports to use the new location in package @tiptap/pm/tables. Update AlertLabel component to use the new type definition for LucideIcon. * updated lock file * removed default exports from editor/core * fixed injecting css into the core package itself * seperated css code to have single source of origin wrt to the package * removed default imports from document editor * all instances using index as key while mapping fixed * Update Lite Text Editor package.json to remove @plane/editor-types as a dependency. Update Lite Text Editor index.ts to update the import of IMentionSuggestion and IMentionHighlight from @plane/editor-types to @plane/editor-core. Update Lite Text Editor ui/index.tsx to update the import of UploadImage, DeleteImage, IMentionSuggestion, and RestoreImage from @plane/editor-types to @plane/editor-core. Update Lite Text Editor ui/menus/fixed-menu/index.tsx to update the import of UploadImage from @plane/editor-types to @plane/editor-core. Update turbo.json to remove @plane/editor-types#build as a dependency for @plane/lite-text-editor#build, @plane/rich-text-editor#build, and @plane/document-editor#build. * Remove deprecated import and adjust tippy.js usage in the slash-commands.tsx file of the editor extensions package. * Update dependencies in `rich-text-editor/package.json`, remove `@plane/editor-types` and add `@plane/editor-core` in `rich-text-editor/src/index.ts`, and update imports in `rich-text-editor/src/ui/extensions/index.tsx` and `rich-text-editor/src/ui/index.tsx` to use `@plane/editor-core` instead of `@plane/editor-types`. * Update package.json dependencies and add new types for image deletion, upload, restore, mention highlight, mention suggestion, and slash command item. * Update import statements in various files to use the new package "@plane/editor-core" instead of "@plane/editor-types". * fixed document editor to follow conventions * Refactor imports in the Rich Text Editor package to use relative paths instead of absolute paths. - Updated imports in `index.ts`, `ui/index.tsx`, and `ui/menus/bubble-menu/index.tsx` to use relative paths. - Updated `tsconfig.json` to include the `baseUrl` compiler option and adjust the `include` and `exclude` paths. * Refactor Lite Text Editor code to use relative import paths instead of absolute import paths. * Added LucideIconType to the exports in index.ts for use in other files. Created a new file lucide-icon.ts which contains the type LucideIconType. Updated the icon type in HeadingOneItem in menu-items/index.tsx to use LucideIconType. Updated the Icon type in AlertLabel in alert-label.tsx to use LucideIconType. Updated the Icon type in VerticalDropdownItemProps in vertical-dropdown-menu.tsx to use LucideIconType. Updated the Icon type in BubbleMenuItem in fixed-menu/index.tsx to use LucideIconType. Deleted the file tooltip.tsx since it is no longer used. Updated the Icon type in BubbleMenuItem in bubble-menu/index.tsx to use LucideIconType. * ♻️ refactor: simplify rendering logic in slash-commands.tsx The rendering logic in the file "slash-commands.tsx" has been simplified. Previously, the code used inline positioning for the popup, but it has now been removed. Instead of appending the popup to the document body, it is now appended to the element with the ID "tiptap-container". The "flip" option has also been removed. These changes have improved the readability and maintainability of the code. * fixed build errors caused due to core's internal imports * regression: fixed pages not saving issue and not duplicating with proper content issue * build: Update @tiptap dependencies Updated the @tiptap dependencies in the package.json files of `document-editor`, `extensions`, and `rich-text-editor` packages to version 2.1.13. * 🚑 fix: Correct appendTo selector in slash-commands.tsx Update the `appendTo` function call in `slash-commands.tsx` to use the correct selector `#editor-container` instead of `#tiptap-container`. This ensures that the component is appended to the appropriate container in the editor extension. Note: The commit message assumes that the change is a fix for an issue or error. If it's not a fix, please provide more context so that an appropriate commit type can be determined. --- packages/editor/core/package.json | 36 +- .../core/src/{ui => }/hooks/use-editor.tsx | 11 +- .../{ui => }/hooks/use-read-only-editor.tsx | 6 +- packages/editor/core/src/index.ts | 33 +- .../editor/core/src/lib/editor-commands.ts | 6 +- packages/editor/core/src/styles/editor.css | 51 ++- .../editor/core/src}/styles/table.css | 0 .../{types => core}/src/types/delete-image.ts | 0 packages/editor/core/src/types/lucide-icon.ts | 3 + .../src/types/mention-suggestion.ts | 0 .../src/types/restore-image.ts | 0 .../src/types/slash-commands-suggestion.ts | 0 .../{types => core}/src/types/upload-image.ts | 0 .../core/src/ui/components/editor-content.tsx | 2 +- .../list-helpers/get-next-list-depth.ts | 2 +- .../list-helpers/handle-backspace.ts | 4 +- .../list-helpers/handle-delete.ts | 4 +- .../list-helpers/next-list-is-deeper.ts | 4 +- .../list-helpers/next-list-is-higher.ts | 4 +- .../custom-list-keymap/list-keymap.ts | 2 +- .../src/ui/extensions/horizontal-rule.tsx | 2 +- .../core/src/ui/extensions/image/index.tsx | 11 +- .../ui/extensions/image/read-only-image.tsx | 4 +- .../editor/core/src/ui/extensions/index.tsx | 29 +- .../ui/extensions/table/table-cell/index.ts | 2 +- .../extensions/table/table-cell/table-cell.ts | 2 +- .../ui/extensions/table/table-header/index.ts | 2 +- .../table/table-header/table-header.ts | 3 +- .../ui/extensions/table/table-row/index.ts | 2 +- .../extensions/table/table-row/table-row.ts | 2 +- .../src/ui/extensions/table/table/icons.ts | 4 +- .../src/ui/extensions/table/table/index.ts | 2 +- .../ui/extensions/table/table/table-view.tsx | 4 +- .../src/ui/extensions/table/table/table.ts | 12 +- .../table/table/utilities/create-table.ts | 4 +- .../delete-table-when-all-cells-selected.ts | 2 +- .../table/utilities/is-cell-selection.ts | 2 +- .../editor/core/src/ui/mentions/custom.tsx | 6 +- .../editor/core/src/ui/mentions/index.tsx | 8 +- .../{MentionList.tsx => mention-list.tsx} | 8 +- ...tionNodeView.tsx => mention-node-view.tsx} | 6 +- .../editor/core/src/ui/mentions/suggestion.ts | 8 +- .../core/src/ui/menus/menu-items/index.tsx | 7 +- .../core/src/ui/plugins/delete-image.tsx | 7 +- .../core/src/ui/plugins/upload-image.tsx | 6 +- packages/editor/core/src/ui/props.tsx | 6 +- .../core/src/ui/read-only/extensions.tsx | 18 +- packages/editor/core/tsconfig.json | 14 +- packages/editor/document-editor/package.json | 9 +- .../{ui => }/hooks/use-editor-markings.tsx | 3 +- packages/editor/document-editor/src/index.ts | 6 +- .../src/{ui => }/types/editor-types.ts | 6 + .../editor/document-editor/src/types/mark.ts | 0 .../src/{ui => }/types/menu-actions.d.ts | 0 .../src/ui/components/alert-label.tsx | 5 +- .../src/ui/components/content-browser.tsx | 6 +- .../src/ui/components/editor-header.tsx | 15 +- .../src/ui/components/info-popover.tsx | 2 +- .../src/ui/components/page-renderer.tsx | 2 +- .../src/ui/components/summary-popover.tsx | 4 +- .../src/ui/components/summary-side-bar.tsx | 24 +- .../ui/components/vertical-dropdown-menu.tsx | 49 ++- .../src/ui/extensions/index.tsx | 8 +- .../issue-suggestion-items.tsx | 16 - .../index.tsx | 8 +- .../issue-suggestion-extension.tsx | 0 .../issue-suggestion-items.tsx | 15 + .../issue-suggestion-renderer.tsx | 2 +- .../index.tsx | 4 +- .../issue-widget-card.tsx | 12 +- .../issue-widget-node.tsx | 2 +- .../types.ts | 0 .../editor/document-editor/src/ui/index.tsx | 28 +- .../src/ui/menu/fixed-menu.tsx | 2 +- .../document-editor/src/ui/readonly/index.tsx | 18 +- .../{ui => }/utils/editor-summary-utils.ts | 2 +- .../src/{ui => }/utils/menu-actions.ts | 0 .../src/{ui => }/utils/menu-options.ts | 18 +- packages/editor/document-editor/tsconfig.json | 14 +- packages/editor/extensions/package.json | 9 +- .../src/extensions/slash-commands.tsx | 4 +- packages/editor/extensions/src/index.ts | 6 +- .../extensions/src/styles/drag-drop.css | 53 +++ packages/editor/extensions/tsconfig.json | 14 +- packages/editor/lite-text-editor/package.json | 3 +- packages/editor/lite-text-editor/src/index.ts | 6 +- .../src/ui/extensions/index.tsx | 2 +- .../editor/lite-text-editor/src/ui/index.tsx | 16 +- .../src/ui/menus/fixed-menu/index.tsx | 28 +- .../lite-text-editor/src/ui/tooltip.tsx | 74 ---- .../editor/lite-text-editor/tsconfig.json | 14 +- packages/editor/rich-text-editor/package.json | 5 +- packages/editor/rich-text-editor/src/index.ts | 8 +- .../src/ui/extensions/index.tsx | 5 +- .../editor/rich-text-editor/src/ui/index.tsx | 16 +- .../src/ui/menus/bubble-menu/index.tsx | 12 +- .../ui/menus/bubble-menu/node-selector.tsx | 4 +- .../editor/rich-text-editor/tsconfig.json | 14 +- packages/editor/types/.eslintrc.js | 4 - packages/editor/types/.prettierignore | 6 - packages/editor/types/.prettierrc | 5 - packages/editor/types/Readme.md | 97 ----- packages/editor/types/package.json | 51 --- packages/editor/types/postcss.config.js | 9 - packages/editor/types/src/index.ts | 5 - packages/editor/types/tailwind.config.js | 6 - packages/editor/types/tsconfig.json | 5 - packages/editor/types/tsup.config.ts | 11 - space/pages/_app.tsx | 2 - space/styles/editor.css | 323 ----------------- turbo.json | 9 +- web/pages/_app.tsx | 2 - web/styles/editor.css | 333 ------------------ web/styles/table.css | 206 ----------- yarn.lock | 63 ++-- 115 files changed, 513 insertions(+), 1548 deletions(-) rename packages/editor/core/src/{ui => }/hooks/use-editor.tsx (86%) rename packages/editor/core/src/{ui => }/hooks/use-read-only-editor.tsx (88%) rename {space => packages/editor/core/src}/styles/table.css (100%) rename packages/editor/{types => core}/src/types/delete-image.ts (100%) create mode 100644 packages/editor/core/src/types/lucide-icon.ts rename packages/editor/{types => core}/src/types/mention-suggestion.ts (100%) rename packages/editor/{types => core}/src/types/restore-image.ts (100%) rename packages/editor/{types => core}/src/types/slash-commands-suggestion.ts (100%) rename packages/editor/{types => core}/src/types/upload-image.ts (100%) rename packages/editor/core/src/ui/mentions/{MentionList.tsx => mention-list.tsx} (91%) rename packages/editor/core/src/ui/mentions/{mentionNodeView.tsx => mention-node-view.tsx} (89%) rename packages/editor/document-editor/src/{ui => }/hooks/use-editor-markings.tsx (93%) rename packages/editor/document-editor/src/{ui => }/types/editor-types.ts (59%) create mode 100644 packages/editor/document-editor/src/types/mark.ts rename packages/editor/document-editor/src/{ui => }/types/menu-actions.d.ts (100%) delete mode 100644 packages/editor/document-editor/src/ui/extensions/widgets/IssueEmbedSuggestionList/issue-suggestion-items.tsx rename packages/editor/document-editor/src/ui/extensions/widgets/{IssueEmbedSuggestionList => issue-embed-suggestion-list}/index.tsx (79%) rename packages/editor/document-editor/src/ui/extensions/widgets/{IssueEmbedSuggestionList => issue-embed-suggestion-list}/issue-suggestion-extension.tsx (100%) create mode 100644 packages/editor/document-editor/src/ui/extensions/widgets/issue-embed-suggestion-list/issue-suggestion-items.tsx rename packages/editor/document-editor/src/ui/extensions/widgets/{IssueEmbedSuggestionList => issue-embed-suggestion-list}/issue-suggestion-renderer.tsx (99%) rename packages/editor/document-editor/src/ui/extensions/widgets/{IssueEmbedWidget => issue-embed-widget}/index.tsx (55%) rename packages/editor/document-editor/src/ui/extensions/widgets/{IssueEmbedWidget => issue-embed-widget}/issue-widget-card.tsx (91%) rename packages/editor/document-editor/src/ui/extensions/widgets/{IssueEmbedWidget => issue-embed-widget}/issue-widget-node.tsx (94%) rename packages/editor/document-editor/src/ui/extensions/widgets/{IssueEmbedWidget => issue-embed-widget}/types.ts (100%) rename packages/editor/document-editor/src/{ui => }/utils/editor-summary-utils.ts (94%) rename packages/editor/document-editor/src/{ui => }/utils/menu-actions.ts (100%) rename packages/editor/document-editor/src/{ui => }/utils/menu-options.ts (93%) create mode 100644 packages/editor/extensions/src/styles/drag-drop.css delete mode 100644 packages/editor/lite-text-editor/src/ui/tooltip.tsx delete mode 100644 packages/editor/types/.eslintrc.js delete mode 100644 packages/editor/types/.prettierignore delete mode 100644 packages/editor/types/.prettierrc delete mode 100644 packages/editor/types/Readme.md delete mode 100644 packages/editor/types/package.json delete mode 100644 packages/editor/types/postcss.config.js delete mode 100644 packages/editor/types/src/index.ts delete mode 100644 packages/editor/types/tailwind.config.js delete mode 100644 packages/editor/types/tsconfig.json delete mode 100644 packages/editor/types/tsup.config.ts delete mode 100644 space/styles/editor.css delete mode 100644 web/styles/editor.css delete mode 100644 web/styles/table.css diff --git a/packages/editor/core/package.json b/packages/editor/core/package.json index 2f458995c..ef2be61e3 100644 --- a/packages/editor/core/package.json +++ b/packages/editor/core/package.json @@ -28,28 +28,22 @@ "react-dom": "18.2.0" }, "dependencies": { - "@plane/editor-types": "*", - "@tiptap/core": "^2.1.7", + "@tiptap/core": "^2.1.13", "@tiptap/extension-blockquote": "^2.1.13", - "@tiptap/extension-code-block-lowlight": "^2.1.12", - "@tiptap/extension-color": "^2.1.11", - "@tiptap/extension-image": "^2.1.7", - "@tiptap/extension-link": "^2.1.7", - "@tiptap/extension-list-item": "^2.1.12", - "@tiptap/extension-mention": "^2.1.12", - "@tiptap/extension-table": "^2.1.6", - "@tiptap/extension-table-cell": "^2.1.6", - "@tiptap/extension-table-header": "^2.1.6", - "@tiptap/extension-table-row": "^2.1.6", - "@tiptap/extension-task-item": "^2.1.7", - "@tiptap/extension-task-list": "^2.1.7", - "@tiptap/extension-text-style": "^2.1.11", - "@tiptap/extension-underline": "^2.1.7", - "@tiptap/pm": "^2.1.7", - "@tiptap/prosemirror-tables": "^1.1.4", - "@tiptap/react": "^2.1.7", - "@tiptap/starter-kit": "^2.1.10", - "@tiptap/suggestion": "^2.0.4", + "@tiptap/extension-code-block-lowlight": "^2.1.13", + "@tiptap/extension-color": "^2.1.13", + "@tiptap/extension-image": "^2.1.13", + "@tiptap/extension-link": "^2.1.13", + "@tiptap/extension-list-item": "^2.1.13", + "@tiptap/extension-mention": "^2.1.13", + "@tiptap/extension-task-item": "^2.1.13", + "@tiptap/extension-task-list": "^2.1.13", + "@tiptap/extension-text-style": "^2.1.13", + "@tiptap/extension-underline": "^2.1.13", + "@tiptap/pm": "^2.1.13", + "@tiptap/react": "^2.1.13", + "@tiptap/starter-kit": "^2.1.13", + "@tiptap/suggestion": "^2.0.13", "class-variance-authority": "^0.7.0", "clsx": "^1.2.1", "highlight.js": "^11.8.0", diff --git a/packages/editor/core/src/ui/hooks/use-editor.tsx b/packages/editor/core/src/hooks/use-editor.tsx similarity index 86% rename from packages/editor/core/src/ui/hooks/use-editor.tsx rename to packages/editor/core/src/hooks/use-editor.tsx index 149f9b453..c2923c1e9 100644 --- a/packages/editor/core/src/ui/hooks/use-editor.tsx +++ b/packages/editor/core/src/hooks/use-editor.tsx @@ -1,10 +1,13 @@ import { useEditor as useCustomEditor, Editor } from "@tiptap/react"; import { useImperativeHandle, useRef, MutableRefObject } from "react"; -import { CoreEditorProps } from "../props"; -import { CoreEditorExtensions } from "../extensions"; +import { CoreEditorProps } from "src/ui/props"; +import { CoreEditorExtensions } from "src/ui/extensions"; import { EditorProps } from "@tiptap/pm/view"; -import { getTrimmedHTML } from "../../lib/utils"; -import { DeleteImage, IMentionSuggestion, RestoreImage, UploadImage } from "@plane/editor-types"; +import { getTrimmedHTML } from "src/lib/utils"; +import { DeleteImage } from "src/types/delete-image"; +import { IMentionSuggestion } from "src/types/mention-suggestion"; +import { RestoreImage } from "src/types/restore-image"; +import { UploadImage } from "src/types/upload-image"; interface CustomEditorProps { uploadFile: UploadImage; diff --git a/packages/editor/core/src/ui/hooks/use-read-only-editor.tsx b/packages/editor/core/src/hooks/use-read-only-editor.tsx similarity index 88% rename from packages/editor/core/src/ui/hooks/use-read-only-editor.tsx rename to packages/editor/core/src/hooks/use-read-only-editor.tsx index 5c2429108..ecd49255c 100644 --- a/packages/editor/core/src/ui/hooks/use-read-only-editor.tsx +++ b/packages/editor/core/src/hooks/use-read-only-editor.tsx @@ -1,9 +1,9 @@ import { useEditor as useCustomEditor, Editor } from "@tiptap/react"; import { useImperativeHandle, useRef, MutableRefObject } from "react"; -import { CoreReadOnlyEditorExtensions } from "../read-only/extensions"; -import { CoreReadOnlyEditorProps } from "../read-only/props"; +import { CoreReadOnlyEditorExtensions } from "src/ui/read-only/extensions"; +import { CoreReadOnlyEditorProps } from "src/ui/read-only/props"; import { EditorProps } from "@tiptap/pm/view"; -import { IMentionSuggestion } from "@plane/editor-types"; +import { IMentionSuggestion } from "src/types/mention-suggestion"; interface CustomReadOnlyEditorProps { value: string; diff --git a/packages/editor/core/src/index.ts b/packages/editor/core/src/index.ts index bdf533193..c7e39d240 100644 --- a/packages/editor/core/src/index.ts +++ b/packages/editor/core/src/index.ts @@ -1,23 +1,32 @@ // styles // import "./styles/tailwind.css"; -// import "./styles/editor.css"; -import "./styles/github-dark.css"; +import "src/styles/editor.css"; +import "src/styles/table.css"; +import "src/styles/github-dark.css"; -export { isCellSelection } from "./ui/extensions/table/table/utilities/is-cell-selection"; +export { isCellSelection } from "src/ui/extensions/table/table/utilities/is-cell-selection"; // utils -export * from "./lib/utils"; -export * from "./ui/extensions/table/table"; -export { startImageUpload } from "./ui/plugins/upload-image"; +export * from "src/lib/utils"; +export * from "src/ui/extensions/table/table"; +export { startImageUpload } from "src/ui/plugins/upload-image"; // components -export { EditorContainer } from "./ui/components/editor-container"; -export { EditorContentWrapper } from "./ui/components/editor-content"; +export { EditorContainer } from "src/ui/components/editor-container"; +export { EditorContentWrapper } from "src/ui/components/editor-content"; // hooks -export { useEditor } from "./ui/hooks/use-editor"; -export { useReadOnlyEditor } from "./ui/hooks/use-read-only-editor"; +export { useEditor } from "src/hooks/use-editor"; +export { useReadOnlyEditor } from "src/hooks/use-read-only-editor"; // helper items -export * from "./ui/menus/menu-items"; -export * from "./lib/editor-commands"; +export * from "src/ui/menus/menu-items"; +export * from "src/lib/editor-commands"; + +// types +export type { DeleteImage } from "src/types/delete-image"; +export type { UploadImage } from "src/types/upload-image"; +export type { RestoreImage } from "src/types/restore-image"; +export type { IMentionHighlight, IMentionSuggestion } from "src/types/mention-suggestion"; +export type { ISlashCommandItem, CommandProps } from "src/types/slash-commands-suggestion"; +export type { LucideIconType } from "src/types/lucide-icon"; diff --git a/packages/editor/core/src/lib/editor-commands.ts b/packages/editor/core/src/lib/editor-commands.ts index 4a331e7cd..147797e2d 100644 --- a/packages/editor/core/src/lib/editor-commands.ts +++ b/packages/editor/core/src/lib/editor-commands.ts @@ -1,7 +1,7 @@ -import { UploadImage } from "@plane/editor-types"; import { Editor, Range } from "@tiptap/core"; -import { startImageUpload } from "../ui/plugins/upload-image"; -import { findTableAncestor } from "./utils"; +import { startImageUpload } from "src/ui/plugins/upload-image"; +import { findTableAncestor } from "src/lib/utils"; +import { UploadImage } from "src/types/upload-image"; export const toggleHeadingOne = (editor: Editor, range?: Range) => { if (range) editor.chain().focus().deleteRange(range).setNode("heading", { level: 1 }).run(); diff --git a/packages/editor/core/src/styles/editor.css b/packages/editor/core/src/styles/editor.css index 85d881eeb..ab0312789 100644 --- a/packages/editor/core/src/styles/editor.css +++ b/packages/editor/core/src/styles/editor.css @@ -6,6 +6,12 @@ height: 0; } +/* block quotes */ +.ProseMirror blockquote p::before, +.ProseMirror blockquote p::after { + display: none; +} + .ProseMirror .is-empty::before { content: attr(data-placeholder); float: left; @@ -15,7 +21,6 @@ } /* Custom image styles */ - .ProseMirror img { transition: filter 0.1s ease-in-out; @@ -53,11 +58,12 @@ ul[data-type="taskList"] li > label input[type="checkbox"] { background-color: rgb(var(--color-background-100)); margin: 0; cursor: pointer; - width: 1.2rem; - height: 1.2rem; + width: 0.8rem; + height: 0.8rem; position: relative; - border: 2px solid rgb(var(--color-text-100)); - margin-right: 0.3rem; + border: 1.5px solid rgb(var(--color-text-100)); + margin-right: 0.2rem; + margin-top: 0.15rem; display: grid; place-content: center; @@ -71,8 +77,8 @@ ul[data-type="taskList"] li > label input[type="checkbox"] { &::before { content: ""; - width: 0.65em; - height: 0.65em; + width: 0.5em; + height: 0.5em; transform: scale(0); transition: 120ms transform ease-in-out; box-shadow: inset 1em 1em; @@ -229,3 +235,34 @@ ul[data-type="taskList"] li[data-checked="true"] > div > p { .ProseMirror table * .is-empty::before { opacity: 0; } + +.ProseMirror pre { + background: rgba(var(--color-background-80)); + border-radius: 0.5rem; + color: rgba(var(--color-text-100)); + font-family: "JetBrainsMono", monospace; + padding: 0.75rem 1rem; +} + +.ProseMirror pre code { + background: none; + color: inherit; + font-size: 0.8rem; + padding: 0; +} + +div[data-type="horizontalRule"] { + line-height: 0; + padding: 0.25rem 0; + margin-top: 0; + margin-bottom: 0; + + & > div { + border-bottom: 1px solid rgb(var(--color-text-100)); + } +} + +/* image resizer */ +.moveable-control-box { + z-index: 10 !important; +} diff --git a/space/styles/table.css b/packages/editor/core/src/styles/table.css similarity index 100% rename from space/styles/table.css rename to packages/editor/core/src/styles/table.css diff --git a/packages/editor/types/src/types/delete-image.ts b/packages/editor/core/src/types/delete-image.ts similarity index 100% rename from packages/editor/types/src/types/delete-image.ts rename to packages/editor/core/src/types/delete-image.ts diff --git a/packages/editor/core/src/types/lucide-icon.ts b/packages/editor/core/src/types/lucide-icon.ts new file mode 100644 index 000000000..2211c18e8 --- /dev/null +++ b/packages/editor/core/src/types/lucide-icon.ts @@ -0,0 +1,3 @@ +import { Smile } from "lucide-react"; + +export type LucideIconType = typeof Smile; diff --git a/packages/editor/types/src/types/mention-suggestion.ts b/packages/editor/core/src/types/mention-suggestion.ts similarity index 100% rename from packages/editor/types/src/types/mention-suggestion.ts rename to packages/editor/core/src/types/mention-suggestion.ts diff --git a/packages/editor/types/src/types/restore-image.ts b/packages/editor/core/src/types/restore-image.ts similarity index 100% rename from packages/editor/types/src/types/restore-image.ts rename to packages/editor/core/src/types/restore-image.ts diff --git a/packages/editor/types/src/types/slash-commands-suggestion.ts b/packages/editor/core/src/types/slash-commands-suggestion.ts similarity index 100% rename from packages/editor/types/src/types/slash-commands-suggestion.ts rename to packages/editor/core/src/types/slash-commands-suggestion.ts diff --git a/packages/editor/types/src/types/upload-image.ts b/packages/editor/core/src/types/upload-image.ts similarity index 100% rename from packages/editor/types/src/types/upload-image.ts rename to packages/editor/core/src/types/upload-image.ts diff --git a/packages/editor/core/src/ui/components/editor-content.tsx b/packages/editor/core/src/ui/components/editor-content.tsx index f66edbb12..9c0938788 100644 --- a/packages/editor/core/src/ui/components/editor-content.tsx +++ b/packages/editor/core/src/ui/components/editor-content.tsx @@ -1,6 +1,6 @@ import { Editor, EditorContent } from "@tiptap/react"; import { ReactNode } from "react"; -import { ImageResizer } from "../extensions/image/image-resize"; +import { ImageResizer } from "src/ui/extensions/image/image-resize"; interface EditorContentProps { editor: Editor | null; diff --git a/packages/editor/core/src/ui/extensions/custom-list-keymap/list-helpers/get-next-list-depth.ts b/packages/editor/core/src/ui/extensions/custom-list-keymap/list-helpers/get-next-list-depth.ts index f7583f195..2e4f5fbaa 100644 --- a/packages/editor/core/src/ui/extensions/custom-list-keymap/list-helpers/get-next-list-depth.ts +++ b/packages/editor/core/src/ui/extensions/custom-list-keymap/list-helpers/get-next-list-depth.ts @@ -1,7 +1,7 @@ import { getNodeAtPosition } from "@tiptap/core"; import { EditorState } from "@tiptap/pm/state"; -import { findListItemPos } from "./find-list-item-pos"; +import { findListItemPos } from "src/ui/extensions/custom-list-keymap/list-helpers/find-list-item-pos"; export const getNextListDepth = (typeOrName: string, state: EditorState) => { const listItemPos = findListItemPos(typeOrName, state); diff --git a/packages/editor/core/src/ui/extensions/custom-list-keymap/list-helpers/handle-backspace.ts b/packages/editor/core/src/ui/extensions/custom-list-keymap/list-helpers/handle-backspace.ts index 08906148b..a4f2d5db9 100644 --- a/packages/editor/core/src/ui/extensions/custom-list-keymap/list-helpers/handle-backspace.ts +++ b/packages/editor/core/src/ui/extensions/custom-list-keymap/list-helpers/handle-backspace.ts @@ -1,8 +1,8 @@ import { Editor, isAtStartOfNode, isNodeActive } from "@tiptap/core"; import { Node } from "@tiptap/pm/model"; -import { findListItemPos } from "./find-list-item-pos"; -import { hasListBefore } from "./has-list-before"; +import { findListItemPos } from "src/ui/extensions/custom-list-keymap/list-helpers/find-list-item-pos"; +import { hasListBefore } from "src/ui/extensions/custom-list-keymap/list-helpers/has-list-before"; export const handleBackspace = (editor: Editor, name: string, parentListTypes: string[]) => { // this is required to still handle the undo handling diff --git a/packages/editor/core/src/ui/extensions/custom-list-keymap/list-helpers/handle-delete.ts b/packages/editor/core/src/ui/extensions/custom-list-keymap/list-helpers/handle-delete.ts index 5f47baf9d..9179e0f20 100644 --- a/packages/editor/core/src/ui/extensions/custom-list-keymap/list-helpers/handle-delete.ts +++ b/packages/editor/core/src/ui/extensions/custom-list-keymap/list-helpers/handle-delete.ts @@ -1,7 +1,7 @@ import { Editor, isAtEndOfNode, isNodeActive } from "@tiptap/core"; -import { nextListIsDeeper } from "./next-list-is-deeper"; -import { nextListIsHigher } from "./next-list-is-higher"; +import { nextListIsDeeper } from "src/ui/extensions/custom-list-keymap/list-helpers/next-list-is-deeper"; +import { nextListIsHigher } from "src/ui/extensions/custom-list-keymap/list-helpers/next-list-is-higher"; export const handleDelete = (editor: Editor, name: string) => { // if the cursor is not inside the current node type diff --git a/packages/editor/core/src/ui/extensions/custom-list-keymap/list-helpers/next-list-is-deeper.ts b/packages/editor/core/src/ui/extensions/custom-list-keymap/list-helpers/next-list-is-deeper.ts index 425458b2a..7cd1a63f7 100644 --- a/packages/editor/core/src/ui/extensions/custom-list-keymap/list-helpers/next-list-is-deeper.ts +++ b/packages/editor/core/src/ui/extensions/custom-list-keymap/list-helpers/next-list-is-deeper.ts @@ -1,7 +1,7 @@ import { EditorState } from "@tiptap/pm/state"; -import { findListItemPos } from "./find-list-item-pos"; -import { getNextListDepth } from "./get-next-list-depth"; +import { findListItemPos } from "src/ui/extensions/custom-list-keymap/list-helpers/find-list-item-pos"; +import { getNextListDepth } from "src/ui/extensions/custom-list-keymap/list-helpers/get-next-list-depth"; export const nextListIsDeeper = (typeOrName: string, state: EditorState) => { const listDepth = getNextListDepth(typeOrName, state); diff --git a/packages/editor/core/src/ui/extensions/custom-list-keymap/list-helpers/next-list-is-higher.ts b/packages/editor/core/src/ui/extensions/custom-list-keymap/list-helpers/next-list-is-higher.ts index 8b853b5af..3364c3b87 100644 --- a/packages/editor/core/src/ui/extensions/custom-list-keymap/list-helpers/next-list-is-higher.ts +++ b/packages/editor/core/src/ui/extensions/custom-list-keymap/list-helpers/next-list-is-higher.ts @@ -1,7 +1,7 @@ import { EditorState } from "@tiptap/pm/state"; -import { findListItemPos } from "./find-list-item-pos"; -import { getNextListDepth } from "./get-next-list-depth"; +import { findListItemPos } from "src/ui/extensions/custom-list-keymap/list-helpers/find-list-item-pos"; +import { getNextListDepth } from "src/ui/extensions/custom-list-keymap/list-helpers/get-next-list-depth"; export const nextListIsHigher = (typeOrName: string, state: EditorState) => { const listDepth = getNextListDepth(typeOrName, state); diff --git a/packages/editor/core/src/ui/extensions/custom-list-keymap/list-keymap.ts b/packages/editor/core/src/ui/extensions/custom-list-keymap/list-keymap.ts index b61695973..aabd836d2 100644 --- a/packages/editor/core/src/ui/extensions/custom-list-keymap/list-keymap.ts +++ b/packages/editor/core/src/ui/extensions/custom-list-keymap/list-keymap.ts @@ -1,6 +1,6 @@ import { Extension } from "@tiptap/core"; -import { handleBackspace, handleDelete } from "./list-helpers"; +import { handleBackspace, handleDelete } from "src/ui/extensions/custom-list-keymap/list-helpers"; export type ListKeymapOptions = { listTypes: Array<{ diff --git a/packages/editor/core/src/ui/extensions/horizontal-rule.tsx b/packages/editor/core/src/ui/extensions/horizontal-rule.tsx index a7bbf50e1..cee0ded83 100644 --- a/packages/editor/core/src/ui/extensions/horizontal-rule.tsx +++ b/packages/editor/core/src/ui/extensions/horizontal-rule.tsx @@ -22,7 +22,7 @@ declare module "@tiptap/core" { } } -export default Node.create({ +export const HorizontalRule = Node.create({ name: "horizontalRule", addOptions() { diff --git a/packages/editor/core/src/ui/extensions/image/index.tsx b/packages/editor/core/src/ui/extensions/image/index.tsx index b11bfefce..db8b1c97b 100644 --- a/packages/editor/core/src/ui/extensions/image/index.tsx +++ b/packages/editor/core/src/ui/extensions/image/index.tsx @@ -1,9 +1,10 @@ import { EditorState, Plugin, PluginKey, Transaction } from "@tiptap/pm/state"; import { Node as ProseMirrorNode } from "@tiptap/pm/model"; -import UploadImagesPlugin from "../../plugins/upload-image"; +import { UploadImagesPlugin } from "src/ui/plugins/upload-image"; import ImageExt from "@tiptap/extension-image"; -import { onNodeDeleted, onNodeRestored } from "../../plugins/delete-image"; -import { DeleteImage, RestoreImage } from "@plane/editor-types"; +import { onNodeDeleted, onNodeRestored } from "src/ui/plugins/delete-image"; +import { DeleteImage } from "src/types/delete-image"; +import { RestoreImage } from "src/types/restore-image"; interface ImageNode extends ProseMirrorNode { attrs: { @@ -15,7 +16,7 @@ interface ImageNode extends ProseMirrorNode { const deleteKey = new PluginKey("delete-image"); const IMAGE_NODE_TYPE = "image"; -const ImageExtension = (deleteImage: DeleteImage, restoreFile: RestoreImage, cancelUploadImage?: () => any) => +export const ImageExtension = (deleteImage: DeleteImage, restoreFile: RestoreImage, cancelUploadImage?: () => any) => ImageExt.extend({ addProseMirrorPlugins() { return [ @@ -130,5 +131,3 @@ const ImageExtension = (deleteImage: DeleteImage, restoreFile: RestoreImage, can }; }, }); - -export default ImageExtension; diff --git a/packages/editor/core/src/ui/extensions/image/read-only-image.tsx b/packages/editor/core/src/ui/extensions/image/read-only-image.tsx index 73a763d04..8112eba4e 100644 --- a/packages/editor/core/src/ui/extensions/image/read-only-image.tsx +++ b/packages/editor/core/src/ui/extensions/image/read-only-image.tsx @@ -1,6 +1,6 @@ import Image from "@tiptap/extension-image"; -const ReadOnlyImageExtension = Image.extend({ +export const ReadOnlyImageExtension = Image.extend({ addAttributes() { return { ...this.parent?.(), @@ -13,5 +13,3 @@ const ReadOnlyImageExtension = Image.extend({ }; }, }); - -export default ReadOnlyImageExtension; diff --git a/packages/editor/core/src/ui/extensions/index.tsx b/packages/editor/core/src/ui/extensions/index.tsx index 4ab82f3c8..1406cde67 100644 --- a/packages/editor/core/src/ui/extensions/index.tsx +++ b/packages/editor/core/src/ui/extensions/index.tsx @@ -7,22 +7,25 @@ import TaskItem from "@tiptap/extension-task-item"; import TaskList from "@tiptap/extension-task-list"; import { Markdown } from "tiptap-markdown"; -import TableHeader from "./table/table-header/table-header"; -import Table from "./table/table"; -import TableCell from "./table/table-cell/table-cell"; -import TableRow from "./table/table-row/table-row"; -import HorizontalRule from "./horizontal-rule"; +import { TableHeader } from "src/ui/extensions/table/table-header/table-header"; +import { Table } from "src/ui/extensions/table/table"; +import { TableCell } from "src/ui/extensions/table/table-cell/table-cell"; +import { TableRow } from "src/ui/extensions/table/table-row/table-row"; +import { HorizontalRule } from "src/ui/extensions/horizontal-rule"; -import ImageExtension from "./image"; +import { ImageExtension } from "src/ui/extensions/image"; -import { isValidHttpUrl } from "../../lib/utils"; -import { Mentions } from "../mentions"; +import { isValidHttpUrl } from "src/lib/utils"; +import { Mentions } from "src/ui/mentions"; -import { CustomKeymap } from "./keymap"; -import { CustomCodeBlock } from "./code"; -import { CustomQuoteExtension } from "./quote"; -import { ListKeymap } from "./custom-list-keymap"; -import { IMentionSuggestion, DeleteImage, RestoreImage } from "@plane/editor-types"; +import { CustomKeymap } from "src/ui/extensions/keymap"; +import { CustomCodeBlock } from "src/ui/extensions/code"; +import { CustomQuoteExtension } from "src/ui/extensions/quote"; +import { ListKeymap } from "src/ui/extensions/custom-list-keymap"; + +import { DeleteImage } from "src/types/delete-image"; +import { IMentionSuggestion } from "src/types/mention-suggestion"; +import { RestoreImage } from "src/types/restore-image"; export const CoreEditorExtensions = ( mentionConfig: { diff --git a/packages/editor/core/src/ui/extensions/table/table-cell/index.ts b/packages/editor/core/src/ui/extensions/table/table-cell/index.ts index fb2183381..68a25a9c3 100644 --- a/packages/editor/core/src/ui/extensions/table/table-cell/index.ts +++ b/packages/editor/core/src/ui/extensions/table/table-cell/index.ts @@ -1 +1 @@ -export { default as default } from "./table-cell"; +export { TableCell } from "./table-cell"; diff --git a/packages/editor/core/src/ui/extensions/table/table-cell/table-cell.ts b/packages/editor/core/src/ui/extensions/table/table-cell/table-cell.ts index 1d3e57af9..aedb59411 100644 --- a/packages/editor/core/src/ui/extensions/table/table-cell/table-cell.ts +++ b/packages/editor/core/src/ui/extensions/table/table-cell/table-cell.ts @@ -4,7 +4,7 @@ export interface TableCellOptions { HTMLAttributes: Record; } -export default Node.create({ +export const TableCell = Node.create({ name: "tableCell", addOptions() { diff --git a/packages/editor/core/src/ui/extensions/table/table-header/index.ts b/packages/editor/core/src/ui/extensions/table/table-header/index.ts index cb036c505..290f37d0b 100644 --- a/packages/editor/core/src/ui/extensions/table/table-header/index.ts +++ b/packages/editor/core/src/ui/extensions/table/table-header/index.ts @@ -1 +1 @@ -export { default as default } from "./table-header"; +export { TableHeader } from "./table-header"; diff --git a/packages/editor/core/src/ui/extensions/table/table-header/table-header.ts b/packages/editor/core/src/ui/extensions/table/table-header/table-header.ts index 0148f1a6f..c0decdbf8 100644 --- a/packages/editor/core/src/ui/extensions/table/table-header/table-header.ts +++ b/packages/editor/core/src/ui/extensions/table/table-header/table-header.ts @@ -3,7 +3,8 @@ import { mergeAttributes, Node } from "@tiptap/core"; export interface TableHeaderOptions { HTMLAttributes: Record; } -export default Node.create({ + +export const TableHeader = Node.create({ name: "tableHeader", addOptions() { diff --git a/packages/editor/core/src/ui/extensions/table/table-row/index.ts b/packages/editor/core/src/ui/extensions/table/table-row/index.ts index 8c6eb55aa..24dafb7e0 100644 --- a/packages/editor/core/src/ui/extensions/table/table-row/index.ts +++ b/packages/editor/core/src/ui/extensions/table/table-row/index.ts @@ -1 +1 @@ -export { default as default } from "./table-row"; +export { TableRow } from "./table-row"; diff --git a/packages/editor/core/src/ui/extensions/table/table-row/table-row.ts b/packages/editor/core/src/ui/extensions/table/table-row/table-row.ts index 5df20e6ef..28c9a9a48 100644 --- a/packages/editor/core/src/ui/extensions/table/table-row/table-row.ts +++ b/packages/editor/core/src/ui/extensions/table/table-row/table-row.ts @@ -4,7 +4,7 @@ export interface TableRowOptions { HTMLAttributes: Record; } -export default Node.create({ +export const TableRow = Node.create({ name: "tableRow", addOptions() { diff --git a/packages/editor/core/src/ui/extensions/table/table/icons.ts b/packages/editor/core/src/ui/extensions/table/table/icons.ts index 65e8b8540..c08710ec3 100644 --- a/packages/editor/core/src/ui/extensions/table/table/icons.ts +++ b/packages/editor/core/src/ui/extensions/table/table/icons.ts @@ -1,4 +1,4 @@ -const icons = { +export const icons = { colorPicker: ``, deleteColumn: ``, deleteRow: ``, @@ -47,5 +47,3 @@ const icons = { `, }; - -export default icons; diff --git a/packages/editor/core/src/ui/extensions/table/table/index.ts b/packages/editor/core/src/ui/extensions/table/table/index.ts index ac51d0e2c..8efc43120 100644 --- a/packages/editor/core/src/ui/extensions/table/table/index.ts +++ b/packages/editor/core/src/ui/extensions/table/table/index.ts @@ -1 +1 @@ -export { default as default } from "./table"; +export { Table } from "./table"; diff --git a/packages/editor/core/src/ui/extensions/table/table/table-view.tsx b/packages/editor/core/src/ui/extensions/table/table/table-view.tsx index 5b0622243..bc42b49ff 100644 --- a/packages/editor/core/src/ui/extensions/table/table/table-view.tsx +++ b/packages/editor/core/src/ui/extensions/table/table/table-view.tsx @@ -4,9 +4,9 @@ import { Decoration, NodeView } from "@tiptap/pm/view"; import tippy, { Instance, Props } from "tippy.js"; import { Editor } from "@tiptap/core"; -import { CellSelection, TableMap, updateColumnsOnResize } from "@tiptap/prosemirror-tables"; +import { CellSelection, TableMap, updateColumnsOnResize } from "@tiptap/pm/tables"; -import icons from "./icons"; +import { icons } from "src/ui/extensions/table/table/icons"; export function updateColumns( node: ProseMirrorNode, diff --git a/packages/editor/core/src/ui/extensions/table/table/table.ts b/packages/editor/core/src/ui/extensions/table/table/table.ts index 71c75f616..5600fd82a 100644 --- a/packages/editor/core/src/ui/extensions/table/table/table.ts +++ b/packages/editor/core/src/ui/extensions/table/table/table.ts @@ -19,12 +19,12 @@ import { tableEditing, toggleHeader, toggleHeaderCell, -} from "@tiptap/prosemirror-tables"; +} from "@tiptap/pm/tables"; -import { tableControls } from "./table-controls"; -import { TableView } from "./table-view"; -import { createTable } from "./utilities/create-table"; -import { deleteTableWhenAllCellsSelected } from "./utilities/delete-table-when-all-cells-selected"; +import { tableControls } from "src/ui/extensions/table/table/table-controls"; +import { TableView } from "src/ui/extensions/table/table/table-view"; +import { createTable } from "src/ui/extensions/table/table/utilities/create-table"; +import { deleteTableWhenAllCellsSelected } from "src/ui/extensions/table/table/utilities/delete-table-when-all-cells-selected"; export interface TableOptions { HTMLAttributes: Record; @@ -72,7 +72,7 @@ declare module "@tiptap/core" { } } -export default Node.create({ +export const Table = Node.create({ name: "table", addOptions() { diff --git a/packages/editor/core/src/ui/extensions/table/table/utilities/create-table.ts b/packages/editor/core/src/ui/extensions/table/table/utilities/create-table.ts index 5a2299fb4..7299dd442 100644 --- a/packages/editor/core/src/ui/extensions/table/table/utilities/create-table.ts +++ b/packages/editor/core/src/ui/extensions/table/table/utilities/create-table.ts @@ -1,7 +1,7 @@ import { Fragment, Node as ProsemirrorNode, Schema } from "@tiptap/pm/model"; -import { createCell } from "./create-cell"; -import { getTableNodeTypes } from "./get-table-node-types"; +import { createCell } from "src/ui/extensions/table/table/utilities/create-cell"; +import { getTableNodeTypes } from "src/ui/extensions/table/table/utilities/get-table-node-types"; export function createTable( schema: Schema, diff --git a/packages/editor/core/src/ui/extensions/table/table/utilities/delete-table-when-all-cells-selected.ts b/packages/editor/core/src/ui/extensions/table/table/utilities/delete-table-when-all-cells-selected.ts index 7b5386382..c08228a00 100644 --- a/packages/editor/core/src/ui/extensions/table/table/utilities/delete-table-when-all-cells-selected.ts +++ b/packages/editor/core/src/ui/extensions/table/table/utilities/delete-table-when-all-cells-selected.ts @@ -1,6 +1,6 @@ import { findParentNodeClosestToPos, KeyboardShortcutCommand } from "@tiptap/core"; -import { isCellSelection } from "./is-cell-selection"; +import { isCellSelection } from "src/ui/extensions/table/table/utilities/is-cell-selection"; export const deleteTableWhenAllCellsSelected: KeyboardShortcutCommand = ({ editor }) => { const { selection } = editor.state; diff --git a/packages/editor/core/src/ui/extensions/table/table/utilities/is-cell-selection.ts b/packages/editor/core/src/ui/extensions/table/table/utilities/is-cell-selection.ts index 28917a299..42ea5759c 100644 --- a/packages/editor/core/src/ui/extensions/table/table/utilities/is-cell-selection.ts +++ b/packages/editor/core/src/ui/extensions/table/table/utilities/is-cell-selection.ts @@ -1,4 +1,4 @@ -import { CellSelection } from "@tiptap/prosemirror-tables"; +import { CellSelection } from "@tiptap/pm/tables"; export function isCellSelection(value: unknown): value is CellSelection { return value instanceof CellSelection; diff --git a/packages/editor/core/src/ui/mentions/custom.tsx b/packages/editor/core/src/ui/mentions/custom.tsx index e25da6f47..6a47d79f0 100644 --- a/packages/editor/core/src/ui/mentions/custom.tsx +++ b/packages/editor/core/src/ui/mentions/custom.tsx @@ -1,8 +1,8 @@ import { Mention, MentionOptions } from "@tiptap/extension-mention"; import { mergeAttributes } from "@tiptap/core"; import { ReactNodeViewRenderer } from "@tiptap/react"; -import mentionNodeView from "./mentionNodeView"; -import { IMentionHighlight } from "@plane/editor-types"; +import { MentionNodeView } from "src/ui/mentions/mention-node-view"; +import { IMentionHighlight } from "src/types/mention-suggestion"; export interface CustomMentionOptions extends MentionOptions { mentionHighlights: IMentionHighlight[]; @@ -31,7 +31,7 @@ export const CustomMention = Mention.extend({ }, addNodeView() { - return ReactNodeViewRenderer(mentionNodeView); + return ReactNodeViewRenderer(MentionNodeView); }, parseHTML() { diff --git a/packages/editor/core/src/ui/mentions/index.tsx b/packages/editor/core/src/ui/mentions/index.tsx index b78923f6c..f6d3e5b1f 100644 --- a/packages/editor/core/src/ui/mentions/index.tsx +++ b/packages/editor/core/src/ui/mentions/index.tsx @@ -1,8 +1,8 @@ // @ts-nocheck -import suggestion from "./suggestion"; -import { CustomMention } from "./custom"; -import { IMentionHighlight, IMentionSuggestion } from "@plane/editor-types"; +import { Suggestion } from "src/ui/mentions/suggestion"; +import { CustomMention } from "src/ui/mentions/custom"; +import { IMentionHighlight } from "src/types/mention-suggestion"; export const Mentions = (mentionSuggestions: IMentionSuggestion[], mentionHighlights: IMentionHighlight[], readonly) => CustomMention.configure({ @@ -11,5 +11,5 @@ export const Mentions = (mentionSuggestions: IMentionSuggestion[], mentionHighli }, readonly: readonly, mentionHighlights: mentionHighlights, - suggestion: suggestion(mentionSuggestions), + suggestion: Suggestion(mentionSuggestions), }); diff --git a/packages/editor/core/src/ui/mentions/MentionList.tsx b/packages/editor/core/src/ui/mentions/mention-list.tsx similarity index 91% rename from packages/editor/core/src/ui/mentions/MentionList.tsx rename to packages/editor/core/src/ui/mentions/mention-list.tsx index d103a9e0a..afbf10970 100644 --- a/packages/editor/core/src/ui/mentions/MentionList.tsx +++ b/packages/editor/core/src/ui/mentions/mention-list.tsx @@ -1,6 +1,6 @@ -import { IMentionSuggestion } from "@plane/editor-types"; import { Editor } from "@tiptap/react"; -import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useState } from "react"; +import { forwardRef, useEffect, useImperativeHandle, useState } from "react"; +import { IMentionSuggestion } from "src/types/mention-suggestion"; interface MentionListProps { items: IMentionSuggestion[]; @@ -9,7 +9,7 @@ interface MentionListProps { } // eslint-disable-next-line react/display-name -const MentionList = forwardRef((props: MentionListProps, ref) => { +export const MentionList = forwardRef((props: MentionListProps, ref) => { const [selectedIndex, setSelectedIndex] = useState(0); const selectItem = (index: number) => { @@ -98,5 +98,3 @@ const MentionList = forwardRef((props: MentionListProps, ref) => { }); MentionList.displayName = "MentionList"; - -export default MentionList; diff --git a/packages/editor/core/src/ui/mentions/mentionNodeView.tsx b/packages/editor/core/src/ui/mentions/mention-node-view.tsx similarity index 89% rename from packages/editor/core/src/ui/mentions/mentionNodeView.tsx rename to packages/editor/core/src/ui/mentions/mention-node-view.tsx index 8e9672d9f..1c3755f6c 100644 --- a/packages/editor/core/src/ui/mentions/mentionNodeView.tsx +++ b/packages/editor/core/src/ui/mentions/mention-node-view.tsx @@ -1,12 +1,12 @@ /* eslint-disable react/display-name */ // @ts-nocheck import { NodeViewWrapper } from "@tiptap/react"; -import { cn } from "../../lib/utils"; +import { cn } from "src/lib/utils"; import { useRouter } from "next/router"; -import { IMentionHighlight } from "@plane/editor-types"; +import { IMentionHighlight } from "src/types/mention-suggestion"; // eslint-disable-next-line import/no-anonymous-default-export -export default (props) => { +export const MentionNodeView = (props) => { const router = useRouter(); const highlights = props.extension.options.mentionHighlights as IMentionHighlight[]; diff --git a/packages/editor/core/src/ui/mentions/suggestion.ts b/packages/editor/core/src/ui/mentions/suggestion.ts index 60ba6f4bc..6d706cb79 100644 --- a/packages/editor/core/src/ui/mentions/suggestion.ts +++ b/packages/editor/core/src/ui/mentions/suggestion.ts @@ -2,10 +2,10 @@ import { ReactRenderer } from "@tiptap/react"; import { Editor } from "@tiptap/core"; import tippy from "tippy.js"; -import MentionList from "./MentionList"; -import { IMentionSuggestion } from "@plane/editor-types"; +import { MentionList } from "src/ui/mentions/mention-list"; +import { IMentionSuggestion } from "src/types/mention-suggestion"; -const Suggestion = (suggestions: IMentionSuggestion[]) => ({ +export const Suggestion = (suggestions: IMentionSuggestion[]) => ({ items: ({ query }: { query: string }) => suggestions.filter((suggestion) => suggestion.title.toLowerCase().startsWith(query.toLowerCase())).slice(0, 5), render: () => { @@ -55,5 +55,3 @@ const Suggestion = (suggestions: IMentionSuggestion[]) => ({ }; }, }); - -export default Suggestion; diff --git a/packages/editor/core/src/ui/menus/menu-items/index.tsx b/packages/editor/core/src/ui/menus/menu-items/index.tsx index 98069b694..610d677f8 100644 --- a/packages/editor/core/src/ui/menus/menu-items/index.tsx +++ b/packages/editor/core/src/ui/menus/menu-items/index.tsx @@ -30,14 +30,15 @@ import { toggleStrike, toggleTaskList, toggleUnderline, -} from "../../../lib/editor-commands"; -import { UploadImage } from "@plane/editor-types"; +} from "src/lib/editor-commands"; +import { LucideIconType } from "src/types/lucide-icon"; +import { UploadImage } from "src/types/upload-image"; export interface EditorMenuItem { name: string; isActive: () => boolean; command: () => void; - icon: typeof BoldIcon; + icon: LucideIconType; } export const HeadingOneItem = (editor: Editor): EditorMenuItem => ({ diff --git a/packages/editor/core/src/ui/plugins/delete-image.tsx b/packages/editor/core/src/ui/plugins/delete-image.tsx index 6b772cebf..afe13730a 100644 --- a/packages/editor/core/src/ui/plugins/delete-image.tsx +++ b/packages/editor/core/src/ui/plugins/delete-image.tsx @@ -1,6 +1,7 @@ import { EditorState, Plugin, PluginKey, Transaction } from "@tiptap/pm/state"; import { Node as ProseMirrorNode } from "@tiptap/pm/model"; -import { DeleteImage, RestoreImage } from "@plane/editor-types"; +import { DeleteImage } from "src/types/delete-image"; +import { RestoreImage } from "src/types/restore-image"; const deleteKey = new PluginKey("delete-image"); const IMAGE_NODE_TYPE = "image"; @@ -12,7 +13,7 @@ interface ImageNode extends ProseMirrorNode { }; } -const TrackImageDeletionPlugin = (deleteImage: DeleteImage): Plugin => +export const TrackImageDeletionPlugin = (deleteImage: DeleteImage): Plugin => new Plugin({ key: deleteKey, appendTransaction: (transactions: readonly Transaction[], oldState: EditorState, newState: EditorState) => { @@ -53,8 +54,6 @@ const TrackImageDeletionPlugin = (deleteImage: DeleteImage): Plugin => }, }); -export default TrackImageDeletionPlugin; - export async function onNodeDeleted(src: string, deleteImage: DeleteImage): Promise { try { const assetUrlWithWorkspaceId = new URL(src).pathname.substring(1); diff --git a/packages/editor/core/src/ui/plugins/upload-image.tsx b/packages/editor/core/src/ui/plugins/upload-image.tsx index 4dee70da4..323f3834a 100644 --- a/packages/editor/core/src/ui/plugins/upload-image.tsx +++ b/packages/editor/core/src/ui/plugins/upload-image.tsx @@ -1,10 +1,10 @@ -import { UploadImage } from "@plane/editor-types"; import { EditorState, Plugin, PluginKey } from "@tiptap/pm/state"; import { Decoration, DecorationSet, EditorView } from "@tiptap/pm/view"; +import { UploadImage } from "src/types/upload-image"; const uploadKey = new PluginKey("upload-image"); -const UploadImagesPlugin = (cancelUploadImage?: () => any) => +export const UploadImagesPlugin = (cancelUploadImage?: () => any) => new Plugin({ key: uploadKey, state: { @@ -60,8 +60,6 @@ const UploadImagesPlugin = (cancelUploadImage?: () => any) => }, }); -export default UploadImagesPlugin; - function findPlaceholder(state: EditorState, id: {}) { const decos = uploadKey.getState(state); const found = decos.find(undefined, undefined, (spec: { id: number | undefined }) => spec.id == id); diff --git a/packages/editor/core/src/ui/props.tsx b/packages/editor/core/src/ui/props.tsx index edd070d7b..2aaeb4264 100644 --- a/packages/editor/core/src/ui/props.tsx +++ b/packages/editor/core/src/ui/props.tsx @@ -1,7 +1,7 @@ -import { UploadImage } from "@plane/editor-types"; import { EditorProps } from "@tiptap/pm/view"; -import { findTableAncestor } from "../lib/utils"; -import { startImageUpload } from "./plugins/upload-image"; +import { findTableAncestor } from "src/lib/utils"; +import { UploadImage } from "src/types/upload-image"; +import { startImageUpload } from "src/ui/plugins/upload-image"; export function CoreEditorProps( uploadFile: UploadImage, diff --git a/packages/editor/core/src/ui/read-only/extensions.tsx b/packages/editor/core/src/ui/read-only/extensions.tsx index cdf7f88e5..5795d6c4a 100644 --- a/packages/editor/core/src/ui/read-only/extensions.tsx +++ b/packages/editor/core/src/ui/read-only/extensions.tsx @@ -8,15 +8,16 @@ import TaskList from "@tiptap/extension-task-list"; import { Markdown } from "tiptap-markdown"; import Gapcursor from "@tiptap/extension-gapcursor"; -import TableHeader from "../extensions/table/table-header/table-header"; -import Table from "../extensions/table/table"; -import TableCell from "../extensions/table/table-cell/table-cell"; -import TableRow from "../extensions/table/table-row/table-row"; +import { TableHeader } from "src/ui/extensions/table/table-header/table-header"; +import { Table } from "src/ui/extensions/table/table"; +import { TableCell } from "src/ui/extensions/table/table-cell/table-cell"; +import { TableRow } from "src/ui/extensions/table/table-row/table-row"; +import { HorizontalRule } from "src/ui/extensions/horizontal-rule"; -import ReadOnlyImageExtension from "../extensions/image/read-only-image"; -import { isValidHttpUrl } from "../../lib/utils"; -import { Mentions } from "../mentions"; -import { IMentionSuggestion } from "@plane/editor-types"; +import { ReadOnlyImageExtension } from "src/ui/extensions/image/read-only-image"; +import { isValidHttpUrl } from "src/lib/utils"; +import { Mentions } from "src/ui/mentions"; +import { IMentionSuggestion } from "src/types/mention-suggestion"; export const CoreReadOnlyEditorExtensions = (mentionConfig: { mentionSuggestions: IMentionSuggestion[]; @@ -71,6 +72,7 @@ export const CoreReadOnlyEditorExtensions = (mentionConfig: { class: "rounded-lg border border-custom-border-300", }, }), + HorizontalRule, TiptapUnderline, TextStyle, Color, diff --git a/packages/editor/core/tsconfig.json b/packages/editor/core/tsconfig.json index 57d0e9a74..c15534037 100644 --- a/packages/editor/core/tsconfig.json +++ b/packages/editor/core/tsconfig.json @@ -1,5 +1,15 @@ { "extends": "tsconfig/react-library.json", - "include": ["src/**/*", "index.d.ts"], - "exclude": ["dist", "build", "node_modules"] + "include": [ + "src/**/*", + "index.d.ts" + ], + "exclude": [ + "dist", + "build", + "node_modules" + ], + "compilerOptions": { + "baseUrl": "." + } } diff --git a/packages/editor/document-editor/package.json b/packages/editor/document-editor/package.json index 737a0eae0..61a075e5f 100644 --- a/packages/editor/document-editor/package.json +++ b/packages/editor/document-editor/package.json @@ -30,12 +30,11 @@ "dependencies": { "@plane/editor-core": "*", "@plane/editor-extensions": "*", - "@plane/editor-types": "*", "@plane/ui": "*", - "@tiptap/core": "^2.1.7", - "@tiptap/extension-placeholder": "^2.1.11", - "@tiptap/pm": "^2.1.12", - "@tiptap/suggestion": "^2.1.12", + "@tiptap/core": "^2.1.13", + "@tiptap/extension-placeholder": "^2.1.13", + "@tiptap/pm": "^2.1.13", + "@tiptap/suggestion": "^2.1.13", "eslint": "8.36.0", "eslint-config-next": "13.2.4", "react-popper": "^2.3.0", diff --git a/packages/editor/document-editor/src/ui/hooks/use-editor-markings.tsx b/packages/editor/document-editor/src/hooks/use-editor-markings.tsx similarity index 93% rename from packages/editor/document-editor/src/ui/hooks/use-editor-markings.tsx rename to packages/editor/document-editor/src/hooks/use-editor-markings.tsx index 9dfef6c39..1eb72eaab 100644 --- a/packages/editor/document-editor/src/ui/hooks/use-editor-markings.tsx +++ b/packages/editor/document-editor/src/hooks/use-editor-markings.tsx @@ -1,6 +1,5 @@ -import { Editor } from "@tiptap/react"; import { useState } from "react"; -import { IMarking } from ".."; +import { IMarking } from "src/types/editor-types"; export const useEditorMarkings = () => { const [markings, setMarkings] = useState([]); diff --git a/packages/editor/document-editor/src/index.ts b/packages/editor/document-editor/src/index.ts index 356e1faf9..c074009f4 100644 --- a/packages/editor/document-editor/src/index.ts +++ b/packages/editor/document-editor/src/index.ts @@ -1,3 +1,3 @@ -export { DocumentEditor, DocumentEditorWithRef } from "./ui"; -export { DocumentReadOnlyEditor, DocumentReadOnlyEditorWithRef } from "./ui/readonly"; -export { FixedMenu } from "./ui/menu/fixed-menu"; +export { DocumentEditor, DocumentEditorWithRef } from "src/ui"; +export { DocumentReadOnlyEditor, DocumentReadOnlyEditorWithRef } from "src/ui/readonly"; +export { FixedMenu } from "src/ui/menu/fixed-menu"; diff --git a/packages/editor/document-editor/src/ui/types/editor-types.ts b/packages/editor/document-editor/src/types/editor-types.ts similarity index 59% rename from packages/editor/document-editor/src/ui/types/editor-types.ts rename to packages/editor/document-editor/src/types/editor-types.ts index 10e9b16b6..5a28daf9e 100644 --- a/packages/editor/document-editor/src/ui/types/editor-types.ts +++ b/packages/editor/document-editor/src/types/editor-types.ts @@ -5,3 +5,9 @@ export interface DocumentDetails { last_updated_by: string; last_updated_at: Date; } +export interface IMarking { + type: "heading"; + level: number; + text: string; + sequence: number; +} diff --git a/packages/editor/document-editor/src/types/mark.ts b/packages/editor/document-editor/src/types/mark.ts new file mode 100644 index 000000000..e69de29bb diff --git a/packages/editor/document-editor/src/ui/types/menu-actions.d.ts b/packages/editor/document-editor/src/types/menu-actions.d.ts similarity index 100% rename from packages/editor/document-editor/src/ui/types/menu-actions.d.ts rename to packages/editor/document-editor/src/types/menu-actions.d.ts diff --git a/packages/editor/document-editor/src/ui/components/alert-label.tsx b/packages/editor/document-editor/src/ui/components/alert-label.tsx index 395ea2317..69b6dd02d 100644 --- a/packages/editor/document-editor/src/ui/components/alert-label.tsx +++ b/packages/editor/document-editor/src/ui/components/alert-label.tsx @@ -1,12 +1,11 @@ -import { Icon } from "lucide-react"; +import { LucideIconType } from "@plane/editor-core"; interface IAlertLabelProps { - Icon?: Icon; + Icon?: LucideIconType; backgroundColor: string; textColor?: string; label: string; } - export const AlertLabel = (props: IAlertLabelProps) => { const { Icon, backgroundColor, textColor, label } = props; diff --git a/packages/editor/document-editor/src/ui/components/content-browser.tsx b/packages/editor/document-editor/src/ui/components/content-browser.tsx index a21ca268f..18a50a5a8 100644 --- a/packages/editor/document-editor/src/ui/components/content-browser.tsx +++ b/packages/editor/document-editor/src/ui/components/content-browser.tsx @@ -1,7 +1,7 @@ -import { HeadingComp, HeadingThreeComp, SubheadingComp } from "./heading-component"; -import { IMarking } from ".."; +import { HeadingComp, HeadingThreeComp, SubheadingComp } from "src/ui/components/heading-component"; +import { IMarking } from "src/types/editor-types"; import { Editor } from "@tiptap/react"; -import { scrollSummary } from "../utils/editor-summary-utils"; +import { scrollSummary } from "src/utils/editor-summary-utils"; interface ContentBrowserProps { editor: Editor; diff --git a/packages/editor/document-editor/src/ui/components/editor-header.tsx b/packages/editor/document-editor/src/ui/components/editor-header.tsx index 7e2167ba0..3501785a7 100644 --- a/packages/editor/document-editor/src/ui/components/editor-header.tsx +++ b/packages/editor/document-editor/src/ui/components/editor-header.tsx @@ -1,13 +1,12 @@ import { Editor } from "@tiptap/react"; import { Archive, RefreshCw, Lock } from "lucide-react"; -import { IMarking } from ".."; -import { FixedMenu } from "../menu"; -import { UploadImage } from "@plane/editor-types"; -import { DocumentDetails } from "../types/editor-types"; -import { AlertLabel } from "./alert-label"; -import { IVerticalDropdownItemProps, VerticalDropdownMenu } from "./vertical-dropdown-menu"; -import { SummaryPopover } from "./summary-popover"; -import { InfoPopover } from "./info-popover"; +import { IMarking, DocumentDetails } from "src/types/editor-types"; +import { FixedMenu } from "src/ui/menu"; +import { UploadImage } from "@plane/editor-core"; +import { AlertLabel } from "src/ui/components/alert-label"; +import { IVerticalDropdownItemProps, VerticalDropdownMenu } from "src/ui/components/vertical-dropdown-menu"; +import { SummaryPopover } from "src/ui/components/summary-popover"; +import { InfoPopover } from "src/ui/components/info-popover"; interface IEditorHeader { editor: Editor; diff --git a/packages/editor/document-editor/src/ui/components/info-popover.tsx b/packages/editor/document-editor/src/ui/components/info-popover.tsx index 0d650667e..f78dd3473 100644 --- a/packages/editor/document-editor/src/ui/components/info-popover.tsx +++ b/packages/editor/document-editor/src/ui/components/info-popover.tsx @@ -2,7 +2,7 @@ import { useState } from "react"; import { usePopper } from "react-popper"; import { Calendar, History, Info } from "lucide-react"; // types -import { DocumentDetails } from "../types/editor-types"; +import { DocumentDetails } from "src/types/editor-types"; type Props = { documentDetails: DocumentDetails; diff --git a/packages/editor/document-editor/src/ui/components/page-renderer.tsx b/packages/editor/document-editor/src/ui/components/page-renderer.tsx index d25e9ca43..c2d001abe 100644 --- a/packages/editor/document-editor/src/ui/components/page-renderer.tsx +++ b/packages/editor/document-editor/src/ui/components/page-renderer.tsx @@ -1,7 +1,7 @@ import { EditorContainer, EditorContentWrapper } from "@plane/editor-core"; import { Editor } from "@tiptap/react"; import { useState } from "react"; -import { DocumentDetails } from "../types/editor-types"; +import { DocumentDetails } from "src/types/editor-types"; type IPageRenderer = { documentDetails: DocumentDetails; diff --git a/packages/editor/document-editor/src/ui/components/summary-popover.tsx b/packages/editor/document-editor/src/ui/components/summary-popover.tsx index 61361c049..d3ec64f1c 100644 --- a/packages/editor/document-editor/src/ui/components/summary-popover.tsx +++ b/packages/editor/document-editor/src/ui/components/summary-popover.tsx @@ -3,9 +3,9 @@ import { Editor } from "@tiptap/react"; import { usePopper } from "react-popper"; import { List } from "lucide-react"; // components -import { ContentBrowser } from "./content-browser"; +import { ContentBrowser } from "src/ui/components/content-browser"; // types -import { IMarking } from ".."; +import { IMarking } from "src/types/editor-types"; type Props = { editor: Editor; diff --git a/packages/editor/document-editor/src/ui/components/summary-side-bar.tsx b/packages/editor/document-editor/src/ui/components/summary-side-bar.tsx index b3bf23464..44ede3e8d 100644 --- a/packages/editor/document-editor/src/ui/components/summary-side-bar.tsx +++ b/packages/editor/document-editor/src/ui/components/summary-side-bar.tsx @@ -1,6 +1,6 @@ import { Editor } from "@tiptap/react"; -import { IMarking } from ".."; -import { ContentBrowser } from "./content-browser"; +import { IMarking } from "src/types/editor-types"; +import { ContentBrowser } from "src/ui/components/content-browser"; interface ISummarySideBarProps { editor: Editor; @@ -8,14 +8,12 @@ interface ISummarySideBarProps { sidePeekVisible: boolean; } -export const SummarySideBar = ({ editor, markings, sidePeekVisible }: ISummarySideBarProps) => { - return ( -
- -
- ); -}; +export const SummarySideBar = ({ editor, markings, sidePeekVisible }: ISummarySideBarProps) => ( +
+ +
+); diff --git a/packages/editor/document-editor/src/ui/components/vertical-dropdown-menu.tsx b/packages/editor/document-editor/src/ui/components/vertical-dropdown-menu.tsx index 93fea4730..43843e507 100644 --- a/packages/editor/document-editor/src/ui/components/vertical-dropdown-menu.tsx +++ b/packages/editor/document-editor/src/ui/components/vertical-dropdown-menu.tsx @@ -1,5 +1,6 @@ -import { Button, CustomMenu } from "@plane/ui"; -import { ChevronUp, Icon, MoreVertical } from "lucide-react"; +import { LucideIconType } from "@plane/editor-core"; +import { CustomMenu } from "@plane/ui"; +import { MoreVertical } from "lucide-react"; type TMenuItems = | "archive_page" @@ -14,7 +15,7 @@ type TMenuItems = export interface IVerticalDropdownItemProps { key: number; type: TMenuItems; - Icon: Icon; + Icon: LucideIconType; label: string; action: () => Promise | void; } @@ -23,27 +24,23 @@ export interface IVerticalDropdownMenuProps { items: IVerticalDropdownItemProps[]; } -const VerticalDropdownItem = ({ Icon, label, action }: IVerticalDropdownItemProps) => { - return ( - - -
{label}
-
- ); -}; +const VerticalDropdownItem = ({ Icon, label, action }: IVerticalDropdownItemProps) => ( + + +
{label}
+
+); -export const VerticalDropdownMenu = ({ items }: IVerticalDropdownMenuProps) => { - return ( - } - > - {items.map((item, index) => ( - - ))} - - ); -}; +export const VerticalDropdownMenu = ({ items }: IVerticalDropdownMenuProps) => ( + } + > + {items.map((item) => ( + + ))} + +); diff --git a/packages/editor/document-editor/src/ui/extensions/index.tsx b/packages/editor/document-editor/src/ui/extensions/index.tsx index 968328a76..155245f9e 100644 --- a/packages/editor/document-editor/src/ui/extensions/index.tsx +++ b/packages/editor/document-editor/src/ui/extensions/index.tsx @@ -1,11 +1,11 @@ import Placeholder from "@tiptap/extension-placeholder"; -import { IssueWidgetExtension } from "./widgets/IssueEmbedWidget"; +import { IssueWidgetExtension } from "src/ui/extensions/widgets/issue-embed-widget"; -import { IIssueEmbedConfig } from "./widgets/IssueEmbedWidget/types"; +import { IIssueEmbedConfig } from "src/ui/extensions/widgets/issue-embed-widget/types"; import { SlashCommand, DragAndDrop } from "@plane/editor-extensions"; -import { ISlashCommandItem, UploadImage } from "@plane/editor-types"; -import { IssueSuggestions } from "./widgets/IssueEmbedSuggestionList"; +import { ISlashCommandItem, UploadImage } from "@plane/editor-core"; +import { IssueSuggestions } from "src/ui/extensions/widgets/issue-embed-suggestion-list"; import { LayersIcon } from "@plane/ui"; export const DocumentEditorExtensions = ( diff --git a/packages/editor/document-editor/src/ui/extensions/widgets/IssueEmbedSuggestionList/issue-suggestion-items.tsx b/packages/editor/document-editor/src/ui/extensions/widgets/IssueEmbedSuggestionList/issue-suggestion-items.tsx deleted file mode 100644 index b1f27ece3..000000000 --- a/packages/editor/document-editor/src/ui/extensions/widgets/IssueEmbedSuggestionList/issue-suggestion-items.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { IIssueListSuggestion } from "."; - -export const getIssueSuggestionItems = (issueSuggestions: Array) => { - return ({ query }: { query: string }) => { - const search = query.toLowerCase(); - const filteredSuggestions = issueSuggestions.filter((item) => { - return ( - item.title.toLowerCase().includes(search) || - item.identifier.toLowerCase().includes(search) || - item.priority.toLowerCase().includes(search) - ); - }); - - return filteredSuggestions; - }; -}; diff --git a/packages/editor/document-editor/src/ui/extensions/widgets/IssueEmbedSuggestionList/index.tsx b/packages/editor/document-editor/src/ui/extensions/widgets/issue-embed-suggestion-list/index.tsx similarity index 79% rename from packages/editor/document-editor/src/ui/extensions/widgets/IssueEmbedSuggestionList/index.tsx rename to packages/editor/document-editor/src/ui/extensions/widgets/issue-embed-suggestion-list/index.tsx index 07a10031d..acc6213c2 100644 --- a/packages/editor/document-editor/src/ui/extensions/widgets/IssueEmbedSuggestionList/index.tsx +++ b/packages/editor/document-editor/src/ui/extensions/widgets/issue-embed-suggestion-list/index.tsx @@ -1,7 +1,7 @@ import { Editor, Range } from "@tiptap/react"; -import { IssueEmbedSuggestions } from "./issue-suggestion-extension"; -import { getIssueSuggestionItems } from "./issue-suggestion-items"; -import { IssueListRenderer } from "./issue-suggestion-renderer"; +import { IssueEmbedSuggestions } from "src/ui/extensions/widgets/issue-embed-suggestion-list/issue-suggestion-extension"; +import { getIssueSuggestionItems } from "src/ui/extensions/widgets/issue-embed-suggestion-list/issue-suggestion-items"; +import { IssueListRenderer } from "src/ui/extensions/widgets/issue-embed-suggestion-list/issue-suggestion-renderer"; import { v4 as uuidv4 } from "uuid"; export type CommandProps = { @@ -19,7 +19,7 @@ export interface IIssueListSuggestion { export const IssueSuggestions = (suggestions: any[]) => { const mappedSuggestions: IIssueListSuggestion[] = suggestions.map((suggestion): IIssueListSuggestion => { - let transactionId = uuidv4(); + const transactionId = uuidv4(); return { title: suggestion.name, priority: suggestion.priority.toString(), diff --git a/packages/editor/document-editor/src/ui/extensions/widgets/IssueEmbedSuggestionList/issue-suggestion-extension.tsx b/packages/editor/document-editor/src/ui/extensions/widgets/issue-embed-suggestion-list/issue-suggestion-extension.tsx similarity index 100% rename from packages/editor/document-editor/src/ui/extensions/widgets/IssueEmbedSuggestionList/issue-suggestion-extension.tsx rename to packages/editor/document-editor/src/ui/extensions/widgets/issue-embed-suggestion-list/issue-suggestion-extension.tsx diff --git a/packages/editor/document-editor/src/ui/extensions/widgets/issue-embed-suggestion-list/issue-suggestion-items.tsx b/packages/editor/document-editor/src/ui/extensions/widgets/issue-embed-suggestion-list/issue-suggestion-items.tsx new file mode 100644 index 000000000..df468f2ee --- /dev/null +++ b/packages/editor/document-editor/src/ui/extensions/widgets/issue-embed-suggestion-list/issue-suggestion-items.tsx @@ -0,0 +1,15 @@ +import { IIssueListSuggestion } from "src/ui/extensions/widgets/issue-embed-suggestion-list"; + +export const getIssueSuggestionItems = + (issueSuggestions: Array) => + ({ query }: { query: string }) => { + const search = query.toLowerCase(); + const filteredSuggestions = issueSuggestions.filter( + (item) => + item.title.toLowerCase().includes(search) || + item.identifier.toLowerCase().includes(search) || + item.priority.toLowerCase().includes(search) + ); + + return filteredSuggestions; + }; diff --git a/packages/editor/document-editor/src/ui/extensions/widgets/IssueEmbedSuggestionList/issue-suggestion-renderer.tsx b/packages/editor/document-editor/src/ui/extensions/widgets/issue-embed-suggestion-list/issue-suggestion-renderer.tsx similarity index 99% rename from packages/editor/document-editor/src/ui/extensions/widgets/IssueEmbedSuggestionList/issue-suggestion-renderer.tsx rename to packages/editor/document-editor/src/ui/extensions/widgets/issue-embed-suggestion-list/issue-suggestion-renderer.tsx index 487d4f075..0a166c3e3 100644 --- a/packages/editor/document-editor/src/ui/extensions/widgets/IssueEmbedSuggestionList/issue-suggestion-renderer.tsx +++ b/packages/editor/document-editor/src/ui/extensions/widgets/issue-embed-suggestion-list/issue-suggestion-renderer.tsx @@ -171,7 +171,7 @@ const IssueSuggestionList = ({ section === currentSection && index === selectedIndex, } )} - key={index} + key={item.identifier} onClick={() => selectItem(index)} >
{item.identifier}
diff --git a/packages/editor/document-editor/src/ui/extensions/widgets/IssueEmbedWidget/index.tsx b/packages/editor/document-editor/src/ui/extensions/widgets/issue-embed-widget/index.tsx similarity index 55% rename from packages/editor/document-editor/src/ui/extensions/widgets/IssueEmbedWidget/index.tsx rename to packages/editor/document-editor/src/ui/extensions/widgets/issue-embed-widget/index.tsx index fb521efef..9bbb34aa5 100644 --- a/packages/editor/document-editor/src/ui/extensions/widgets/IssueEmbedWidget/index.tsx +++ b/packages/editor/document-editor/src/ui/extensions/widgets/issue-embed-widget/index.tsx @@ -1,5 +1,5 @@ -import { IssueWidget } from "./issue-widget-node"; -import { IIssueEmbedConfig } from "./types"; +import { IssueWidget } from "src/ui/extensions/widgets/issue-embed-widget/issue-widget-node"; +import { IIssueEmbedConfig } from "src/ui/extensions/widgets/issue-embed-widget/types"; interface IssueWidgetExtensionProps { issueEmbedConfig?: IIssueEmbedConfig; diff --git a/packages/editor/document-editor/src/ui/extensions/widgets/IssueEmbedWidget/issue-widget-card.tsx b/packages/editor/document-editor/src/ui/extensions/widgets/issue-embed-widget/issue-widget-card.tsx similarity index 91% rename from packages/editor/document-editor/src/ui/extensions/widgets/IssueEmbedWidget/issue-widget-card.tsx rename to packages/editor/document-editor/src/ui/extensions/widgets/issue-embed-widget/issue-widget-card.tsx index 18dad8cae..78554c26d 100644 --- a/packages/editor/document-editor/src/ui/extensions/widgets/IssueEmbedWidget/issue-widget-card.tsx +++ b/packages/editor/document-editor/src/ui/extensions/widgets/issue-embed-widget/issue-widget-card.tsx @@ -4,7 +4,7 @@ import { NodeViewWrapper } from "@tiptap/react"; import { Avatar, AvatarGroup, Loader, PriorityIcon } from "@plane/ui"; import { Calendar, AlertTriangle } from "lucide-react"; -const IssueWidgetCard = (props) => { +export const IssueWidgetCard = (props) => { const [loading, setLoading] = useState(1); const [issueDetails, setIssueDetails] = useState(); @@ -42,11 +42,9 @@ const IssueWidgetCard = (props) => {
- {issueDetails.assignee_details.map((assignee) => { - return ( - - ); - })} + {issueDetails.assignee_details.map((assignee) => ( + + ))}
{issueDetails.target_date && ( @@ -76,5 +74,3 @@ const IssueWidgetCard = (props) => { ); }; - -export default IssueWidgetCard; diff --git a/packages/editor/document-editor/src/ui/extensions/widgets/IssueEmbedWidget/issue-widget-node.tsx b/packages/editor/document-editor/src/ui/extensions/widgets/issue-embed-widget/issue-widget-node.tsx similarity index 94% rename from packages/editor/document-editor/src/ui/extensions/widgets/IssueEmbedWidget/issue-widget-node.tsx rename to packages/editor/document-editor/src/ui/extensions/widgets/issue-embed-widget/issue-widget-node.tsx index c30fe5e5b..c13637bd9 100644 --- a/packages/editor/document-editor/src/ui/extensions/widgets/IssueEmbedWidget/issue-widget-node.tsx +++ b/packages/editor/document-editor/src/ui/extensions/widgets/issue-embed-widget/issue-widget-node.tsx @@ -1,5 +1,5 @@ import { mergeAttributes, Node } from "@tiptap/core"; -import IssueWidgetCard from "./issue-widget-card"; +import { IssueWidgetCard } from "src/ui/extensions/widgets/issue-embed-widget/issue-widget-card"; import { ReactNodeViewRenderer } from "@tiptap/react"; export const IssueWidget = Node.create({ diff --git a/packages/editor/document-editor/src/ui/extensions/widgets/IssueEmbedWidget/types.ts b/packages/editor/document-editor/src/ui/extensions/widgets/issue-embed-widget/types.ts similarity index 100% rename from packages/editor/document-editor/src/ui/extensions/widgets/IssueEmbedWidget/types.ts rename to packages/editor/document-editor/src/ui/extensions/widgets/issue-embed-widget/types.ts diff --git a/packages/editor/document-editor/src/ui/index.tsx b/packages/editor/document-editor/src/ui/index.tsx index a99d1e6a8..df3554024 100644 --- a/packages/editor/document-editor/src/ui/index.tsx +++ b/packages/editor/document-editor/src/ui/index.tsx @@ -1,17 +1,16 @@ "use client"; import React, { useState } from "react"; -import { getEditorClassNames, useEditor } from "@plane/editor-core"; -import { DocumentEditorExtensions } from "./extensions"; -import { IDuplicationConfig, IPageArchiveConfig, IPageLockConfig } from "./types/menu-actions"; -import { EditorHeader } from "./components/editor-header"; -import { useEditorMarkings } from "./hooks/use-editor-markings"; -import { SummarySideBar } from "./components/summary-side-bar"; -import { DocumentDetails } from "./types/editor-types"; -import { PageRenderer } from "./components/page-renderer"; -import { getMenuOptions } from "./utils/menu-options"; +import { UploadImage, DeleteImage, RestoreImage, getEditorClassNames, useEditor } from "@plane/editor-core"; +import { DocumentEditorExtensions } from "src/ui/extensions"; +import { IDuplicationConfig, IPageArchiveConfig, IPageLockConfig } from "src/types/menu-actions"; +import { EditorHeader } from "src/ui/components/editor-header"; +import { useEditorMarkings } from "src/hooks/use-editor-markings"; +import { SummarySideBar } from "src/ui/components/summary-side-bar"; +import { DocumentDetails } from "src/types/editor-types"; +import { PageRenderer } from "src/ui/components/page-renderer"; +import { getMenuOptions } from "src/utils/menu-options"; import { useRouter } from "next/router"; -import { IEmbedConfig } from "./extensions/widgets/IssueEmbedWidget/types"; -import { UploadImage, DeleteImage, RestoreImage } from "@plane/editor-types"; +import { IEmbedConfig } from "src/ui/extensions/widgets/issue-embed-widget/types"; interface IDocumentEditor { // document info @@ -59,13 +58,6 @@ interface EditorHandle { setEditorValue: (content: string) => void; } -export interface IMarking { - type: "heading"; - level: number; - text: string; - sequence: number; -} - const DocumentEditor = ({ documentDetails, onChange, diff --git a/packages/editor/document-editor/src/ui/menu/fixed-menu.tsx b/packages/editor/document-editor/src/ui/menu/fixed-menu.tsx index f4b205484..cac42e1f9 100644 --- a/packages/editor/document-editor/src/ui/menu/fixed-menu.tsx +++ b/packages/editor/document-editor/src/ui/menu/fixed-menu.tsx @@ -17,8 +17,8 @@ import { HeadingThreeItem, findTableAncestor, EditorMenuItem, + UploadImage, } from "@plane/editor-core"; -import { UploadImage } from "@plane/editor-types"; export type BubbleMenuItem = EditorMenuItem; diff --git a/packages/editor/document-editor/src/ui/readonly/index.tsx b/packages/editor/document-editor/src/ui/readonly/index.tsx index e7897755e..7445bfd6d 100644 --- a/packages/editor/document-editor/src/ui/readonly/index.tsx +++ b/packages/editor/document-editor/src/ui/readonly/index.tsx @@ -1,15 +1,15 @@ import { getEditorClassNames, useReadOnlyEditor } from "@plane/editor-core"; import { useRouter } from "next/router"; import { useState, forwardRef, useEffect } from "react"; -import { EditorHeader } from "../components/editor-header"; -import { PageRenderer } from "../components/page-renderer"; -import { SummarySideBar } from "../components/summary-side-bar"; -import { IssueWidgetExtension } from "../extensions/widgets/IssueEmbedWidget"; -import { IEmbedConfig } from "../extensions/widgets/IssueEmbedWidget/types"; -import { useEditorMarkings } from "../hooks/use-editor-markings"; -import { DocumentDetails } from "../types/editor-types"; -import { IPageArchiveConfig, IPageLockConfig, IDuplicationConfig } from "../types/menu-actions"; -import { getMenuOptions } from "../utils/menu-options"; +import { EditorHeader } from "src/ui/components/editor-header"; +import { PageRenderer } from "src/ui/components/page-renderer"; +import { SummarySideBar } from "src/ui/components/summary-side-bar"; +import { IssueWidgetExtension } from "src/ui/extensions/widgets/issue-embed-widget"; +import { IEmbedConfig } from "src/ui/extensions/widgets/issue-embed-widget/types"; +import { useEditorMarkings } from "src/hooks/use-editor-markings"; +import { DocumentDetails } from "src/types/editor-types"; +import { IPageArchiveConfig, IPageLockConfig, IDuplicationConfig } from "src/types/menu-actions"; +import { getMenuOptions } from "src/utils/menu-options"; interface IDocumentReadOnlyEditor { value: string; diff --git a/packages/editor/document-editor/src/ui/utils/editor-summary-utils.ts b/packages/editor/document-editor/src/utils/editor-summary-utils.ts similarity index 94% rename from packages/editor/document-editor/src/ui/utils/editor-summary-utils.ts rename to packages/editor/document-editor/src/utils/editor-summary-utils.ts index 248f439e3..b5160fddd 100644 --- a/packages/editor/document-editor/src/ui/utils/editor-summary-utils.ts +++ b/packages/editor/document-editor/src/utils/editor-summary-utils.ts @@ -1,5 +1,5 @@ import { Editor } from "@tiptap/react"; -import { IMarking } from ".."; +import { IMarking } from "src/types/editor-types"; function findNthH1(editor: Editor, n: number, level: number): number { let count = 0; diff --git a/packages/editor/document-editor/src/ui/utils/menu-actions.ts b/packages/editor/document-editor/src/utils/menu-actions.ts similarity index 100% rename from packages/editor/document-editor/src/ui/utils/menu-actions.ts rename to packages/editor/document-editor/src/utils/menu-actions.ts diff --git a/packages/editor/document-editor/src/ui/utils/menu-options.ts b/packages/editor/document-editor/src/utils/menu-options.ts similarity index 93% rename from packages/editor/document-editor/src/ui/utils/menu-options.ts rename to packages/editor/document-editor/src/utils/menu-options.ts index 0b4d02476..befed424d 100644 --- a/packages/editor/document-editor/src/ui/utils/menu-options.ts +++ b/packages/editor/document-editor/src/utils/menu-options.ts @@ -1,19 +1,9 @@ import { Editor } from "@tiptap/react"; -import { - Archive, - ArchiveIcon, - ArchiveRestoreIcon, - ClipboardIcon, - Copy, - Link, - Lock, - Unlock, - XCircle, -} from "lucide-react"; +import { Archive, ArchiveRestoreIcon, ClipboardIcon, Copy, Link, Lock, Unlock } from "lucide-react"; import { NextRouter } from "next/router"; -import { IVerticalDropdownItemProps } from "../components/vertical-dropdown-menu"; -import { IDuplicationConfig, IPageArchiveConfig, IPageLockConfig } from "../types/menu-actions"; -import { copyMarkdownToClipboard, CopyPageLink } from "./menu-actions"; +import { IVerticalDropdownItemProps } from "src/ui/components/vertical-dropdown-menu"; +import { IDuplicationConfig, IPageArchiveConfig, IPageLockConfig } from "src/types/menu-actions"; +import { copyMarkdownToClipboard, CopyPageLink } from "src/utils/menu-actions"; export interface MenuOptionsProps { editor: Editor; diff --git a/packages/editor/document-editor/tsconfig.json b/packages/editor/document-editor/tsconfig.json index 57d0e9a74..c15534037 100644 --- a/packages/editor/document-editor/tsconfig.json +++ b/packages/editor/document-editor/tsconfig.json @@ -1,5 +1,15 @@ { "extends": "tsconfig/react-library.json", - "include": ["src/**/*", "index.d.ts"], - "exclude": ["dist", "build", "node_modules"] + "include": [ + "src/**/*", + "index.d.ts" + ], + "exclude": [ + "dist", + "build", + "node_modules" + ], + "compilerOptions": { + "baseUrl": "." + } } diff --git a/packages/editor/extensions/package.json b/packages/editor/extensions/package.json index 48abd7701..dda0e58db 100644 --- a/packages/editor/extensions/package.json +++ b/packages/editor/extensions/package.json @@ -29,11 +29,10 @@ }, "dependencies": { "@plane/editor-core": "*", - "@plane/editor-types": "*", - "@tiptap/core": "^2.1.7", - "@tiptap/pm": "^2.1.7", - "@tiptap/react": "^2.1.7", - "@tiptap/suggestion": "^2.0.4", + "@tiptap/core": "^2.1.13", + "@tiptap/pm": "^2.1.13", + "@tiptap/react": "^2.1.13", + "@tiptap/suggestion": "^2.1.13", "eslint": "8.36.0", "eslint-config-next": "13.2.4", "lucide-react": "^0.294.0", diff --git a/packages/editor/extensions/src/extensions/slash-commands.tsx b/packages/editor/extensions/src/extensions/slash-commands.tsx index 92152b43a..4b12494b2 100644 --- a/packages/editor/extensions/src/extensions/slash-commands.tsx +++ b/packages/editor/extensions/src/extensions/slash-commands.tsx @@ -3,7 +3,6 @@ import { Editor, Range, Extension } from "@tiptap/core"; import Suggestion from "@tiptap/suggestion"; import { ReactRenderer } from "@tiptap/react"; import tippy from "tippy.js"; -import type { UploadImage, ISlashCommandItem, CommandProps } from "@plane/editor-types"; import { CaseSensitive, Code2, @@ -19,6 +18,9 @@ import { Table, } from "lucide-react"; import { + UploadImage, + ISlashCommandItem, + CommandProps, cn, insertTableCommand, toggleBlockquote, diff --git a/packages/editor/extensions/src/index.ts b/packages/editor/extensions/src/index.ts index 76461c2e6..c0532c594 100644 --- a/packages/editor/extensions/src/index.ts +++ b/packages/editor/extensions/src/index.ts @@ -1,2 +1,4 @@ -export { SlashCommand } from "./extensions/slash-commands"; -export { DragAndDrop } from "./extensions/drag-drop"; +import "src/styles/drag-drop.css"; + +export { SlashCommand } from "src/extensions/slash-commands"; +export { DragAndDrop } from "src/extensions/drag-drop"; diff --git a/packages/editor/extensions/src/styles/drag-drop.css b/packages/editor/extensions/src/styles/drag-drop.css new file mode 100644 index 000000000..d95a8654b --- /dev/null +++ b/packages/editor/extensions/src/styles/drag-drop.css @@ -0,0 +1,53 @@ +.drag-handle { + position: fixed; + opacity: 1; + transition: opacity ease-in 0.2s; + height: 18px; + width: 15px; + display: grid; + place-items: center; + z-index: 10; + cursor: grab; + border-radius: 2px; + background-color: rgb(var(--color-background-90)); +} + +.drag-handle:hover { + background-color: rgb(var(--color-background-80)); + transition: background-color 0.2s; +} + +.drag-handle.hidden { + opacity: 0; + pointer-events: none; +} + +@media screen and (max-width: 600px) { + .drag-handle { + display: none; + pointer-events: none; + } +} + +.drag-handle-container { + height: 15px; + width: 15px; + cursor: grab; + display: grid; + place-items: center; +} + +.drag-handle-dots { + height: 100%; + width: 12px; + display: grid; + grid-template-columns: repeat(2, 1fr); + place-items: center; +} + +.drag-handle-dot { + height: 2.75px; + width: 3px; + background-color: rgba(var(--color-text-200)); + border-radius: 50%; +} diff --git a/packages/editor/extensions/tsconfig.json b/packages/editor/extensions/tsconfig.json index 57d0e9a74..c15534037 100644 --- a/packages/editor/extensions/tsconfig.json +++ b/packages/editor/extensions/tsconfig.json @@ -1,5 +1,15 @@ { "extends": "tsconfig/react-library.json", - "include": ["src/**/*", "index.d.ts"], - "exclude": ["dist", "build", "node_modules"] + "include": [ + "src/**/*", + "index.d.ts" + ], + "exclude": [ + "dist", + "build", + "node_modules" + ], + "compilerOptions": { + "baseUrl": "." + } } diff --git a/packages/editor/lite-text-editor/package.json b/packages/editor/lite-text-editor/package.json index bcaa36a02..7882d60ff 100644 --- a/packages/editor/lite-text-editor/package.json +++ b/packages/editor/lite-text-editor/package.json @@ -30,8 +30,7 @@ }, "dependencies": { "@plane/editor-core": "*", - "@plane/ui": "*", - "@plane/editor-types": "*" + "@plane/ui": "*" }, "devDependencies": { "@types/node": "18.15.3", diff --git a/packages/editor/lite-text-editor/src/index.ts b/packages/editor/lite-text-editor/src/index.ts index f09ce54a4..c37d45039 100644 --- a/packages/editor/lite-text-editor/src/index.ts +++ b/packages/editor/lite-text-editor/src/index.ts @@ -1,3 +1,3 @@ -export { LiteTextEditor, LiteTextEditorWithRef } from "./ui"; -export { LiteReadOnlyEditor, LiteReadOnlyEditorWithRef } from "./ui/read-only"; -export type { IMentionSuggestion, IMentionHighlight } from "@plane/editor-types"; +export { LiteTextEditor, LiteTextEditorWithRef } from "src/ui"; +export { LiteReadOnlyEditor, LiteReadOnlyEditorWithRef } from "src/ui/read-only"; +export type { IMentionSuggestion, IMentionHighlight } from "@plane/editor-core"; diff --git a/packages/editor/lite-text-editor/src/ui/extensions/index.tsx b/packages/editor/lite-text-editor/src/ui/extensions/index.tsx index 4531e9516..527fd5674 100644 --- a/packages/editor/lite-text-editor/src/ui/extensions/index.tsx +++ b/packages/editor/lite-text-editor/src/ui/extensions/index.tsx @@ -1,4 +1,4 @@ -import { EnterKeyExtension } from "./enter-key-extension"; +import { EnterKeyExtension } from "src/ui/extensions/enter-key-extension"; export const LiteTextEditorExtensions = (onEnterKeyPress?: () => void) => [ // EnterKeyExtension(onEnterKeyPress), diff --git a/packages/editor/lite-text-editor/src/ui/index.tsx b/packages/editor/lite-text-editor/src/ui/index.tsx index 0eb0e20df..57774ab5d 100644 --- a/packages/editor/lite-text-editor/src/ui/index.tsx +++ b/packages/editor/lite-text-editor/src/ui/index.tsx @@ -1,8 +1,16 @@ import * as React from "react"; -import { EditorContainer, EditorContentWrapper, getEditorClassNames, useEditor } from "@plane/editor-core"; -import { FixedMenu } from "./menus/fixed-menu"; -import { LiteTextEditorExtensions } from "./extensions"; -import { UploadImage, DeleteImage, IMentionSuggestion, RestoreImage } from "@plane/editor-types"; +import { + UploadImage, + DeleteImage, + IMentionSuggestion, + RestoreImage, + EditorContainer, + EditorContentWrapper, + getEditorClassNames, + useEditor, +} from "@plane/editor-core"; +import { FixedMenu } from "src/ui/menus/fixed-menu"; +import { LiteTextEditorExtensions } from "src/ui/extensions"; interface ILiteTextEditor { value: string; diff --git a/packages/editor/lite-text-editor/src/ui/menus/fixed-menu/index.tsx b/packages/editor/lite-text-editor/src/ui/menus/fixed-menu/index.tsx index 95bd8d6dd..71ad4e0e1 100644 --- a/packages/editor/lite-text-editor/src/ui/menus/fixed-menu/index.tsx +++ b/packages/editor/lite-text-editor/src/ui/menus/fixed-menu/index.tsx @@ -9,27 +9,21 @@ import { ImageItem, isCellSelection, ItalicItem, + LucideIconType, NumberedListItem, QuoteItem, StrikeThroughItem, TableItem, UnderLineItem, + UploadImage, } from "@plane/editor-core"; import { Tooltip } from "@plane/ui"; -import type { SVGProps } from "react"; -import { UploadImage } from "@plane/editor-types"; -interface LucideProps extends Partial> { - size?: string | number; - absoluteStrokeWidth?: boolean; -} - -type LucideIcon = (props: LucideProps) => JSX.Element; export interface BubbleMenuItem { name: string; isActive: () => boolean; command: () => void; - icon: LucideIcon; + icon: LucideIconType; } type EditorBubbleMenuProps = { @@ -127,8 +121,8 @@ export const FixedMenu = (props: EditorBubbleMenuProps) => {
- {basicTextFormattingItems.map((item, index) => ( - {item.name}}> + {basicTextFormattingItems.map((item) => ( + {item.name}}>
- {listFormattingItems.map((item, index) => ( - {item.name}}> + {listFormattingItems.map((item) => ( + {item.name}}>
- {userActionItems.map((item, index) => ( - {item.name}}> + {userActionItems.map((item) => ( + {item.name}}>
- {complexItems.map((item, index) => ( - {item.name}}> + {complexItems.map((item) => ( + {item.name}}>
- } - position={position} - renderTarget={({ isOpen: isTooltipOpen, ref: eleReference, ...tooltipProps }) => - React.cloneElement(children, { - ref: eleReference, - ...tooltipProps, - ...children.props, - }) - } - /> - ); -}; diff --git a/packages/editor/lite-text-editor/tsconfig.json b/packages/editor/lite-text-editor/tsconfig.json index 57d0e9a74..c15534037 100644 --- a/packages/editor/lite-text-editor/tsconfig.json +++ b/packages/editor/lite-text-editor/tsconfig.json @@ -1,5 +1,15 @@ { "extends": "tsconfig/react-library.json", - "include": ["src/**/*", "index.d.ts"], - "exclude": ["dist", "build", "node_modules"] + "include": [ + "src/**/*", + "index.d.ts" + ], + "exclude": [ + "dist", + "build", + "node_modules" + ], + "compilerOptions": { + "baseUrl": "." + } } diff --git a/packages/editor/rich-text-editor/package.json b/packages/editor/rich-text-editor/package.json index baac553b8..245248d45 100644 --- a/packages/editor/rich-text-editor/package.json +++ b/packages/editor/rich-text-editor/package.json @@ -31,9 +31,8 @@ "dependencies": { "@plane/editor-core": "*", "@plane/editor-extensions": "*", - "@plane/editor-types": "*", - "@tiptap/core": "^2.1.11", - "@tiptap/extension-placeholder": "^2.1.11", + "@tiptap/core": "^2.1.13", + "@tiptap/extension-placeholder": "^2.1.13", "lucide-react": "^0.294.0" }, "devDependencies": { diff --git a/packages/editor/rich-text-editor/src/index.ts b/packages/editor/rich-text-editor/src/index.ts index 7dc0783d9..eb745c45b 100644 --- a/packages/editor/rich-text-editor/src/index.ts +++ b/packages/editor/rich-text-editor/src/index.ts @@ -1,4 +1,4 @@ -export { RichTextEditor, RichTextEditorWithRef } from "./ui"; -export { RichReadOnlyEditor, RichReadOnlyEditorWithRef } from "./ui/read-only"; -export type { RichTextEditorProps, IRichTextEditor } from "./ui"; -export type { IMentionHighlight, IMentionSuggestion } from "@plane/editor-types"; +export { RichTextEditor, RichTextEditorWithRef } from "src/ui"; +export { RichReadOnlyEditor, RichReadOnlyEditorWithRef } from "src/ui/read-only"; +export type { RichTextEditorProps, IRichTextEditor } from "src/ui"; +export type { IMentionHighlight, IMentionSuggestion } from "@plane/editor-core"; diff --git a/packages/editor/rich-text-editor/src/ui/extensions/index.tsx b/packages/editor/rich-text-editor/src/ui/extensions/index.tsx index 9a9d406b7..1e81c8173 100644 --- a/packages/editor/rich-text-editor/src/ui/extensions/index.tsx +++ b/packages/editor/rich-text-editor/src/ui/extensions/index.tsx @@ -1,7 +1,6 @@ -import { SlashCommand } from "@plane/editor-extensions"; +import { SlashCommand, DragAndDrop } from "@plane/editor-extensions"; import Placeholder from "@tiptap/extension-placeholder"; -import { DragAndDrop } from "@plane/editor-extensions"; -import { UploadImage } from "@plane/editor-types"; +import { UploadImage } from "@plane/editor-core"; export const RichTextEditorExtensions = ( uploadFile: UploadImage, diff --git a/packages/editor/rich-text-editor/src/ui/index.tsx b/packages/editor/rich-text-editor/src/ui/index.tsx index 5d34eb85d..17d701600 100644 --- a/packages/editor/rich-text-editor/src/ui/index.tsx +++ b/packages/editor/rich-text-editor/src/ui/index.tsx @@ -1,9 +1,17 @@ "use client"; import * as React from "react"; -import { EditorContainer, EditorContentWrapper, getEditorClassNames, useEditor } from "@plane/editor-core"; -import { EditorBubbleMenu } from "./menus/bubble-menu"; -import { RichTextEditorExtensions } from "./extensions"; -import { DeleteImage, IMentionSuggestion, RestoreImage, UploadImage } from "@plane/editor-types"; +import { + DeleteImage, + EditorContainer, + EditorContentWrapper, + getEditorClassNames, + IMentionSuggestion, + RestoreImage, + UploadImage, + useEditor, +} from "@plane/editor-core"; +import { EditorBubbleMenu } from "src/ui/menus/bubble-menu"; +import { RichTextEditorExtensions } from "src/ui/extensions"; export type IRichTextEditor = { value: string; diff --git a/packages/editor/rich-text-editor/src/ui/menus/bubble-menu/index.tsx b/packages/editor/rich-text-editor/src/ui/menus/bubble-menu/index.tsx index 7e9c834a7..2e7dd25b8 100644 --- a/packages/editor/rich-text-editor/src/ui/menus/bubble-menu/index.tsx +++ b/packages/editor/rich-text-editor/src/ui/menus/bubble-menu/index.tsx @@ -1,15 +1,15 @@ import { BubbleMenu, BubbleMenuProps, isNodeSelection } from "@tiptap/react"; import { FC, useEffect, useState } from "react"; -import { BoldIcon } from "lucide-react"; -import { NodeSelector } from "./node-selector"; -import { LinkSelector } from "./link-selector"; +import { NodeSelector } from "src/ui/menus/bubble-menu/node-selector"; +import { LinkSelector } from "src/ui/menus/bubble-menu/link-selector"; import { BoldItem, cn, CodeItem, isCellSelection, ItalicItem, + LucideIconType, StrikeThroughItem, UnderLineItem, } from "@plane/editor-core"; @@ -18,7 +18,7 @@ export interface BubbleMenuItem { name: string; isActive: () => boolean; command: () => void; - icon: typeof BoldIcon; + icon: LucideIconType; } type EditorBubbleMenuProps = Omit; @@ -117,9 +117,9 @@ export const EditorBubbleMenu: FC = (props: any) => { }} />
- {items.map((item, index) => ( + {items.map((item) => (
diff --git a/web/components/web-hooks/form/form.tsx b/web/components/web-hooks/form/form.tsx index 43600b04a..4d98c2b7f 100644 --- a/web/components/web-hooks/form/form.tsx +++ b/web/components/web-hooks/form/form.tsx @@ -1,11 +1,8 @@ import React, { FC, useEffect, useState } from "react"; -import { useRouter } from "next/router"; import { Controller, useForm } from "react-hook-form"; import { observer } from "mobx-react-lite"; // mobx store import { useMobxStore } from "lib/mobx/store-provider"; -// hooks -import useToast from "hooks/use-toast"; // components import { WebhookIndividualEventOptions, @@ -13,17 +10,16 @@ import { WebhookOptions, WebhookSecretKey, WebhookToggle, - getCurrentHookAsCSV, } from "components/web-hooks"; // ui import { Button } from "@plane/ui"; -// helpers -import { csvDownload } from "helpers/download.helper"; // types import { IWebhook, TWebhookEventTypes } from "types"; type Props = { data?: Partial; + onSubmit: (data: IWebhook, webhookEventType: TWebhookEventTypes) => Promise; + handleClose?: () => void; }; const initialWebhookPayload: Partial = { @@ -36,18 +32,12 @@ const initialWebhookPayload: Partial = { }; export const WebhookForm: FC = observer((props) => { - const { data } = props; + const { data, onSubmit, handleClose } = props; // states const [webhookEventType, setWebhookEventType] = useState("all"); - // router - const router = useRouter(); - const { workspaceSlug } = router.query; - // toast - const { setToastAlert } = useToast(); // mobx store const { - webhook: { createWebhook, updateWebhook }, - workspace: { currentWorkspace }, + webhook: { webhookSecretKey }, } = useMobxStore(); // use form const { @@ -58,74 +48,8 @@ export const WebhookForm: FC = observer((props) => { defaultValues: { ...initialWebhookPayload, ...data }, }); - const handleCreateWebhook = async (formData: IWebhook) => { - if (!workspaceSlug) return; - - let payload: Partial = { - url: formData.url, - }; - - if (webhookEventType === "all") - payload = { - ...payload, - project: true, - cycle: true, - module: true, - issue: true, - issue_comment: true, - }; - else - payload = { - ...payload, - project: formData.project ?? false, - cycle: formData.cycle ?? false, - module: formData.module ?? false, - issue: formData.issue ?? false, - issue_comment: formData.issue_comment ?? false, - }; - - await createWebhook(workspaceSlug.toString(), payload) - .then(({ webHook, secretKey }) => { - setToastAlert({ - type: "success", - title: "Success!", - message: "Webhook created successfully.", - }); - - const csvData = getCurrentHookAsCSV(currentWorkspace, webHook, secretKey); - csvDownload(csvData, `webhook-secret-key-${Date.now()}`); - - if (webHook && webHook.id) - router.push({ pathname: `/${workspaceSlug}/settings/webhooks/${webHook.id}`, query: { isCreated: true } }); - }) - .catch((error) => { - setToastAlert({ - type: "error", - title: "Error!", - message: error?.error ?? "Something went wrong. Please try again.", - }); - }); - }; - - const handleUpdateWebhook = async (formData: IWebhook) => { - if (!workspaceSlug || !data || !data.id) return; - - const payload = { - url: formData?.url, - is_active: formData?.is_active, - project: formData?.project, - cycle: formData?.cycle, - module: formData?.module, - issue: formData?.issue, - issue_comment: formData?.issue_comment, - }; - - return await updateWebhook(workspaceSlug.toString(), data.id, payload); - }; - const handleFormSubmit = async (formData: IWebhook) => { - if (data) await handleUpdateWebhook(formData); - else await handleCreateWebhook(formData); + await onSubmit(formData, webhookEventType); }; useEffect(() => { @@ -161,12 +85,26 @@ export const WebhookForm: FC = observer((props) => {
{webhookEventType === "individual" && }
-
- {data && } - -
+ {data ? ( +
+ + + +
+ ) : ( +
+ + {!webhookSecretKey && ( + + )} +
+ )}
); diff --git a/web/components/web-hooks/form/secret-key.tsx b/web/components/web-hooks/form/secret-key.tsx index eecc7aa71..e3cc6e45f 100644 --- a/web/components/web-hooks/form/secret-key.tsx +++ b/web/components/web-hooks/form/secret-key.tsx @@ -56,11 +56,11 @@ export const WebhookSecretKey: FC = observer((props) => { }; const handleRegenerateSecretKey = () => { - if (!workspaceSlug || !webhookId) return; + if (!workspaceSlug || !data.id) return; setIsRegenerating(true); - regenerateSecretKey(workspaceSlug.toString(), webhookId.toString()) + regenerateSecretKey(workspaceSlug.toString(), data.id) .then(() => { setToastAlert({ type: "success", @@ -92,10 +92,10 @@ export const WebhookSecretKey: FC = observer((props) => { <> {(data || webhookSecretKey) && (
-
Secret key
+ {webhookId &&
Secret key
}
Generate a token to sign-in to the webhook payload
-
+
{shouldShowKey ? (

{webhookSecretKey}

diff --git a/web/components/web-hooks/generated-hook-details.tsx b/web/components/web-hooks/generated-hook-details.tsx new file mode 100644 index 000000000..60dfeda30 --- /dev/null +++ b/web/components/web-hooks/generated-hook-details.tsx @@ -0,0 +1,33 @@ +// components +import { WebhookSecretKey } from "./form"; +// ui +import { Button } from "@plane/ui"; +// types +import { IWebhook } from "types"; + +type Props = { + handleClose: () => void; + webhookDetails: IWebhook; +}; + +export const GeneratedHookDetails: React.FC = (props) => { + const { handleClose, webhookDetails } = props; + + return ( +
+
+

Key created

+

+ Copy and save this secret key in Plane Pages. You can{"'"}t see this key after you hit Close. A CSV file + containing the key has been downloaded. +

+
+ +
+ +
+
+ ); +}; diff --git a/web/components/web-hooks/index.ts b/web/components/web-hooks/index.ts index 79fe4a520..fd23f4330 100644 --- a/web/components/web-hooks/index.ts +++ b/web/components/web-hooks/index.ts @@ -1,6 +1,8 @@ -export * from "./form"; export * from "./delete-webhook-modal"; export * from "./empty-state"; +export * from "./form"; +export * from "./generated-hook-details"; export * from "./utils"; +export * from "./create-webhook-modal"; export * from "./webhooks-list-item"; export * from "./webhooks-list"; diff --git a/web/pages/[workspaceSlug]/settings/webhooks/[webhookId].tsx b/web/pages/[workspaceSlug]/settings/webhooks/[webhookId].tsx index b5e4ff64a..c8b5d2cce 100644 --- a/web/pages/[workspaceSlug]/settings/webhooks/[webhookId].tsx +++ b/web/pages/[workspaceSlug]/settings/webhooks/[webhookId].tsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from "react"; +import { useState } from "react"; import { useRouter } from "next/router"; import { observer } from "mobx-react-lite"; import useSWR from "swr"; @@ -7,6 +7,8 @@ import { useMobxStore } from "lib/mobx/store-provider"; // layouts import { AppLayout } from "layouts/app-layout"; import { WorkspaceSettingLayout } from "layouts/settings-layout"; +// hooks +import useToast from "hooks/use-toast"; // components import { WorkspaceSettingHeader } from "components/headers"; import { DeleteWebhookModal, WebhookDeleteSection, WebhookForm } from "components/web-hooks"; @@ -14,22 +16,21 @@ import { DeleteWebhookModal, WebhookDeleteSection, WebhookForm } from "component import { Spinner } from "@plane/ui"; // types import { NextPageWithLayout } from "types/app"; +import { IWebhook } from "types"; const WebhookDetailsPage: NextPageWithLayout = observer(() => { // states const [deleteWebhookModal, setDeleteWebhookModal] = useState(false); // router const router = useRouter(); - const { workspaceSlug, webhookId, isCreated } = router.query; + const { workspaceSlug, webhookId } = router.query; // mobx store const { - webhook: { currentWebhook, clearSecretKey, fetchWebhookById }, + webhook: { currentWebhook, fetchWebhookById, updateWebhook }, user: { currentWorkspaceRole }, } = useMobxStore(); - - useEffect(() => { - if (isCreated !== "true") clearSecretKey(); - }, [clearSecretKey, isCreated]); + // toast + const { setToastAlert } = useToast(); const isAdmin = currentWorkspaceRole === 20; @@ -40,6 +41,34 @@ const WebhookDetailsPage: NextPageWithLayout = observer(() => { : null ); + const handleUpdateWebhook = async (formData: IWebhook) => { + if (!workspaceSlug || !formData || !formData.id) return; + const payload = { + url: formData?.url, + is_active: formData?.is_active, + project: formData?.project, + cycle: formData?.cycle, + module: formData?.module, + issue: formData?.issue, + issue_comment: formData?.issue_comment, + }; + await updateWebhook(workspaceSlug.toString(), formData.id, payload) + .then(() => { + setToastAlert({ + type: "success", + title: "Success!", + message: "Webhook updated successfully.", + }); + }) + .catch((error) => { + setToastAlert({ + type: "error", + title: "Error!", + message: error?.error ?? "Something went wrong. Please try again.", + }); + }); + }; + if (!isAdmin) return (
@@ -58,7 +87,7 @@ const WebhookDetailsPage: NextPageWithLayout = observer(() => { <> setDeleteWebhookModal(false)} />
- + await handleUpdateWebhook(data)} data={currentWebhook} /> {currentWebhook && setDeleteWebhookModal(true)} />}
diff --git a/web/pages/[workspaceSlug]/settings/webhooks/create.tsx b/web/pages/[workspaceSlug]/settings/webhooks/create.tsx deleted file mode 100644 index 6615d4c68..000000000 --- a/web/pages/[workspaceSlug]/settings/webhooks/create.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import React from "react"; -import { observer } from "mobx-react-lite"; -// mobx store -import { useMobxStore } from "lib/mobx/store-provider"; -// layouts -import { AppLayout } from "layouts/app-layout"; -import { WorkspaceSettingLayout } from "layouts/settings-layout"; -// components -import { WorkspaceSettingHeader } from "components/headers"; -import { WebhookForm } from "components/web-hooks"; -// types -import { NextPageWithLayout } from "types/app"; - -const CreateWebhookPage: NextPageWithLayout = observer(() => { - const { - user: { currentWorkspaceRole }, - } = useMobxStore(); - - const isAdmin = currentWorkspaceRole === 20; - - if (!isAdmin) - return ( -
-

You are not authorized to access this page.

-
- ); - - return ( -
- -
- ); -}); - -CreateWebhookPage.getLayout = function getLayout(page: React.ReactElement) { - return ( - }> - {page} - - ); -}; - -export default CreateWebhookPage; diff --git a/web/pages/[workspaceSlug]/settings/webhooks/index.tsx b/web/pages/[workspaceSlug]/settings/webhooks/index.tsx index 0fe6e4e71..407c3ebab 100644 --- a/web/pages/[workspaceSlug]/settings/webhooks/index.tsx +++ b/web/pages/[workspaceSlug]/settings/webhooks/index.tsx @@ -1,5 +1,4 @@ -import React from "react"; -import Link from "next/link"; +import React, { useEffect, useState } from "react"; import { useRouter } from "next/router"; import useSWR from "swr"; import { observer } from "mobx-react-lite"; @@ -10,18 +9,22 @@ import { AppLayout } from "layouts/app-layout"; import { WorkspaceSettingLayout } from "layouts/settings-layout"; // components import { WorkspaceSettingHeader } from "components/headers"; -import { WebhooksList, WebhooksEmptyState } from "components/web-hooks"; +import { WebhooksList, WebhooksEmptyState, CreateWebhookModal } from "components/web-hooks"; // ui import { Button, Spinner } from "@plane/ui"; // types import { NextPageWithLayout } from "types/app"; const WebhooksListPage: NextPageWithLayout = observer(() => { + // states + const [showCreateWebhookModal, setShowCreateWebhookModal] = useState(false); + // router const router = useRouter(); const { workspaceSlug } = router.query; const { - webhook: { fetchWebhooks, webhooks }, + webhook: { fetchWebhooks, createWebhook, clearSecretKey, webhooks, webhookSecretKey }, + workspace: { currentWorkspace }, user: { currentWorkspaceRole }, } = useMobxStore(); @@ -32,6 +35,11 @@ const WebhooksListPage: NextPageWithLayout = observer(() => { workspaceSlug && isAdmin ? () => fetchWebhooks(workspaceSlug.toString()) : null ); + // clear secret key when modal is closed. + useEffect(() => { + if (!showCreateWebhookModal && webhookSecretKey) clearSecretKey(); + }, [showCreateWebhookModal, webhookSecretKey, clearSecretKey]); + if (!isAdmin) return (
@@ -48,21 +56,28 @@ const WebhooksListPage: NextPageWithLayout = observer(() => { return (
+ { + setShowCreateWebhookModal(false); + }} + /> {Object.keys(webhooks).length > 0 ? (
Webhooks
- - - +
) : (
- + setShowCreateWebhookModal(true)} />
)}
From 0a617eec267b7bf5ee6ba0a65c9d3a9474b40dd3 Mon Sep 17 00:00:00 2001 From: "M. Palanikannan" <73993394+Palanikannan1437@users.noreply.github.com> Date: Tue, 26 Dec 2023 16:45:00 +0530 Subject: [PATCH 20/40] =?UTF-8?q?=F0=9F=94=A7=20fix:=20Pages=20mutation=20?= =?UTF-8?q?on=20component=20mount=20(#3230)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 🔧 chore: Update revalidate option and add useEffect hook in PageDetailsPage component - Set the `revalidate` option to `false` in the `commonSwrOptions` object. - Add an `useEffect` hook that calls the `mutatePageDetails` function with specific options. - Inside the `useEffect` hook, set `revalidate` to `true`, `populateCache` to `true`, and define a rollback function for error handling. - If an error occurs during the rollback, display an error alert message using the `actionCompleteAlert` function. - In the `updatePage` function, ensure that `workspaceSlug`, `projectId`, and `pageId` are all defined before proceeding. * ♻️ refactor: Update code styling for inline code in CoreEditorExtensions In the `packages/editor/core/src/ui/extensions/index.tsx` file, the code for inline code styling in the CoreEditorExtensions component has been updated. Previously, it was set to `false`, but now it is defined as an object with specific HTML attributes. The code styling includes a rounded-md background, custom primary color, margin, padding, font styling, and disabling spellcheck. This change improves the visual appearance and readability of inline code elements in the editor. --- .../editor/core/src/ui/extensions/index.tsx | 12 ++++++------ .../projects/[projectId]/pages/[pageId].tsx | 18 +++++++++++++++++- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/packages/editor/core/src/ui/extensions/index.tsx b/packages/editor/core/src/ui/extensions/index.tsx index 1406cde67..4ae55f00c 100644 --- a/packages/editor/core/src/ui/extensions/index.tsx +++ b/packages/editor/core/src/ui/extensions/index.tsx @@ -52,12 +52,12 @@ export const CoreEditorExtensions = ( class: "leading-normal -mb-2", }, }, - // blockquote: { - // HTMLAttributes: { - // class: "border-l-4 border-custom-border-300", - // }, - // }, - code: false, + code: { + HTMLAttributes: { + class: "rounded-md bg-custom-primary-30 mx-1 px-1 py-1 font-mono font-medium text-custom-text-1000", + spellcheck: "false", + }, + }, codeBlock: false, horizontalRule: false, dropcursor: { diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/pages/[pageId].tsx b/web/pages/[workspaceSlug]/projects/[projectId]/pages/[pageId].tsx index 067d3e18f..f91be2c2d 100644 --- a/web/pages/[workspaceSlug]/projects/[projectId]/pages/[pageId].tsx +++ b/web/pages/[workspaceSlug]/projects/[projectId]/pages/[pageId].tsx @@ -177,7 +177,7 @@ const PageDetailsPage: NextPageWithLayout = observer(() => { onErrorAction: () => void ) => { const commonSwrOptions: MutatorOptions = { - revalidate: true, + revalidate: false, populateCache: false, rollbackOnError: () => { onErrorAction(); @@ -201,6 +201,22 @@ const PageDetailsPage: NextPageWithLayout = observer(() => { }); }; + useEffect(() => { + mutatePageDetails(undefined, { + revalidate: true, + populateCache: true, + rollbackOnError: () => { + actionCompleteAlert({ + title: `Page could not be updated`, + message: `Sorry, page could not be updated, please try again later`, + type: "error", + }); + return true; + }, + }); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + const updatePage = async (formData: IPage) => { if (!workspaceSlug || !projectId || !pageId) return; From 1e27c7936d10765350889eacec2432ee6c78744f Mon Sep 17 00:00:00 2001 From: sriram veeraghanta Date: Tue, 26 Dec 2023 17:03:43 +0530 Subject: [PATCH 21/40] fix: eslint dependencies fixes --- packages/editor/document-editor/package.json | 3 +-- packages/editor/extensions/package.json | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/editor/document-editor/package.json b/packages/editor/document-editor/package.json index 61a075e5f..72dfab954 100644 --- a/packages/editor/document-editor/package.json +++ b/packages/editor/document-editor/package.json @@ -35,7 +35,6 @@ "@tiptap/extension-placeholder": "^2.1.13", "@tiptap/pm": "^2.1.13", "@tiptap/suggestion": "^2.1.13", - "eslint": "8.36.0", "eslint-config-next": "13.2.4", "react-popper": "^2.3.0", "tippy.js": "^6.3.7", @@ -45,7 +44,7 @@ "@types/node": "18.15.3", "@types/react": "^18.2.42", "@types/react-dom": "^18.2.17", - "eslint": "^7.32.0", + "eslint": "8.36.0", "postcss": "^8.4.29", "tailwind-config-custom": "*", "tsconfig": "*", diff --git a/packages/editor/extensions/package.json b/packages/editor/extensions/package.json index dda0e58db..94801928c 100644 --- a/packages/editor/extensions/package.json +++ b/packages/editor/extensions/package.json @@ -33,7 +33,6 @@ "@tiptap/pm": "^2.1.13", "@tiptap/react": "^2.1.13", "@tiptap/suggestion": "^2.1.13", - "eslint": "8.36.0", "eslint-config-next": "13.2.4", "lucide-react": "^0.294.0", "tippy.js": "^6.3.7" @@ -42,7 +41,7 @@ "@types/node": "18.15.3", "@types/react": "^18.2.42", "@types/react-dom": "^18.2.17", - "eslint": "^7.32.0", + "eslint": "8.36.0", "postcss": "^8.4.29", "tailwind-config-custom": "*", "tsconfig": "*", From eabb31a764d44d50a69458abc16ae27163502a7b Mon Sep 17 00:00:00 2001 From: sriram veeraghanta Date: Tue, 26 Dec 2023 17:04:59 +0530 Subject: [PATCH 22/40] fix: upgrading turbo repo changes --- package.json | 2 +- yarn.lock | 68 ++++++++++++++++++++++++++-------------------------- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/package.json b/package.json index 06e84557b..b5d997662 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "prettier": "latest", "prettier-plugin-tailwindcss": "^0.5.4", "tailwindcss": "^3.3.3", - "turbo": "^1.11.1" + "turbo": "^1.11.2" }, "resolutions": { "@types/react": "18.2.42" diff --git a/yarn.lock b/yarn.lock index 617ebf75b..ad1268469 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8495,47 +8495,47 @@ tunnel-agent@^0.6.0: dependencies: safe-buffer "^5.0.1" -turbo-darwin-64@1.11.1: - version "1.11.1" - resolved "https://registry.yarnpkg.com/turbo-darwin-64/-/turbo-darwin-64-1.11.1.tgz#fc9c2e578bd2d270b9942b11750a519a39850c57" - integrity sha512-JmwL8kcfxncDf2SZFioSa6dUvpMq/HbMcurh9mGm6BxWLQoB0d3fP/q3HizgCSbOE4ihScXoQ+c/C2xhl6Ngjg== +turbo-darwin-64@1.11.2: + version "1.11.2" + resolved "https://registry.yarnpkg.com/turbo-darwin-64/-/turbo-darwin-64-1.11.2.tgz#fc3d4d74b325a27aef11b6a52a61f07d466846b9" + integrity sha512-toFmRG/adriZY3hOps7nYCfqHAS+Ci6xqgX3fbo82kkLpC6OBzcXnleSwuPqjHVAaRNhVoB83L5njcE9Qwi2og== -turbo-darwin-arm64@1.11.1: - version "1.11.1" - resolved "https://registry.yarnpkg.com/turbo-darwin-arm64/-/turbo-darwin-arm64-1.11.1.tgz#77ba7f16106dc6e48acad03ce37ccf41d2851017" - integrity sha512-lIpT7nPkU0xmpkI8VOGQcgoQKmUATRMpRhTDclz6j/Px7Qtxjc+2PitKHKfR3aCnseoRMGkgMzPEJTPUwCpnlQ== +turbo-darwin-arm64@1.11.2: + version "1.11.2" + resolved "https://registry.yarnpkg.com/turbo-darwin-arm64/-/turbo-darwin-arm64-1.11.2.tgz#583a4d0025bc3f953a9eeb7065cb173f481a9965" + integrity sha512-FCsEDZ8BUSFYEOSC3rrARQrj7x2VOrmVcfrMUIhexTxproRh4QyMxLfr6LALk4ymx6jbDCxWa6Szal8ckldFbA== -turbo-linux-64@1.11.1: - version "1.11.1" - resolved "https://registry.yarnpkg.com/turbo-linux-64/-/turbo-linux-64-1.11.1.tgz#40458e4db3c7b56b6347a42d9e4aab43acdcf197" - integrity sha512-mHFSqMkgy3h/M8Ocj2oiOr6CqlCqB6coCPWVIAmraBk+SQywwsszgJ69GWBfm7lwwJvb3B1YN1wkZNe9ZZnBfg== +turbo-linux-64@1.11.2: + version "1.11.2" + resolved "https://registry.yarnpkg.com/turbo-linux-64/-/turbo-linux-64-1.11.2.tgz#55ef996d856cb397b9fb2855a554ccef1cee9dd7" + integrity sha512-Vzda/o/QyEske5CxLf0wcu7UUS+7zB90GgHZV4tyN+WZtoouTvbwuvZ3V6b5Wgd3OJ/JwWR0CXDK7Sf4VEMr7A== -turbo-linux-arm64@1.11.1: - version "1.11.1" - resolved "https://registry.yarnpkg.com/turbo-linux-arm64/-/turbo-linux-arm64-1.11.1.tgz#3eb32d42851dbe7fb9627de29687171af2c20295" - integrity sha512-6ybojTkAkymo1Ig7kU3s2YQUUSRf3l2qatPZgw3v4OmFTSU2feCU1sHjAEqhHwEjV1KciDo1wRl1gjjyby4foQ== +turbo-linux-arm64@1.11.2: + version "1.11.2" + resolved "https://registry.yarnpkg.com/turbo-linux-arm64/-/turbo-linux-arm64-1.11.2.tgz#64d6093c9a2f32f410624564fd10685c847d947e" + integrity sha512-bRLwovQRz0yxDZrM4tQEAYV0fBHEaTzUF0JZ8RG1UmZt/CqtpnUrJpYb1VK8hj1z46z9YehARpYCwQ2K0qU4yw== -turbo-windows-64@1.11.1: - version "1.11.1" - resolved "https://registry.yarnpkg.com/turbo-windows-64/-/turbo-windows-64-1.11.1.tgz#b30bd6bd113fee6e455e96f99cf4cc069ef4964b" - integrity sha512-ytWy6+yEtBfv6nbgCKW6HsolgUFAC1PZGMPzbqRGnCm2eLVWhDuwO1Yk7uq4cvdrpXcXgOMcPEoJZxUCDbeJaQ== +turbo-windows-64@1.11.2: + version "1.11.2" + resolved "https://registry.yarnpkg.com/turbo-windows-64/-/turbo-windows-64-1.11.2.tgz#f4164be9c42796c86ca3929e27f1992a4310b9ed" + integrity sha512-LgTWqkHAKgyVuLYcEPxZVGPInTjjeCnN5KQMdJ4uQZ+xMDROvMFS2rM93iQl4ieDJgidwHCxxCxaU9u8c3d/Kg== -turbo-windows-arm64@1.11.1: - version "1.11.1" - resolved "https://registry.yarnpkg.com/turbo-windows-arm64/-/turbo-windows-arm64-1.11.1.tgz#9e152b30232ada57144004f0ff7939933ae0d57d" - integrity sha512-O04DdJoRavOh/v9/MM5wWCEtOekO4aiLljNZc/fOh853sOhid61ZRSEYUmS9ecjmZ/OjKqedIfbkitaQ77c4xA== +turbo-windows-arm64@1.11.2: + version "1.11.2" + resolved "https://registry.yarnpkg.com/turbo-windows-arm64/-/turbo-windows-arm64-1.11.2.tgz#ca1b4d7ac6fe8c931baef1a270ac07bbd924277b" + integrity sha512-829aVBU7IX0c/B4G7g1VI8KniAGutHhIupkYMgF6xPkYVev2G3MYe6DMS/vsLt9GGM9ulDtdWxWrH5P2ngK8IQ== -turbo@^1.11.1: - version "1.11.1" - resolved "https://registry.yarnpkg.com/turbo/-/turbo-1.11.1.tgz#1a779ee58382397e2f4c538bc0f15a820081ba8c" - integrity sha512-pmIsyTcyBJ5iJIaTjJyCxAq7YquDqyRai6FW2q0mFAkwK3k0p36wJ5yH85U2Ue6esrTKzeSEKskP4/fa7dv4+A== +turbo@^1.11.2: + version "1.11.2" + resolved "https://registry.yarnpkg.com/turbo/-/turbo-1.11.2.tgz#7bae6df12c210e9b12973aad8f0e7b077039d4ce" + integrity sha512-jPC7LVQJzebs5gWf8FmEvsvXGNyKbN+O9qpvv98xpNaM59aS0/Irhd0H0KbcqnXfsz7ETlzOC3R+xFWthC4Z8A== optionalDependencies: - turbo-darwin-64 "1.11.1" - turbo-darwin-arm64 "1.11.1" - turbo-linux-64 "1.11.1" - turbo-linux-arm64 "1.11.1" - turbo-windows-64 "1.11.1" - turbo-windows-arm64 "1.11.1" + turbo-darwin-64 "1.11.2" + turbo-darwin-arm64 "1.11.2" + turbo-linux-64 "1.11.2" + turbo-linux-arm64 "1.11.2" + turbo-windows-64 "1.11.2" + turbo-windows-arm64 "1.11.2" type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" From 37fe9a185c5df1a0a922674a70c0e7d3c96f80d2 Mon Sep 17 00:00:00 2001 From: sriram veeraghanta Date: Tue, 26 Dec 2023 18:13:13 +0530 Subject: [PATCH 23/40] fix: adding token to the build pr workflow (#3254) * fix: adding token to the build pr workflow * fix: using automatic github token --- .github/workflows/build-test-pull-request.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build-test-pull-request.yml b/.github/workflows/build-test-pull-request.yml index c74975f48..b7583e953 100644 --- a/.github/workflows/build-test-pull-request.yml +++ b/.github/workflows/build-test-pull-request.yml @@ -1,6 +1,6 @@ name: Build Pull Request Contents -on: +on: pull_request: types: ["opened", "synchronize"] @@ -14,13 +14,15 @@ jobs: steps: - name: Checkout Repository to Actions uses: actions/checkout@v3.3.0 + with: + token: ${{ secrets.GITHUB_TOKEN }} - name: Setup Node.js 18.x uses: actions/setup-node@v2 with: node-version: 18.x - cache: 'yarn' - + cache: "yarn" + - name: Get changed files id: changed-files uses: tj-actions/changed-files@v38 @@ -44,5 +46,3 @@ jobs: run: | yarn yarn build --filter=space - - From 440cfc0f2030b6bb49f07fdd6eb16f1abb5c8f69 Mon Sep 17 00:00:00 2001 From: sriram veeraghanta Date: Tue, 26 Dec 2023 18:59:24 +0530 Subject: [PATCH 24/40] fix: adding access token to build Pr (#3257) --- .github/workflows/build-test-pull-request.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-test-pull-request.yml b/.github/workflows/build-test-pull-request.yml index b7583e953..fd5d5ad03 100644 --- a/.github/workflows/build-test-pull-request.yml +++ b/.github/workflows/build-test-pull-request.yml @@ -15,7 +15,7 @@ jobs: - name: Checkout Repository to Actions uses: actions/checkout@v3.3.0 with: - token: ${{ secrets.GITHUB_TOKEN }} + token: ${{ secrets.ACCESS_TOKEN }} - name: Setup Node.js 18.x uses: actions/setup-node@v2 From 05eb728c407f407bbb27b88ae52a9238c1efdf09 Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com> Date: Wed, 27 Dec 2023 15:16:13 +0530 Subject: [PATCH 25/40] chore: cycle & module sidebar improvement (#3251) * chore: no lead option added in module lead select dropdown * chore: module lead select dropdown code refactor * chore: cycle sidebar improvement * chore: module sidebar improvement * style: cycle and module sidebar improvement * style: app sidebar improvement --- web/components/cycles/sidebar.tsx | 82 ++++++++++++----- web/components/modules/select/lead.tsx | 9 +- .../modules/sidebar-select/select-lead.tsx | 15 ++- web/components/modules/sidebar.tsx | 92 ++++++++++++++----- web/components/project/sidebar-list.tsx | 8 +- 5 files changed, 153 insertions(+), 53 deletions(-) diff --git a/web/components/cycles/sidebar.tsx b/web/components/cycles/sidebar.tsx index 1fd1cd05c..dcf86bb46 100644 --- a/web/components/cycles/sidebar.tsx +++ b/web/components/cycles/sidebar.tsx @@ -17,7 +17,16 @@ import { CycleDeleteModal } from "components/cycles/delete-modal"; import { CustomRangeDatePicker } from "components/ui"; import { Avatar, CustomMenu, Loader, LayersIcon } from "@plane/ui"; // icons -import { ChevronDown, LinkIcon, Trash2, UserCircle2, AlertCircle, ChevronRight, MoveRight } from "lucide-react"; +import { + ChevronDown, + LinkIcon, + Trash2, + UserCircle2, + AlertCircle, + ChevronRight, + CalendarCheck2, + CalendarClock, +} from "lucide-react"; // helpers import { copyUrlToClipboard } from "helpers/string.helper"; import { @@ -357,8 +366,7 @@ export const CycleDetailsSidebar: React.FC = observer((props) => {
-
-

{cycleDetails.name}

+
{currentCycle && ( = observer((props) => { : `${currentCycle.label}`} )} -
- +
+

{cycleDetails.name}

+
+ + {cycleDetails.description && ( + + {cycleDetails.description} + + )} + +
+
+
+ + Start Date +
+
+ - {areYearsEqual ? renderShortDate(startDate, "_ _") : renderShortMonthDate(startDate, "_ _")} + + {areYearsEqual + ? renderShortDate(startDate, "No date selected") + : renderShortMonthDate(startDate, "No date selected")} + = observer((props) => { leaveFrom="opacity-100 translate-y-0" leaveTo="opacity-0 translate-y-1" > - + { @@ -410,16 +442,32 @@ export const CycleDetailsSidebar: React.FC = observer((props) => { - - +
+
+ +
+
+ + Target Date +
+
+ <> - {areYearsEqual ? renderShortDate(endDate, "_ _") : renderShortMonthDate(endDate, "_ _")} + + {areYearsEqual + ? renderShortDate(endDate, "No date selected") + : renderShortMonthDate(endDate, "No date selected")} + = observer((props) => { leaveFrom="opacity-100 translate-y-0" leaveTo="opacity-0 translate-y-1" > - + { @@ -451,15 +499,7 @@ export const CycleDetailsSidebar: React.FC = observer((props) => {
-
- {cycleDetails.description && ( - - {cycleDetails.description} - - )} - -
diff --git a/web/components/modules/select/lead.tsx b/web/components/modules/select/lead.tsx index d84d67237..8f376618c 100644 --- a/web/components/modules/select/lead.tsx +++ b/web/components/modules/select/lead.tsx @@ -7,7 +7,7 @@ import { ProjectMemberService } from "services/project"; import { Avatar, CustomSearchSelect } from "@plane/ui"; // icons import { Combobox } from "@headlessui/react"; -import { UserCircle } from "lucide-react"; +import { UserCircle, UserCircle2 } from "lucide-react"; // fetch-keys import { PROJECT_MEMBERS } from "constants/fetch-keys"; @@ -65,9 +65,10 @@ export const ModuleLeadSelect: React.FC = ({ value, onChange }) => { value="" className="flex cursor-pointer select-none items-center justify-between gap-2 truncate rounded px-1 py-1.5 text-custom-text-200" > - - No Lead - +
+ + No lead +
} onChange={onChange} diff --git a/web/components/modules/sidebar-select/select-lead.tsx b/web/components/modules/sidebar-select/select-lead.tsx index f675925c4..91a70504f 100644 --- a/web/components/modules/sidebar-select/select-lead.tsx +++ b/web/components/modules/sidebar-select/select-lead.tsx @@ -31,6 +31,17 @@ export const SidebarLeadSelect: FC = (props) => { : null ); + const noLeadOption = { + value: "", + query: "No lead", + content: ( +
+ + No lead +
+ ), + }; + const options = members?.map((member) => ({ value: member.member.id, query: member.member.display_name, @@ -42,6 +53,8 @@ export const SidebarLeadSelect: FC = (props) => { ), })); + const leadOption = (options || []).concat(noLeadOption); + const selectedOption = members?.find((m) => m.member.id === value)?.member; return ( @@ -69,7 +82,7 @@ export const SidebarLeadSelect: FC = (props) => {
) } - options={options} + options={leadOption} maxHeight="md" onChange={onChange} /> diff --git a/web/components/modules/sidebar.tsx b/web/components/modules/sidebar.tsx index 3c9552465..3fe7bf57e 100644 --- a/web/components/modules/sidebar.tsx +++ b/web/components/modules/sidebar.tsx @@ -15,7 +15,17 @@ import ProgressChart from "components/core/sidebar/progress-chart"; import { CustomRangeDatePicker } from "components/ui"; import { CustomMenu, Loader, LayersIcon, CustomSelect, ModuleStatusIcon } from "@plane/ui"; // icon -import { AlertCircle, ChevronDown, ChevronRight, Info, LinkIcon, MoveRight, Plus, Trash2 } from "lucide-react"; +import { + AlertCircle, + CalendarCheck2, + CalendarClock, + ChevronDown, + ChevronRight, + Info, + LinkIcon, + Plus, + Trash2, +} from "lucide-react"; // helpers import { isDateGreaterThanToday, @@ -227,7 +237,13 @@ export const ModuleDetailsSidebar: React.FC = observer((props) => { else newValues.push(value); } - updateFilters(workspaceSlug.toString(), projectId.toString(), EFilterType.FILTERS, { [key]: newValues }, moduleId); + updateFilters( + workspaceSlug.toString(), + projectId.toString(), + EFilterType.FILTERS, + { [key]: newValues }, + moduleId + ); }, [workspaceSlug, projectId, moduleId, issueFilters, updateFilters] ); @@ -328,8 +344,7 @@ export const ModuleDetailsSidebar: React.FC = observer((props) => {
-

{moduleDetails.name}

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

{moduleDetails.name}

+
-
- + {moduleDetails.description && ( + + {moduleDetails.description} + + )} + +
+
+
+ + + Start Date +
+
+ - {areYearsEqual ? renderShortDate(startDate, "_ _") : renderShortMonthDate(startDate, "_ _")} + + {areYearsEqual + ? renderShortDate(startDate, "No date selected") + : renderShortMonthDate(startDate, "No date selected")} + = observer((props) => { leaveFrom="opacity-100 translate-y-0" leaveTo="opacity-0 translate-y-1" > - + { @@ -402,16 +441,32 @@ export const ModuleDetailsSidebar: React.FC = observer((props) => { - - +
+
+ +
+
+ + Target Date +
+
+ <> - {areYearsEqual ? renderShortDate(endDate, "_ _") : renderShortMonthDate(endDate, "_ _")} + + {areYearsEqual + ? renderShortDate(endDate, "No date selected") + : renderShortMonthDate(endDate, "No date selected")} + = observer((props) => { leaveFrom="opacity-100 translate-y-0" leaveTo="opacity-0 translate-y-1" > - + { @@ -442,15 +497,6 @@ export const ModuleDetailsSidebar: React.FC = observer((props) => {
-
- - {moduleDetails.description && ( - - {moduleDetails.description} - - )} - -
{ > Favorites {open ? ( - + ) : ( - + )} {isAuthorizedUser && ( @@ -215,9 +215,9 @@ export const ProjectSidebarList: FC = observer(() => { > Projects {open ? ( - + ) : ( - + )} {isAuthorizedUser && ( From b2824366a851d96be4c6d8914248c64ca9b8f352 Mon Sep 17 00:00:00 2001 From: Bavisetti Narayan <72156168+NarayanBavisetti@users.noreply.github.com> Date: Wed, 27 Dec 2023 15:33:31 +0530 Subject: [PATCH 26/40] fix: external api serializer (#3259) * fix: passed workspace id and project id as context * fix: issue activity --- apiserver/plane/api/serializers/issue.py | 4 ++-- apiserver/plane/api/serializers/module.py | 14 +++++++------- apiserver/plane/api/views/issue.py | 11 ++++++++++- apiserver/plane/api/views/module.py | 6 +++--- 4 files changed, 22 insertions(+), 13 deletions(-) diff --git a/apiserver/plane/api/serializers/issue.py b/apiserver/plane/api/serializers/issue.py index ab61ae523..75396e9bb 100644 --- a/apiserver/plane/api/serializers/issue.py +++ b/apiserver/plane/api/serializers/issue.py @@ -96,7 +96,7 @@ class IssueSerializer(BaseSerializer): if ( data.get("state") and not State.objects.filter( - project_id=self.context.get("project_id"), pk=data.get("state") + project_id=self.context.get("project_id"), pk=data.get("state").id ).exists() ): raise serializers.ValidationError( @@ -107,7 +107,7 @@ class IssueSerializer(BaseSerializer): if ( data.get("parent") and not Issue.objects.filter( - workspace_id=self.context.get("workspace_id"), pk=data.get("parent") + workspace_id=self.context.get("workspace_id"), pk=data.get("parent").id ).exists() ): raise serializers.ValidationError( diff --git a/apiserver/plane/api/serializers/module.py b/apiserver/plane/api/serializers/module.py index 65710e8af..a96a9b54d 100644 --- a/apiserver/plane/api/serializers/module.py +++ b/apiserver/plane/api/serializers/module.py @@ -65,18 +65,18 @@ class ModuleSerializer(BaseSerializer): def create(self, validated_data): members = validated_data.pop("members", None) - project = self.context["project"] - - module = Module.objects.create(**validated_data, project=project) + project_id = self.context["project_id"] + workspace_id = self.context["workspace_id"] + module = Module.objects.create(**validated_data, project_id=project_id) if members is not None: ModuleMember.objects.bulk_create( [ ModuleMember( module=module, - member=member, - project=project, - workspace=project.workspace, + member_id=str(member), + project_id=project_id, + workspace_id=workspace_id, created_by=module.created_by, updated_by=module.updated_by, ) @@ -97,7 +97,7 @@ class ModuleSerializer(BaseSerializer): [ ModuleMember( module=instance, - member=member, + member_id=str(member), project=instance.project, workspace=instance.project.workspace, created_by=instance.created_by, diff --git a/apiserver/plane/api/views/issue.py b/apiserver/plane/api/views/issue.py index 41745010f..1ac8ddcff 100644 --- a/apiserver/plane/api/views/issue.py +++ b/apiserver/plane/api/views/issue.py @@ -221,11 +221,20 @@ class IssueAPIEndpoint(WebhookMixin, BaseAPIView): def patch(self, request, slug, project_id, pk=None): issue = Issue.objects.get(workspace__slug=slug, project_id=project_id, pk=pk) + project = Project.objects.get(pk=project_id) current_instance = json.dumps( IssueSerializer(issue).data, cls=DjangoJSONEncoder ) requested_data = json.dumps(self.request.data, cls=DjangoJSONEncoder) - serializer = IssueSerializer(issue, data=request.data, partial=True) + serializer = IssueSerializer( + issue, + data=request.data, + context={ + "project_id": project_id, + "workspace_id": project.workspace_id, + }, + partial=True, + ) if serializer.is_valid(): serializer.save() issue_activity.delay( diff --git a/apiserver/plane/api/views/module.py b/apiserver/plane/api/views/module.py index 221c7f31b..959b7ccc3 100644 --- a/apiserver/plane/api/views/module.py +++ b/apiserver/plane/api/views/module.py @@ -121,8 +121,8 @@ class ModuleAPIEndpoint(WebhookMixin, BaseAPIView): ) def post(self, request, slug, project_id): - project = Project.objects.get(workspace__slug=slug, pk=project_id) - serializer = ModuleSerializer(data=request.data, context={"project": project}) + project = Project.objects.get(pk=project_id, workspace__slug=slug) + serializer = ModuleSerializer(data=request.data, context={"project_id": project_id, "workspace_id": project.workspace_id}) if serializer.is_valid(): serializer.save() module = Module.objects.get(pk=serializer.data["id"]) @@ -132,7 +132,7 @@ class ModuleAPIEndpoint(WebhookMixin, BaseAPIView): def patch(self, request, slug, project_id, pk): module = Module.objects.get(pk=pk, project_id=project_id, workspace__slug=slug) - serializer = ModuleSerializer(module, data=request.data) + serializer = ModuleSerializer(module, data=request.data, context={"project_id": project_id}, partial=True) if serializer.is_valid(): serializer.save() return Response(serializer.data, status=status.HTTP_201_CREATED) From 78428fb564addcf514190de81cd5a0d15efee16a Mon Sep 17 00:00:00 2001 From: Bavisetti Narayan <72156168+NarayanBavisetti@users.noreply.github.com> Date: Wed, 27 Dec 2023 15:35:15 +0530 Subject: [PATCH 27/40] chore: estimates and issue parent id fixes (#3188) * chore: validations and bug fixes * chore: estimate point character limit validation --------- Co-authored-by: LAKHAN BAHETI --- apiserver/plane/app/serializers/estimate.py | 10 +++++++ apiserver/plane/app/views/estimate.py | 8 +++--- apiserver/plane/app/views/search.py | 3 ++- .../plane/bgtasks/issue_activites_task.py | 4 +-- .../create-update-estimate-modal.tsx | 26 +++++++++++++++++-- 5 files changed, 42 insertions(+), 9 deletions(-) diff --git a/apiserver/plane/app/serializers/estimate.py b/apiserver/plane/app/serializers/estimate.py index 4a1cda779..2c2f26e4e 100644 --- a/apiserver/plane/app/serializers/estimate.py +++ b/apiserver/plane/app/serializers/estimate.py @@ -4,6 +4,7 @@ from .base import BaseSerializer from plane.db.models import Estimate, EstimatePoint from plane.app.serializers import WorkspaceLiteSerializer, ProjectLiteSerializer +from rest_framework import serializers class EstimateSerializer(BaseSerializer): workspace_detail = WorkspaceLiteSerializer(read_only=True, source="workspace") @@ -19,6 +20,15 @@ class EstimateSerializer(BaseSerializer): class EstimatePointSerializer(BaseSerializer): + + def validate(self, data): + if not data: + raise serializers.ValidationError("Estimate points are required") + value = data.get("value") + if value and len(value) > 20: + raise serializers.ValidationError("Value can't be more than 20 characters") + return data + class Meta: model = EstimatePoint fields = "__all__" diff --git a/apiserver/plane/app/views/estimate.py b/apiserver/plane/app/views/estimate.py index ec9393f5b..8f14b230b 100644 --- a/apiserver/plane/app/views/estimate.py +++ b/apiserver/plane/app/views/estimate.py @@ -53,11 +53,11 @@ class BulkEstimatePointEndpoint(BaseViewSet): ) estimate_points = request.data.get("estimate_points", []) - - if not len(estimate_points) or len(estimate_points) > 8: + + serializer = EstimatePointSerializer(data=request.data.get("estimate_points"), many=True) + if not serializer.is_valid(): return Response( - {"error": "Estimate points are required"}, - status=status.HTTP_400_BAD_REQUEST, + serializer.errors, status=status.HTTP_400_BAD_REQUEST ) estimate_serializer = EstimateSerializer(data=request.data.get("estimate")) diff --git a/apiserver/plane/app/views/search.py b/apiserver/plane/app/views/search.py index ac560643a..4ecb71127 100644 --- a/apiserver/plane/app/views/search.py +++ b/apiserver/plane/app/views/search.py @@ -50,7 +50,8 @@ class GlobalSearchEndpoint(BaseAPIView): q = Q() for field in fields: if field == "sequence_id": - sequences = re.findall(r"\d+\.\d+|\d+", query) + # Match whole integers only (exclude decimal numbers) + sequences = re.findall(r"\b\d+\b", query) for sequence_id in sequences: q |= Q(**{"sequence_id": sequence_id}) else: diff --git a/apiserver/plane/bgtasks/issue_activites_task.py b/apiserver/plane/bgtasks/issue_activites_task.py index 3b2b40223..5d4c0650c 100644 --- a/apiserver/plane/bgtasks/issue_activites_task.py +++ b/apiserver/plane/bgtasks/issue_activites_task.py @@ -112,8 +112,8 @@ def track_parent( epoch, ): if current_instance.get("parent") != requested_data.get("parent"): - old_parent = Issue.objects.filter(pk=current_instance.get("parent")).first() - new_parent = Issue.objects.filter(pk=requested_data.get("parent")).first() + old_parent = Issue.objects.filter(pk=current_instance.get("parent")).first() if current_instance.get("parent") is not None else None + new_parent = Issue.objects.filter(pk=requested_data.get("parent")).first() if requested_data.get("parent") is not None else None issue_activities.append( IssueActivity( diff --git a/web/components/estimates/create-update-estimate-modal.tsx b/web/components/estimates/create-update-estimate-modal.tsx index 6f0f98e86..b24172688 100644 --- a/web/components/estimates/create-update-estimate-modal.tsx +++ b/web/components/estimates/create-update-estimate-modal.tsx @@ -129,6 +129,22 @@ export const CreateUpdateEstimateModal: React.FC = observer((props) => { return; } + if ( + formData.value1.length > 20 || + formData.value2.length > 20 || + formData.value3.length > 20 || + formData.value4.length > 20 || + formData.value5.length > 20 || + formData.value6.length > 20 + ) { + setToastAlert({ + type: "error", + title: "Error!", + message: "Estimate point cannot have more than 20 characters.", + }); + return; + } + if ( checkDuplicates([ formData.value1, @@ -269,6 +285,12 @@ export const CreateUpdateEstimateModal: React.FC = observer((props) => { ( = observer((props) => { ? "Updating Estimate..." : "Update Estimate" : isSubmitting - ? "Creating Estimate..." - : "Create Estimate"} + ? "Creating Estimate..." + : "Create Estimate"}
From 54964924f0762344f387cf2bfa722870519ee926 Mon Sep 17 00:00:00 2001 From: sriram veeraghanta Date: Wed, 27 Dec 2023 16:15:56 +0530 Subject: [PATCH 28/40] fix: adding links to dashboard summary items --- web/components/workspace/issues-stats.tsx | 86 +++++++++-------------- 1 file changed, 33 insertions(+), 53 deletions(-) diff --git a/web/components/workspace/issues-stats.tsx b/web/components/workspace/issues-stats.tsx index 1fa5cf2df..b8cc8432f 100644 --- a/web/components/workspace/issues-stats.tsx +++ b/web/components/workspace/issues-stats.tsx @@ -7,6 +7,7 @@ import { Info } from "lucide-react"; // types import { IUserWorkspaceDashboard } from "types"; import { useRouter } from "next/router"; +import Link from "next/link"; type Props = { data: IUserWorkspaceDashboard | undefined; @@ -19,61 +20,40 @@ export const IssuesStats: React.FC = ({ data }) => {
-
-

Issues assigned to you

-
- {data ? ( -
router.push(`/${workspaceSlug}/workspace-views/assigned`)} - > - {data.assigned_issues_count} -
- ) : ( - - - - )} -
-
-
-

Pending issues

-
- {data ? ( - data.pending_issues_count - ) : ( - - - - )} -
-
+ +
+

Issues assigned to you

+
+
{data?.assigned_issues_count}
+
+
+ + +
+

Pending issues

+
{data?.pending_issues_count}
+
+
-
-

Completed issues

-
- {data ? ( - data.completed_issues_count - ) : ( - - - - )} -
-
-
-

Issues due by this week

-
- {data ? ( - data.issues_due_week_count - ) : ( - - - - )} -
-
+ +
+

Completed issues

+
{data?.completed_issues_count}
+
+ + +
+

Issues due by this week

+
{data?.issues_due_week_count}
+
+
From 10bdcc906c51811b0d5ac2c71031565139631080 Mon Sep 17 00:00:00 2001 From: sriram veeraghanta Date: Wed, 27 Dec 2023 16:35:43 +0530 Subject: [PATCH 29/40] fix: adding links to workspace sidebar dropdown --- web/components/workspace/sidebar-dropdown.tsx | 58 ++++++++++--------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/web/components/workspace/sidebar-dropdown.tsx b/web/components/workspace/sidebar-dropdown.tsx index 8d1cfa27d..cc3c878e4 100644 --- a/web/components/workspace/sidebar-dropdown.tsx +++ b/web/components/workspace/sidebar-dropdown.tsx @@ -16,7 +16,7 @@ import { Avatar, Loader } from "@plane/ui"; import { IWorkspace } from "types"; // Static Data -const userLinks = (workspaceSlug: string, userId: string) => [ +const WORKSPACE_DROPDOWN_ITEMS = (workspaceSlug: string, userId: string) => [ { name: "Workspace Settings", href: `/${workspaceSlug}/settings`, @@ -155,8 +155,8 @@ export const WorkspaceSidebarDropdown = observer(() => { workspaces.map((workspace: IWorkspace) => ( {() => ( - + )} )) @@ -198,17 +198,19 @@ export const WorkspaceSidebarDropdown = observer(() => {

No workspace found!

)}
- { - setTrackElement("APP_SIEDEBAR_WORKSPACE_DROPDOWN"); - router.push("/create-workspace"); - }} - className="flex w-full items-center gap-2 px-2 py-1 text-sm text-custom-sidebar-text-200 hover:bg-custom-sidebar-background-80" - > - - Create Workspace + + {() => ( + { + setTrackElement("APP_SIEDEBAR_WORKSPACE_DROPDOWN"); + }} + > + + Create Workspace + + )}
@@ -222,18 +224,20 @@ export const WorkspaceSidebarDropdown = observer(() => { )}
- {userLinks(workspaceSlug?.toString() ?? "", currentUser?.id ?? "").map((link, index) => ( - { - router.push(link.href); - }} - className="flex w-full cursor-pointer items-center justify-start rounded px-2 py-1 text-sm text-custom-sidebar-text-200 hover:bg-custom-sidebar-background-80" - > - {link.name} - - ))} + {WORKSPACE_DROPDOWN_ITEMS(workspaceSlug?.toString() ?? "", currentUser?.id ?? "").map( + (link, index) => ( + + {() => ( + + {link.name} + + )} + + ) + )}
Date: Thu, 28 Dec 2023 11:54:16 +0530 Subject: [PATCH 30/40] fix: adding links to the sidebar --- web/components/project/sidebar-list-item.tsx | 43 ++++++++++---------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/web/components/project/sidebar-list-item.tsx b/web/components/project/sidebar-list-item.tsx index 4ed1bf2c4..56cc6130d 100644 --- a/web/components/project/sidebar-list-item.tsx +++ b/web/components/project/sidebar-list-item.tsx @@ -253,32 +253,31 @@ export const ProjectSidebarListItem: React.FC = observer((props) => { )} {project.archive_in > 0 && ( - router.push(`/${workspaceSlug}/projects/${project?.id}/archived-issues/`)} - > -
- - Archived Issues -
+ + +
+ + Archived Issues +
+
)} - router.push(`/${workspaceSlug}/projects/${project?.id}/draft-issues`)} - > -
- - Draft Issues -
+ + +
+ + Draft Issues +
+
- router.push(`/${workspaceSlug}/projects/${project?.id}/settings`)} - > -
- - Settings -
+ + +
+ + Settings +
+
- {/* leave project */} {isViewerOrGuest && ( From 685e62a72f5a5f40d279ac785525cf26d49e03e8 Mon Sep 17 00:00:00 2001 From: sriram veeraghanta Date: Thu, 28 Dec 2023 14:29:20 +0530 Subject: [PATCH 31/40] fix: replacing onclick redirections with link tag. (#3263) * fix: adding links to dashboard summary items * fix: adding links to workspace sidebar dropdown * fix: adding links to the sidebar --- web/components/project/sidebar-list-item.tsx | 43 +++++----- web/components/workspace/issues-stats.tsx | 86 +++++++------------ web/components/workspace/sidebar-dropdown.tsx | 58 +++++++------ 3 files changed, 85 insertions(+), 102 deletions(-) diff --git a/web/components/project/sidebar-list-item.tsx b/web/components/project/sidebar-list-item.tsx index 4ed1bf2c4..56cc6130d 100644 --- a/web/components/project/sidebar-list-item.tsx +++ b/web/components/project/sidebar-list-item.tsx @@ -253,32 +253,31 @@ export const ProjectSidebarListItem: React.FC = observer((props) => { )} {project.archive_in > 0 && ( - router.push(`/${workspaceSlug}/projects/${project?.id}/archived-issues/`)} - > -
- - Archived Issues -
+ + +
+ + Archived Issues +
+
)} - router.push(`/${workspaceSlug}/projects/${project?.id}/draft-issues`)} - > -
- - Draft Issues -
+ + +
+ + Draft Issues +
+
- router.push(`/${workspaceSlug}/projects/${project?.id}/settings`)} - > -
- - Settings -
+ + +
+ + Settings +
+
- {/* leave project */} {isViewerOrGuest && ( diff --git a/web/components/workspace/issues-stats.tsx b/web/components/workspace/issues-stats.tsx index 1fa5cf2df..b8cc8432f 100644 --- a/web/components/workspace/issues-stats.tsx +++ b/web/components/workspace/issues-stats.tsx @@ -7,6 +7,7 @@ import { Info } from "lucide-react"; // types import { IUserWorkspaceDashboard } from "types"; import { useRouter } from "next/router"; +import Link from "next/link"; type Props = { data: IUserWorkspaceDashboard | undefined; @@ -19,61 +20,40 @@ export const IssuesStats: React.FC = ({ data }) => {
-
-

Issues assigned to you

-
- {data ? ( -
router.push(`/${workspaceSlug}/workspace-views/assigned`)} - > - {data.assigned_issues_count} -
- ) : ( - - - - )} -
-
-
-

Pending issues

-
- {data ? ( - data.pending_issues_count - ) : ( - - - - )} -
-
+ +
+

Issues assigned to you

+
+
{data?.assigned_issues_count}
+
+
+ + +
+

Pending issues

+
{data?.pending_issues_count}
+
+
-
-

Completed issues

-
- {data ? ( - data.completed_issues_count - ) : ( - - - - )} -
-
-
-

Issues due by this week

-
- {data ? ( - data.issues_due_week_count - ) : ( - - - - )} -
-
+ +
+

Completed issues

+
{data?.completed_issues_count}
+
+ + +
+

Issues due by this week

+
{data?.issues_due_week_count}
+
+
diff --git a/web/components/workspace/sidebar-dropdown.tsx b/web/components/workspace/sidebar-dropdown.tsx index 8d1cfa27d..cc3c878e4 100644 --- a/web/components/workspace/sidebar-dropdown.tsx +++ b/web/components/workspace/sidebar-dropdown.tsx @@ -16,7 +16,7 @@ import { Avatar, Loader } from "@plane/ui"; import { IWorkspace } from "types"; // Static Data -const userLinks = (workspaceSlug: string, userId: string) => [ +const WORKSPACE_DROPDOWN_ITEMS = (workspaceSlug: string, userId: string) => [ { name: "Workspace Settings", href: `/${workspaceSlug}/settings`, @@ -155,8 +155,8 @@ export const WorkspaceSidebarDropdown = observer(() => { workspaces.map((workspace: IWorkspace) => ( {() => ( - + )} )) @@ -198,17 +198,19 @@ export const WorkspaceSidebarDropdown = observer(() => {

No workspace found!

)}
- { - setTrackElement("APP_SIEDEBAR_WORKSPACE_DROPDOWN"); - router.push("/create-workspace"); - }} - className="flex w-full items-center gap-2 px-2 py-1 text-sm text-custom-sidebar-text-200 hover:bg-custom-sidebar-background-80" - > - - Create Workspace + + {() => ( + { + setTrackElement("APP_SIEDEBAR_WORKSPACE_DROPDOWN"); + }} + > + + Create Workspace + + )}
@@ -222,18 +224,20 @@ export const WorkspaceSidebarDropdown = observer(() => { )}
- {userLinks(workspaceSlug?.toString() ?? "", currentUser?.id ?? "").map((link, index) => ( - { - router.push(link.href); - }} - className="flex w-full cursor-pointer items-center justify-start rounded px-2 py-1 text-sm text-custom-sidebar-text-200 hover:bg-custom-sidebar-background-80" - > - {link.name} - - ))} + {WORKSPACE_DROPDOWN_ITEMS(workspaceSlug?.toString() ?? "", currentUser?.id ?? "").map( + (link, index) => ( + + {() => ( + + {link.name} + + )} + + ) + )}
Date: Thu, 28 Dec 2023 14:30:33 +0530 Subject: [PATCH 32/40] Style/UI improvements (#3269) * style: update `Workspace Issues` -> `All Issues` header. * style: fix issue activity text overflow issue. --- web/components/headers/global-issues.tsx | 2 +- web/components/issues/peek-overview/activity/card.tsx | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/web/components/headers/global-issues.tsx b/web/components/headers/global-issues.tsx index ef4c2b3f5..0b27bdd81 100644 --- a/web/components/headers/global-issues.tsx +++ b/web/components/headers/global-issues.tsx @@ -95,7 +95,7 @@ export const GlobalIssuesHeader: React.FC = observer((props) => { ) } - label={`Workspace ${activeLayout === "spreadsheet" ? "Issues" : "Views"}`} + label={`All ${activeLayout === "spreadsheet" ? "Issues" : "Views"}`} />
diff --git a/web/components/issues/peek-overview/activity/card.tsx b/web/components/issues/peek-overview/activity/card.tsx index b8acb63d9..86d1a138c 100644 --- a/web/components/issues/peek-overview/activity/card.tsx +++ b/web/components/issues/peek-overview/activity/card.tsx @@ -88,7 +88,7 @@ export const IssueActivityCard: FC = (props) => {
-
+
{activityItem.field === "archived_at" && activityItem.new_value !== "restore" ? ( Plane ) : activityItem.actor_detail.is_bot ? ( @@ -101,8 +101,8 @@ export const IssueActivityCard: FC = (props) => { : activityItem.actor_detail.display_name} - )}{" "} - {message}{" "} + )} + {message} Date: Thu, 28 Dec 2023 17:17:04 +0530 Subject: [PATCH 33/40] fix: onboarding redirection loop and bug fixes (#3250) * chore: try and catch added in handleSignInRedirection * chore: remove unnecessary hooks * fix: handleCopyIssueLink url updated * chore: swap next_url with next_path and validate redirection logic for next_path url --- .../auth-screens/not-authorized-view.tsx | 7 ++- .../quick-action-dropdowns/archived-issue.tsx | 2 +- .../quick-action-dropdowns/cycle-issue.tsx | 2 +- .../quick-action-dropdowns/module-issue.tsx | 2 +- .../quick-action-dropdowns/project-issue.tsx | 2 +- web/hooks/use-sign-in-redirection.ts | 60 ++++++++++++------- web/hooks/use-user-auth.tsx | 20 +++++-- web/hooks/use-user.tsx | 2 +- web/layouts/auth-layout/user-wrapper.tsx | 2 +- web/pages/onboarding/index.tsx | 12 ++-- 10 files changed, 69 insertions(+), 42 deletions(-) diff --git a/web/components/auth-screens/not-authorized-view.tsx b/web/components/auth-screens/not-authorized-view.tsx index 353bb8fce..f0a3e3d90 100644 --- a/web/components/auth-screens/not-authorized-view.tsx +++ b/web/components/auth-screens/not-authorized-view.tsx @@ -18,7 +18,8 @@ type Props = { export const NotAuthorizedView: React.FC = ({ actionButton, type }) => { const { user } = useUser(); - const { asPath: currentPath } = useRouter(); + const { query } = useRouter(); + const { next_path } = query; return ( @@ -37,7 +38,7 @@ export const NotAuthorizedView: React.FC = ({ actionButton, type }) => { {user ? (

You have signed in as {user.email}.
- + Sign in {" "} with different account that has access to this page. @@ -45,7 +46,7 @@ export const NotAuthorizedView: React.FC = ({ actionButton, type }) => { ) : (

You need to{" "} - + Sign in {" "} with an account that has access to this page. diff --git a/web/components/issues/issue-layouts/quick-action-dropdowns/archived-issue.tsx b/web/components/issues/issue-layouts/quick-action-dropdowns/archived-issue.tsx index 07631a7de..133cce1f9 100644 --- a/web/components/issues/issue-layouts/quick-action-dropdowns/archived-issue.tsx +++ b/web/components/issues/issue-layouts/quick-action-dropdowns/archived-issue.tsx @@ -23,7 +23,7 @@ export const ArchivedIssueQuickActions: React.FC = (props) => const { setToastAlert } = useToast(); const handleCopyIssueLink = () => { - copyUrlToClipboard(`/${workspaceSlug}/projects/${issue.project}/archived-issues/${issue.id}`).then(() => + copyUrlToClipboard(`${workspaceSlug}/projects/${issue.project}/archived-issues/${issue.id}`).then(() => setToastAlert({ type: "success", title: "Link copied", diff --git a/web/components/issues/issue-layouts/quick-action-dropdowns/cycle-issue.tsx b/web/components/issues/issue-layouts/quick-action-dropdowns/cycle-issue.tsx index 5faace440..af018a652 100644 --- a/web/components/issues/issue-layouts/quick-action-dropdowns/cycle-issue.tsx +++ b/web/components/issues/issue-layouts/quick-action-dropdowns/cycle-issue.tsx @@ -27,7 +27,7 @@ export const CycleIssueQuickActions: React.FC = (props) => { const { setToastAlert } = useToast(); const handleCopyIssueLink = () => { - copyUrlToClipboard(`/${workspaceSlug}/projects/${issue.project}/issues/${issue.id}`).then(() => + copyUrlToClipboard(`${workspaceSlug}/projects/${issue.project}/issues/${issue.id}`).then(() => setToastAlert({ type: "success", title: "Link copied", diff --git a/web/components/issues/issue-layouts/quick-action-dropdowns/module-issue.tsx b/web/components/issues/issue-layouts/quick-action-dropdowns/module-issue.tsx index 7bd35e321..0ad1f610b 100644 --- a/web/components/issues/issue-layouts/quick-action-dropdowns/module-issue.tsx +++ b/web/components/issues/issue-layouts/quick-action-dropdowns/module-issue.tsx @@ -27,7 +27,7 @@ export const ModuleIssueQuickActions: React.FC = (props) => { const { setToastAlert } = useToast(); const handleCopyIssueLink = () => { - copyUrlToClipboard(`/${workspaceSlug}/projects/${issue.project}/issues/${issue.id}`).then(() => + copyUrlToClipboard(`${workspaceSlug}/projects/${issue.project}/issues/${issue.id}`).then(() => setToastAlert({ type: "success", title: "Link copied", diff --git a/web/components/issues/issue-layouts/quick-action-dropdowns/project-issue.tsx b/web/components/issues/issue-layouts/quick-action-dropdowns/project-issue.tsx index 0f4fe28ce..12438b2a3 100644 --- a/web/components/issues/issue-layouts/quick-action-dropdowns/project-issue.tsx +++ b/web/components/issues/issue-layouts/quick-action-dropdowns/project-issue.tsx @@ -37,7 +37,7 @@ export const ProjectIssueQuickActions: React.FC = (props) => const { setToastAlert } = useToast(); const handleCopyIssueLink = () => { - copyUrlToClipboard(`/${workspaceSlug}/projects/${issue.project}/issues/${issue.id}`).then(() => + copyUrlToClipboard(`${workspaceSlug}/projects/${issue.project}/issues/${issue.id}`).then(() => setToastAlert({ type: "success", title: "Link copied", diff --git a/web/hooks/use-sign-in-redirection.ts b/web/hooks/use-sign-in-redirection.ts index 1863e510e..25d4e8bbd 100644 --- a/web/hooks/use-sign-in-redirection.ts +++ b/web/hooks/use-sign-in-redirection.ts @@ -17,36 +17,54 @@ const useSignInRedirection = (): UseSignInRedirectionProps => { const [error, setError] = useState(null); // router const router = useRouter(); - const { next_url } = router.query; + const { next_path } = router.query; // mobx store const { user: { fetchCurrentUser, fetchCurrentUserSettings }, } = useMobxStore(); + const isValidURL = (url: string): boolean => { + const disallowedSchemes = /^(https?|ftp):\/\//i; + return !disallowedSchemes.test(url); + }; + + console.log("next_path", next_path); + const handleSignInRedirection = useCallback( async (user: IUser) => { - // if the user is not onboarded, redirect them to the onboarding page - if (!user.is_onboarded) { - router.push("/onboarding"); - return; - } - // if next_url is provided, redirect the user to that url - if (next_url) { - router.push(next_url.toString()); - return; - } + try { + // if the user is not onboarded, redirect them to the onboarding page + if (!user.is_onboarded) { + router.push("/onboarding"); + return; + } + // if next_path is provided, redirect the user to that url + if (next_path) { + if (isValidURL(next_path.toString())) { + router.push(next_path.toString()); + return; + } else { + router.push("/"); + return; + } + } - // if the user is onboarded, fetch their last workspace details - await fetchCurrentUserSettings() - .then((userSettings: IUserSettings) => { - const workspaceSlug = - userSettings?.workspace?.last_workspace_slug || userSettings?.workspace?.fallback_workspace_slug; - if (workspaceSlug) router.push(`/${workspaceSlug}`); - else router.push("/profile"); - }) - .catch((err) => setError(err)); + // Fetch the current user settings + const userSettings: IUserSettings = await fetchCurrentUserSettings(); + + // Extract workspace details + const workspaceSlug = + userSettings?.workspace?.last_workspace_slug || userSettings?.workspace?.fallback_workspace_slug; + + // Redirect based on workspace details or to profile if not available + if (workspaceSlug) router.push(`/${workspaceSlug}`); + else router.push("/profile"); + } catch (error) { + console.error("Error in handleSignInRedirection:", error); + setError(error); + } }, - [fetchCurrentUserSettings, router, next_url] + [fetchCurrentUserSettings, router, next_path] ); const updateUserInfo = useCallback(async () => { diff --git a/web/hooks/use-user-auth.tsx b/web/hooks/use-user-auth.tsx index 882c0b713..8290a4545 100644 --- a/web/hooks/use-user-auth.tsx +++ b/web/hooks/use-user-auth.tsx @@ -12,7 +12,7 @@ const workspaceService = new WorkspaceService(); const useUserAuth = (routeAuth: "sign-in" | "onboarding" | "admin" | null = "admin") => { const router = useRouter(); - const { next_url } = router.query; + const { next_path } = router.query; const [isRouteAccess, setIsRouteAccess] = useState(true); const { @@ -29,6 +29,11 @@ const useUserAuth = (routeAuth: "sign-in" | "onboarding" | "admin" | null = "adm shouldRetryOnError: false, }); + const isValidURL = (url: string): boolean => { + const disallowedSchemes = /^(https?|ftp):\/\//i; + return !disallowedSchemes.test(url); + }; + useEffect(() => { const handleWorkSpaceRedirection = async () => { workspaceService.userWorkspaces().then(async (userWorkspaces) => { @@ -84,8 +89,15 @@ const useUserAuth = (routeAuth: "sign-in" | "onboarding" | "admin" | null = "adm if (!isLoading) { setIsRouteAccess(() => true); if (user) { - if (next_url) router.push(next_url.toString()); - else handleUserRouteAuthentication(); + if (next_path) { + if (isValidURL(next_path.toString())) { + router.push(next_path.toString()); + return; + } else { + router.push("/"); + return; + } + } else handleUserRouteAuthentication(); } else { if (routeAuth === "sign-in") { setIsRouteAccess(() => false); @@ -97,7 +109,7 @@ const useUserAuth = (routeAuth: "sign-in" | "onboarding" | "admin" | null = "adm } } } - }, [user, isLoading, routeAuth, router, next_url]); + }, [user, isLoading, routeAuth, router, next_path]); return { isLoading: isRouteAccess, diff --git a/web/hooks/use-user.tsx b/web/hooks/use-user.tsx index 97518fed6..2203faaa2 100644 --- a/web/hooks/use-user.tsx +++ b/web/hooks/use-user.tsx @@ -31,7 +31,7 @@ export default function useUser({ redirectTo = "", redirectIfFound = false, opti ) { router.push(redirectTo); return; - // const nextLocation = router.asPath.split("?next=")[1]; + // const nextLocation = router.asPath.split("?next_path=")[1]; // if (nextLocation) { // router.push(nextLocation as string); // return; diff --git a/web/layouts/auth-layout/user-wrapper.tsx b/web/layouts/auth-layout/user-wrapper.tsx index 50b17fdb7..ccc30a382 100644 --- a/web/layouts/auth-layout/user-wrapper.tsx +++ b/web/layouts/auth-layout/user-wrapper.tsx @@ -56,7 +56,7 @@ export const UserAuthWrapper: FC = observer((props) => { if (currentUserError) { const redirectTo = router.asPath; - router.push(`/?next=${redirectTo}`); + router.push(`/?next_path=${redirectTo}`); return null; } diff --git a/web/pages/onboarding/index.tsx b/web/pages/onboarding/index.tsx index f6df0c4fc..e695b1f4c 100644 --- a/web/pages/onboarding/index.tsx +++ b/web/pages/onboarding/index.tsx @@ -11,8 +11,6 @@ import { Controller, useForm } from "react-hook-form"; import { useMobxStore } from "lib/mobx/store-provider"; // services import { WorkspaceService } from "services/workspace.service"; -// hooks -import useUserAuth from "hooks/use-user-auth"; // layouts import DefaultLayout from "layouts/default-layout"; import { UserAuthWrapper } from "layouts/auth-layout"; @@ -45,8 +43,6 @@ const OnboardingPage: NextPageWithLayout = observer(() => { const { setTheme } = useTheme(); - const {} = useUserAuth("onboarding"); - const { control, setValue } = useForm<{ full_name: string }>({ defaultValues: { full_name: "", @@ -158,8 +154,8 @@ const OnboardingPage: NextPageWithLayout = observer(() => { currentUser?.first_name ? `${currentUser?.first_name} ${currentUser?.last_name ?? ""}` : value.length > 0 - ? value - : currentUser?.email + ? value + : currentUser?.email } src={currentUser?.avatar} size={35} @@ -174,8 +170,8 @@ const OnboardingPage: NextPageWithLayout = observer(() => { {currentUser?.first_name ? `${currentUser?.first_name} ${currentUser?.last_name ?? ""}` : value.length > 0 - ? value - : null} + ? value + : null}

)} From 62b9b259c03a994c08e88457b26ceb956152f563 Mon Sep 17 00:00:00 2001 From: sriram veeraghanta Date: Thu, 28 Dec 2023 18:53:06 +0530 Subject: [PATCH 34/40] fix: adding issue title to the activity (#3271) --- web/components/core/activity.tsx | 15 ++------------- web/components/profile/overview/activity.tsx | 8 ++------ 2 files changed, 4 insertions(+), 19 deletions(-) diff --git a/web/components/core/activity.tsx b/web/components/core/activity.tsx index 37f8d2626..1ac34cf73 100644 --- a/web/components/core/activity.tsx +++ b/web/components/core/activity.tsx @@ -11,7 +11,6 @@ import { CopyPlus, Calendar, Link2Icon, - RocketIcon, Users2Icon, ArchiveIcon, PaperclipIcon, @@ -48,8 +47,8 @@ const IssueLink = ({ activity }: { activity: IIssueActivity }) => { rel={activity.issue === null ? "" : "noopener noreferrer"} className="inline-flex items-center gap-1 font-medium text-custom-text-100 hover:underline" > - {activity.issue_detail ? `${activity.project_detail.identifier}-${activity.issue_detail.sequence_id}` : "Issue"} - + {activity.issue_detail ? `${activity.project_detail.identifier}-${activity.issue_detail.sequence_id}` : "Issue"}{" "} + {activity.issue_detail?.name}
); @@ -163,7 +162,6 @@ const activityDetails: { className="inline-flex items-center gap-1 font-medium text-custom-text-100 hover:underline" > attachment - {showIssue && ( <> @@ -239,7 +237,6 @@ const activityDetails: { className="inline-flex items-center gap-1 truncate font-medium text-custom-text-100 hover:underline" > {activity.new_value} - ); @@ -254,7 +251,6 @@ const activityDetails: { className="inline-flex items-center gap-1 truncate font-medium text-custom-text-100 hover:underline" > {activity.new_value} - ); @@ -269,7 +265,6 @@ const activityDetails: { className="inline-flex items-center gap-1 truncate font-medium text-custom-text-100 hover:underline" > {activity.old_value} - ); @@ -398,7 +393,6 @@ const activityDetails: { className="inline-flex items-center gap-1 font-medium text-custom-text-100 hover:underline" > link - {showIssue && ( <> @@ -420,7 +414,6 @@ const activityDetails: { className="inline-flex items-center gap-1 font-medium text-custom-text-100 hover:underline" > link - {showIssue && ( <> @@ -442,7 +435,6 @@ const activityDetails: { className="inline-flex items-center gap-1 font-medium text-custom-text-100 hover:underline" > link - {showIssue && ( <> @@ -469,7 +461,6 @@ const activityDetails: { className="inline-flex items-center gap-1 truncate font-medium text-custom-text-100 hover:underline" > {activity.new_value} - ); @@ -484,7 +475,6 @@ const activityDetails: { className="inline-flex items-center gap-1 truncate font-medium text-custom-text-100 hover:underline" > {activity.new_value} - ); @@ -499,7 +489,6 @@ const activityDetails: { className="inline-flex items-center gap-1 truncate font-medium text-custom-text-100 hover:underline" > {activity.old_value} - ); diff --git a/web/components/profile/overview/activity.tsx b/web/components/profile/overview/activity.tsx index 1bba6a25f..9512a98f2 100644 --- a/web/components/profile/overview/activity.tsx +++ b/web/components/profile/overview/activity.tsx @@ -1,7 +1,5 @@ import { useRouter } from "next/router"; - import useSWR from "swr"; - // services import { UserService } from "services/user.service"; // components @@ -9,7 +7,6 @@ import { ActivityMessage } from "components/core"; // ui import { ProfileEmptyState } from "components/ui"; import { Loader } from "@plane/ui"; -import { Rocket } from "lucide-react"; // image import recentActivityEmptyState from "public/empty-state/recent_activity.svg"; // helpers @@ -67,10 +64,9 @@ export const ProfileActivity = () => { href={`/${workspaceSlug}/projects/${activity.project}/issues/${activity.issue}`} target="_blank" rel="noopener noreferrer" - className="inline-flex items-center gap-1 font-medium text-custom-text-100 hover:underline" + className="inline-flex items-center gap-1 font-medium text-custom-text-200 hover:underline" > - Issue - + Issue. )} From 1d5a3a02c14b7397f1b3cffbd7d556e49d358093 Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com> Date: Fri, 29 Dec 2023 15:22:30 +0530 Subject: [PATCH 35/40] fix: issue parent select (#3267) --- .../issues/sidebar-select/parent.tsx | 45 ++++++++++--------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/web/components/issues/sidebar-select/parent.tsx b/web/components/issues/sidebar-select/parent.tsx index d0a834190..70c104141 100644 --- a/web/components/issues/sidebar-select/parent.tsx +++ b/web/components/issues/sidebar-select/parent.tsx @@ -35,31 +35,34 @@ export const SidebarParentSelect: React.FC = ({ onChange, issueDetails, p issueId={issueId as string} projectId={projectId as string} /> - - + + {issueDetails?.parent && ( + )} - {issueDetails?.parent && } - +
); }; From 10ab081a0b80a5549c7e894b4caafe9a89d5861d Mon Sep 17 00:00:00 2001 From: Bavisetti Narayan <72156168+NarayanBavisetti@users.noreply.github.com> Date: Fri, 29 Dec 2023 15:24:07 +0530 Subject: [PATCH 36/40] chore: cycle current status (#3270) * dev: cycle status * chore: cycle status logic updated --------- Co-authored-by: Anmol Singh Bhatia --- apiserver/plane/app/serializers/cycle.py | 1 + apiserver/plane/app/views/cycle.py | 34 +++++++++++++++++-- .../cycles/active-cycle-details.tsx | 4 +-- web/components/cycles/cycles-board-card.tsx | 11 ++---- web/components/cycles/cycles-list-item.tsx | 11 ++---- web/components/cycles/gantt-chart/blocks.tsx | 31 ++++++++--------- web/components/cycles/sidebar.tsx | 6 +--- .../cycles/transfer-issues-modal.tsx | 4 +-- .../issue-layouts/roots/cycle-layout-root.tsx | 7 +--- web/helpers/date-time.helper.ts | 12 ------- web/store/cycle/cycles.store.ts | 5 ++- web/types/cycles.d.ts | 3 ++ 12 files changed, 63 insertions(+), 66 deletions(-) diff --git a/apiserver/plane/app/serializers/cycle.py b/apiserver/plane/app/serializers/cycle.py index 104a3dd06..63abf3a03 100644 --- a/apiserver/plane/app/serializers/cycle.py +++ b/apiserver/plane/app/serializers/cycle.py @@ -40,6 +40,7 @@ class CycleSerializer(BaseSerializer): started_estimates = serializers.IntegerField(read_only=True) workspace_detail = WorkspaceLiteSerializer(read_only=True, source="workspace") project_detail = ProjectLiteSerializer(read_only=True, source="project") + status = serializers.CharField(read_only=True) def validate(self, data): if ( diff --git a/apiserver/plane/app/views/cycle.py b/apiserver/plane/app/views/cycle.py index d2f82d75b..02f259de3 100644 --- a/apiserver/plane/app/views/cycle.py +++ b/apiserver/plane/app/views/cycle.py @@ -11,6 +11,10 @@ from django.db.models import ( Count, Prefetch, Sum, + Case, + When, + Value, + CharField ) from django.core import serializers from django.utils import timezone @@ -157,6 +161,28 @@ class CycleViewSet(WebhookMixin, BaseViewSet): ), ) ) + .annotate( + status=Case( + When( + Q(start_date__lte=timezone.now()) & Q(end_date__gte=timezone.now()), + then=Value("CURRENT") + ), + When( + start_date__gt=timezone.now(), + then=Value("UPCOMING") + ), + When( + end_date__lt=timezone.now(), + then=Value("COMPLETED") + ), + When( + Q(start_date__isnull=True) & Q(end_date__isnull=True), + then=Value("DRAFT") + ), + default=Value("DRAFT"), + output_field=CharField(), + ) + ) .prefetch_related( Prefetch( "issue_cycle__issue__assignees", @@ -177,7 +203,7 @@ class CycleViewSet(WebhookMixin, BaseViewSet): queryset = self.get_queryset() cycle_view = request.GET.get("cycle_view", "all") - queryset = queryset.order_by("-is_favorite","-created_at") + queryset = queryset.order_by("-is_favorite", "-created_at") # Current Cycle if cycle_view == "current": @@ -575,7 +601,9 @@ class CycleIssueViewSet(WebhookMixin, BaseViewSet): ) ) - issues = IssueStateSerializer(issues, many=True, fields=fields if fields else None).data + issues = IssueStateSerializer( + issues, many=True, fields=fields if fields else None + ).data issue_dict = {str(issue["id"]): issue for issue in issues} return Response(issue_dict, status=status.HTTP_200_OK) @@ -805,4 +833,4 @@ class TransferCycleIssueEndpoint(BaseAPIView): updated_cycles, ["cycle_id"], batch_size=100 ) - return Response({"message": "Success"}, status=status.HTTP_200_OK) \ No newline at end of file + return Response({"message": "Success"}, status=status.HTTP_200_OK) diff --git a/web/components/cycles/active-cycle-details.tsx b/web/components/cycles/active-cycle-details.tsx index ea982099f..47beaa262 100644 --- a/web/components/cycles/active-cycle-details.tsx +++ b/web/components/cycles/active-cycle-details.tsx @@ -28,7 +28,7 @@ import { ViewIssueLabel } from "components/issues"; // icons import { AlarmClock, AlertTriangle, ArrowRight, CalendarDays, Star, Target } from "lucide-react"; // helpers -import { getDateRangeStatus, renderShortDateWithYearFormat, findHowManyDaysLeft } from "helpers/date-time.helper"; +import { renderShortDateWithYearFormat, findHowManyDaysLeft } from "helpers/date-time.helper"; import { truncateText } from "helpers/string.helper"; // types import { ICycle } from "types"; @@ -137,7 +137,7 @@ export const ActiveCycleDetails: React.FC = observer((props cancelled: cycle.cancelled_issues, }; - const cycleStatus = getDateRangeStatus(cycle.start_date, cycle.end_date); + const cycleStatus = cycle.status.toLocaleLowerCase(); const handleAddToFavorites = (e: MouseEvent) => { e.preventDefault(); diff --git a/web/components/cycles/cycles-board-card.tsx b/web/components/cycles/cycles-board-card.tsx index f020b0998..d43d56872 100644 --- a/web/components/cycles/cycles-board-card.tsx +++ b/web/components/cycles/cycles-board-card.tsx @@ -10,15 +10,10 @@ import { Avatar, AvatarGroup, CustomMenu, Tooltip, LayersIcon, CycleGroupIcon } // icons import { Info, LinkIcon, Pencil, Star, Trash2 } from "lucide-react"; // helpers -import { - getDateRangeStatus, - findHowManyDaysLeft, - renderShortDate, - renderShortMonthDate, -} from "helpers/date-time.helper"; +import { findHowManyDaysLeft, renderShortDate, renderShortMonthDate } from "helpers/date-time.helper"; import { copyTextToClipboard } from "helpers/string.helper"; // types -import { ICycle } from "types"; +import { ICycle, TCycleGroups } from "types"; // store import { useMobxStore } from "lib/mobx/store-provider"; // constants @@ -45,7 +40,7 @@ export const CyclesBoardCard: FC = (props) => { const [updateModal, setUpdateModal] = useState(false); const [deleteModal, setDeleteModal] = useState(false); // computed - const cycleStatus = getDateRangeStatus(cycle.start_date, cycle.end_date); + const cycleStatus = cycle.status.toLocaleLowerCase() as TCycleGroups; const isCompleted = cycleStatus === "completed"; const endDate = new Date(cycle.end_date ?? ""); const startDate = new Date(cycle.start_date ?? ""); diff --git a/web/components/cycles/cycles-list-item.tsx b/web/components/cycles/cycles-list-item.tsx index 86b3bffa9..9ea26ab39 100644 --- a/web/components/cycles/cycles-list-item.tsx +++ b/web/components/cycles/cycles-list-item.tsx @@ -13,15 +13,10 @@ import { CustomMenu, Tooltip, CircularProgressIndicator, CycleGroupIcon, AvatarG // icons import { Check, Info, LinkIcon, Pencil, Star, Trash2, User2 } from "lucide-react"; // helpers -import { - getDateRangeStatus, - findHowManyDaysLeft, - renderShortDate, - renderShortMonthDate, -} from "helpers/date-time.helper"; +import { findHowManyDaysLeft, renderShortDate, renderShortMonthDate } from "helpers/date-time.helper"; import { copyTextToClipboard } from "helpers/string.helper"; // types -import { ICycle } from "types"; +import { ICycle, TCycleGroups } from "types"; // constants import { CYCLE_STATUS } from "constants/cycle"; import { EUserWorkspaceRoles } from "constants/workspace"; @@ -50,7 +45,7 @@ export const CyclesListItem: FC = (props) => { const [updateModal, setUpdateModal] = useState(false); const [deleteModal, setDeleteModal] = useState(false); // computed - const cycleStatus = getDateRangeStatus(cycle.start_date, cycle.end_date); + const cycleStatus = cycle.status.toLocaleLowerCase() as TCycleGroups; const isCompleted = cycleStatus === "completed"; const endDate = new Date(cycle.end_date ?? ""); const startDate = new Date(cycle.start_date ?? ""); diff --git a/web/components/cycles/gantt-chart/blocks.tsx b/web/components/cycles/gantt-chart/blocks.tsx index 03614592c..76a4d9235 100644 --- a/web/components/cycles/gantt-chart/blocks.tsx +++ b/web/components/cycles/gantt-chart/blocks.tsx @@ -3,7 +3,7 @@ import { useRouter } from "next/router"; // ui import { Tooltip, ContrastIcon } from "@plane/ui"; // helpers -import { getDateRangeStatus, renderShortDate } from "helpers/date-time.helper"; +import { renderShortDate } from "helpers/date-time.helper"; // types import { ICycle } from "types"; @@ -11,8 +11,7 @@ export const CycleGanttBlock = ({ data }: { data: ICycle }) => { const router = useRouter(); const { workspaceSlug } = router.query; - const cycleStatus = getDateRangeStatus(data?.start_date, data?.end_date); - + const cycleStatus = data.status.toLocaleLowerCase(); return (
{ cycleStatus === "current" ? "#09a953" : cycleStatus === "upcoming" - ? "#f7ae59" - : cycleStatus === "completed" - ? "#3f76ff" - : cycleStatus === "draft" - ? "rgb(var(--color-text-200))" - : "", + ? "#f7ae59" + : cycleStatus === "completed" + ? "#3f76ff" + : cycleStatus === "draft" + ? "rgb(var(--color-text-200))" + : "", }} onClick={() => router.push(`/${workspaceSlug}/projects/${data?.project}/cycles/${data?.id}`)} > @@ -52,7 +51,7 @@ export const CycleGanttSidebarBlock = ({ data }: { data: ICycle }) => { const router = useRouter(); const { workspaceSlug } = router.query; - const cycleStatus = getDateRangeStatus(data?.start_date, data?.end_date); + const cycleStatus = data.status.toLocaleLowerCase(); return (
{ cycleStatus === "current" ? "#09a953" : cycleStatus === "upcoming" - ? "#f7ae59" - : cycleStatus === "completed" - ? "#3f76ff" - : cycleStatus === "draft" - ? "rgb(var(--color-text-200))" - : "" + ? "#f7ae59" + : cycleStatus === "completed" + ? "#3f76ff" + : cycleStatus === "draft" + ? "rgb(var(--color-text-200))" + : "" }`} />
{data?.name}
diff --git a/web/components/cycles/sidebar.tsx b/web/components/cycles/sidebar.tsx index dcf86bb46..18c233d6c 100644 --- a/web/components/cycles/sidebar.tsx +++ b/web/components/cycles/sidebar.tsx @@ -31,7 +31,6 @@ import { import { copyUrlToClipboard } from "helpers/string.helper"; import { findHowManyDaysLeft, - getDateRangeStatus, isDateGreaterThanToday, renderDateFormat, renderShortDate, @@ -275,10 +274,7 @@ export const CycleDetailsSidebar: React.FC = observer((props) => { [workspaceSlug, projectId, cycleId, issueFilters, updateFilters] ); - const cycleStatus = - cycleDetails?.start_date && cycleDetails?.end_date - ? getDateRangeStatus(cycleDetails?.start_date, cycleDetails?.end_date) - : "draft"; + const cycleStatus = cycleDetails.status.toLocaleLowerCase(); const isCompleted = cycleStatus === "completed"; const isStartValid = new Date(`${cycleDetails?.start_date}`) <= new Date(); diff --git a/web/components/cycles/transfer-issues-modal.tsx b/web/components/cycles/transfer-issues-modal.tsx index 55555e221..dd462e360 100644 --- a/web/components/cycles/transfer-issues-modal.tsx +++ b/web/components/cycles/transfer-issues-modal.tsx @@ -15,8 +15,6 @@ import { AlertCircle, Search, X } from "lucide-react"; import { INCOMPLETE_CYCLES_LIST } from "constants/fetch-keys"; // types import { ICycle } from "types"; -//helper -import { getDateRangeStatus } from "helpers/date-time.helper"; type Props = { isOpen: boolean; @@ -138,7 +136,7 @@ export const TransferIssuesModal: React.FC = observer(({ isOpen, handleCl
{option?.name} - {getDateRangeStatus(option?.start_date, option?.end_date)} + {option.status}
diff --git a/web/components/issues/issue-layouts/roots/cycle-layout-root.tsx b/web/components/issues/issue-layouts/roots/cycle-layout-root.tsx index f967956f0..f77dfbed4 100644 --- a/web/components/issues/issue-layouts/roots/cycle-layout-root.tsx +++ b/web/components/issues/issue-layouts/roots/cycle-layout-root.tsx @@ -17,8 +17,6 @@ import { import { TransferIssues, TransferIssuesModal } from "components/cycles"; // ui import { Spinner } from "@plane/ui"; -// helpers -import { getDateRangeStatus } from "helpers/date-time.helper"; export const CycleLayoutRoot: React.FC = observer(() => { const [transferIssuesModal, setTransferIssuesModal] = useState(false); @@ -50,10 +48,7 @@ export const CycleLayoutRoot: React.FC = observer(() => { const activeLayout = issueFilters?.displayFilters?.layout; const cycleDetails = cycleId ? cycleStore.cycle_details[cycleId.toString()] : undefined; - const cycleStatus = - cycleDetails?.start_date && cycleDetails?.end_date - ? getDateRangeStatus(cycleDetails?.start_date, cycleDetails?.end_date) - : "draft"; + const cycleStatus = cycleDetails?.status.toLocaleLowerCase() ?? "draft"; return ( <> diff --git a/web/helpers/date-time.helper.ts b/web/helpers/date-time.helper.ts index fa346d5aa..ab6116d77 100644 --- a/web/helpers/date-time.helper.ts +++ b/web/helpers/date-time.helper.ts @@ -170,18 +170,6 @@ export const formatLongDateDistance = (date: string | Date) => { } }; -export const getDateRangeStatus = (startDate: string | null | undefined, endDate: string | null | undefined) => { - if (!startDate || !endDate) return "draft"; - - const now = new Date(); - const start = new Date(startDate); - const end = new Date(endDate); - - if (start <= now && end >= now) return "current"; - else if (start > now) return "upcoming"; - else return "completed"; -}; - export const renderShortDateWithYearFormat = (date: string | Date, placeholder?: string) => { if (!date || date === "") return null; diff --git a/web/store/cycle/cycles.store.ts b/web/store/cycle/cycles.store.ts index 96122ec14..b6602172d 100644 --- a/web/store/cycle/cycles.store.ts +++ b/web/store/cycle/cycles.store.ts @@ -7,7 +7,6 @@ import { RootStore } from "../root"; import { ProjectService } from "services/project"; import { IssueService } from "services/issue"; import { CycleService } from "services/cycle.service"; -import { getDateRangeStatus } from "helpers/date-time.helper"; export interface ICycleStore { loader: boolean; @@ -318,7 +317,7 @@ export class CycleStore implements ICycleStore { }; addCycleToFavorites = async (workspaceSlug: string, projectId: string, cycle: ICycle) => { - const cycleStatus = getDateRangeStatus(cycle.start_date, cycle.end_date); + const cycleStatus = cycle.status; const statusCyclesList = this.cycles[projectId]?.[cycleStatus] ?? []; const allCyclesList = this.projectCycles ?? []; @@ -379,7 +378,7 @@ export class CycleStore implements ICycleStore { }; removeCycleFromFavorites = async (workspaceSlug: string, projectId: string, cycle: ICycle) => { - const cycleStatus = getDateRangeStatus(cycle.start_date, cycle.end_date); + const cycleStatus = cycle.status; const statusCyclesList = this.cycles[projectId]?.[cycleStatus] ?? []; const allCyclesList = this.projectCycles ?? []; diff --git a/web/types/cycles.d.ts b/web/types/cycles.d.ts index c3c5248aa..4f243deeb 100644 --- a/web/types/cycles.d.ts +++ b/web/types/cycles.d.ts @@ -2,6 +2,8 @@ import type { IUser, IIssue, IProjectLite, IWorkspaceLite, IIssueFilterOptions, export type TCycleView = "all" | "active" | "upcoming" | "completed" | "draft"; +export type TCycleGroups = "current" | "upcoming" | "completed" | "draft"; + export type TCycleLayout = "list" | "board" | "gantt"; export interface ICycle { @@ -24,6 +26,7 @@ export interface ICycle { owned_by: IUser; project: string; project_detail: IProjectLite; + status: TCycleGroups; sort_order: number; start_date: string | null; started_issues: number; From e584259c04da7876175f78a30ecc7c0f600b5c4e Mon Sep 17 00:00:00 2001 From: Nikhil <118773738+pablohashescobar@users.noreply.github.com> Date: Fri, 29 Dec 2023 16:32:12 +0530 Subject: [PATCH 37/40] feat: add external id and external source field to issue, cycle, module, label, comment, state and inbox issues (#3277) --- ...ernal_id_cycle_external_source_and_more.py | 83 +++++++++++++++++++ apiserver/plane/db/models/cycle.py | 2 + apiserver/plane/db/models/inbox.py | 2 + apiserver/plane/db/models/issue.py | 6 ++ apiserver/plane/db/models/module.py | 2 + apiserver/plane/db/models/state.py | 2 + 6 files changed, 97 insertions(+) create mode 100644 apiserver/plane/db/migrations/0051_cycle_external_id_cycle_external_source_and_more.py diff --git a/apiserver/plane/db/migrations/0051_cycle_external_id_cycle_external_source_and_more.py b/apiserver/plane/db/migrations/0051_cycle_external_id_cycle_external_source_and_more.py new file mode 100644 index 000000000..19267dfc2 --- /dev/null +++ b/apiserver/plane/db/migrations/0051_cycle_external_id_cycle_external_source_and_more.py @@ -0,0 +1,83 @@ +# Generated by Django 4.2.7 on 2023-12-29 10:20 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('db', '0050_user_use_case_alter_workspace_organization_size'), + ] + + operations = [ + migrations.AddField( + model_name='cycle', + name='external_id', + field=models.CharField(blank=True, max_length=255, null=True), + ), + migrations.AddField( + model_name='cycle', + name='external_source', + field=models.CharField(blank=True, max_length=255, null=True), + ), + migrations.AddField( + model_name='inboxissue', + name='external_id', + field=models.CharField(blank=True, max_length=255, null=True), + ), + migrations.AddField( + model_name='inboxissue', + name='external_source', + field=models.CharField(blank=True, max_length=255, null=True), + ), + migrations.AddField( + model_name='issue', + name='external_id', + field=models.CharField(blank=True, max_length=255, null=True), + ), + migrations.AddField( + model_name='issue', + name='external_source', + field=models.CharField(blank=True, max_length=255, null=True), + ), + migrations.AddField( + model_name='issuecomment', + name='external_id', + field=models.CharField(blank=True, max_length=255, null=True), + ), + migrations.AddField( + model_name='issuecomment', + name='external_source', + field=models.CharField(blank=True, max_length=255, null=True), + ), + migrations.AddField( + model_name='label', + name='external_id', + field=models.CharField(blank=True, max_length=255, null=True), + ), + migrations.AddField( + model_name='label', + name='external_source', + field=models.CharField(blank=True, max_length=255, null=True), + ), + migrations.AddField( + model_name='module', + name='external_id', + field=models.CharField(blank=True, max_length=255, null=True), + ), + migrations.AddField( + model_name='module', + name='external_source', + field=models.CharField(blank=True, max_length=255, null=True), + ), + migrations.AddField( + model_name='state', + name='external_id', + field=models.CharField(blank=True, max_length=255, null=True), + ), + migrations.AddField( + model_name='state', + name='external_source', + field=models.CharField(blank=True, max_length=255, null=True), + ), + ] diff --git a/apiserver/plane/db/models/cycle.py b/apiserver/plane/db/models/cycle.py index 56301e3d3..e5e2c355b 100644 --- a/apiserver/plane/db/models/cycle.py +++ b/apiserver/plane/db/models/cycle.py @@ -18,6 +18,8 @@ class Cycle(ProjectBaseModel): ) view_props = models.JSONField(default=dict) sort_order = models.FloatField(default=65535) + external_source = models.CharField(max_length=255, null=True, blank=True) + external_id = models.CharField(max_length=255, blank=True, null=True) class Meta: verbose_name = "Cycle" diff --git a/apiserver/plane/db/models/inbox.py b/apiserver/plane/db/models/inbox.py index 497a20f00..6ad88e681 100644 --- a/apiserver/plane/db/models/inbox.py +++ b/apiserver/plane/db/models/inbox.py @@ -39,6 +39,8 @@ class InboxIssue(ProjectBaseModel): "db.Issue", related_name="inbox_duplicate", on_delete=models.SET_NULL, null=True ) source = models.TextField(blank=True, null=True) + external_source = models.CharField(max_length=255, null=True, blank=True) + external_id = models.CharField(max_length=255, blank=True, null=True) class Meta: verbose_name = "InboxIssue" diff --git a/apiserver/plane/db/models/issue.py b/apiserver/plane/db/models/issue.py index 9b293a75d..54acd5c5d 100644 --- a/apiserver/plane/db/models/issue.py +++ b/apiserver/plane/db/models/issue.py @@ -102,6 +102,8 @@ class Issue(ProjectBaseModel): completed_at = models.DateTimeField(null=True) archived_at = models.DateField(null=True) is_draft = models.BooleanField(default=False) + external_source = models.CharField(max_length=255, null=True, blank=True) + external_id = models.CharField(max_length=255, blank=True, null=True) objects = models.Manager() issue_objects = IssueManager() @@ -366,6 +368,8 @@ class IssueComment(ProjectBaseModel): default="INTERNAL", max_length=100, ) + external_source = models.CharField(max_length=255, null=True, blank=True) + external_id = models.CharField(max_length=255, blank=True, null=True) def save(self, *args, **kwargs): self.comment_stripped = ( @@ -416,6 +420,8 @@ class Label(ProjectBaseModel): description = models.TextField(blank=True) color = models.CharField(max_length=255, blank=True) sort_order = models.FloatField(default=65535) + external_source = models.CharField(max_length=255, null=True, blank=True) + external_id = models.CharField(max_length=255, blank=True, null=True) class Meta: unique_together = ["name", "project"] diff --git a/apiserver/plane/db/models/module.py b/apiserver/plane/db/models/module.py index ae540cc6c..e485eea62 100644 --- a/apiserver/plane/db/models/module.py +++ b/apiserver/plane/db/models/module.py @@ -41,6 +41,8 @@ class Module(ProjectBaseModel): ) view_props = models.JSONField(default=dict) sort_order = models.FloatField(default=65535) + external_source = models.CharField(max_length=255, null=True, blank=True) + external_id = models.CharField(max_length=255, blank=True, null=True) class Meta: unique_together = ["name", "project"] diff --git a/apiserver/plane/db/models/state.py b/apiserver/plane/db/models/state.py index 2fa1ebe38..3370f239d 100644 --- a/apiserver/plane/db/models/state.py +++ b/apiserver/plane/db/models/state.py @@ -24,6 +24,8 @@ class State(ProjectBaseModel): max_length=20, ) default = models.BooleanField(default=False) + external_source = models.CharField(max_length=255, null=True, blank=True) + external_id = models.CharField(max_length=255, blank=True, null=True) def __str__(self): """Return name of the state""" From f132fe59aed3b4ea7ada30a1f6b7e8b9816098e7 Mon Sep 17 00:00:00 2001 From: Prateek Shourya Date: Fri, 29 Dec 2023 16:35:03 +0530 Subject: [PATCH 38/40] Chore/user role validation (#3260) * chore: remove `Save View` option for guest/ viewer from project issues header. * chore: allow guest/ viewer to clear applied filters in project issues. * chore: disable `date`, `label` property access for guests/ viewer in all project issue views. * chore: update `Workspace Issues` -> `All Issues` header. * chore: refactor apply/ clear filter implementation in All Issues. * Revert "chore: refactor apply/ clear filter implementation in All Issues." This reverts commit 024822d54f4061eb2686d811a2b87cd0789b6b90. * Revert "chore: allow guest/ viewer to clear applied filters in project issues." This reverts commit 3dae871d23424d55abac95e16522696ad3c2a5c4. * Revert "chore: update `Workspace Issues` -> `All Issues` header." This reverts commit 03f90be188bc6b2f98a780ae22e0a29d9c59268d. * chore: remove `cursor-pointer` style from non actionable issue properties. --- .../applied-filters/roots/project-root.tsx | 16 ++++++++++------ .../issues/issue-layouts/kanban/properties.tsx | 6 +++--- .../issues/issue-layouts/list/properties.tsx | 6 +++--- .../issues/issue-layouts/properties/date.tsx | 3 ++- .../issues/issue-layouts/properties/labels.tsx | 8 ++++++-- web/components/issues/sidebar-select/label.tsx | 4 +++- web/components/issues/view-select/due-date.tsx | 4 ++-- web/components/issues/view-select/start-date.tsx | 4 ++-- 8 files changed, 31 insertions(+), 20 deletions(-) diff --git a/web/components/issues/issue-layouts/filters/applied-filters/roots/project-root.tsx b/web/components/issues/issue-layouts/filters/applied-filters/roots/project-root.tsx index 6d7369bb9..31317366c 100644 --- a/web/components/issues/issue-layouts/filters/applied-filters/roots/project-root.tsx +++ b/web/components/issues/issue-layouts/filters/applied-filters/roots/project-root.tsx @@ -1,29 +1,32 @@ import { useRouter } from "next/router"; import { observer } from "mobx-react-lite"; - // mobx store import { useMobxStore } from "lib/mobx/store-provider"; // components import { AppliedFiltersList, SaveFilterView } from "components/issues"; - // types import { IIssueFilterOptions } from "types"; import { EFilterType } from "store/issues/types"; +// constants +import { EUserWorkspaceRoles } from "constants/workspace"; export const ProjectAppliedFiltersRoot: React.FC = observer(() => { + // router const router = useRouter(); const { workspaceSlug, projectId } = router.query as { workspaceSlug: string; projectId: string; }; - + // mobx stores const { projectLabel: { projectLabels }, projectState: projectStateStore, projectMember: { projectMembers }, projectIssuesFilter: { issueFilters, updateFilters }, + user: { currentProjectRole }, } = useMobxStore(); - + // derived values + const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER; const userFilters = issueFilters?.filters; // filters whose value not null or empty array @@ -73,8 +76,9 @@ export const ProjectAppliedFiltersRoot: React.FC = observer(() => { members={projectMembers?.map((m) => m.member)} states={projectStateStore.states?.[projectId?.toString() ?? ""]} /> - - + {isEditingAllowed && ( + + )}
); }); diff --git a/web/components/issues/issue-layouts/kanban/properties.tsx b/web/components/issues/issue-layouts/kanban/properties.tsx index 9590c9068..5be5a12c5 100644 --- a/web/components/issues/issue-layouts/kanban/properties.tsx +++ b/web/components/issues/issue-layouts/kanban/properties.tsx @@ -166,7 +166,7 @@ export const KanBanProperties: React.FC = observer((props) => {/* sub-issues */} {displayProperties && displayProperties?.sub_issue_count && !!issue?.sub_issues_count && ( -
+
{issue.sub_issues_count}
@@ -176,7 +176,7 @@ export const KanBanProperties: React.FC = observer((props) => {/* attachments */} {displayProperties && displayProperties?.attachment_count && !!issue?.attachment_count && ( -
+
{issue.attachment_count}
@@ -186,7 +186,7 @@ export const KanBanProperties: React.FC = observer((props) => {/* link */} {displayProperties && displayProperties?.link && !!issue?.link_count && ( -
+
{issue.link_count}
diff --git a/web/components/issues/issue-layouts/list/properties.tsx b/web/components/issues/issue-layouts/list/properties.tsx index eeff3b273..07129910f 100644 --- a/web/components/issues/issue-layouts/list/properties.tsx +++ b/web/components/issues/issue-layouts/list/properties.tsx @@ -137,7 +137,7 @@ export const ListProperties: FC = observer((props) => { {/* sub-issues */} {displayProperties && displayProperties?.sub_issue_count && !!issue?.sub_issues_count && ( -
+
{issue.sub_issues_count}
@@ -147,7 +147,7 @@ export const ListProperties: FC = observer((props) => { {/* attachments */} {displayProperties && displayProperties?.attachment_count && !!issue?.attachment_count && ( -
+
{issue.attachment_count}
@@ -157,7 +157,7 @@ export const ListProperties: FC = observer((props) => { {/* link */} {displayProperties && displayProperties?.link && !!issue?.link_count && ( -
+
{issue.link_count}
diff --git a/web/components/issues/issue-layouts/properties/date.tsx b/web/components/issues/issue-layouts/properties/date.tsx index cfe3481e3..d0bb29711 100644 --- a/web/components/issues/issue-layouts/properties/date.tsx +++ b/web/components/issues/issue-layouts/properties/date.tsx @@ -61,6 +61,7 @@ export const IssuePropertyDate: React.FC = observer((props) ref={dropdownBtn} className="border-none outline-none" onClick={(e) => e.stopPropagation()} + disabled={disabled} > = observer((props)
diff --git a/web/components/issues/issue-layouts/properties/labels.tsx b/web/components/issues/issue-layouts/properties/labels.tsx index 282268d7b..d0045c3d4 100644 --- a/web/components/issues/issue-layouts/properties/labels.tsx +++ b/web/components/issues/issue-layouts/properties/labels.tsx @@ -128,7 +128,11 @@ export const IssuePropertyLabels: React.FC = observer((pro ))} ) : ( -
+
= observer((pro ) : (
diff --git a/web/components/issues/sidebar-select/label.tsx b/web/components/issues/sidebar-select/label.tsx index ca7abd8be..6340383e9 100644 --- a/web/components/issues/sidebar-select/label.tsx +++ b/web/components/issues/sidebar-select/label.tsx @@ -92,7 +92,9 @@ export const SidebarLabelSelect: React.FC = observer((props) => { return (