Compare commits

...

5 Commits

Author SHA1 Message Date
gakshita
2e4ecf0c6e Merge branch 'preview' of https://github.com/makeplane/plane into feat-workspace-switcher 2025-05-09 13:07:31 +05:30
gakshita
dd24b95eea fix: typo 2025-05-07 17:08:08 +05:30
gakshita
bc17897ff3 fix: empty state 2025-05-07 17:06:17 +05:30
gakshita
84e2fe7d06 fix: refactor 2025-05-07 13:09:15 +05:30
gakshita
62a397a4b4 feat: added page for workspace switcher 2025-05-06 19:27:47 +05:30
26 changed files with 361 additions and 0 deletions

View File

@@ -500,6 +500,13 @@
"export": "Exportovat",
"member": "{count, plural, one{# člen} few{# členové} other{# členů}}",
"new_password_must_be_different_from_old_password": "Nové heslo musí být odlišné od starého hesla",
"choose_workspace_for_integration": "Vyberte pracovní prostor pro připojení této aplikace",
"integrations_description": "Aplikace, které pracují s Plane, musí být připojeny k pracovnímu prostoru, kde jste správce.",
"create_a_new_workspace": "Vytvořit nový pracovní prostor",
"no_workspaces_to_connect": "Žádné pracovní prostory k připojení",
"no_workspaces_to_connect_description": "Musíte vytvořit pracovní prostor, abyste mohli připojit integraci a šablony",
"learn_more_about_workspaces": "Zjistit více o pracovních prostorech",
"project_view": {
"sort_by": {
"created_at": "Vytvořeno dne",

View File

@@ -500,6 +500,13 @@
"export": "Exportieren",
"member": "{count, plural, one{# Mitglied} few{# Mitglieder} other{# Mitglieder}}",
"new_password_must_be_different_from_old_password": "Das neue Passwort muss von dem alten Passwort abweichen",
"choose_workspace_for_integration": "Wählen Sie einen Arbeitsbereich aus, um diese App zu verbinden",
"integrations_description": "Apps, die mit Plane arbeiten, müssen einen Arbeitsbereich verbinden, in dem Sie ein Administrator sind.",
"create_a_new_workspace": "Neuen Arbeitsbereich erstellen",
"learn_more_about_workspaces": "Mehr über Arbeitsbereiche erfahren",
"no_workspaces_to_connect": "Keine Arbeitsbereiche zum Verbinden",
"no_workspaces_to_connect_description": "Sie müssen einen Arbeitsbereich erstellen, um Integrationen und Vorlagen zu verbinden",
"project_view": {
"sort_by": {
"created_at": "Erstellt am",

View File

@@ -334,6 +334,13 @@
"new_password_must_be_different_from_old_password": "New password must be different from old password",
"edited": "edited",
"bot": "Bot",
"choose_workspace_for_integration": "Choose a workspace to connect this app to",
"integrations_description": "Apps that work with Plane must connect to a workspace where you are an admin.",
"create_a_new_workspace": "Create a new workspace",
"learn_more_about_workspaces": "Learn more about workspaces",
"no_workspaces_to_connect": "No workspaces to connect",
"no_workspaces_to_connect_description": "You will need to create a workspace to be able to connect integrations and templates",
"project_view": {
"sort_by": {
"created_at": "Created at",

View File

@@ -504,6 +504,13 @@
"new_password_must_be_different_from_old_password": "La nueva contraseña debe ser diferente a la contraseña anterior",
"edited": "Modificado",
"bot": "Bot",
"choose_workspace_for_integration": "Elige un espacio de trabajo para conectar esta app",
"integrations_description": "Las apps que funcionan con Plane deben conectarse a un espacio de trabajo donde eres administrador.",
"create_a_new_workspace": "Crear un nuevo espacio de trabajo",
"learn_more_about_workspaces": "Aprende más sobre espacios de trabajo",
"no_workspaces_to_connect": "No hay espacios de trabajo para conectar",
"no_workspaces_to_connect_description": "Necesitarás crear un espacio de trabajo para poder conectar integraciones y plantillas",
"project_view": {
"sort_by": {
"created_at": "Creado el",

View File

@@ -502,6 +502,13 @@
"new_password_must_be_different_from_old_password": "Le nouveau mot de passe doit être différent du mot de passe précédent",
"edited": "Modifié",
"bot": "Bot",
"choose_workspace_for_integration": "Choisissez un espace de travail pour connecter cette application",
"integrations_description": "Les applications qui fonctionnent avec Plane doivent se connecter à un espace de travail où vous êtes administrateur.",
"create_a_new_workspace": "Créer un nouvel espace de travail",
"learn_more_about_workspaces": "En savoir plus sur les espaces de travail",
"no_workspaces_to_connect": "Aucun espace de travail à connecter",
"no_workspaces_to_connect_description": "Vous devez créer un espace de travail pour pouvoir connecter des intégrations et des modèles",
"project_view": {
"sort_by": {
"created_at": "Créé le",

View File

@@ -500,6 +500,13 @@
"export": "Ekspor",
"member": "{count, plural, one{# anggota} other{# anggota}}",
"new_password_must_be_different_from_old_password": "Kata sandi baru harus berbeda dari kata sandi lama",
"choose_workspace_for_integration": "Pilih ruang kerja untuk menghubungkan aplikasi ini",
"integrations_description": "Aplikasi yang bekerja dengan Plane harus menghubungkan ke ruang kerja di mana Anda adalah admin.",
"create_a_new_workspace": "Buat ruang kerja baru",
"learn_more_about_workspaces": "Pelajari lebih lanjut tentang ruang kerja",
"no_workspaces_to_connect": "Tidak ada ruang kerja untuk menghubungkan",
"no_workspaces_to_connect_description": "Anda perlu membuat ruang kerja untuk dapat menghubungkan integrasi dan template",
"project_view": {
"sort_by": {
"created_at": "Dibuat pada",

View File

@@ -502,6 +502,13 @@
"new_password_must_be_different_from_old_password": "La nuova password deve essere diversa dalla password precedente",
"edited": "Modificato",
"bot": "Bot",
"choose_workspace_for_integration": "Scegli uno spazio di lavoro per connettere questa app",
"integrations_description": "Le app che funzionano con Plane devono connettersi a uno spazio di lavoro dove sei amministratore.",
"create_a_new_workspace": "Crea uno spazio di lavoro nuovo",
"learn_more_about_workspaces": "Scopri di più sui tuoi spazi di lavoro",
"no_workspaces_to_connect": "Nessuno spazio di lavoro per connettere",
"no_workspaces_to_connect_description": "Devi creare uno spazio di lavoro per poter connettere le integrazioni e i modelli",
"project_view": {
"sort_by": {
"created_at": "Creato il",

View File

@@ -502,6 +502,13 @@
"new_password_must_be_different_from_old_password": "新しいパスワードは古いパスワードと異なる必要があります",
"edited": "編集済み",
"bot": "ボット",
"choose_workspace_for_integration": "このアプリケーションに接続するワークスペースを選択してください",
"integrations_description": "Planeのアプリケーションは、管理者であるワークスペースに接続する必要があります。",
"create_a_new_workspace": "新しいワークスペースを作成",
"learn_more_about_workspaces": "ワークスペースについて詳しくはこちら",
"no_workspaces_to_connect": "接続するワークスペースがありません",
"no_workspaces_to_connect_description": "接続するワークスペースを作成する必要があります",
"project_view": {
"sort_by": {
"created_at": "作成日時",

View File

@@ -502,6 +502,13 @@
"new_password_must_be_different_from_old_password": "새 비밀번호는 이전 비밀번호와 다르게 설정해야 합니다",
"edited": "수정됨",
"bot": "봇",
"choose_workspace_for_integration": "이 앱에 연결할 작업 공간을 선택하세요",
"integrations_description": "Plane의 앱은 관리자인 작업 공간에 연결해야 합니다.",
"create_a_new_workspace": "새 작업 공간 만들기",
"learn_more_about_workspaces": "작업 공간에 대해 자세히 알아보기",
"no_workspaces_to_connect": "연결할 작업 공간이 없습니다",
"no_workspaces_to_connect_description": "연결할 작업 공간을 만들어야 합니다",
"project_view": {
"sort_by": {
"created_at": "생성일",

View File

@@ -502,6 +502,13 @@
"new_password_must_be_different_from_old_password": "Nowe hasło musi być innym niż stare hasło",
"edited": "Edytowano",
"bot": "Bot",
"choose_workspace_for_integration": "Wybierz przestrzeń roboczą do połączenia tej aplikacji",
"integrations_description": "Aplikacje, które działają z Plane, muszą być połączone z przestrzenią roboczą, w której jesteś administratorem.",
"create_a_new_workspace": "Utwórz nową przestrzeń roboczą",
"learn_more_about_workspaces": "Dowiedz się więcej o przestrzeniach roboczych",
"no_workspaces_to_connect": "Brak przestrzeni roboczych do połączenia",
"no_workspaces_to_connect_description": "Musisz utworzyć przestrzeń roboczą, aby móc połączyć integracje i szablony",
"project_view": {
"sort_by": {
"created_at": "Utworzono dnia",

View File

@@ -502,6 +502,13 @@
"new_password_must_be_different_from_old_password": "Nova senha deve ser diferente da senha antiga",
"edited": "editado",
"bot": "robô",
"choose_workspace_for_integration": "Escolha um espaço de trabalho para conectar esta aplicação",
"integrations_description": "Aplicações que funcionam com Plane devem se conectar a um espaço de trabalho onde você é administrador.",
"create_a_new_workspace": "Criar um novo espaço de trabalho",
"no_workspaces_to_connect": "Nenhum espaço de trabalho para conectar",
"no_workspaces_to_connect_description": "Você precisa criar um espaço de trabalho para poder conectar integrações e templates",
"learn_more_about_workspaces": "Saiba mais sobre espaços de trabalho",
"project_view": {
"sort_by": {
"created_at": "Criado em",

View File

@@ -500,6 +500,13 @@
"export": "Exportă",
"member": "{count, plural, one{# membru} other{# membri}}",
"new_password_must_be_different_from_old_password": "Parola nouă trebuie să fie diferită de parola veche",
"choose_workspace_for_integration": "Alegeți un spațiu de lucru pentru a conecta această aplicație",
"integrations_description": "Aplicațiile care funcționează cu Plane trebuie să se conecteze la un spațiu de lucru unde sunteți administrator.",
"create_a_new_workspace": "Creați un nou spațiu de lucru",
"no_workspaces_to_connect": "Nu există spații de lucru pentru a conecta",
"no_workspaces_to_connect_description": "Trebuie să creați un spațiu de lucru pentru a putea conecta integrări și modele",
"learn_more_about_workspaces": "Află mai multe despre spațiile de lucru",
"project_view": {
"sort_by": {
"created_at": "Creat la",

View File

@@ -502,6 +502,13 @@
"new_password_must_be_different_from_old_password": "Новое пароль должен отличаться от старого пароля",
"edited": "Редактировано",
"bot": "Бот",
"choose_workspace_for_integration": "Выберите рабочее пространство для подключения этого приложения",
"integrations_description": "Приложения, которые работают с Plane, должны быть подключены к рабочему пространству, где вы являетесь администратором.",
"create_a_new_workspace": "Создать новое рабочее пространство",
"learn_more_about_workspaces": "Узнать больше о рабочих пространствах",
"no_workspaces_to_connect": "Нет рабочих пространств для подключения",
"no_workspaces_to_connect_description": "Вы должны создать рабочее пространство, чтобы подключить интеграции и шаблоны",
"project_view": {
"sort_by": {
"created_at": "Дата создания",

View File

@@ -502,6 +502,13 @@
"new_password_must_be_different_from_old_password": "Nové heslo musí byť odlišné od starého hesla",
"edited": "Upravené",
"bot": "Bot",
"choose_workspace_for_integration": "Vyberte pracovný priestor pre pripojenie tejto aplikácie",
"integrations_description": "Aplikácie, ktoré fungujú s Plane, musia byť pripojené k pracovnom priestoru, kde ste správca.",
"create_a_new_workspace": "Vytvoriť nový pracovný priestor",
"learn_more_about_workspaces": "Zjistit více o pracovních prostorech",
"no_workspaces_to_connect": "Žádné pracovní prostory k připojení",
"no_workspaces_to_connect_description": "Musíte vytvořit pracovní prostor, abyste mohli připojit integraci a šablony",
"project_view": {
"sort_by": {
"created_at": "Vytvorené dňa",

View File

@@ -502,6 +502,13 @@
"new_password_must_be_different_from_old_password": "Yeni şifre eski şifreden farklı olmalı",
"edited": "düzenlendi",
"bot": "Bot",
"choose_workspace_for_integration": "Bu uygulamayı bağlamak için bir çalışma alanı seçin",
"integrations_description": "Plane ile çalışan uygulamalar, yönetici olduğunuz bir çalışma alanına bağlanmalıdır.",
"create_a_new_workspace": "Yeni bir çalışma alanı oluştur",
"learn_more_about_workspaces": "Çalışma alanları hakkında daha fazla bilgi edinin",
"no_workspaces_to_connect": "Bağlamak için çalışma alanı yok",
"no_workspaces_to_connect_description": "Bir çalışma alanı oluşturmak için lütfen bu sayfaya dönün",
"project_view": {
"sort_by": {
"created_at": "Oluşturulma tarihi",

View File

@@ -502,6 +502,13 @@
"new_password_must_be_different_from_old_password": "Новий пароль повинен бути відмінним від старого пароля",
"edited": "Редагувано",
"bot": "Бот",
"choose_workspace_for_integration": "Виберіть робочий простір для підключення цієї програми",
"integrations_description": "Програми, які працюють з Plane, повинні бути підключені до робочого простору, де ви є адміністратором.",
"create_a_new_workspace": "Створити новий робочий простір",
"learn_more_about_workspaces": "Дізнатися більше про робочі простори",
"no_workspaces_to_connect": "Немає робочих просторів для підключення",
"no_workspaces_to_connect_description": "Ви повинні створити робочий простір, щоб підключити інтеграції та шаблони",
"project_view": {
"sort_by": {
"created_at": "Створено",

View File

@@ -502,6 +502,13 @@
"new_password_must_be_different_from_old_password": "Mật khẩu mới phải khác mật khẩu cũ",
"edited": "đã chỉnh sửa",
"bot": "bot",
"choose_workspace_for_integration": "Chọn không gian làm việc để kết nối ứng dụng này",
"integrations_description": "Ứng dụng làm việc với Plane phải kết nối với không gian làm việc mà bạn là quản trị viên.",
"create_a_new_workspace": "Tạo không gian làm việc mới",
"learn_more_about_workspaces": "Tìm hiểu thêm về không gian làm việc",
"no_workspaces_to_connect": "Không có không gian làm việc để kết nối",
"no_workspaces_to_connect_description": "Bạn cần tạo không gian làm việc để kết nối ứng dụng này",
"project_view": {
"sort_by": {
"created_at": "Thời gian tạo",

View File

@@ -502,6 +502,13 @@
"new_password_must_be_different_from_old_password": "新密码必须不同于旧密码",
"edited": "已编辑",
"bot": "机器人",
"choose_workspace_for_integration": "选择工作区以连接此应用程序",
"integrations_description": "与 Plane 一起工作的应用程序必须连接到您是管理员的工作区",
"create_a_new_workspace": "创建新的工作区",
"learn_more_about_workspaces": "了解更多关于工作区的信息",
"no_workspaces_to_connect": "没有工作区可连接",
"no_workspaces_to_connect_description": "您需要创建工作区才能连接此应用程序",
"project_view": {
"sort_by": {
"created_at": "创建时间",

View File

@@ -502,6 +502,13 @@
"new_password_must_be_different_from_old_password": "新密碼必須與舊密碼不同",
"edited": "已編輯",
"bot": "機器人",
"choose_workspace_for_integration": "選擇工作區以連接此應用程式",
"integrations_description": "與 Plane 一起工作的應用程式必須連接到您是管理員的工作區",
"create_a_new_workspace": "建立新的工作區",
"learn_more_about_workspaces": "了解更多關於工作區的資訊",
"no_workspaces_to_connect": "沒有工作區可連接",
"no_workspaces_to_connect_description": "您需要建立工作區才能連接整合和模板",
"project_view": {
"sort_by": {
"created_at": "建立時間",

View File

@@ -0,0 +1,9 @@
import { Metadata } from "next";
export const metadata: Metadata = {
title: "Workspaces",
};
export default function WorkspacesLayout({ children }: { children: React.ReactNode }) {
return children;
}

View File

@@ -0,0 +1,45 @@
"use client";
import React from "react";
import { observer } from "mobx-react";
import Image from "next/image";
import Link from "next/link";
import { useTheme } from "next-themes";
// hooks
import { useTranslation } from "@plane/i18n";
import { WorkspacePicker } from "@/components/common/workspace-picker";
import { useUser } from "@/hooks/store";
// services
import { AuthenticationWrapper } from "@/lib/wrappers";
// images
import BlackHorizontalLogo from "@/public/plane-logos/black-horizontal-with-blue-logo.png";
import WhiteHorizontalLogo from "@/public/plane-logos/white-horizontal-with-blue-logo.png";
const WorkspacePickerPage = observer(() => {
// hooks
const { t } = useTranslation();
const { data: currentUser } = useUser();
// next-themes
const { resolvedTheme } = useTheme();
const logo = resolvedTheme === "light" ? BlackHorizontalLogo : WhiteHorizontalLogo;
return (
<AuthenticationWrapper>
<div className="flex flex-col h-full gap-y-2 pb-20">
<div className="flex items-center justify-between p-10 lg:px-20 xl:px-36">
<Link href="/" className="bg-custom-background-100 px-3">
<div className="h-[30px] w-[133px]">
<Image src={logo} alt="Plane logo" />
</div>
</Link>
<div className="text-sm text-custom-text-100">{currentUser?.email}</div>
</div>
<WorkspacePicker />
</div>
</AuthenticationWrapper>
);
});
export default WorkspacePickerPage;

View File

@@ -0,0 +1,49 @@
import { cn } from "@/helpers/common.helper";
import { getFileURL } from "@/helpers/file.helper";
interface IWorkspaceLogoProps {
workspace: {
logo_url: string;
name: string;
};
className?: string;
size?: "sm" | "md" | "lg";
}
const WorkspaceLogo = (props: IWorkspaceLogoProps) => {
const { workspace, className, size = "md" } = props;
const sizeClass = size === "sm" ? "h-6 w-6 text-sm" : size === "md" ? "h-8 w-8 text-sm" : "h-10 w-10 text-base";
return (
<div className={cn("flex gap-3 items-center", className)}>
{workspace.logo_url && workspace.logo_url !== "" ? (
<div className={cn("relative my-auto flex rounded", sizeClass)}>
<img
src={getFileURL(workspace.logo_url)}
className={cn("absolute left-0 top-0 h-full w-full rounded-md object-cover", sizeClass)}
alt="Workspace Logo"
/>
</div>
) : (
<span
className={cn(
"relative flex h-8 w-8 flex-shrink-0 items-center justify-center p-2 text-base uppercase font-medium border-custom-border-200",
{ "rounded-md bg-custom-primary-500 text-white": !workspace?.logo_url },
sizeClass
)}
>
{workspace?.logo_url && workspace.logo_url !== "" ? (
<img
src={getFileURL(workspace.logo_url)}
className="absolute left-0 top-0 h-full w-full rounded object-cover"
alt={"workspace_logo"}
/>
) : (
(workspace?.name?.[0] ?? "...")
)}
</span>
)}
</div>
);
};
export default WorkspaceLogo;

View File

@@ -0,0 +1,111 @@
import { useState } from "react";
import Image from "next/image";
import Link from "next/link";
import { useSearchParams } from "next/navigation";
import { useTheme } from "next-themes";
import { Check } from "lucide-react";
import { useTranslation } from "@plane/i18n";
import { getButtonStyling, Loader } from "@plane/ui";
import { cn } from "@plane/utils";
import { useWorkspace } from "@/hooks/store";
import DarkImage from "@/public/empty-state/marketplace/empty-workspace-dark.png";
import LightImage from "@/public/empty-state/marketplace/empty-workspace-light.png";
import WorkspaceLogo from "../workspace-logo";
export const WorkspacePicker = () => {
// router
const searchParams = useSearchParams();
const nextPath = searchParams.get("next_path");
// store
const { loader, currentUserAdminWorkspaces } = useWorkspace();
const { t } = useTranslation();
// state
const [selectedWorkspace, setSelectedWorkspace] = useState<string | null>(null);
// hook
const { resolvedTheme } = useTheme();
const image = resolvedTheme === "dark" ? DarkImage : LightImage;
if (!loader && currentUserAdminWorkspaces?.length === 0) {
return (
<div className="relative flex flex-col gap-4 h-full w-full justify-center px-8 pb-8 items-center">
<div className="text-3xl font-bold text-center">{t("no_workspaces_to_connect")}</div>
<div className="font-medium text-custom-text-300 max-w-[450px] text-center">
{t("no_workspaces_to_connect_description")}
</div>
<div className="overflow-y-auto vertical-scrollbar scrollbar-sm mb-10 w-full md:w-fit">
<div className="w-full flex flex-col gap-2 items-center md:w-[450px]">
<Image src={image} alt="empty workspace" />
<div className="flex gap-2 flex-col md:flex-row">
<Link
href="https://plane.so/"
target="_blank"
className={cn(
getButtonStyling("outline-primary", "md"),
"border-custom-border-200 text-custom-text-100"
)}
>
{t("learn_more_about_workspaces")}
</Link>
<Link
href="/create-workspace"
className={cn("text-sm text-custom-text-300 w-full", getButtonStyling("primary", "md"))}
>
{t("create_a_new_workspace")}
</Link>
</div>
</div>
</div>
</div>
);
}
return (
<div className="relative flex flex-col gap-4 h-full w-full justify-center px-8 pb-8 items-center">
<div className="text-3xl font-bold text-center">{t("choose_workspace_for_integration")}</div>
<div className="font-medium text-custom-text-300 max-w-[450px] text-center">{t("integrations_description")}</div>
<div className="overflow-y-auto vertical-scrollbar scrollbar-sm mb-10 w-full md:w-fit">
<div className="w-full flex flex-col md:w-[450px] bg-custom-background-90 rounded p-4 gap-2 border-[0.5px] border-custom-border-200">
{loader && (
<Loader className="w-full flex flex-col gap-2">
{Array.from({ length: 4 }).map((_, index) => (
<Loader.Item key={index} height="43px" />
))}
</Loader>
)}
{!loader &&
currentUserAdminWorkspaces?.map((workspace) => (
<div key={workspace.id} className="w-full bg-custom-background-100 rounded">
<Link
href={`/${workspace.slug}${nextPath || ""}`}
className={cn(
"rounded p-2.5 flex items-center gap-2 border-[0.5px] border-custom-border-200 transition-all duration-200",
"hover:bg-custom-primary-100/20 hover:border-custom-primary-100",
{
"bg-custom-primary-100/20 border-custom-primary-100": selectedWorkspace === workspace.id,
}
)}
onClick={() => setSelectedWorkspace(workspace.id)}
>
<div className="flex gap-2 items-center">
<WorkspaceLogo
workspace={{
logo_url: workspace.logo_url ?? "",
name: workspace.name,
}}
size="sm"
/>
<div className="text-sm text-custom-text-200 font-medium">{workspace.name}</div>
</div>
{selectedWorkspace === workspace.id && (
<div className="ml-auto size-[14px] bg-custom-primary-100 rounded-full flex items-center justify-center">
<Check className="text-white w-[10px] h-[10px] m-auto" />
</div>
)}
</Link>
</div>
))}
</div>
</div>
</div>
);
};

View File

@@ -3,6 +3,7 @@ import set from "lodash/set";
import { action, computed, observable, makeObservable, runInAction } from "mobx";
// types
import { computedFn } from "mobx-utils";
import { EUserPermissions } from "@plane/constants";
import { IWorkspaceSidebarNavigationItem, IWorkspace, IWorkspaceSidebarNavigation } from "@plane/types";
// services
import { WorkspaceService } from "@/plane-web/services";
@@ -20,6 +21,7 @@ export interface IWorkspaceRootStore {
// computed
currentWorkspace: IWorkspace | null;
workspacesCreatedByCurrentUser: IWorkspace[] | null;
currentUserAdminWorkspaces: IWorkspace[] | null;
navigationPreferencesMap: Record<string, IWorkspaceSidebarNavigation>;
// computed actions
getWorkspaceBySlug: (workspaceSlug: string) => IWorkspace | null;
@@ -68,6 +70,7 @@ export class WorkspaceRootStore implements IWorkspaceRootStore {
// computed
currentWorkspace: computed,
workspacesCreatedByCurrentUser: computed,
currentUserAdminWorkspaces: computed,
// computed actions
getWorkspaceBySlug: action,
getWorkspaceById: action,
@@ -113,6 +116,17 @@ export class WorkspaceRootStore implements IWorkspaceRootStore {
return userWorkspaces || null;
}
/**
* computed value of all the workspaces where current user is admin
*/
get currentUserAdminWorkspaces() {
if (!this.workspaces) return null;
const user = this.user.data;
if (!user) return null;
const userWorkspaces = Object.values(this.workspaces ?? {})?.filter((w) => w.role === EUserPermissions.ADMIN);
return userWorkspaces || null;
}
/**
* get workspace info from the array of workspaces in the store using workspace slug
* @param workspaceSlug

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 245 KiB