feat: init
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled

This commit is contained in:
chuan
2025-11-11 01:56:44 +08:00
commit bba4bb40c8
4638 changed files with 447437 additions and 0 deletions

View File

@@ -0,0 +1,29 @@
"use client";
import { observer } from "mobx-react";
import { useTranslation } from "@plane/i18n";
import { AnalyticsIcon } from "@plane/propel/icons";
// plane imports
import { Breadcrumbs, Header } from "@plane/ui";
// components
import { BreadcrumbLink } from "@/components/common/breadcrumb-link";
export const WorkspaceAnalyticsHeader = observer(() => {
const { t } = useTranslation();
return (
<Header>
<Header.LeftItem>
<Breadcrumbs>
<Breadcrumbs.Item
component={
<BreadcrumbLink
label={t("workspace_analytics.label")}
icon={<AnalyticsIcon className="h-4 w-4 text-custom-text-300" />}
/>
}
/>
</Breadcrumbs>
</Header.LeftItem>
</Header>
);
});

View File

@@ -0,0 +1,14 @@
"use client";
// components
import { AppHeader } from "@/components/core/app-header";
import { ContentWrapper } from "@/components/core/content-wrapper";
import { WorkspaceAnalyticsHeader } from "./header";
export default function WorkspaceAnalyticsTabLayout({ children }: { children: React.ReactNode }) {
return (
<>
<AppHeader header={<WorkspaceAnalyticsHeader />} />
<ContentWrapper>{children}</ContentWrapper>
</>
);
}

View File

@@ -0,0 +1,123 @@
"use client";
import { useMemo } from "react";
import { observer } from "mobx-react";
import { useRouter } from "next/navigation";
// plane package imports
import { EUserPermissions, EUserPermissionsLevel, PROJECT_TRACKER_ELEMENTS } from "@plane/constants";
import { useTranslation } from "@plane/i18n";
import { Tabs } from "@plane/ui";
import type { TabItem } from "@plane/ui";
// components
import AnalyticsFilterActions from "@/components/analytics/analytics-filter-actions";
import { PageHead } from "@/components/core/page-title";
import { ComicBoxButton } from "@/components/empty-state/comic-box-button";
import { DetailedEmptyState } from "@/components/empty-state/detailed-empty-state-root";
// hooks
import { captureClick } from "@/helpers/event-tracker.helper";
import { useCommandPalette } from "@/hooks/store/use-command-palette";
import { useProject } from "@/hooks/store/use-project";
import { useWorkspace } from "@/hooks/store/use-workspace";
import { useUserPermissions } from "@/hooks/store/user";
import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path";
import { getAnalyticsTabs } from "@/plane-web/components/analytics/tabs";
type Props = {
params: {
tabId: string;
workspaceSlug: string;
};
};
const AnalyticsPage = observer((props: Props) => {
// props
const { params } = props;
const { tabId } = params;
// hooks
const router = useRouter();
// plane imports
const { t } = useTranslation();
// store hooks
const { toggleCreateProjectModal } = useCommandPalette();
const { workspaceProjectIds, loader } = useProject();
const { currentWorkspace } = useWorkspace();
const { allowPermissions } = useUserPermissions();
// helper hooks
const resolvedPath = useResolvedAssetPath({ basePath: "/empty-state/onboarding/analytics" });
// permissions
const canPerformEmptyStateActions = allowPermissions(
[EUserPermissions.ADMIN, EUserPermissions.MEMBER],
EUserPermissionsLevel.WORKSPACE
);
// derived values
const pageTitle = currentWorkspace?.name
? t(`workspace_analytics.page_label`, { workspace: currentWorkspace?.name })
: undefined;
const ANALYTICS_TABS = useMemo(() => getAnalyticsTabs(t), [t]);
const tabs: TabItem[] = useMemo(
() =>
ANALYTICS_TABS.map((tab) => ({
key: tab.key,
label: tab.label,
content: <tab.content />,
onClick: () => {
router.push(`/${currentWorkspace?.slug}/analytics/${tab.key}`);
},
disabled: tab.isDisabled,
})),
[ANALYTICS_TABS, router, currentWorkspace?.slug]
);
const defaultTab = tabId || ANALYTICS_TABS[0].key;
return (
<>
<PageHead title={pageTitle} />
{workspaceProjectIds && (
<>
{workspaceProjectIds.length > 0 || loader === "init-loader" ? (
<div className="flex h-full overflow-hidden bg-custom-background-100 justify-between items-center ">
<Tabs
tabs={tabs}
storageKey={`analytics-page-${currentWorkspace?.id}`}
defaultTab={defaultTab}
size="md"
tabListContainerClassName="px-6 py-2 border-b border-custom-border-200 flex items-center justify-between"
tabListClassName="my-2 w-auto"
tabClassName="px-3"
tabPanelClassName="h-full overflow-hidden overflow-y-auto px-2"
storeInLocalStorage={false}
actions={<AnalyticsFilterActions />}
/>
</div>
) : (
<DetailedEmptyState
title={t("workspace_analytics.empty_state.general.title")}
description={t("workspace_analytics.empty_state.general.description")}
assetPath={resolvedPath}
customPrimaryButton={
<ComicBoxButton
label={t("workspace_analytics.empty_state.general.primary_button.text")}
title={t("workspace_analytics.empty_state.general.primary_button.comic.title")}
description={t("workspace_analytics.empty_state.general.primary_button.comic.description")}
onClick={() => {
toggleCreateProjectModal(true);
captureClick({ elementName: PROJECT_TRACKER_ELEMENTS.EMPTY_STATE_CREATE_PROJECT_BUTTON });
}}
disabled={!canPerformEmptyStateActions}
/>
}
/>
)}
</>
)}
</>
);
});
export default AnalyticsPage;