From 05c759597cb23b95715bf784245135871eafa9f6 Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com> Date: Fri, 15 Sep 2023 11:26:42 +0530 Subject: [PATCH 1/5] chore: custom theme mode svg added --- web/public/theme-mode/custom-mode.svg | 54 +++++++++++++++++++ web/public/theme-mode/custom-theme-banner.svg | 33 ++++++++++++ web/public/theme-mode/dark-high-contrast.svg | 34 ++++++++++++ web/public/theme-mode/dark-mode.svg | 41 ++++++++++++++ web/public/theme-mode/light-high-contrast.svg | 42 +++++++++++++++ web/public/theme-mode/light-mode.svg | 42 +++++++++++++++ 6 files changed, 246 insertions(+) create mode 100644 web/public/theme-mode/custom-mode.svg create mode 100644 web/public/theme-mode/custom-theme-banner.svg create mode 100644 web/public/theme-mode/dark-high-contrast.svg create mode 100644 web/public/theme-mode/dark-mode.svg create mode 100644 web/public/theme-mode/light-high-contrast.svg create mode 100644 web/public/theme-mode/light-mode.svg diff --git a/web/public/theme-mode/custom-mode.svg b/web/public/theme-mode/custom-mode.svg new file mode 100644 index 00000000000..01be18d5b40 --- /dev/null +++ b/web/public/theme-mode/custom-mode.svg @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/public/theme-mode/custom-theme-banner.svg b/web/public/theme-mode/custom-theme-banner.svg new file mode 100644 index 00000000000..b7434cd764e --- /dev/null +++ b/web/public/theme-mode/custom-theme-banner.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/public/theme-mode/dark-high-contrast.svg b/web/public/theme-mode/dark-high-contrast.svg new file mode 100644 index 00000000000..e5839b28600 --- /dev/null +++ b/web/public/theme-mode/dark-high-contrast.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/public/theme-mode/dark-mode.svg b/web/public/theme-mode/dark-mode.svg new file mode 100644 index 00000000000..b8c14711c17 --- /dev/null +++ b/web/public/theme-mode/dark-mode.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/public/theme-mode/light-high-contrast.svg b/web/public/theme-mode/light-high-contrast.svg new file mode 100644 index 00000000000..c2f5ded22be --- /dev/null +++ b/web/public/theme-mode/light-high-contrast.svg @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/public/theme-mode/light-mode.svg b/web/public/theme-mode/light-mode.svg new file mode 100644 index 00000000000..9c7fdae4b8d --- /dev/null +++ b/web/public/theme-mode/light-mode.svg @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 7c52b5b3e8338fc856b73202190c86945f512b10 Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com> Date: Fri, 15 Sep 2023 12:13:28 +0530 Subject: [PATCH 2/5] style: workspace settings ui revamp --- web/components/exporter/guide.tsx | 87 ++--- web/components/exporter/single-export.tsx | 2 +- web/components/integration/guide.tsx | 157 ++++----- web/components/integration/single-import.tsx | 2 +- .../integration/single-integration-card.tsx | 35 +- .../integration-and-import-export-banner.tsx | 2 +- .../[workspaceSlug]/settings/billing.tsx | 18 +- .../[workspaceSlug]/settings/exports.tsx | 17 +- .../[workspaceSlug]/settings/imports.tsx | 25 +- web/pages/[workspaceSlug]/settings/index.tsx | 301 +++++++++--------- .../[workspaceSlug]/settings/integrations.tsx | 18 +- .../[workspaceSlug]/settings/members.tsx | 97 +++--- 12 files changed, 399 insertions(+), 362 deletions(-) diff --git a/web/components/exporter/guide.tsx b/web/components/exporter/guide.tsx index 67b7c6d4d6f..45fc5027087 100644 --- a/web/components/exporter/guide.tsx +++ b/web/components/exporter/guide.tsx @@ -46,32 +46,38 @@ const IntegrationGuide = () => { return ( <> -
+
<> -
+
{EXPORTERS_LIST.map((service) => (
-
-
- {`${service.title} -
-
-

{service.title}

-

{service.description}

+
+
+
+ {`${service.title} +
+
+

+ {service.title} +

+

+ {service.description} +

+
- {service.type} now + {service.type} @@ -80,10 +86,11 @@ const IntegrationGuide = () => {
))}
-
-

-
-
Previous Exports
+
+
+
+

Previous Exports

+
-

- {exporterServices && exporterServices?.results ? ( - exporterServices?.results?.length > 0 ? ( -
-
- {exporterServices?.results.map((service) => ( - - ))} +
+
+ {exporterServices && exporterServices?.results ? ( + exporterServices?.results?.length > 0 ? ( +
+
+ {exporterServices?.results.map((service) => ( + + ))} +
-
+ ) : ( +

No previous export available.

+ ) ) : ( -

No previous export available.

- ) - ) : ( - - - - - - - )} + + + + + + + )} +
{provider && ( diff --git a/web/components/exporter/single-export.tsx b/web/components/exporter/single-export.tsx index c8ef2dc1a07..772119f25a3 100644 --- a/web/components/exporter/single-export.tsx +++ b/web/components/exporter/single-export.tsx @@ -23,7 +23,7 @@ export const SingleExport: React.FC = ({ service, refreshing }) => { }; return ( -
+

diff --git a/web/components/integration/guide.tsx b/web/components/integration/guide.tsx index 7c1dd20fe99..a819566bfab 100644 --- a/web/components/integration/guide.tsx +++ b/web/components/integration/guide.tsx @@ -21,7 +21,6 @@ import { import { Loader, PrimaryButton } from "components/ui"; // icons import { ArrowPathIcon } from "@heroicons/react/24/outline"; -import { ArrowRightIcon } from "components/icons"; // types import { IImporterService } from "types"; // fetch-keys @@ -57,10 +56,10 @@ const IntegrationGuide = () => { data={importToDelete} user={user} /> -
+
{(!provider || provider === "csv") && ( <> -
+ {/*
Relocation Guide
@@ -78,85 +77,87 @@ const IntegrationGuide = () => {
-
-
- {IMPORTERS_EXPORTERS_LIST.map((service) => ( -
-
-
- {`${service.title} -
-
-

{service.title}

-

{service.description}

-
- +
*/} + {IMPORTERS_EXPORTERS_LIST.map((service) => ( +
+
+
+ {`${service.title} +
+
+

{service.title}

+

+ {service.description} +

- ))} -
-
-

- Previous Imports - -

- {importerServices ? ( - importerServices.length > 0 ? ( -
-
- {importerServices.map((service) => ( - handleDeleteImport(service)} - /> - ))} + +
+ ))} +
+
+

+ Previous Imports + +

+
+
+ {importerServices ? ( + importerServices.length > 0 ? ( +
+
+ {importerServices.map((service) => ( + handleDeleteImport(service)} + /> + ))} +
-
+ ) : ( +

+ No previous imports available. +

+ ) ) : ( -

- No previous imports available. -

- ) - ) : ( - - - - - - - )} + + + + + + + )} +
)} diff --git a/web/components/integration/single-import.tsx b/web/components/integration/single-import.tsx index b74628a83bb..9ebe1ad224e 100644 --- a/web/components/integration/single-import.tsx +++ b/web/components/integration/single-import.tsx @@ -16,7 +16,7 @@ type Props = { }; export const SingleImport: React.FC = ({ service, refreshing, handleDelete }) => ( -
+

diff --git a/web/components/integration/single-integration-card.tsx b/web/components/integration/single-integration-card.tsx index 0a59de8b795..fab37b0c8ee 100644 --- a/web/components/integration/single-integration-card.tsx +++ b/web/components/integration/single-integration-card.tsx @@ -15,6 +15,7 @@ import { DangerButton, Loader, PrimaryButton } from "components/ui"; // icons import GithubLogo from "public/services/github.png"; import SlackLogo from "public/services/slack.png"; +import { CheckCircle2 } from "lucide-react"; // types import { IAppIntegration, IWorkspaceIntegration } from "types"; // fetch-keys @@ -27,13 +28,12 @@ type Props = { const integrationDetails: { [key: string]: any } = { github: { logo: GithubLogo, - installed: - "Activate GitHub integrations on individual projects to sync with specific repositories.", + installed: "Activate GitHub on individual projects to sync with specific repositories.", notInstalled: "Connect with GitHub with your Plane workspace to sync project issues.", }, slack: { logo: SlackLogo, - installed: "Activate Slack integrations on individual projects to sync with specific channels.", + installed: "Activate Slack on individual projects to sync with specific channels.", notInstalled: "Connect with Slack with your Plane workspace to sync project issues.", }, }; @@ -99,31 +99,22 @@ export const SingleIntegrationCard: React.FC = ({ integration }) => { ); return ( -
+
-
+
{`${integration.title}
-

+

{integration.title} - {workspaceIntegrations ? ( - isInstalled ? ( - - Installed - - ) : ( - - {" "} - Not Installed - - ) - ) : null} + {workspaceIntegrations + ? isInstalled && + : null}

-

+

{workspaceIntegrations ? isInstalled ? integrationDetails[integration.provider].installed @@ -135,12 +126,12 @@ export const SingleIntegrationCard: React.FC = ({ integration }) => { {workspaceIntegrations ? ( isInstalled ? ( - - {deletingIntegration ? "Removing..." : "Remove installation"} + + {deletingIntegration ? "Uninstalling..." : "Uninstall"} ) : ( - {isInstalling ? "Installing..." : "Add installation"} + {isInstalling ? "Installing..." : "Install"} ) ) : ( diff --git a/web/components/ui/integration-and-import-export-banner.tsx b/web/components/ui/integration-and-import-export-banner.tsx index 541c49efcad..aa79abaf354 100644 --- a/web/components/ui/integration-and-import-export-banner.tsx +++ b/web/components/ui/integration-and-import-export-banner.tsx @@ -6,7 +6,7 @@ type Props = { }; export const IntegrationAndImportExportBanner: React.FC = ({ bannerName, description }) => ( -

+

{bannerName}

{description && (
diff --git a/web/pages/[workspaceSlug]/settings/billing.tsx b/web/pages/[workspaceSlug]/settings/billing.tsx index 6731cd33f3f..aaa64f97eda 100644 --- a/web/pages/[workspaceSlug]/settings/billing.tsx +++ b/web/pages/[workspaceSlug]/settings/billing.tsx @@ -8,7 +8,8 @@ import useSWR from "swr"; import workspaceService from "services/workspace.service"; // layouts import { WorkspaceAuthorizationLayout } from "layouts/auth-layout"; -import { SettingsHeader } from "components/workspace"; +// component +import { SettingsSidebar } from "components/project"; // ui import { SecondaryButton } from "components/ui"; import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; @@ -42,14 +43,17 @@ const BillingSettings: NextPage = () => { } > -
- -
+
+
+ +
+
-

Billing & Plans

-

Free launch preview

+
+

Billing & Plan

+
-
+

Current plan

diff --git a/web/pages/[workspaceSlug]/settings/exports.tsx b/web/pages/[workspaceSlug]/settings/exports.tsx index 7f98d36184f..b825e0cea59 100644 --- a/web/pages/[workspaceSlug]/settings/exports.tsx +++ b/web/pages/[workspaceSlug]/settings/exports.tsx @@ -6,10 +6,9 @@ import useSWR from "swr"; import workspaceService from "services/workspace.service"; // layouts import { WorkspaceAuthorizationLayout } from "layouts/auth-layout"; -import { SettingsHeader } from "components/workspace"; // components import ExportGuide from "components/exporter/guide"; -import { IntegrationAndImportExportBanner } from "components/ui"; +import { SettingsSidebar } from "components/project"; // ui import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; // types @@ -41,10 +40,16 @@ const ImportExport: NextPage = () => { } > -

- - - +
+
+ +
+
+
+

Exports

+
+ +
); diff --git a/web/pages/[workspaceSlug]/settings/imports.tsx b/web/pages/[workspaceSlug]/settings/imports.tsx index a0a46f0bc9d..205923f7c0b 100644 --- a/web/pages/[workspaceSlug]/settings/imports.tsx +++ b/web/pages/[workspaceSlug]/settings/imports.tsx @@ -6,10 +6,9 @@ import useSWR from "swr"; import workspaceService from "services/workspace.service"; // layouts import { WorkspaceAuthorizationLayout } from "layouts/auth-layout"; -import { SettingsHeader } from "components/workspace"; // components import IntegrationGuide from "components/integration/guide"; -import { IntegrationAndImportExportBanner } from "components/ui"; +import { SettingsSidebar } from "components/project"; // ui import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; // types @@ -41,15 +40,19 @@ const ImportExport: NextPage = () => { } > -
- - - +
+
+ +
+
+
+

Imports

+
+ +
+

Previous Imports

+
+
); diff --git a/web/pages/[workspaceSlug]/settings/index.tsx b/web/pages/[workspaceSlug]/settings/index.tsx index bd7ea1bd9b1..ffad4a55c6f 100644 --- a/web/pages/[workspaceSlug]/settings/index.tsx +++ b/web/pages/[workspaceSlug]/settings/index.tsx @@ -16,14 +16,16 @@ import useUserAuth from "hooks/use-user-auth"; import { WorkspaceAuthorizationLayout } from "layouts/auth-layout"; // components import { ImageUploadModal } from "components/core"; -import { DeleteWorkspaceModal, SettingsHeader } from "components/workspace"; +import { DeleteWorkspaceModal } from "components/workspace"; +import { SettingsSidebar } from "components/project"; // ui -import { Spinner, Input, CustomSelect, SecondaryButton, DangerButton } from "components/ui"; +import { Disclosure, Transition } from "@headlessui/react"; +import { Spinner, Input, CustomSelect, DangerButton, PrimaryButton, Icon } from "components/ui"; import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; // icons -import { LinkIcon } from "@heroicons/react/24/outline"; +import { Pencil } from "lucide-react"; // helpers -import { copyTextToClipboard, truncateText } from "helpers/string.helper"; +import { truncateText } from "helpers/string.helper"; // types import type { IWorkspace } from "types"; import type { NextPage } from "next"; @@ -135,6 +137,7 @@ const WorkspaceSettings: NextPage = () => { logo: "", }; }); + setIsImageUploadModalOpen(false); }) .catch(() => { setToastAlert({ @@ -162,6 +165,8 @@ const WorkspaceSettings: NextPage = () => { setIsImageUploadModalOpen(false)} + isRemoving={isImageRemoving} + handleDelete={() => handleDelete(activeWorkspace?.logo)} onSuccess={(imageUrl) => { setIsImageUploading(true); setValue("logo", imageUrl); @@ -178,67 +183,109 @@ const WorkspaceSettings: NextPage = () => { data={activeWorkspace ?? null} user={user} /> -
- +
+
+ +
{activeWorkspace ? ( -
-
-
-

Logo

-

- Max file size is 5MB. Supported file types are .jpg and .png. -

+
+
+
+
-
-
+
+

{watch("name")}

+ {`${ + typeof window !== "undefined" && + window.location.origin.replace("http://", "").replace("https://", "") + }/${activeWorkspace.slug}`} +
- {isAdmin && ( -
- { - setIsImageUploadModalOpen(true); - }} - > - {isImageUploading ? "Uploading..." : "Upload"} - - {activeWorkspace.logo && activeWorkspace.logo !== "" && ( - handleDelete(activeWorkspace.logo)} - loading={isImageRemoving} - > - {isImageRemoving ? "Removing..." : "Remove"} - - )} -
- )}
-
-
-

URL

-

Your workspace URL.

-
-
-
+ +
+
+
+

Workspace Name

+ +
+ +
+

Company Size

+ ( + c === value) ?? "Select organization size" + } + width="w-full" + input + disabled={!isAdmin} + > + {ORGANIZATION_SIZE?.map((item) => ( + + {item} + + ))} + + )} + /> +
+ +
+

Workspace URL

{ disabled />
- - copyTextToClipboard( - `${typeof window !== "undefined" && window.location.origin}/${ - activeWorkspace.slug - }` - ).then(() => { - setToastAlert({ - type: "success", - title: "Link Copied!", - message: "Workspace link copied to clipboard.", - }); - }) - } - outline - > - - -
-
-
-
-

Name

-

Give a name to your workspace.

-
- + -
-
-
-
-

Organization Size

-

What size is your organization?

-
-
- ( - c === value) ?? "Select organization size" - } - width="w-full" - input - disabled={!isAdmin} - > - {ORGANIZATION_SIZE?.map((item) => ( - - {item} - - ))} - - )} - /> + > + {isSubmitting ? "Updating..." : "Update Workspace"} +
- {isAdmin && ( - <> -
- + {({ open }) => ( +
+ - {isSubmitting ? "Updating..." : "Update Workspace"} - -
-
-
-

Danger Zone

-

- The danger zone of the workspace delete page is a critical area that requires - careful consideration and attention. When deleting a workspace, all of the - data and resources within that workspace will be permanently removed and - cannot be recovered. -

-
-
- setIsOpen(true)} outline> - Delete the workspace - -
+ Delete Workspace + + + + + +
+ + The danger zone of the project delete page is a critical area that + requires careful consideration and attention. When deleting a project, all + of the data and resources within that project will be permanently removed + and cannot be recovered. + +
+ setIsOpen(true)} + className="!text-sm" + outline + > + Delete my project + +
+
+
+
- - )} + )} +
) : ( -
+
)} diff --git a/web/pages/[workspaceSlug]/settings/integrations.tsx b/web/pages/[workspaceSlug]/settings/integrations.tsx index 1b7a540c424..99508512fd0 100644 --- a/web/pages/[workspaceSlug]/settings/integrations.tsx +++ b/web/pages/[workspaceSlug]/settings/integrations.tsx @@ -9,9 +9,9 @@ import workspaceService from "services/workspace.service"; import IntegrationService from "services/integration"; // layouts import { WorkspaceAuthorizationLayout } from "layouts/auth-layout"; -import { SettingsHeader } from "components/workspace"; // components import { SingleIntegrationCard } from "components/integration"; +import { SettingsSidebar } from "components/project"; // ui import { IntegrationAndImportExportBanner, Loader } from "components/ui"; import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; @@ -48,19 +48,21 @@ const WorkspaceIntegrations: NextPage = () => { } > -
- -
+
+
+ +
+
-
+
{appIntegrations ? ( appIntegrations.map((integration) => ( )) ) : ( - - - + + + )}
diff --git a/web/pages/[workspaceSlug]/settings/members.tsx b/web/pages/[workspaceSlug]/settings/members.tsx index 9090e1c1729..f0fdf90dc57 100644 --- a/web/pages/[workspaceSlug]/settings/members.tsx +++ b/web/pages/[workspaceSlug]/settings/members.tsx @@ -13,15 +13,15 @@ import useUser from "hooks/use-user"; import useWorkspaceMembers from "hooks/use-workspace-members"; // layouts import { WorkspaceAuthorizationLayout } from "layouts/auth-layout"; -import { SettingsHeader } from "components/workspace"; // components import ConfirmWorkspaceMemberRemove from "components/workspace/confirm-workspace-member-remove"; import SendWorkspaceInvitationModal from "components/workspace/send-workspace-invitation-modal"; +import { SettingsSidebar } from "components/project"; // ui -import { CustomMenu, CustomSelect, Loader } from "components/ui"; +import { CustomMenu, CustomSelect, Icon, Loader, PrimaryButton } from "components/ui"; import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; // icons -import { PlusIcon } from "@heroicons/react/24/outline"; +import { XMarkIcon } from "components/icons"; // types import type { NextPage } from "next"; // fetch-keys @@ -143,9 +143,8 @@ const MembersSettings: NextPage = () => { }); }) .finally(() => { - mutateMembers( - (prevData: any) => - prevData?.filter((item: any) => item.id !== selectedRemoveMember) + mutateMembers((prevData: any) => + prevData?.filter((item: any) => item.id !== selectedRemoveMember) ); }); } @@ -187,19 +186,14 @@ const MembersSettings: NextPage = () => { user={user} onSuccess={handleInviteModalSuccess} /> -
- -
-
-

Members

- +
+
+ +
+
+
+

Members

+ setInviteModal(true)}>Add Member
{!workspaceMembers || !workspaceInvitations ? ( @@ -209,23 +203,30 @@ const MembersSettings: NextPage = () => { ) : ( -
+
{members.length > 0 ? members.map((member) => ( -
+
{member.avatar && member.avatar !== "" ? ( -
- {member.display_name -
+ + + {member.display_name + + ) : member.display_name || member.email ? ( -
- {(member.display_name || member.email)?.charAt(0)} -
+ + + {(member.display_name || member.email)?.charAt(0)} + + ) : (
? @@ -244,14 +245,16 @@ const MembersSettings: NextPage = () => { ) : ( -

{member.display_name || member.email}

+

+ {member.display_name || member.email} +

)} {isOwner && ( -

{member.email}

+

{member.email}

)}
-
+
{!member?.status && (

Pending

@@ -263,9 +266,22 @@ const MembersSettings: NextPage = () => {
)} + + {ROLE[member.role as keyof typeof ROLE]} + + {member.memberId !== user?.id && ( + + )} + + } value={member.role} - onChange={(value: any) => { + onChange={(value: 5 | 10 | 15 | 20 | undefined) => { if (!workspaceSlug) return; mutateMembers( @@ -323,7 +339,14 @@ const MembersSettings: NextPage = () => { } }} > - {user?.id === member.memberId ? "Leave" : "Remove member"} + + + + + {" "} + {user?.id === member.memberId ? "Leave" : "Remove member"} + +
From 2028b39d739de53749595b8914760aad3d0de4a3 Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com> Date: Fri, 15 Sep 2023 12:16:34 +0530 Subject: [PATCH 3/5] style: project settings and image upload modal improvement --- .../core/modals/image-upload-modal.tsx | 38 +++--- web/components/project/settings-sidebar.tsx | 127 ++++++++++++++---- .../projects/[projectId]/settings/index.tsx | 108 +++++++-------- .../projects/[projectId]/settings/members.tsx | 2 +- 4 files changed, 182 insertions(+), 93 deletions(-) diff --git a/web/components/core/modals/image-upload-modal.tsx b/web/components/core/modals/image-upload-modal.tsx index 14e4844de68..df4f21e12b7 100644 --- a/web/components/core/modals/image-upload-modal.tsx +++ b/web/components/core/modals/image-upload-modal.tsx @@ -1,6 +1,5 @@ import React, { useCallback, useState } from "react"; -import NextImage from "next/image"; import { useRouter } from "next/router"; // react-dropzone @@ -12,7 +11,7 @@ import fileServices from "services/file.service"; // hooks import useWorkspaceDetails from "hooks/use-workspace-details"; // ui -import { PrimaryButton, SecondaryButton } from "components/ui"; +import { DangerButton, PrimaryButton, SecondaryButton } from "components/ui"; // icons import { UserCircleIcon } from "components/icons"; @@ -21,6 +20,8 @@ type Props = { onClose: () => void; isOpen: boolean; onSuccess: (url: string) => void; + isRemoving: boolean; + handleDelete: () => void; userImage?: boolean; }; @@ -29,6 +30,8 @@ export const ImageUploadModal: React.FC = ({ onSuccess, isOpen, onClose, + isRemoving, + handleDelete, userImage, }) => { const [image, setImage] = useState(null); @@ -148,12 +151,10 @@ export const ImageUploadModal: React.FC = ({ > Edit - ) : ( @@ -182,15 +183,22 @@ export const ImageUploadModal: React.FC = ({

File formats supported- .jpeg, .jpg, .png, .webp, .svg

-
- Cancel - - {isImageUploading ? "Uploading..." : "Upload & Save"} - +
+
+ + {isRemoving ? "Removing..." : "Remove"} + +
+
+ Cancel + + {isImageUploading ? "Uploading..." : "Upload & Save"} + +
diff --git a/web/components/project/settings-sidebar.tsx b/web/components/project/settings-sidebar.tsx index 9da5c10586f..a147c8a3aad 100644 --- a/web/components/project/settings-sidebar.tsx +++ b/web/components/project/settings-sidebar.tsx @@ -2,7 +2,11 @@ import React from "react"; import { useRouter } from "next/router"; import Link from "next/link"; -export const SettingsSidebar = () => { +type Props = { + profilePage?: boolean; +}; + +export const SettingsSidebar: React.FC = ({ profilePage = false }) => { const router = useRouter(); const { workspaceSlug, projectId } = router.query; @@ -43,30 +47,107 @@ export const SettingsSidebar = () => { href: `/${workspaceSlug}/projects/${projectId}/settings/automations`, }, ]; + + const workspaceLinks: Array<{ + label: string; + href: string; + }> = [ + { + label: "General", + href: `/${workspaceSlug}/settings`, + }, + { + label: "Members", + href: `/${workspaceSlug}/settings/members`, + }, + { + label: "Billing & Plans", + href: `/${workspaceSlug}/settings/billing`, + }, + { + label: "Integrations", + href: `/${workspaceSlug}/settings/integrations`, + }, + { + label: "Imports", + href: `/${workspaceSlug}/settings/imports`, + }, + { + label: "Exports", + href: `/${workspaceSlug}/settings/exports`, + }, + ]; + + const profileLinks: Array<{ + label: string; + href: string; + }> = [ + { + label: "Profile", + href: `/${workspaceSlug}/me/profile`, + }, + { + label: "Activity", + href: `/${workspaceSlug}/me/profile/activity`, + }, + { + label: "Preferences", + href: `/${workspaceSlug}/me/profile/preferences`, + }, + ]; + return ( -
- SETTINGS -
- {projectLinks.map((link) => ( - - -
- {link.label} -
-
- - ))} +
+
+ SETTINGS +
+ {(projectId ? projectLinks : workspaceLinks).map((link) => ( + + +
+ {link.label} +
+
+ + ))} +
+ {!projectId && ( +
+ My Account +
+ {profileLinks.map((link) => ( + + +
+ {link.label} +
+
+ + ))} +
+
+ )}
); }; diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/settings/index.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/settings/index.tsx index 612d21c145c..a31295fcccb 100644 --- a/web/pages/[workspaceSlug]/projects/[projectId]/settings/index.tsx +++ b/web/pages/[workspaceSlug]/projects/[projectId]/settings/index.tsx @@ -25,7 +25,6 @@ import { TextArea, Loader, CustomSelect, - SecondaryButton, DangerButton, Icon, PrimaryButton, @@ -67,7 +66,7 @@ const GeneralSettings: NextPage = () => { : null ); - const { data: memberDetails, error } = useSWR( + const { data: memberDetails } = useSWR( workspaceSlug && projectId ? USER_PROJECT_VIEW(projectId.toString()) : null, workspaceSlug && projectId ? () => projectService.projectMemberMe(workspaceSlug.toString(), projectId.toString()) @@ -388,59 +387,60 @@ const GeneralSettings: NextPage = () => { )}
- - - {({ open }) => ( -
- - Danger Zone - - - - - -
- - The danger zone of the project delete page is a critical area that - requires careful consideration and attention. When deleting a project, all - of the data and resources within that project will be permanently removed - and cannot be recovered. - -
- {projectDetails ? ( -
- setSelectedProject(projectDetails.id ?? null)} - className="!text-sm" - outline - > - Delete my project - -
- ) : ( - - - - )} + {isAdmin && ( + + {({ open }) => ( +
+ + Delete Project + + + + + +
+ + The danger zone of the project delete page is a critical area that + requires careful consideration and attention. When deleting a project, + all of the data and resources within that project will be permanently + removed and cannot be recovered. + +
+ {projectDetails ? ( +
+ setSelectedProject(projectDetails.id ?? null)} + className="!text-sm" + outline + > + Delete my project + +
+ ) : ( + + + + )} +
-
- - -
- )} - + + +
+ )} + + )}
diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/settings/members.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/settings/members.tsx index 8a4d807861e..9c0474fa6ce 100644 --- a/web/pages/[workspaceSlug]/projects/[projectId]/settings/members.tsx +++ b/web/pages/[workspaceSlug]/projects/[projectId]/settings/members.tsx @@ -390,7 +390,7 @@ const MembersSettings: NextPage = () => { )}
-
+
{!member.member && (
Pending From 462ecba3e09a404ee02c7b3eba65bdd42aa7da87 Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com> Date: Fri, 15 Sep 2023 12:27:19 +0530 Subject: [PATCH 4/5] style: profile setting ui revamp --- web/components/core/activity.tsx | 32 +- web/components/web-view/activity-message.tsx | 30 +- .../[workspaceSlug]/me/profile/activity.tsx | 321 +++++++------ .../[workspaceSlug]/me/profile/index.tsx | 430 +++++++++--------- 4 files changed, 393 insertions(+), 420 deletions(-) diff --git a/web/components/core/activity.tsx b/web/components/core/activity.tsx index c8f6377b789..4a20c15e817 100644 --- a/web/components/core/activity.tsx +++ b/web/components/core/activity.tsx @@ -90,14 +90,14 @@ const activityDetails: { ); }, - icon:
) : ( diff --git a/web/pages/[workspaceSlug]/me/profile/index.tsx b/web/pages/[workspaceSlug]/me/profile/index.tsx index 6c0af1bc27d..6b083143eb4 100644 --- a/web/pages/[workspaceSlug]/me/profile/index.tsx +++ b/web/pages/[workspaceSlug]/me/profile/index.tsx @@ -1,4 +1,6 @@ import React, { useEffect, useState } from "react"; +import { useRouter } from "next/router"; +import Link from "next/link"; // react-hook-form import { Controller, useForm } from "react-hook-form"; @@ -10,21 +12,15 @@ import useUserAuth from "hooks/use-user-auth"; import useToast from "hooks/use-toast"; // layouts import { WorkspaceAuthorizationLayout } from "layouts/auth-layout"; -import SettingsNavbar from "layouts/settings-navbar"; // components import { ImagePickerPopover, ImageUploadModal } from "components/core"; +import { SettingsSidebar } from "components/project"; // ui -import { - CustomSearchSelect, - CustomSelect, - DangerButton, - Input, - SecondaryButton, - Spinner, -} from "components/ui"; +import { CustomSearchSelect, CustomSelect, Input, PrimaryButton, Spinner } from "components/ui"; import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; // icons import { UserIcon } from "@heroicons/react/24/outline"; +import { UserCircle } from "lucide-react"; // types import type { NextPage } from "next"; import type { IUser } from "types"; @@ -46,6 +42,9 @@ const Profile: NextPage = () => { const [isRemoving, setIsRemoving] = useState(false); const [isImageUploadModalOpen, setIsImageUploadModalOpen] = useState(false); + const router = useRouter(); + const { workspaceSlug } = router.query; + const { register, handleSubmit, @@ -126,6 +125,7 @@ const Profile: NextPage = () => { if (!prevData) return prevData; return { ...prevData, avatar: "" }; }, false); + setIsRemoving(false); }) .catch(() => { setToastAlert({ @@ -155,6 +155,8 @@ const Profile: NextPage = () => { setIsImageUploadModalOpen(false)} + isRemoving={isRemoving} + handleDelete={() => handleDelete(myProfile?.avatar, true)} onSuccess={(url) => { setValue("avatar", url); handleSubmit(onSubmit)(); @@ -164,81 +166,49 @@ const Profile: NextPage = () => { userImage /> {myProfile ? ( -
-
-
-

Profile Settings

-

- This information will be visible to only you. -

+
+
+
+
- -
- -
-
-

Profile Picture

-

- Max file size is 5MB. Supported file types are .jpg and .png. -

-
-
-
- -
- { - setIsImageUploadModalOpen(true); - }} - > - Upload - - {myProfile.avatar && myProfile.avatar !== "" && ( - handleDelete(myProfile.avatar, true)} - loading={isRemoving} - > - {isRemoving ? "Removing..." : "Remove"} - - )} +
+
+ {myProfile?.name +
+
+
+ +
-
-
-
-
-

Cover Photo

-

- Select your cover photo from the given library. -

-
-
-
-
- {myProfile?.name -
+ +
+ ( { @@ -249,157 +219,167 @@ const Profile: NextPage = () => { "https://images.unsplash.com/photo-1506383796573-caf02b4a79ab" } /> -
-
+ )} + />
-
-
-
-

Full Name

-
-
- - -
-
-
-
-

Display Name

-

- This could be your first name, or a nickname — however you{"'"}d like people to - refer to you in Plane. -

-
-
- { - if (value.trim().length < 1) return "Display name can't be empty."; - - if (value.split(" ").length > 1) - return "Display name can't have two consecutive spaces."; - - if (value.replace(/\s/g, "").length < 1) - return "Display name must be at least 1 characters long."; - - if (value.replace(/\s/g, "").length > 20) - return "Display name must be less than 20 characters long."; - - return true; - }, - }} - /> -
-
-
-
-

Email

-

- The email address that you are using. -

-
-
- -
-
-
-
-

Role

-

Add your role.

+ +
+
+
+ {`${watch("first_name")} ${watch("last_name")}`} +
+ {watch("email")} +
+ + + + + + + View Profile + +
-
- ( - - {USER_ROLES.map((item) => ( - - {item.label} - - ))} - + +
+
+

First Name

+ +
+ +
+

Last Name

+ +
+ +
+

Email

+ +
+ +
+

Role

+ ( + + {USER_ROLES.map((item) => ( + + {item.label} + + ))} + + )} + /> + {errors.role && ( + Please select a role )} - /> - {errors.role && Please select a role} -
-
-
-
-

Timezone

-

Select a timezone

-
-
- ( - t.value === value)?.label ?? value - : "Select a timezone" - } - options={timeZoneOptions} - onChange={onChange} - verticalPosition="top" - optionsClassName="w-full" - input - /> +
+ +
+

Display name

+ + { + if (value.trim().length < 1) return "Display name can't be empty."; + + if (value.split(" ").length > 1) + return "Display name can't have two consecutive spaces."; + + if (value.replace(/\s/g, "").length < 1) + return "Display name must be at least 1 characters long."; + + if (value.replace(/\s/g, "").length > 20) + return "Display name must be less than 20 characters long."; + + return true; + }, + }} + /> +
+ +
+

Timezone

+ + ( + t.value === value)?.label ?? value + : "Select a timezone" + } + options={timeZoneOptions} + onChange={onChange} + verticalPosition="top" + optionsClassName="w-full" + input + /> + )} + /> + {errors.role && ( + Please select a role )} - /> - {errors.role && Please select a role} +
+ +
+ + {isSubmitting ? "Updating Project..." : "Update Project"} + +
-
- - {isSubmitting ? "Updating..." : "Update profile"} - -
- -
+
+ ) : (
From c24058c46cc97b1042abc29350ce28186d3bf771 Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com> Date: Fri, 15 Sep 2023 13:53:08 +0530 Subject: [PATCH 5/5] chore: settings ui improvement and bug fixes --- .../automation/auto-close-automation.tsx | 6 +- .../labels/create-update-label-inline.tsx | 8 +- web/components/labels/single-label.tsx | 2 +- .../project/confirm-project-member-remove.tsx | 2 +- web/components/project/member-select.tsx | 2 +- .../project/send-project-invitation-modal.tsx | 15 ++- web/components/states/single-state.tsx | 43 +++--- .../confirm-workspace-member-remove.tsx | 2 +- web/components/workspace/index.ts | 1 - web/components/workspace/settings-header.tsx | 13 -- web/layouts/settings-navbar.tsx | 127 ------------------ .../me/profile/preferences.tsx | 22 ++- .../[projectId]/settings/features.tsx | 10 +- .../projects/[projectId]/settings/index.tsx | 3 +- .../projects/[projectId]/settings/labels.tsx | 6 +- .../projects/[projectId]/settings/members.tsx | 6 +- .../[workspaceSlug]/settings/members.tsx | 6 +- 17 files changed, 78 insertions(+), 196 deletions(-) delete mode 100644 web/components/workspace/settings-header.tsx delete mode 100644 web/layouts/settings-navbar.tsx diff --git a/web/components/automation/auto-close-automation.tsx b/web/components/automation/auto-close-automation.tsx index 8235c806347..868d6455737 100644 --- a/web/components/automation/auto-close-automation.tsx +++ b/web/components/automation/auto-close-automation.tsx @@ -103,8 +103,8 @@ export const AutoCloseAutomation: React.FC = ({ projectDetails, handleCha {projectDetails?.close_in !== 0 && (
-
-
+
+
Auto-close issues that are inactive for
@@ -138,7 +138,7 @@ export const AutoCloseAutomation: React.FC = ({ projectDetails, handleCha
-
+
Auto-close Status
( open ? "text-custom-text-100" : "text-custom-text-200" }`} > - diff --git a/web/components/labels/single-label.tsx b/web/components/labels/single-label.tsx index 464b331529d..be981e510d1 100644 --- a/web/components/labels/single-label.tsx +++ b/web/components/labels/single-label.tsx @@ -43,7 +43,7 @@ export const SingleLabel: React.FC = ({ > addLabelToGroup(label)}> - + Convert to group diff --git a/web/components/project/confirm-project-member-remove.tsx b/web/components/project/confirm-project-member-remove.tsx index bfce430a71a..4edc278219c 100644 --- a/web/components/project/confirm-project-member-remove.tsx +++ b/web/components/project/confirm-project-member-remove.tsx @@ -79,7 +79,7 @@ const ConfirmProjectMemberRemove: React.FC = ({ isOpen, onClose, data, ha
-
+
Cancel {isDeleteLoading ? "Removing..." : "Remove"} diff --git a/web/components/project/member-select.tsx b/web/components/project/member-select.tsx index e6eee911d20..5a1ec5cb1f7 100644 --- a/web/components/project/member-select.tsx +++ b/web/components/project/member-select.tsx @@ -49,7 +49,7 @@ export const MemberSelect: React.FC = ({ value, onChange }) => { {selectedOption ? ( selectedOption?.display_name ) : ( - Select + Select )}
} diff --git a/web/components/project/send-project-invitation-modal.tsx b/web/components/project/send-project-invitation-modal.tsx index b8f383f05ff..07b90840c86 100644 --- a/web/components/project/send-project-invitation-modal.tsx +++ b/web/components/project/send-project-invitation-modal.tsx @@ -219,7 +219,9 @@ const SendProjectInvitationModal: React.FC = (props) => { }
) : ( -
Select co-worker
+
+ Select co-worker +
)}
-
+
Cancel {isDeleteLoading ? "Removing..." : "Remove"} diff --git a/web/components/workspace/index.ts b/web/components/workspace/index.ts index 8e354a718a4..bb0f28a9367 100644 --- a/web/components/workspace/index.ts +++ b/web/components/workspace/index.ts @@ -6,7 +6,6 @@ export * from "./help-section"; export * from "./issues-list"; export * from "./issues-pie-chart"; export * from "./issues-stats"; -export * from "./settings-header"; export * from "./sidebar-dropdown"; export * from "./sidebar-menu"; export * from "./sidebar-quick-action"; diff --git a/web/components/workspace/settings-header.tsx b/web/components/workspace/settings-header.tsx deleted file mode 100644 index 2f11b8a9825..00000000000 --- a/web/components/workspace/settings-header.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import SettingsNavbar from "layouts/settings-navbar"; - -export const SettingsHeader = () => ( -
-
-

Workspace Settings

-

- This information will be displayed to every member of the workspace. -

-
- -
-); diff --git a/web/layouts/settings-navbar.tsx b/web/layouts/settings-navbar.tsx deleted file mode 100644 index 462a4b6a095..00000000000 --- a/web/layouts/settings-navbar.tsx +++ /dev/null @@ -1,127 +0,0 @@ -import Link from "next/link"; -import { useRouter } from "next/router"; - -type Props = { - profilePage?: boolean; -}; - -const SettingsNavbar: React.FC = ({ profilePage = false }) => { - const router = useRouter(); - const { workspaceSlug, projectId } = router.query; - - const workspaceLinks: Array<{ - label: string; - href: string; - }> = [ - { - label: "General", - href: `/${workspaceSlug}/settings`, - }, - { - label: "Members", - href: `/${workspaceSlug}/settings/members`, - }, - { - label: "Billing & Plans", - href: `/${workspaceSlug}/settings/billing`, - }, - { - label: "Integrations", - href: `/${workspaceSlug}/settings/integrations`, - }, - { - label: "Imports", - href: `/${workspaceSlug}/settings/imports`, - }, - { - label: "Exports", - href: `/${workspaceSlug}/settings/exports`, - }, - ]; - - const projectLinks: Array<{ - label: string; - href: string; - }> = [ - { - label: "General", - href: `/${workspaceSlug}/projects/${projectId}/settings`, - }, - { - label: "Control", - href: `/${workspaceSlug}/projects/${projectId}/settings/control`, - }, - { - label: "Members", - href: `/${workspaceSlug}/projects/${projectId}/settings/members`, - }, - { - label: "Features", - href: `/${workspaceSlug}/projects/${projectId}/settings/features`, - }, - { - label: "States", - href: `/${workspaceSlug}/projects/${projectId}/settings/states`, - }, - { - label: "Labels", - href: `/${workspaceSlug}/projects/${projectId}/settings/labels`, - }, - { - label: "Integrations", - href: `/${workspaceSlug}/projects/${projectId}/settings/integrations`, - }, - { - label: "Estimates", - href: `/${workspaceSlug}/projects/${projectId}/settings/estimates`, - }, - { - label: "Automations", - href: `/${workspaceSlug}/projects/${projectId}/settings/automations`, - }, - ]; - - const profileLinks: Array<{ - label: string; - href: string; - }> = [ - { - label: "General", - href: `/${workspaceSlug}/me/profile`, - }, - { - label: "Activity", - href: `/${workspaceSlug}/me/profile/activity`, - }, - { - label: "Preferences", - href: `/${workspaceSlug}/me/profile/preferences`, - }, - ]; - - return ( -
- {(profilePage ? profileLinks : projectId ? projectLinks : workspaceLinks).map((link) => ( - - -
- {link.label} -
-
- - ))} -
- ); -}; - -export default SettingsNavbar; diff --git a/web/pages/[workspaceSlug]/me/profile/preferences.tsx b/web/pages/[workspaceSlug]/me/profile/preferences.tsx index 8205ec129cc..031ed367cb1 100644 --- a/web/pages/[workspaceSlug]/me/profile/preferences.tsx +++ b/web/pages/[workspaceSlug]/me/profile/preferences.tsx @@ -3,7 +3,6 @@ import { useEffect, useState } from "react"; import useUserAuth from "hooks/use-user-auth"; // layouts import { WorkspaceAuthorizationLayout } from "layouts/auth-layout"; -import SettingsNavbar from "layouts/settings-navbar"; // components import { CustomThemeSelector, ThemeSwitch } from "components/core"; // ui @@ -15,6 +14,7 @@ import { ICustomTheme } from "types"; import { observer } from "mobx-react-lite"; // mobx store import { useMobxStore } from "lib/mobx/store-provider"; +import { SettingsSidebar } from "components/project"; const ProfilePreferences = observer(() => { const { user: myProfile } = useUserAuth(); @@ -59,18 +59,16 @@ const ProfilePreferences = observer(() => { } > {myProfile ? ( -
-
-
-

Profile Settings

-

- This information will be visible to only you. -

-
- +
+
+
-
-
+ +
+
+

Acitivity

+
+

Theme

diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/settings/features.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/settings/features.tsx index 0aaaf0b1c93..e72616c0ad6 100644 --- a/web/pages/[workspaceSlug]/projects/[projectId]/settings/features.tsx +++ b/web/pages/[workspaceSlug]/projects/[projectId]/settings/features.tsx @@ -19,7 +19,8 @@ import { ToggleSwitch } from "components/ui"; import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; // icons import { ModuleIcon } from "components/icons"; -import { Contrast, FileText, Inbox, Layers } from "lucide-react"; +import { FileText, Inbox, Layers } from "lucide-react"; +import { ContrastOutlined } from "@mui/icons-material"; // types import { IProject } from "types"; import type { NextPage } from "next"; @@ -33,7 +34,10 @@ const featuresList = [ title: "Cycles", description: "Cycles are enabled for all the projects in this workspace. Access them from the sidebar.", - icon: , + icon: ( + + ), + property: "cycle_view", }, { @@ -61,7 +65,7 @@ const featuresList = [ title: "Inbox", description: "Inbox are enabled for all the projects in this workspace. Access it from the issues views page.", - icon: , + icon: , property: "inbox_view", }, ]; diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/settings/index.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/settings/index.tsx index a31295fcccb..cd9e9e6ec2b 100644 --- a/web/pages/[workspaceSlug]/projects/[projectId]/settings/index.tsx +++ b/web/pages/[workspaceSlug]/projects/[projectId]/settings/index.tsx @@ -167,6 +167,7 @@ const GeneralSettings: NextPage = () => { }; const currentNetwork = NETWORK_CHOICES.find((n) => n.key === projectDetails?.network); + const selectedNetwork = NETWORK_CHOICES.find((n) => n.key === watch("network")); const isAdmin = memberDetails?.role === 20; @@ -349,7 +350,7 @@ const GeneralSettings: NextPage = () => { { } > -

+
-
+

Labels

@@ -129,7 +129,7 @@ const LabelsSettings: NextPage = () => { Add label
-
+
{labelForm && ( {
-

Members

+

Members

setInviteModal(true)}>Add Member
{!projectMembers || !projectInvitations ? ( @@ -386,7 +386,9 @@ const MembersSettings: NextPage = () => {

{member.display_name || member.email}

)} {isOwner && ( -

{member.email}

+

+ {member.email} +

)}
diff --git a/web/pages/[workspaceSlug]/settings/members.tsx b/web/pages/[workspaceSlug]/settings/members.tsx index f0fdf90dc57..435bdd24eae 100644 --- a/web/pages/[workspaceSlug]/settings/members.tsx +++ b/web/pages/[workspaceSlug]/settings/members.tsx @@ -192,7 +192,7 @@ const MembersSettings: NextPage = () => {
-

Members

+

Members

setInviteModal(true)}>Add Member
{!workspaceMembers || !workspaceInvitations ? ( @@ -250,7 +250,9 @@ const MembersSettings: NextPage = () => {

)} {isOwner && ( -

{member.email}

+

+ {member.email} +

)}