chore: adding page titles using project title. (#3692)

* chore: adding page titles

* chore: added title to remaining pages

* fix: added observer at required places

---------

Co-authored-by: LAKHAN BAHETI <lakhanbaheti9@gmail.com>
This commit is contained in:
sriram veeraghanta 2024-02-20 13:36:38 +05:30 committed by GitHub
parent 07a4cb1f7d
commit cf3b888465
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
60 changed files with 1684 additions and 1215 deletions

View file

@ -4,7 +4,7 @@ import { observer } from "mobx-react-lite";
import useSWR from "swr";
import { useTheme } from "next-themes";
// store hooks
import { useUser } from "hooks/store";
import { useUser, useWorkspace } from "hooks/store";
// layouts
import { AppLayout } from "layouts/app-layout";
import { WorkspaceSettingLayout } from "layouts/settings-layout";
@ -23,6 +23,7 @@ import { NextPageWithLayout } from "lib/types";
import { API_TOKENS_LIST } from "constants/fetch-keys";
import { EUserWorkspaceRoles } from "constants/workspace";
import { WORKSPACE_SETTINGS_EMPTY_STATE_DETAILS } from "constants/empty-state";
import { PageHead } from "components/core";
const apiTokenService = new APITokenService();
@ -39,6 +40,7 @@ const ApiTokensPage: NextPageWithLayout = observer(() => {
membership: { currentWorkspaceRole },
currentUser,
} = useUser();
const { currentWorkspace } = useWorkspace();
const isAdmin = currentWorkspaceRole === EUserWorkspaceRoles.ADMIN;
@ -49,12 +51,16 @@ const ApiTokensPage: NextPageWithLayout = observer(() => {
const emptyStateDetail = WORKSPACE_SETTINGS_EMPTY_STATE_DETAILS["api-tokens"];
const isLightMode = resolvedTheme ? resolvedTheme === "light" : currentUser?.theme.theme === "light";
const emptyStateImage = getEmptyStateImagePath("workspace-settings", "api-tokens", isLightMode);
const pageTitle = currentWorkspace?.name ? `${currentWorkspace.name} - API Tokens` : undefined;
if (!isAdmin)
return (
<div className="mt-10 flex h-full w-full justify-center p-4">
<p className="text-sm text-custom-text-300">You are not authorized to access this page.</p>
</div>
<>
<PageHead title={pageTitle} />
<div className="mt-10 flex h-full w-full justify-center p-4">
<p className="text-sm text-custom-text-300">You are not authorized to access this page.</p>
</div>
</>
);
if (!tokens) {
@ -63,6 +69,7 @@ const ApiTokensPage: NextPageWithLayout = observer(() => {
return (
<>
<PageHead title={pageTitle} />
<CreateApiTokenModal isOpen={isCreateTokenModalOpen} onClose={() => setIsCreateTokenModalOpen(false)} />
<section className="h-full w-full overflow-y-auto py-8 pr-9">
{tokens.length > 0 ? (

View file

@ -1,11 +1,12 @@
import { observer } from "mobx-react-lite";
// hooks
import { useUser } from "hooks/store";
import { useUser, useWorkspace } from "hooks/store";
// layouts
import { AppLayout } from "layouts/app-layout";
import { WorkspaceSettingLayout } from "layouts/settings-layout";
// component
import { WorkspaceSettingHeader } from "components/headers";
import { PageHead } from "components/core";
// ui
import { Button } from "@plane/ui";
// types
@ -18,33 +19,41 @@ const BillingSettingsPage: NextPageWithLayout = observer(() => {
const {
membership: { currentWorkspaceRole },
} = useUser();
const { currentWorkspace } = useWorkspace();
// derived values
const isAdmin = currentWorkspaceRole === EUserWorkspaceRoles.ADMIN;
const pageTitle = currentWorkspace?.name ? `${currentWorkspace.name} - Billing & Plans` : undefined;
if (!isAdmin)
return (
<div className="mt-10 flex h-full w-full justify-center p-4">
<p className="text-sm text-custom-text-300">You are not authorized to access this page.</p>
</div>
<>
<PageHead title={pageTitle} />
<div className="mt-10 flex h-full w-full justify-center p-4">
<p className="text-sm text-custom-text-300">You are not authorized to access this page.</p>
</div>
</>
);
return (
<section className="w-full overflow-y-auto py-8 pr-9">
<div>
<div className="flex items-center border-b border-custom-border-100 py-3.5">
<h3 className="text-xl font-medium">Billing & Plans</h3>
</div>
</div>
<div className="px-4 py-6">
<>
<PageHead title={pageTitle} />
<section className="w-full overflow-y-auto py-8 pr-9">
<div>
<h4 className="text-md mb-1 leading-6">Current plan</h4>
<p className="mb-3 text-sm text-custom-text-200">You are currently using the free plan</p>
<a href="https://plane.so/pricing" target="_blank" rel="noreferrer">
<Button variant="neutral-primary">View Plans</Button>
</a>
<div className="flex items-center border-b border-custom-border-100 py-3.5">
<h3 className="text-xl font-medium">Billing & Plans</h3>
</div>
</div>
</div>
</section>
<div className="px-4 py-6">
<div>
<h4 className="text-md mb-1 leading-6">Current plan</h4>
<p className="mb-3 text-sm text-custom-text-200">You are currently using the free plan</p>
<a href="https://plane.so/pricing" target="_blank" rel="noreferrer">
<Button variant="neutral-primary">View Plans</Button>
</a>
</div>
</div>
</section>
</>
);
});

View file

@ -1,12 +1,13 @@
import { observer } from "mobx-react-lite";
// hooks
import { useUser } from "hooks/store";
import { useUser, useWorkspace } from "hooks/store";
// layout
import { AppLayout } from "layouts/app-layout";
import { WorkspaceSettingLayout } from "layouts/settings-layout";
// components
import { WorkspaceSettingHeader } from "components/headers";
import ExportGuide from "components/exporter/guide";
import { PageHead } from "components/core";
// types
import { NextPageWithLayout } from "lib/types";
// constants
@ -17,24 +18,33 @@ const ExportsPage: NextPageWithLayout = observer(() => {
const {
membership: { currentWorkspaceRole },
} = useUser();
const { currentWorkspace } = useWorkspace();
// derived values
const hasPageAccess =
currentWorkspaceRole && [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER].includes(currentWorkspaceRole);
const pageTitle = currentWorkspace?.name ? `${currentWorkspace.name} - Exports` : undefined;
if (!hasPageAccess)
return (
<div className="mt-10 flex h-full w-full justify-center p-4">
<p className="text-sm text-custom-text-300">You are not authorized to access this page.</p>
</div>
<>
<PageHead title={pageTitle} />
<div className="mt-10 flex h-full w-full justify-center p-4">
<p className="text-sm text-custom-text-300">You are not authorized to access this page.</p>
</div>
</>
);
return (
<div className="w-full overflow-y-auto py-8 pr-9">
<div className="flex items-center border-b border-custom-border-100 py-3.5">
<h3 className="text-xl font-medium">Exports</h3>
<>
<PageHead title={pageTitle} />
<div className="w-full overflow-y-auto py-8 pr-9">
<div className="flex items-center border-b border-custom-border-100 py-3.5">
<h3 className="text-xl font-medium">Exports</h3>
</div>
<ExportGuide />
</div>
<ExportGuide />
</div>
</>
);
});

View file

@ -1,12 +1,13 @@
import { observer } from "mobx-react-lite";
// hooks
import { useUser } from "hooks/store";
import { useUser, useWorkspace } from "hooks/store";
// layouts
import { WorkspaceSettingLayout } from "layouts/settings-layout";
import { AppLayout } from "layouts/app-layout";
// components
import IntegrationGuide from "components/integration/guide";
import { WorkspaceSettingHeader } from "components/headers";
import { PageHead } from "components/core";
// types
import { NextPageWithLayout } from "lib/types";
// constants
@ -17,23 +18,32 @@ const ImportsPage: NextPageWithLayout = observer(() => {
const {
membership: { currentWorkspaceRole },
} = useUser();
const { currentWorkspace } = useWorkspace();
// derived values
const isAdmin = currentWorkspaceRole === EUserWorkspaceRoles.ADMIN;
const pageTitle = currentWorkspace?.name ? `${currentWorkspace.name} - Imports` : undefined;
if (!isAdmin)
return (
<div className="mt-10 flex h-full w-full justify-center p-4">
<p className="text-sm text-custom-text-300">You are not authorized to access this page.</p>
</div>
<>
<PageHead title={pageTitle} />
<div className="mt-10 flex h-full w-full justify-center p-4">
<p className="text-sm text-custom-text-300">You are not authorized to access this page.</p>
</div>
</>
);
return (
<section className="w-full overflow-y-auto py-8 pr-9">
<div className="flex items-center border-b border-custom-border-100 py-3.5">
<h3 className="text-xl font-medium">Imports</h3>
</div>
<IntegrationGuide />
</section>
<>
<PageHead title={pageTitle} />
<section className="w-full overflow-y-auto py-8 pr-9">
<div className="flex items-center border-b border-custom-border-100 py-3.5">
<h3 className="text-xl font-medium">Imports</h3>
</div>
<IntegrationGuide />
</section>
</>
);
});

View file

@ -1,14 +1,30 @@
import { ReactElement } from "react";
import { observer } from "mobx-react";
// layouts
import { AppLayout } from "layouts/app-layout";
import { WorkspaceSettingLayout } from "layouts/settings-layout";
// hooks
import { useWorkspace } from "hooks/store";
// components
import { WorkspaceSettingHeader } from "components/headers";
import { WorkspaceDetails } from "components/workspace";
import { PageHead } from "components/core";
// types
import { NextPageWithLayout } from "lib/types";
const WorkspaceSettingsPage: NextPageWithLayout = () => <WorkspaceDetails />;
const WorkspaceSettingsPage: NextPageWithLayout = observer(() => {
// store hooks
const { currentWorkspace } = useWorkspace();
// derived values
const pageTitle = currentWorkspace?.name ? `${currentWorkspace.name} - General Settings` : undefined;
return (
<>
<PageHead title={pageTitle} />
<WorkspaceDetails />
</>
);
});
WorkspaceSettingsPage.getLayout = function getLayout(page: ReactElement) {
return (

View file

@ -3,7 +3,7 @@ import { useRouter } from "next/router";
import { observer } from "mobx-react-lite";
import useSWR from "swr";
// hooks
import { useUser } from "hooks/store";
import { useUser, useWorkspace } from "hooks/store";
// services
import { IntegrationService } from "services/integrations";
// layouts
@ -12,6 +12,7 @@ import { WorkspaceSettingLayout } from "layouts/settings-layout";
// components
import { SingleIntegrationCard } from "components/integration";
import { WorkspaceSettingHeader } from "components/headers";
import { PageHead } from "components/core";
// ui
import { IntegrationAndImportExportBanner, IntegrationsSettingsLoader } from "components/ui";
// types
@ -31,14 +32,20 @@ const WorkspaceIntegrationsPage: NextPageWithLayout = observer(() => {
const {
membership: { currentWorkspaceRole },
} = useUser();
const { currentWorkspace } = useWorkspace();
// derived values
const isAdmin = currentWorkspaceRole === EUserWorkspaceRoles.ADMIN;
const pageTitle = currentWorkspace?.name ? `${currentWorkspace.name} - Integrations` : undefined;
if (!isAdmin)
return (
<div className="mt-10 flex h-full w-full justify-center p-4">
<p className="text-sm text-custom-text-300">You are not authorized to access this page.</p>
</div>
<>
<PageHead title={pageTitle} />
<div className="mt-10 flex h-full w-full justify-center p-4">
<p className="text-sm text-custom-text-300">You are not authorized to access this page.</p>
</div>
</>
);
const { data: appIntegrations } = useSWR(workspaceSlug && isAdmin ? APP_INTEGRATIONS : null, () =>
@ -46,16 +53,21 @@ const WorkspaceIntegrationsPage: NextPageWithLayout = observer(() => {
);
return (
<section className="w-full overflow-y-auto py-8 pr-9">
<IntegrationAndImportExportBanner bannerName="Integrations" />
<div>
{appIntegrations ? (
appIntegrations.map((integration) => <SingleIntegrationCard key={integration.id} integration={integration} />)
) : (
<IntegrationsSettingsLoader />
)}
</div>
</section>
<>
<PageHead title={pageTitle} />
<section className="w-full overflow-y-auto py-8 pr-9">
<IntegrationAndImportExportBanner bannerName="Integrations" />
<div>
{appIntegrations ? (
appIntegrations.map((integration) => (
<SingleIntegrationCard key={integration.id} integration={integration} />
))
) : (
<IntegrationsSettingsLoader />
)}
</div>
</section>
</>
);
});

View file

@ -3,7 +3,7 @@ import { useRouter } from "next/router";
import { observer } from "mobx-react-lite";
import { Search } from "lucide-react";
// hooks
import { useEventTracker, useMember, useUser } from "hooks/store";
import { useEventTracker, useMember, useUser, useWorkspace } from "hooks/store";
import useToast from "hooks/use-toast";
// layouts
import { AppLayout } from "layouts/app-layout";
@ -11,6 +11,7 @@ import { WorkspaceSettingLayout } from "layouts/settings-layout";
// components
import { WorkspaceSettingHeader } from "components/headers";
import { SendWorkspaceInvitationModal, WorkspaceMembersList } from "components/workspace";
import { PageHead } from "components/core";
// ui
import { Button } from "@plane/ui";
// types
@ -37,6 +38,7 @@ const WorkspaceMembersSettingsPage: NextPageWithLayout = observer(() => {
const {
workspace: { inviteMembersToWorkspace },
} = useMember();
const { currentWorkspace } = useWorkspace();
// toast alert
const { setToastAlert } = useToast();
@ -83,11 +85,14 @@ const WorkspaceMembersSettingsPage: NextPageWithLayout = observer(() => {
});
};
// derived values
const hasAddMemberPermission =
currentWorkspaceRole && [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER].includes(currentWorkspaceRole);
const pageTitle = currentWorkspace?.name ? `${currentWorkspace.name} - Members` : undefined;
return (
<>
<PageHead title={pageTitle} />
<SendWorkspaceInvitationModal
isOpen={inviteModal}
onClose={() => setInviteModal(false)}

View file

@ -3,7 +3,7 @@ import { useRouter } from "next/router";
import { observer } from "mobx-react-lite";
import useSWR from "swr";
// hooks
import { useUser, useWebhook } from "hooks/store";
import { useUser, useWebhook, useWorkspace } from "hooks/store";
// layouts
import { AppLayout } from "layouts/app-layout";
import { WorkspaceSettingLayout } from "layouts/settings-layout";
@ -12,6 +12,7 @@ import useToast from "hooks/use-toast";
// components
import { WorkspaceSettingHeader } from "components/headers";
import { DeleteWebhookModal, WebhookDeleteSection, WebhookForm } from "components/web-hooks";
import { PageHead } from "components/core";
// ui
import { Spinner } from "@plane/ui";
// types
@ -29,6 +30,7 @@ const WebhookDetailsPage: NextPageWithLayout = observer(() => {
membership: { currentWorkspaceRole },
} = useUser();
const { currentWebhook, fetchWebhookById, updateWebhook } = useWebhook();
const { currentWorkspace } = useWorkspace();
// toast
const { setToastAlert } = useToast();
@ -38,6 +40,7 @@ const WebhookDetailsPage: NextPageWithLayout = observer(() => {
// }, [clearSecretKey, isCreated]);
const isAdmin = currentWorkspaceRole === 20;
const pageTitle = currentWorkspace?.name ? `${currentWorkspace.name} - Webhook` : undefined;
useSWR(
workspaceSlug && webhookId && isAdmin ? `WEBHOOK_DETAILS_${workspaceSlug}_${webhookId}` : null,
@ -76,9 +79,12 @@ const WebhookDetailsPage: NextPageWithLayout = observer(() => {
if (!isAdmin)
return (
<div className="mt-10 flex h-full w-full justify-center p-4">
<p className="text-sm text-custom-text-300">You are not authorized to access this page.</p>
</div>
<>
<PageHead title={pageTitle} />
<div className="mt-10 flex h-full w-full justify-center p-4">
<p className="text-sm text-custom-text-300">You are not authorized to access this page.</p>
</div>
</>
);
if (!currentWebhook)
@ -90,6 +96,7 @@ const WebhookDetailsPage: NextPageWithLayout = observer(() => {
return (
<>
<PageHead title={pageTitle} />
<DeleteWebhookModal isOpen={deleteWebhookModal} onClose={() => setDeleteWebhookModal(false)} />
<div className="w-full space-y-8 overflow-y-auto py-8 pr-9">
<WebhookForm onSubmit={async (data) => await handleUpdateWebhook(data)} data={currentWebhook} />

View file

@ -19,6 +19,7 @@ import { WebhookSettingsLoader } from "components/ui";
import { NextPageWithLayout } from "lib/types";
// constants
import { WORKSPACE_SETTINGS_EMPTY_STATE_DETAILS } from "constants/empty-state";
import { PageHead } from "components/core";
const WebhooksListPage: NextPageWithLayout = observer(() => {
// states
@ -47,6 +48,7 @@ const WebhooksListPage: NextPageWithLayout = observer(() => {
const isLightMode = resolvedTheme ? resolvedTheme === "light" : currentUser?.theme.theme === "light";
const emptyStateImage = getEmptyStateImagePath("workspace-settings", "webhooks", isLightMode);
const pageTitle = currentWorkspace?.name ? `${currentWorkspace.name} - Webhooks` : undefined;
// clear secret key when modal is closed.
useEffect(() => {
@ -55,53 +57,59 @@ const WebhooksListPage: NextPageWithLayout = observer(() => {
if (!isAdmin)
return (
<div className="mt-10 flex h-full w-full justify-center p-4">
<p className="text-sm text-custom-text-300">You are not authorized to access this page.</p>
</div>
<>
<PageHead title={pageTitle} />
<div className="mt-10 flex h-full w-full justify-center p-4">
<p className="text-sm text-custom-text-300">You are not authorized to access this page.</p>
</div>
</>
);
if (!webhooks) return <WebhookSettingsLoader />;
return (
<div className="h-full w-full overflow-hidden py-8 pr-9">
<CreateWebhookModal
createWebhook={createWebhook}
clearSecretKey={clearSecretKey}
currentWorkspace={currentWorkspace}
isOpen={showCreateWebhookModal}
onClose={() => {
setShowCreateWebhookModal(false);
}}
/>
{Object.keys(webhooks).length > 0 ? (
<div className="flex h-full w-full flex-col">
<div className="flex items-center justify-between gap-4 border-b border-custom-border-200 pb-3.5">
<div className="text-xl font-medium">Webhooks</div>
<Button variant="primary" size="sm" onClick={() => setShowCreateWebhookModal(true)}>
Add webhook
</Button>
<>
<PageHead title={pageTitle} />
<div className="h-full w-full overflow-hidden py-8 pr-9">
<CreateWebhookModal
createWebhook={createWebhook}
clearSecretKey={clearSecretKey}
currentWorkspace={currentWorkspace}
isOpen={showCreateWebhookModal}
onClose={() => {
setShowCreateWebhookModal(false);
}}
/>
{Object.keys(webhooks).length > 0 ? (
<div className="flex h-full w-full flex-col">
<div className="flex items-center justify-between gap-4 border-b border-custom-border-200 pb-3.5">
<div className="text-xl font-medium">Webhooks</div>
<Button variant="primary" size="sm" onClick={() => setShowCreateWebhookModal(true)}>
Add webhook
</Button>
</div>
<WebhooksList />
</div>
<WebhooksList />
</div>
) : (
<div className="flex h-full w-full flex-col">
<div className="flex items-center justify-between gap-4 border-b border-custom-border-200 pb-3.5">
<div className="text-xl font-medium">Webhooks</div>
<Button variant="primary" size="sm" onClick={() => setShowCreateWebhookModal(true)}>
Add webhook
</Button>
) : (
<div className="flex h-full w-full flex-col">
<div className="flex items-center justify-between gap-4 border-b border-custom-border-200 pb-3.5">
<div className="text-xl font-medium">Webhooks</div>
<Button variant="primary" size="sm" onClick={() => setShowCreateWebhookModal(true)}>
Add webhook
</Button>
</div>
<div className="h-full w-full flex items-center justify-center">
<EmptyState
title={emptyStateDetail.title}
description={emptyStateDetail.description}
image={emptyStateImage}
size="lg"
/>
</div>
</div>
<div className="h-full w-full flex items-center justify-center">
<EmptyState
title={emptyStateDetail.title}
description={emptyStateDetail.description}
image={emptyStateImage}
size="lg"
/>
</div>
</div>
)}
</div>
)}
</div>
</>
);
});