Merge branch 'preview' of github.com:makeplane/plane into develop

This commit is contained in:
sriram veeraghanta 2024-02-09 15:59:44 +05:30
commit 41a3cb708c
11 changed files with 118 additions and 64 deletions

View File

@ -10,6 +10,8 @@ import { CustomAnalyticsSelectBar, CustomAnalyticsMainContent, CustomAnalyticsSi
import { IAnalyticsParams } from "@plane/types"; import { IAnalyticsParams } from "@plane/types";
// fetch-keys // fetch-keys
import { ANALYTICS } from "constants/fetch-keys"; import { ANALYTICS } from "constants/fetch-keys";
import { cn } from "helpers/common.helper";
import { useApplication } from "hooks/store";
type Props = { type Props = {
additionalParams?: Partial<IAnalyticsParams>; additionalParams?: Partial<IAnalyticsParams>;
@ -46,11 +48,13 @@ export const CustomAnalytics: React.FC<Props> = observer((props) => {
workspaceSlug ? () => analyticsService.getAnalytics(workspaceSlug.toString(), params) : null workspaceSlug ? () => analyticsService.getAnalytics(workspaceSlug.toString(), params) : null
); );
const { theme: themeStore } = useApplication();
const isProjectLevel = projectId ? true : false; const isProjectLevel = projectId ? true : false;
return ( return (
<div className={`flex flex-col-reverse overflow-hidden ${fullScreen ? "md:grid md:h-full md:grid-cols-4" : ""}`}> <div className={cn("relative w-full h-full flex overflow-hidden", isProjectLevel ? "flex-col-reverse" : "")}>
<div className="col-span-3 flex h-full flex-col overflow-hidden"> <div className="w-full flex h-full flex-col overflow-hidden">
<CustomAnalyticsSelectBar <CustomAnalyticsSelectBar
control={control} control={control}
setValue={setValue} setValue={setValue}
@ -61,16 +65,22 @@ export const CustomAnalytics: React.FC<Props> = observer((props) => {
<CustomAnalyticsMainContent <CustomAnalyticsMainContent
analytics={analytics} analytics={analytics}
error={analyticsError} error={analyticsError}
fullScreen={fullScreen}
params={params} params={params}
fullScreen={fullScreen}
/> />
</div> </div>
<CustomAnalyticsSidebar
analytics={analytics} <div
params={params} className={cn(
fullScreen={fullScreen} "border-l border-custom-border-200 transition-all",
isProjectLevel={isProjectLevel} !isProjectLevel
/> ? "absolute right-0 top-0 bottom-0 md:relative flex-shrink-0 h-full max-w-[250px] sm:max-w-full"
: ""
)}
style={themeStore.workspaceAnalyticsSidebarCollapsed ? { right: `-${window?.innerWidth || 0}px` } : {}}
>
<CustomAnalyticsSidebar analytics={analytics} params={params} isProjectLevel={isProjectLevel} />
</div>
</div> </div>
); );
}); });

View File

@ -22,9 +22,8 @@ export const CustomAnalyticsSelectBar: React.FC<Props> = observer((props) => {
return ( return (
<div <div
className={`grid items-center gap-4 px-5 py-2.5 ${isProjectLevel ? "grid-cols-3" : "grid-cols-2"} ${ className={`grid items-center gap-4 px-5 py-2.5 ${isProjectLevel ? "grid-cols-1 sm:grid-cols-3" : "grid-cols-2"} ${fullScreen ? "md:py-5 lg:grid-cols-4" : ""
fullScreen ? "md:py-5 lg:grid-cols-4" : "" }`}
}`}
> >
{!isProjectLevel && ( {!isProjectLevel && (
<div> <div>

View File

@ -17,9 +17,9 @@ export const CustomAnalyticsSidebarProjectsList: React.FC<Props> = observer((pro
const { getProjectById } = useProject(); const { getProjectById } = useProject();
return ( return (
<div className="hidden h-full overflow-hidden md:flex md:flex-col"> <div className="relative flex flex-col gap-4 h-full">
<h4 className="font-medium">Selected Projects</h4> <h4 className="font-medium">Selected Projects</h4>
<div className="mt-4 h-full space-y-6 overflow-y-auto"> <div className="relative space-y-6 overflow-hidden overflow-y-auto">
{projectIds.map((projectId) => { {projectIds.map((projectId) => {
const project = getProjectById(projectId); const project = getProjectById(projectId);

View File

@ -26,7 +26,7 @@ export const CustomAnalyticsSidebarHeader = observer(() => {
<> <>
{projectId ? ( {projectId ? (
cycleDetails ? ( cycleDetails ? (
<div className="hidden h-full overflow-y-auto md:block"> <div className="h-full overflow-y-auto">
<h4 className="break-words font-medium">Analytics for {cycleDetails.name}</h4> <h4 className="break-words font-medium">Analytics for {cycleDetails.name}</h4>
<div className="mt-4 space-y-4"> <div className="mt-4 space-y-4">
<div className="flex items-center gap-2 text-xs"> <div className="flex items-center gap-2 text-xs">
@ -52,7 +52,7 @@ export const CustomAnalyticsSidebarHeader = observer(() => {
</div> </div>
</div> </div>
) : moduleDetails ? ( ) : moduleDetails ? (
<div className="hidden h-full overflow-y-auto md:block"> <div className="h-full overflow-y-auto">
<h4 className="break-words font-medium">Analytics for {moduleDetails.name}</h4> <h4 className="break-words font-medium">Analytics for {moduleDetails.name}</h4>
<div className="mt-4 space-y-4"> <div className="mt-4 space-y-4">
<div className="flex items-center gap-2 text-xs"> <div className="flex items-center gap-2 text-xs">
@ -78,7 +78,7 @@ export const CustomAnalyticsSidebarHeader = observer(() => {
</div> </div>
</div> </div>
) : ( ) : (
<div className="hidden h-full overflow-y-auto md:flex md:flex-col"> <div className="h-full overflow-y-auto">
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
{projectDetails?.emoji ? ( {projectDetails?.emoji ? (
<div className="grid h-6 w-6 flex-shrink-0 place-items-center">{renderEmoji(projectDetails.emoji)}</div> <div className="grid h-6 w-6 flex-shrink-0 place-items-center">{renderEmoji(projectDetails.emoji)}</div>

View File

@ -1,4 +1,4 @@
import { useEffect } from "react"; import { useEffect, } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
import { mutate } from "swr"; import { mutate } from "swr";
@ -19,18 +19,18 @@ import { renderFormattedDate } from "helpers/date-time.helper";
import { IAnalyticsParams, IAnalyticsResponse, IExportAnalyticsFormData, IWorkspace } from "@plane/types"; import { IAnalyticsParams, IAnalyticsResponse, IExportAnalyticsFormData, IWorkspace } from "@plane/types";
// fetch-keys // fetch-keys
import { ANALYTICS } from "constants/fetch-keys"; import { ANALYTICS } from "constants/fetch-keys";
import { cn } from "helpers/common.helper";
type Props = { type Props = {
analytics: IAnalyticsResponse | undefined; analytics: IAnalyticsResponse | undefined;
params: IAnalyticsParams; params: IAnalyticsParams;
fullScreen: boolean;
isProjectLevel: boolean; isProjectLevel: boolean;
}; };
const analyticsService = new AnalyticsService(); const analyticsService = new AnalyticsService();
export const CustomAnalyticsSidebar: React.FC<Props> = observer((props) => { export const CustomAnalyticsSidebar: React.FC<Props> = observer((props) => {
const { analytics, params, fullScreen, isProjectLevel = false } = props; const { analytics, params, isProjectLevel = false } = props;
// router // router
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId, cycleId, moduleId } = router.query; const { workspaceSlug, projectId, cycleId, moduleId } = router.query;
@ -138,18 +138,14 @@ export const CustomAnalyticsSidebar: React.FC<Props> = observer((props) => {
const selectedProjects = params.project && params.project.length > 0 ? params.project : workspaceProjectIds; const selectedProjects = params.project && params.project.length > 0 ? params.project : workspaceProjectIds;
return ( return (
<div <div className={cn("relative h-full flex w-full gap-2 justify-between items-start px-5 py-4 bg-custom-sidebar-background-100", !isProjectLevel ? "flex-col" : "")}
className={`flex items-center justify-between space-y-2 px-5 py-2.5 ${
fullScreen
? "overflow-hidden border-l border-custom-border-200 md:h-full md:flex-col md:items-start md:space-y-4 md:border-l md:border-custom-border-200 md:py-5"
: ""
}`}
> >
<div className="flex flex-wrap items-center gap-2"> <div className="flex flex-wrap items-center gap-2">
<div className="flex items-center gap-1 rounded-md bg-custom-background-80 px-3 py-1 text-xs text-custom-text-200"> <div className="flex items-center gap-1 rounded-md bg-custom-background-80 px-3 py-1 text-xs text-custom-text-200">
<LayersIcon height={14} width={14} /> <LayersIcon height={14} width={14} />
{analytics ? analytics.total : "..."} Issues {analytics ? analytics.total : "..."} <div className={cn(isProjectLevel ? "hidden md:block" : "")}>Issues</div>
</div> </div>
{isProjectLevel && ( {isProjectLevel && (
<div className="flex items-center gap-1 rounded-md bg-custom-background-80 px-3 py-1 text-xs text-custom-text-200"> <div className="flex items-center gap-1 rounded-md bg-custom-background-80 px-3 py-1 text-xs text-custom-text-200">
@ -158,36 +154,36 @@ export const CustomAnalyticsSidebar: React.FC<Props> = observer((props) => {
(cycleId (cycleId
? cycleDetails?.created_at ? cycleDetails?.created_at
: moduleId : moduleId
? moduleDetails?.created_at ? moduleDetails?.created_at
: projectDetails?.created_at) ?? "" : projectDetails?.created_at) ?? ""
)} )}
</div> </div>
)} )}
</div> </div>
<div className="h-full w-full overflow-hidden">
{fullScreen ? ( <div className={cn("h-full w-full overflow-hidden", isProjectLevel ? "hidden" : "block")}>
<> <>
{!isProjectLevel && selectedProjects && selectedProjects.length > 0 && ( {!isProjectLevel && selectedProjects && selectedProjects.length > 0 && (
<CustomAnalyticsSidebarProjectsList projectIds={selectedProjects} /> <CustomAnalyticsSidebarProjectsList projectIds={selectedProjects} />
)} )}
<CustomAnalyticsSidebarHeader /> <CustomAnalyticsSidebarHeader />
</> </>
) : null}
</div> </div>
<div className="flex flex-wrap items-center gap-2 justify-self-end">
<div className="flex flex-wrap items-center gap-2 justify-end">
<Button <Button
variant="neutral-primary" variant="neutral-primary"
prependIcon={<RefreshCw className="h-3.5 w-3.5" />} prependIcon={<RefreshCw className="h-3 md:h-3.5 w-3 md:w-3.5" />}
onClick={() => { onClick={() => {
if (!workspaceSlug) return; if (!workspaceSlug) return;
mutate(ANALYTICS(workspaceSlug.toString(), params)); mutate(ANALYTICS(workspaceSlug.toString(), params));
}} }}
> >
Refresh <div className={cn(isProjectLevel ? "hidden md:block" : "")}>Refresh</div>
</Button> </Button>
<Button variant="primary" prependIcon={<Download className="h-3.5 w-3.5" />} onClick={exportAnalytics}> <Button variant="primary" prependIcon={<Download className="h-3.5 w-3.5" />} onClick={exportAnalytics}>
Export as CSV <div className={cn(isProjectLevel ? "hidden md:block" : "")}>Export as CSV</div>
</Button> </Button>
</div> </div>
</div> </div>

View File

@ -20,16 +20,15 @@ export const ProjectAnalyticsModalMainContent: React.FC<Props> = observer((props
return ( return (
<Tab.Group as={React.Fragment}> <Tab.Group as={React.Fragment}>
<Tab.List as="div" className="space-x-2 border-b border-custom-border-200 p-5 pt-0"> <Tab.List as="div" className="flex space-x-2 border-b border-custom-border-200 px-0 md:px-5 py-0 md:py-3">
{ANALYTICS_TABS.map((tab) => ( {ANALYTICS_TABS.map((tab) => (
<Tab <Tab
key={tab.key} key={tab.key}
className={({ selected }) => className={({ selected }) =>
`rounded-3xl border border-custom-border-200 px-4 py-2 text-xs hover:bg-custom-background-80 ${ `rounded-0 w-full md:w-max md:rounded-3xl border-b md:border border-custom-border-200 focus:outline-none px-0 md:px-4 py-2 text-xs hover:bg-custom-background-80 ${selected ? "border-custom-primary-100 text-custom-primary-100 md:bg-custom-background-80 md:text-custom-text-200 md:border-custom-border-200" : "border-transparent"
selected ? "bg-custom-background-80" : ""
}` }`
} }
onClick={() => {}} onClick={() => { }}
> >
{tab.title} {tab.title}
</Tab> </Tab>

View File

@ -64,7 +64,7 @@ export const UserProfileHeader: FC<TUserProfileHeader> = observer((props) => {
</CustomMenu.MenuItem> </CustomMenu.MenuItem>
))} ))}
</CustomMenu> </CustomMenu>
<button className="transition-all block md:hidden" onClick={() => { themStore.toggleProfileSidebar(); console.log(themStore.profileSidebarCollapsed) }}> <button className="transition-all block md:hidden" onClick={() => { themStore.toggleProfileSidebar() }}>
<PanelRight className={ <PanelRight className={
cn("w-4 h-4 block md:hidden", !themStore.profileSidebarCollapsed ? "text-[#3E63DD]" : "text-custom-text-200") cn("w-4 h-4 block md:hidden", !themStore.profileSidebarCollapsed ? "text-[#3E63DD]" : "text-custom-text-200")
} /> } />

View File

@ -1,13 +1,35 @@
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { ArrowLeft, BarChart2 } from "lucide-react"; import { BarChart2, PanelRight } from "lucide-react";
// ui // ui
import { Breadcrumbs } from "@plane/ui"; import { Breadcrumbs } from "@plane/ui";
// components // components
import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle"; import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle";
import { BreadcrumbLink } from "components/common"; import { BreadcrumbLink } from "components/common";
import { useApplication } from "hooks/store";
import { observer } from "mobx-react";
import { cn } from "helpers/common.helper";
import { useEffect } from "react";
export const WorkspaceAnalyticsHeader = () => { export const WorkspaceAnalyticsHeader = observer(() => {
const router = useRouter(); const router = useRouter();
const { analytics_tab } = router.query;
const { theme: themeStore } = useApplication();
useEffect(() => {
const handleToggleWorkspaceAnalyticsSidebar = () => {
if (window && window.innerWidth < 768) {
themeStore.toggleWorkspaceAnalyticsSidebar(true);
}
if (window && themeStore.workspaceAnalyticsSidebarCollapsed && window.innerWidth >= 768) {
themeStore.toggleWorkspaceAnalyticsSidebar(false);
}
};
window.addEventListener("resize", handleToggleWorkspaceAnalyticsSidebar);
handleToggleWorkspaceAnalyticsSidebar();
return () => window.removeEventListener("resize", handleToggleWorkspaceAnalyticsSidebar);
}, [themeStore]);
return ( return (
<> <>
@ -16,7 +38,7 @@ export const WorkspaceAnalyticsHeader = () => {
> >
<div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap"> <div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
<SidebarHamburgerToggle /> <SidebarHamburgerToggle />
<div> <div className="flex items-center justify-between w-full">
<Breadcrumbs> <Breadcrumbs>
<Breadcrumbs.BreadcrumbItem <Breadcrumbs.BreadcrumbItem
type="text" type="text"
@ -25,9 +47,14 @@ export const WorkspaceAnalyticsHeader = () => {
} }
/> />
</Breadcrumbs> </Breadcrumbs>
{analytics_tab === 'custom' &&
<button className="block md:hidden" onClick={() => { themeStore.toggleWorkspaceAnalyticsSidebar() }}>
<PanelRight className={cn("w-4 h-4 block md:hidden", !themeStore.workspaceAnalyticsSidebarCollapsed ? "text-custom-primary-100" : "text-custom-text-200")} />
</button>
}
</div> </div>
</div> </div>
</div> </div>
</> </>
); );
}; });

View File

@ -30,7 +30,7 @@ export const ProfileSidebar = observer(() => {
const { workspaceSlug, userId } = router.query; const { workspaceSlug, userId } = router.query;
// store hooks // store hooks
const { currentUser } = useUser(); const { currentUser } = useUser();
const { theme: themStore } = useApplication(); const { theme: themeStore } = useApplication();
const ref = useRef<HTMLDivElement>(null); const ref = useRef<HTMLDivElement>(null);
const { data: userProjectsData } = useSWR( const { data: userProjectsData } = useSWR(
@ -41,9 +41,9 @@ export const ProfileSidebar = observer(() => {
); );
useOutsideClickDetector(ref, () => { useOutsideClickDetector(ref, () => {
if (themStore.profileSidebarCollapsed === false) { if (themeStore.profileSidebarCollapsed === false) {
if (window.innerWidth < 768) { if (window.innerWidth < 768) {
themStore.toggleProfileSidebar(); themeStore.toggleProfileSidebar();
} }
} }
}); });
@ -62,22 +62,22 @@ export const ProfileSidebar = observer(() => {
useEffect(() => { useEffect(() => {
const handleToggleProfileSidebar = () => { const handleToggleProfileSidebar = () => {
if (window && window.innerWidth < 768) { if (window && window.innerWidth < 768) {
themStore.toggleProfileSidebar(true); themeStore.toggleProfileSidebar(true);
} }
if (window && themStore.profileSidebarCollapsed && window.innerWidth >= 768) { if (window && themeStore.profileSidebarCollapsed && window.innerWidth >= 768) {
themStore.toggleProfileSidebar(false); themeStore.toggleProfileSidebar(false);
} }
}; };
window.addEventListener("resize", handleToggleProfileSidebar); window.addEventListener("resize", handleToggleProfileSidebar);
handleToggleProfileSidebar(); handleToggleProfileSidebar();
return () => window.removeEventListener("resize", handleToggleProfileSidebar); return () => window.removeEventListener("resize", handleToggleProfileSidebar);
}, [themStore]); }, [themeStore]);
return ( return (
<div <div
className={`flex-shrink-0 overflow-hidden overflow-y-auto shadow-custom-shadow-sm border-l border-custom-border-100 bg-custom-sidebar-background-100 h-full z-[5] fixed md:relative transition-all w-full md:w-[300px]`} className={`flex-shrink-0 overflow-hidden overflow-y-auto shadow-custom-shadow-sm border-l border-custom-border-100 bg-custom-sidebar-background-100 h-full z-[5] fixed md:relative transition-all w-full md:w-[300px]`}
style={themStore.profileSidebarCollapsed ? { marginLeft: `${window?.innerWidth || 0}px` } : {}} style={themeStore.profileSidebarCollapsed ? { marginLeft: `${window?.innerWidth || 0}px` } : {}}
> >
{userProjectsData ? ( {userProjectsData ? (
<> <>

View File

@ -15,8 +15,11 @@ import { ANALYTICS_TABS } from "constants/analytics";
import { EUserWorkspaceRoles } from "constants/workspace"; import { EUserWorkspaceRoles } from "constants/workspace";
// type // type
import { NextPageWithLayout } from "lib/types"; import { NextPageWithLayout } from "lib/types";
import { useRouter } from "next/router";
const AnalyticsPage: NextPageWithLayout = observer(() => { const AnalyticsPage: NextPageWithLayout = observer(() => {
const router = useRouter()
const { analytics_tab } = router.query
// theme // theme
const { resolvedTheme } = useTheme(); const { resolvedTheme } = useTheme();
// store hooks // store hooks
@ -38,17 +41,19 @@ const AnalyticsPage: NextPageWithLayout = observer(() => {
<> <>
{workspaceProjectIds && workspaceProjectIds.length > 0 ? ( {workspaceProjectIds && workspaceProjectIds.length > 0 ? (
<div className="flex h-full flex-col overflow-hidden bg-custom-background-100"> <div className="flex h-full flex-col overflow-hidden bg-custom-background-100">
<Tab.Group as={Fragment}> <Tab.Group as={Fragment} defaultIndex={analytics_tab === 'custom' ? 1 : 0}>
<Tab.List as="div" className="space-x-2 border-b border-custom-border-200 px-5 py-3"> <Tab.List as="div" className="flex space-x-2 border-b border-custom-border-200 px-0 md:px-5 py-0 md:py-3">
{ANALYTICS_TABS.map((tab) => ( {ANALYTICS_TABS.map((tab) => (
<Tab <Tab
key={tab.key} key={tab.key}
className={({ selected }) => className={({ selected }) =>
`rounded-3xl border border-custom-border-200 px-4 py-2 text-xs hover:bg-custom-background-80 ${ `rounded-0 w-full md:w-max md:rounded-3xl border-b md:border border-custom-border-200 focus:outline-none px-0 md:px-4 py-2 text-xs hover:bg-custom-background-80 ${selected ? "border-custom-primary-100 text-custom-primary-100 md:bg-custom-background-80 md:text-custom-text-200 md:border-custom-border-200" : "border-transparent"
selected ? "bg-custom-background-80" : ""
}` }`
} }
onClick={() => {}} onClick={() => {
router.query.analytics_tab = tab.key
router.push(router)
}}
> >
{tab.title} {tab.title}
</Tab> </Tab>

View File

@ -8,10 +8,12 @@ export interface IThemeStore {
theme: string | null; theme: string | null;
sidebarCollapsed: boolean | undefined; sidebarCollapsed: boolean | undefined;
profileSidebarCollapsed: boolean | undefined; profileSidebarCollapsed: boolean | undefined;
workspaceAnalyticsSidebarCollapsed: boolean | undefined;
// actions // actions
toggleSidebar: (collapsed?: boolean) => void; toggleSidebar: (collapsed?: boolean) => void;
setTheme: (theme: any) => void; setTheme: (theme: any) => void;
toggleProfileSidebar: (collapsed?: boolean) => void; toggleProfileSidebar: (collapsed?: boolean) => void;
toggleWorkspaceAnalyticsSidebar: (collapsed?: boolean) => void;
} }
export class ThemeStore implements IThemeStore { export class ThemeStore implements IThemeStore {
@ -19,6 +21,7 @@ export class ThemeStore implements IThemeStore {
sidebarCollapsed: boolean | undefined = undefined; sidebarCollapsed: boolean | undefined = undefined;
theme: string | null = null; theme: string | null = null;
profileSidebarCollapsed: boolean | undefined = undefined; profileSidebarCollapsed: boolean | undefined = undefined;
workspaceAnalyticsSidebarCollapsed: boolean | undefined = undefined;
// root store // root store
rootStore; rootStore;
@ -28,10 +31,12 @@ export class ThemeStore implements IThemeStore {
sidebarCollapsed: observable.ref, sidebarCollapsed: observable.ref,
theme: observable.ref, theme: observable.ref,
profileSidebarCollapsed: observable.ref, profileSidebarCollapsed: observable.ref,
workspaceAnalyticsSidebarCollapsed: observable.ref,
// action // action
toggleSidebar: action, toggleSidebar: action,
setTheme: action, setTheme: action,
toggleProfileSidebar: action, toggleProfileSidebar: action,
toggleWorkspaceAnalyticsSidebar: action
// computed // computed
}); });
// root store // root store
@ -64,6 +69,19 @@ export class ThemeStore implements IThemeStore {
localStorage.setItem("profile_sidebar_collapsed", this.profileSidebarCollapsed.toString()); localStorage.setItem("profile_sidebar_collapsed", this.profileSidebarCollapsed.toString());
}; };
/**
* Toggle the profile sidebar collapsed state
* @param collapsed
*/
toggleWorkspaceAnalyticsSidebar = (collapsed?: boolean) => {
if (collapsed === undefined) {
this.workspaceAnalyticsSidebarCollapsed = !this.workspaceAnalyticsSidebarCollapsed;
} else {
this.workspaceAnalyticsSidebarCollapsed = collapsed;
}
localStorage.setItem("workspace_analytics_sidebar_collapsed", this.workspaceAnalyticsSidebarCollapsed.toString());
};
/** /**
* Sets the user theme and applies it to the platform * Sets the user theme and applies it to the platform
* @param _theme * @param _theme