From eb91533e84ea15f120bd360190fb16cdc45e8b6b Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia Date: Wed, 15 Jan 2025 18:15:27 +0530 Subject: [PATCH 01/26] chore: asset path helper hook added --- web/core/hooks/use-resolved-asset-path.tsx | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 web/core/hooks/use-resolved-asset-path.tsx diff --git a/web/core/hooks/use-resolved-asset-path.tsx b/web/core/hooks/use-resolved-asset-path.tsx new file mode 100644 index 00000000000..f5543d2006e --- /dev/null +++ b/web/core/hooks/use-resolved-asset-path.tsx @@ -0,0 +1,17 @@ +import { useTheme } from "next-themes"; + +type AssetPathConfig = { + basePath: string; + additionalPath?: string; + extension?: string; +}; + +export const useResolvedAssetPath = ({ basePath, additionalPath = "", extension = "webp" }: AssetPathConfig) => { + // hooks + const { resolvedTheme } = useTheme(); + + // resolved theme + const theme = resolvedTheme === "light" ? "light" : "dark"; + + return `${additionalPath && additionalPath !== "" ? `${basePath}${additionalPath}` : basePath}-${theme}.${extension}`; +}; From 05ab094569c01f09a8d080b6286c6938e85d7b1b Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia Date: Wed, 15 Jan 2025 18:16:11 +0530 Subject: [PATCH 02/26] chore: detailed and simple empty state component added --- .../empty-state/detailed-empty-state-root.tsx | 100 ++++++++++++++++++ web/core/components/empty-state/index.ts | 2 + .../empty-state/simple-empty-state-root.tsx | 62 +++++++++++ 3 files changed, 164 insertions(+) create mode 100644 web/core/components/empty-state/detailed-empty-state-root.tsx create mode 100644 web/core/components/empty-state/simple-empty-state-root.tsx diff --git a/web/core/components/empty-state/detailed-empty-state-root.tsx b/web/core/components/empty-state/detailed-empty-state-root.tsx new file mode 100644 index 00000000000..b90503682a6 --- /dev/null +++ b/web/core/components/empty-state/detailed-empty-state-root.tsx @@ -0,0 +1,100 @@ +"use client"; + +import React from "react"; +import { observer } from "mobx-react"; +import Image from "next/image"; +// ui +import { Button } from "@plane/ui/src/button"; +// utils +import { cn } from "@plane/utils"; + +type EmptyStateSize = "sm" | "md" | "lg"; + +type ButtonConfig = { + text: string; + prependIcon?: React.ReactNode; + appendIcon?: React.ReactNode; + onClick?: () => void; + disabled?: boolean; +}; + +type Props = { + title: string; + description?: string; + assetPath?: string; + size?: EmptyStateSize; + primaryButton?: ButtonConfig; + secondaryButton?: ButtonConfig; + customPrimaryButton?: React.ReactNode; + customSecondaryButton?: React.ReactNode; +}; + +const sizeClasses = { + sm: "md:min-w-[24rem] max-w-[45rem]", + md: "md:min-w-[28rem] max-w-[50rem]", + lg: "md:min-w-[30rem] max-w-[60rem]", +} as const; + +const CustomButton = ({ + config, + variant, + size, +}: { + config: ButtonConfig; + variant: "primary" | "neutral-primary"; + size: EmptyStateSize; +}) => ( + +); + +export const DetailedEmptyState: React.FC = observer((props) => { + const { + title, + description, + size = "lg", + primaryButton, + secondaryButton, + customPrimaryButton, + customSecondaryButton, + assetPath, + } = props; + + const hasButtons = primaryButton || secondaryButton || customPrimaryButton || customSecondaryButton; + + return ( +
+
+
+

{title}

+ {description &&

{description}

} +
+ + {assetPath && ( + {title} + )} + + {hasButtons && ( +
+ {/* primary button */} + {customPrimaryButton ?? + (primaryButton?.text && )} + {/* secondary button */} + {customSecondaryButton ?? + (secondaryButton?.text && ( + + ))} +
+ )} +
+
+ ); +}); diff --git a/web/core/components/empty-state/index.ts b/web/core/components/empty-state/index.ts index 57e63c1bb95..3bfec993f84 100644 --- a/web/core/components/empty-state/index.ts +++ b/web/core/components/empty-state/index.ts @@ -1,3 +1,5 @@ export * from "./empty-state"; export * from "./helper"; export * from "./comic-box-button"; +export * from "./detailed-empty-state-root"; +export * from "./simple-empty-state-root"; diff --git a/web/core/components/empty-state/simple-empty-state-root.tsx b/web/core/components/empty-state/simple-empty-state-root.tsx new file mode 100644 index 00000000000..d0ab95076a7 --- /dev/null +++ b/web/core/components/empty-state/simple-empty-state-root.tsx @@ -0,0 +1,62 @@ +"use client"; + +import React from "react"; +import { observer } from "mobx-react"; +import Image from "next/image"; +// utils +import { cn } from "@plane/utils"; + +type EmptyStateSize = "sm" | "md" | "lg"; + +type Props = { + title: string; + description?: string; + assetPath?: string; + size?: EmptyStateSize; +}; + +const sizeConfig = { + sm: { + container: "size-20", + dimensions: 78, + }, + md: { + container: "size-24", + dimensions: 80, + }, + lg: { + container: "size-28", + dimensions: 96, + }, +} as const; + +const getTitleClassName = (hasDescription: boolean) => + cn("font-medium whitespace-pre-line", { + "text-sm text-custom-text-400": !hasDescription, + "text-lg text-custom-text-300": hasDescription, + }); + +export const SimpleEmptyState = observer((props: Props) => { + const { title, description, size = "sm", assetPath } = props; + + return ( +
+ {assetPath && ( +
+ {title} +
+ )} + +

{title}

+ + {description &&

{description}

} +
+ ); +}); From 33075940dc3eaaf828d15a84c37a1015975fd6fa Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia Date: Wed, 15 Jan 2025 18:24:27 +0530 Subject: [PATCH 03/26] chore: section empty state component added --- web/core/components/empty-state/index.ts | 1 + .../empty-state/section-empty-state-root.tsx | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 web/core/components/empty-state/section-empty-state-root.tsx diff --git a/web/core/components/empty-state/index.ts b/web/core/components/empty-state/index.ts index 3bfec993f84..afa892f2712 100644 --- a/web/core/components/empty-state/index.ts +++ b/web/core/components/empty-state/index.ts @@ -3,3 +3,4 @@ export * from "./helper"; export * from "./comic-box-button"; export * from "./detailed-empty-state-root"; export * from "./simple-empty-state-root"; +export * from "./section-empty-state-root"; diff --git a/web/core/components/empty-state/section-empty-state-root.tsx b/web/core/components/empty-state/section-empty-state-root.tsx new file mode 100644 index 00000000000..67c458a2075 --- /dev/null +++ b/web/core/components/empty-state/section-empty-state-root.tsx @@ -0,0 +1,24 @@ +"use client"; + +import { FC } from "react"; + +type Props = { + icon: React.ReactNode; + title: string; + description?: string; + actionElement?: React.ReactNode; +}; + +export const SectionEmptyState: FC = (props) => { + const { title, description, icon, actionElement } = props; + return ( +
+
+
{icon}
+ {title} + {description && {description}} +
+ {actionElement && <>{actionElement}} +
+ ); +}; From be40d60bea4376f361cf15140add5750640cfedc Mon Sep 17 00:00:00 2001 From: Prateek Shourya Date: Wed, 15 Jan 2025 20:47:07 +0530 Subject: [PATCH 04/26] chore: language translation for all empty states --- .../i18n/src/locales/en/translations.json | 208 ++++++++++++++++- .../i18n/src/locales/es/translations.json | 209 +++++++++++++++++- .../i18n/src/locales/fr/translations.json | 208 ++++++++++++++++- .../i18n/src/locales/ja/translations.json | 208 ++++++++++++++++- 4 files changed, 828 insertions(+), 5 deletions(-) diff --git a/packages/i18n/src/locales/en/translations.json b/packages/i18n/src/locales/en/translations.json index 596c3093fa9..9857a013d31 100644 --- a/packages/i18n/src/locales/en/translations.json +++ b/packages/i18n/src/locales/en/translations.json @@ -316,5 +316,211 @@ "change_parent_issue": "Change parent issue", "remove_parent_issue": "Remove parent issue", "add_parent": "Add parent", - "loading_members": "Loading members..." + "loading_members": "Loading members...", + + "workspace_dashboard_empty_state_title": "Overview of your projects, activity, and metrics", + "workspace_dashboard_empty_state_description": "Welcome to Plane, we are excited to have you here. Create your first project and track your issues, and this page will transform into a space that helps you progress. Admins will also see items which help their team progress.", + "workspace_dashboard_empty_state_primary_button_text": "Build your first project", + "workspace_dashboard_empty_state_primary_button_comic_title": "Everything starts with a project in Plane", + "workspace_dashboard_empty_state_primary_button_comic_description": "A project could be a product's roadmap, a marketing campaign, or launching a new car.", + + "workspace_analytics_empty_state_title": "Track progress, workloads, and allocations. Spot trends, remove blockers, and move work faster", + "workspace_analytics_empty_state_description": "See scope versus demand, estimates, and scope creep. Get performance by team members and teams, and make sure your project runs on time.", + "workspace_analytics_empty_state_primary_button_text": "Start your first project", + "workspace_analytics_empty_state_primary_button_comic_title": "Analytics works best with Cycles + Modules", + "workspace_analytics_empty_state_primary_button_comic_description": "First, timebox your issues into Cycles and, if you can, group issues that span more than a cycle into Modules. Check out both on the left nav.", + + "workspace_projects_empty_state_title": "No active projects", + "workspace_projects_empty_state_description": "Think of each project as the parent for goal-oriented work. Projects are where Jobs, Cycles, and Modules live and, along with your colleagues, help you achieve that goal. Create a new project or filter for archived projects.", + "workspace_projects_empty_state_primary_button_text": "Start your first project", + "workspace_projects_empty_state_primary_button_comic_title": "Everything starts with a project in Plane", + "workspace_projects_empty_state_primary_button_comic_description": "A project could be a product's roadmap, a marketing campaign, or launching a new car.", + + "workspace_all_issues_empty_state_title": "No issues in the project", + "workspace_all_issues_empty_state_description": "First project done! Now, slice your work into trackable pieces with issues. Let's go!", + "workspace_all_issues_empty_state_primary_button_text": "Create new issue", + + "workspace_assigned_empty_state_title": "No issues yet", + "workspace_assigned_empty_state_description": "Issues assigned to you can be tracked from here.", + "workspace_assigned_empty_state_primary_button_text": "Create new issue", + + "workspace_created_empty_state_title": "No issues yet", + "workspace_created_empty_state_description": "All issues created by you come here, track them here directly.", + "workspace_created_empty_state_primary_button_text": "Create new issue", + + "workspace_subscribed_empty_state_title": "No issues yet", + "workspace_subscribed_empty_state_description": "Subscribe to issues you are interested in, track all of them here.", + + "workspace_custom_view_empty_state_title": "No issues yet", + "workspace_custom_view_empty_state_description": "Issues that applies to the filters, track all of them here.", + + "workspace_project_not_found_empty_state_title": "No such project exists", + "workspace_project_not_found_empty_state_description": "To create issues or manage your work, you need to create a project or be a part of one.", + "workspace_project_not_found_empty_state_primary_button_text": "Create Project", + "workspace_project_not_found_empty_state_primary_button_comic_title": "Everything starts with a project in Plane", + "workspace_project_not_found_empty_state_primary_button_comic_description": "A project could be a product's roadmap, a marketing campaign, or launching a new car.", + + "workspace_no_projects_empty_state_title": "No project", + "workspace_no_projects_empty_state_description": "To create issues or manage your work, you need to create a project or be a part of one.", + "workspace_no_projects_empty_state_primary_button_text": "Start your first project", + "workspace_no_projects_empty_state_primary_button_comic_title": "Everything starts with a project in Plane", + "workspace_no_projects_empty_state_primary_button_comic_description": "A project could be a product's roadmap, a marketing campaign, or launching a new car.", + + "workspace_settings_api_tokens_empty_state_title": "No API tokens created", + "workspace_settings_api_tokens_empty_state_description": "Plane APIs can be used to integrate your data in Plane with any external system. Create a token to get started.", + + "workspace_settings_webhooks_empty_state_title": "No webhooks added", + "workspace_settings_webhooks_empty_state_description": "Create webhooks to receive real-time updates and automate actions.", + + "workspace_settings_export_empty_state_title": "No previous exports yet", + "workspace_settings_export_empty_state_description": "Anytime you export, you will also have a copy here for reference.", + + "workspace_settings_import_empty_state_title": "No previous imports yet", + "workspace_settings_import_empty_state_description": "Find all your previous imports here and download them.", + + "profile_activity_empty_state_title": "No activities yet", + "profile_activity_empty_state_description": "Get started by creating a new issue! Add details and properties to it. Explore more in Plane to see your activity.", + + "profile_assigned_empty_state_title": "No issues are assigned to you", + "profile_assigned_empty_state_description": "Issues assigned to you can be tracked from here.", + + "profile_created_empty_state_title": "No issues yet", + "profile_created_empty_state_description": "All issues created by you come here, track them here directly.", + + "profile_subscribed_empty_state_title": "No issues yet", + "profile_subscribed_empty_state_description": "Subscribe to issues you are interested in, track all of them here.", + + "project_settings_labels_empty_state_title": "No labels yet", + "project_settings_labels_empty_state_description": "Create labels to help organize and filter issues in you project.", + + "project_settings_integrations_empty_state_title": "No integrations configured", + "project_settings_integrations_empty_state_description": "Configure GitHub and other integrations to sync your project issues.", + + "project_settings_estimate_empty_state_title": "No estimates added", + "project_settings_estimate_empty_state_description": "Create a set of estimates to communicate the amount of work per issue.", + + "project_cycles_empty_state_title": "Group and timebox your work in Cycles.", + "project_cycles_empty_state_description": "Break work down by timeboxed chunks, work backwards from your project deadline to set dates, and make tangible progress as a team.", + "project_cycles_empty_state_primary_button_text": "Set your first cycle", + "project_cycles_empty_state_primary_button_comic_title": "Cycles are repetitive time-boxes.", + "project_cycles_empty_state_primary_button_comic_description": "A sprint, an iteration, and or any other term you use for weekly or fortnightly tracking of work is a cycle.", + + "project_cycle_no_issues_empty_state_title": "No issues added to the cycle", + "project_cycle_no_issues_empty_state_description": "Add or create issues you wish to timebox and deliver within this cycle", + "project_cycle_no_issues_empty_state_primary_button_text": "Create new issue", + "project_cycle_no_issues_empty_state_secondary_button_text": "Add an existing issue", + + "project_cycle_active_empty_state_title": "No active cycle", + "project_cycle_active_empty_state_description": "An active cycle includes any period that encompasses today's date within its range. Find the progress and details of the active cycle here.", + + "project_cycle_completed_no_issues_empty_state_title": "No issues in the cycle", + "project_cycle_completed_no_issues_empty_state_description": "No issues in the cycle. Issues are either transferred or hidden. To see hidden issues if any, update your display properties accordingly.", + + "project_archived_no_cycles_empty_state_title": "No archived cycles yet", + "project_archived_no_cycles_empty_state_description": "To tidy up your project, archive completed cycles. Find them here once archived.", + + "project_cycle_all_empty_state_title": "No cycles", + "project_cycle_all_empty_state_description": "An active cycle includes any period that encompasses today's date within its range. Find the progress and details of the active cycle here.", + + "project_empty_filter_empty_state_title": "No issues found matching the filters applied", + "project_empty_filter_empty_state_secondary_button_text": "Clear all filters", + + "project_archived_empty_filter_empty_state_title": "No issues found matching the filters applied", + "project_archived_empty_filter_empty_state_secondary_button_text": "Clear all filters", + + "project_draft_empty_filter_empty_state_title": "No issues found matching the filters applied", + "project_draft_empty_filter_empty_state_secondary_button_text": "Clear all filters", + + "project_no_issues_empty_state_title": "Create an issue and assign it to someone, even yourself", + "project_no_issues_empty_state_description": "Think of issues as jobs, tasks, work, or JTBD. Which we like. An issue and its sub-issues are usually time-based actionables assigned to members of your team. Your team creates, assigns, and completes issues to move your project towards its goal.", + "project_no_issues_empty_state_primary_button_text": "Create your first issue", + "project_no_issues_empty_state_primary_button_comic_title": "Issues are building blocks in Plane.", + "project_no_issues_empty_state_primary_button_comic_description": "Redesign the Plane UI, Rebrand the company, or Launch the new fuel injection system are examples of issues that likely have sub-issues.", + + "project_archived_no_issues_empty_state_title": "No archived issues yet", + "project_archived_no_issues_empty_state_description": "Manually or through automation, you can archive issues that are completed or cancelled. Find them here once archived.", + "project_archived_no_issues_empty_state_primary_button_text": "Set automation", + + "project_draft_no_issues_empty_state_title": "No draft issues yet", + "project_draft_no_issues_empty_state_description": "Quickly stepping away but want to keep your place? No worries – save a draft now. Your issues will be right here waiting for you.", + + "views_empty_search_empty_state_title": "No matching views", + "views_empty_search_empty_state_description": "No views match the search criteria. Create a new view instead.", + + "projects_empty_search_empty_state_title": "No matching projects", + "projects_empty_search_empty_state_description": "No projects detected with the matching criteria. Create a new project instead.", + + "members_empty_search_empty_state_title": "No matching members", + "members_empty_search_empty_state_description": "Add them to the project if they are already a part of the workspace", + + "project_module_issues_empty_state_title": "No issues in the module", + "project_module_issues_empty_state_description": "Create or add issues which you want to accomplish as part of this module", + "project_module_issues_empty_state_primary_button_text": "Create new issue", + "project_module_issues_empty_state_secondary_button_text": "Add an existing issue", + + "project_module_empty_state_title": "Map your project milestones to Modules and track aggregated work easily.", + "project_module_empty_state_description": "A group of issues that belong to a logical, hierarchical parent form a module. Think of them as a way to track work by project milestones. They have their own periods and deadlines as well as analytics to help you see how close or far you are from a milestone.", + "project_module_empty_state_primary_button_text": "Build your first module", + "project_module_empty_state_primary_button_comic_title": "Modules help group work by hierarchy.", + "project_module_empty_state_primary_button_comic_description": "A cart module, a chassis module, and a warehouse module are all good example of this grouping.", + + "project_archived_no_modules_empty_state_title": "No archived Modules yet", + "project_archived_no_modules_empty_state_description": "To tidy up your project, archive completed or cancelled modules. Find them here once archived.", + + "project_view_empty_state_title": "Save filtered views for your project. Create as many as you need", + "project_view_empty_state_primary_button_text": "Create your first view", + "project_view_empty_state_primary_button_comic_title": "Views work atop Issue properties.", + "project_view_empty_state_primary_button_comic_description": "You can create a view from here with as many properties as filters as you see fit.", + + "project_page_empty_state_title": "Write a note, a doc, or a full knowledge base. Get Galileo, Plane's AI assistant, to help you get started", + "project_page_empty_state_description": "Pages are thoughts potting space in Plane. Take down meeting notes, format them easily, embed issues, lay them out using a library of components, and keep them all in your project's context. To make short work of any doc, invoke Galileo, Plane's AI, with a shortcut or the click of a button.", + "project_page_empty_state_primary_button_text": "Create your first page", + + "project_page_private_empty_state_title": "No private pages yet", + "project_page_private_empty_state_description": "Keep your private thoughts here. When you're ready to share, the team's just a click away.", + "project_page_private_empty_state_primary_button_text": "Create your first page", + + "project_page_public_empty_state_title": "No public pages yet", + "project_page_public_empty_state_description": "See pages shared with everyone in your project right here.", + "project_page_public_empty_state_primary_button_text": "Create your first page", + + "project_page_archived_empty_state_title": "No archived pages yet", + "project_page_archived_empty_state_description": "Archive pages not on your radar. Access them here when needed.", + + "workspace_page_empty_state_title": "Write a note, a doc, or a full knowledge base. Get Galileo, Plane's AI assistant, to help you get started", + "workspace_page_empty_state_description": "Pages are thoughts potting space in Plane. Take down meeting notes, format them easily, embed issues, lay them out using a library of components, and keep them all in your project's context. To make short work of any doc, invoke Galileo, Plane's AI, with a shortcut or the click of a button.", + "workspace_page_empty_state_primary_button_text": "Create your first page", + + "workspace_page_private_empty_state_title": "No private pages yet", + "workspace_page_private_empty_state_description": "Keep your private thoughts here. When you're ready to share, the team's just a click away.", + "workspace_page_private_empty_state_primary_button_text": "Create your first page", + + "command_k_search_empty_state_title": "No results found", + + "issue_relation_search_empty_state_title": "No matching issues found", + "issue_relation_empty_state_title": "No issues found", + + "issue_comment_empty_state_title": "No comments yet", + "issue_comment_empty_state_description": "Comments can be used as a discussion and follow-up space for the issues", + + "notification_detail_empty_state_title": "Select to view details.", + + "notification_all_empty_state_title": "No issues assigned", + "notification_all_empty_state_description": "Updates for issues assigned to you can be seen here", + + "notification_mentions_empty_state_title": "No issues assigned", + "notification_mentions_empty_state_description": "Updates for issues assigned to you can be seen here", + + "active_cycle_progress_empty_state_title": "Add issues to the cycle to view it's progress", + "active_cycle_chart_empty_state_title": "Add issues to the cycle to view the burndown chart.", + "active_cycle_priority_issue_empty_state_title": "Observe high priority issues tackled in the cycle at a glance.", + "active_cycle_assignee_empty_state_title": "Add assignees to issues to see a breakdown of work by assignees.", + "active_cycle_label_empty_state_title": "Add labels to issues to see the breakdown of work by labels.", + + "workspace_active_cycles_empty_state_title": "No active cycles", + "workspace_active_cycles_empty_state_description": "Cycles of your projects that includes any period that encompasses today's date within its range. Find the progress and details of all your active cycle here.", + + "disabled_project_inbox_empty_state_title": "Intake is not enabled for the project.", + "disabled_project_inbox_empty_state_description": "Intake helps you manage incoming requests to your project and add them as issues in your workflow. Enable intake from project settings to manage requests.", + "disabled_project_inbox_empty_state_primary_button_text": "Manage features" } diff --git a/packages/i18n/src/locales/es/translations.json b/packages/i18n/src/locales/es/translations.json index 9f2b98792c2..4f2b15c32b5 100644 --- a/packages/i18n/src/locales/es/translations.json +++ b/packages/i18n/src/locales/es/translations.json @@ -114,7 +114,6 @@ "plane_logo": "Logo de Plane", "workspace_creation_disabled": "Creación de espacio de trabajo deshabilitada", "workspace_request_subject": "Solicitando un nuevo espacio de trabajo", - "workspace_request_body": "Hola administrador(es) de instancia,\n\nPor favor, crea un nuevo espacio de trabajo con la URL [/nombre-del-espacio-de-trabajo] para [propósito de crear el espacio de trabajo].\n\nGracias,\n{{firstName}} {{lastName}}\n{{email}}", "creating_workspace": "Creando espacio de trabajo", "workspace_created_successfully": "Espacio de trabajo creado con éxito", "create_workspace_page": "Página de creación de espacio de trabajo", @@ -316,5 +315,211 @@ "remove_parent_issue": "Eliminar problema padre", "add_parent": "Agregar padre", "loading_members": "Cargando miembros...", - "inbox": "bandeja de entrada" + "inbox": "bandeja de entrada", + + "workspace_dashboard_empty_state_title": "Resumen de tus proyectos, actividad y métricas", + "workspace_dashboard_empty_state_description": "Bienvenido a Plane, estamos emocionados de tenerte aquí. Crea tu primer proyecto y realiza un seguimiento de tus problemas, y esta página se transformará en un espacio que te ayuda a progresar. Los administradores también verán elementos que ayudan a su equipo a progresar.", + "workspace_dashboard_empty_state_primary_button_text": "Construye tu primer proyecto", + "workspace_dashboard_empty_state_primary_button_comic_title": "Todo comienza con un proyecto en Plane", + "workspace_dashboard_empty_state_primary_button_comic_description": "Un proyecto podría ser la hoja de ruta de un producto, una campaña de marketing o el lanzamiento de un nuevo automóvil.", + + "workspace_analytics_empty_state_title": "Rastrea el progreso, las cargas de trabajo y las asignaciones. Identifica tendencias, elimina obstáculos y mueve el trabajo más rápido", + "workspace_analytics_empty_state_description": "Observa el alcance versus la demanda, las estimaciones y el aumento del alcance. Obtén el rendimiento por miembros del equipo y equipos, y asegúrate de que tu proyecto se ejecute a tiempo.", + "workspace_analytics_empty_state_primary_button_text": "Comienza tu primer proyecto", + "workspace_analytics_empty_state_primary_button_comic_title": "El análisis funciona mejor con Ciclos + Módulos", + "workspace_analytics_empty_state_primary_button_comic_description": "Primero, limita en el tiempo tus problemas en Ciclos y, si puedes, agrupa los problemas que abarcan más de un ciclo en Módulos. Revisa ambos en la navegación izquierda.", + + "workspace_projects_empty_state_title": "No hay proyectos activos", + "workspace_projects_empty_state_description": "Piensa en cada proyecto como el padre del trabajo orientado a objetivos. Los proyectos son donde viven los Trabajos, Ciclos y Módulos y, junto con tus colegas, te ayudan a alcanzar ese objetivo. Crea un nuevo proyecto o filtra proyectos archivados.", + "workspace_projects_empty_state_primary_button_text": "Comienza tu primer proyecto", + "workspace_projects_empty_state_primary_button_comic_title": "Todo comienza con un proyecto en Plane", + "workspace_projects_empty_state_primary_button_comic_description": "Un proyecto podría ser la hoja de ruta de un producto, una campaña de marketing o el lanzamiento de un nuevo automóvil.", + + "workspace_all_issues_empty_state_title": "No hay problemas en el proyecto", + "workspace_all_issues_empty_state_description": "¡Primer proyecto completado! Ahora, divide tu trabajo en piezas rastreables con problemas. ¡Vamos!", + "workspace_all_issues_empty_state_primary_button_text": "Crear nuevo problema", + + "workspace_assigned_empty_state_title": "No hay problemas aún", + "workspace_assigned_empty_state_description": "Los problemas asignados a ti pueden ser rastreados desde aquí.", + "workspace_assigned_empty_state_primary_button_text": "Crear nuevo problema", + + "workspace_created_empty_state_title": "No hay problemas aún", + "workspace_created_empty_state_description": "Todos los problemas creados por ti vienen aquí, rastréalos aquí directamente.", + "workspace_created_empty_state_primary_button_text": "Crear nuevo problema", + + "workspace_subscribed_empty_state_title": "No hay problemas aún", + "workspace_subscribed_empty_state_description": "Suscríbete a problemas que te interesen, rastréalos todos aquí.", + + "workspace_custom_view_empty_state_title": "No hay problemas aún", + "workspace_custom_view_empty_state_description": "Problemas que aplican a los filtros, rastréalos todos aquí.", + + "workspace_project_not_found_empty_state_title": "No existe tal proyecto", + "workspace_project_not_found_empty_state_description": "Para crear problemas o gestionar tu trabajo, necesitas crear un proyecto o ser parte de uno.", + "workspace_project_not_found_empty_state_primary_button_text": "Crear Proyecto", + "workspace_project_not_found_empty_state_primary_button_comic_title": "Todo comienza con un proyecto en Plane", + "workspace_project_not_found_empty_state_primary_button_comic_description": "Un proyecto podría ser la hoja de ruta de un producto, una campaña de marketing o el lanzamiento de un nuevo automóvil.", + + "workspace_no_projects_empty_state_title": "No hay proyecto", + "workspace_no_projects_empty_state_description": "Para crear problemas o gestionar tu trabajo, necesitas crear un proyecto o ser parte de uno.", + "workspace_no_projects_empty_state_primary_button_text": "Comienza tu primer proyecto", + "workspace_no_projects_empty_state_primary_button_comic_title": "Todo comienza con un proyecto en Plane", + "workspace_no_projects_empty_state_primary_button_comic_description": "Un proyecto podría ser la hoja de ruta de un producto, una campaña de marketing o el lanzamiento de un nuevo automóvil.", + + "workspace_settings_api_tokens_empty_state_title": "No se han creado tokens API", + "workspace_settings_api_tokens_empty_state_description": "Las APIs de Plane pueden usarse para integrar tus datos en Plane con cualquier sistema externo. Crea un token para comenzar.", + + "workspace_settings_webhooks_empty_state_title": "No se han añadido webhooks", + "workspace_settings_webhooks_empty_state_description": "Crea webhooks para recibir actualizaciones en tiempo real y automatizar acciones.", + + "workspace_settings_export_empty_state_title": "No hay exportaciones previas aún", + "workspace_settings_export_empty_state_description": "Cada vez que exportes, también tendrás una copia aquí para referencia.", + + "workspace_settings_import_empty_state_title": "No hay importaciones previas aún", + "workspace_settings_import_empty_state_description": "Encuentra todas tus importaciones previas aquí y descárgalas.", + + "profile_activity_empty_state_title": "No hay actividades aún", + "profile_activity_empty_state_description": "¡Comienza creando un nuevo problema! Añade detalles y propiedades. Explora más en Plane para ver tu actividad.", + + "profile_assigned_empty_state_title": "No hay problemas asignados a ti", + "profile_assigned_empty_state_description": "Los problemas asignados a ti pueden ser rastreados desde aquí.", + + "profile_created_empty_state_title": "No hay problemas aún", + "profile_created_empty_state_description": "Todos los problemas creados por ti vienen aquí, rastréalos aquí directamente.", + + "profile_subscribed_empty_state_title": "No hay problemas aún", + "profile_subscribed_empty_state_description": "Suscríbete a problemas que te interesen, rastréalos todos aquí.", + + "project_settings_labels_empty_state_title": "No hay etiquetas aún", + "project_settings_labels_empty_state_description": "Crea etiquetas para ayudar a organizar y filtrar problemas en tu proyecto.", + + "project_settings_integrations_empty_state_title": "No hay integraciones configuradas", + "project_settings_integrations_empty_state_description": "Configura GitHub y otras integraciones para sincronizar los problemas de tu proyecto.", + + "project_settings_estimate_empty_state_title": "No se han añadido estimaciones", + "project_settings_estimate_empty_state_description": "Crea un conjunto de estimaciones para comunicar la cantidad de trabajo por problema.", + + "project_cycles_empty_state_title": "Agrupa y limita en el tiempo tu trabajo en Ciclos.", + "project_cycles_empty_state_description": "Divide el trabajo en fragmentos limitados en el tiempo, trabaja hacia atrás desde la fecha límite de tu proyecto para establecer fechas y haz progreso tangible como equipo.", + "project_cycles_empty_state_primary_button_text": "Establece tu primer ciclo", + "project_cycles_empty_state_primary_button_comic_title": "Los Ciclos son cajas de tiempo repetitivas.", + "project_cycles_empty_state_primary_button_comic_description": "Un sprint, una iteración, o cualquier otro término que uses para el seguimiento semanal o quincenal del trabajo es un ciclo.", + + "project_cycle_no_issues_empty_state_title": "No se han añadido problemas al ciclo", + "project_cycle_no_issues_empty_state_description": "Añade o crea problemas que desees limitar en el tiempo y entregar dentro de este ciclo", + "project_cycle_no_issues_empty_state_primary_button_text": "Crear nuevo problema", + "project_cycle_no_issues_empty_state_secondary_button_text": "Añadir un problema existente", + + "project_cycle_active_empty_state_title": "No hay ciclo activo", + "project_cycle_active_empty_state_description": "Un ciclo activo incluye cualquier período que abarque la fecha de hoy dentro de su rango. Encuentra el progreso y los detalles del ciclo activo aquí.", + + "project_cycle_completed_no_issues_empty_state_title": "No hay problemas en el ciclo", + "project_cycle_completed_no_issues_empty_state_description": "No hay problemas en el ciclo. Los problemas están transferidos u ocultos. Para ver problemas ocultos si los hay, actualiza tus propiedades de visualización en consecuencia.", + + "project_archived_no_cycles_empty_state_title": "No hay ciclos archivados aún", + "project_archived_no_cycles_empty_state_description": "Para ordenar tu proyecto, archiva los ciclos completados. Encuéntralos aquí una vez archivados.", + + "project_cycle_all_empty_state_title": "No hay ciclos", + "project_cycle_all_empty_state_description": "Un ciclo activo incluye cualquier período que abarque la fecha de hoy dentro de su rango. Encuentra el progreso y los detalles del ciclo activo aquí.", + + "project_empty_filter_empty_state_title": "No se encontraron problemas que coincidan con los filtros aplicados", + "project_empty_filter_empty_state_secondary_button_text": "Limpiar todos los filtros", + + "project_archived_empty_filter_empty_state_title": "No se encontraron problemas que coincidan con los filtros aplicados", + "project_archived_empty_filter_empty_state_secondary_button_text": "Limpiar todos los filtros", + + "project_draft_empty_filter_empty_state_title": "No se encontraron problemas que coincidan con los filtros aplicados", + "project_draft_empty_filter_empty_state_secondary_button_text": "Limpiar todos los filtros", + + "project_no_issues_empty_state_title": "Crea un problema y asígnalo a alguien, incluso a ti mismo", + "project_no_issues_empty_state_description": "Piensa en los problemas como trabajos, tareas, trabajo o JTBD. Que nos gusta. Un problema y sus sub-problemas son generalmente acciones basadas en tiempo asignadas a miembros de tu equipo. Tu equipo crea, asigna y completa problemas para mover tu proyecto hacia su objetivo.", + "project_no_issues_empty_state_primary_button_text": "Crea tu primer problema", + "project_no_issues_empty_state_primary_button_comic_title": "Los problemas son bloques de construcción en Plane.", + "project_no_issues_empty_state_primary_button_comic_description": "Rediseñar la interfaz de usuario de Plane, Cambiar la marca de la empresa o Lanzar el nuevo sistema de inyección de combustible son ejemplos de problemas que probablemente tengan sub-problemas.", + + "project_archived_no_issues_empty_state_title": "No hay problemas archivados aún", + "project_archived_no_issues_empty_state_description": "Manual o mediante automatización, puedes archivar problemas que están completados o cancelados. Encuéntralos aquí una vez archivados.", + "project_archived_no_issues_empty_state_primary_button_text": "Establecer automatización", + + "project_draft_no_issues_empty_state_title": "No hay problemas en borrador aún", + "project_draft_no_issues_empty_state_description": "¿Te alejas rápidamente pero quieres mantener tu lugar? No te preocupes – guarda un borrador ahora. Tus problemas estarán aquí esperándote.", + + "views_empty_search_empty_state_title": "No hay vistas coincidentes", + "views_empty_search_empty_state_description": "No hay vistas que coincidan con los criterios de búsqueda. Crea una nueva vista en su lugar.", + + "projects_empty_search_empty_state_title": "No hay proyectos coincidentes", + "projects_empty_search_empty_state_description": "No se detectaron proyectos con los criterios coincidentes. Crea un nuevo proyecto en su lugar.", + + "members_empty_search_empty_state_title": "No hay miembros coincidentes", + "members_empty_search_empty_state_description": "Añádelos al proyecto si ya son parte del espacio de trabajo", + + "project_module_issues_empty_state_title": "No hay problemas en el módulo", + "project_module_issues_empty_state_description": "Crea o añade problemas que quieras realizar como parte de este módulo", + "project_module_issues_empty_state_primary_button_text": "Crear nuevo problema", + "project_module_issues_empty_state_secondary_button_text": "Añadir un problema existente", + + "project_module_empty_state_title": "Mapea los hitos de tu proyecto a Módulos y rastrea el trabajo agregado fácilmente.", + "project_module_empty_state_description": "Un grupo de problemas que pertenecen a un padre lógico y jerárquico forman un módulo. Piensa en ellos como una forma de rastrear el trabajo por hitos del proyecto. Tienen sus propios períodos y fechas límite, así como análisis para ayudarte a ver qué tan cerca o lejos estás de un hito.", + "project_module_empty_state_primary_button_text": "Construye tu primer módulo", + "project_module_empty_state_primary_button_comic_title": "Los Módulos ayudan a agrupar el trabajo por jerarquía.", + "project_module_empty_state_primary_button_comic_description": "Un módulo de carrito, un módulo de chasis y un módulo de almacén son todos buenos ejemplos de esta agrupación.", + + "project_archived_no_modules_empty_state_title": "Aún no hay Módulos archivados", + "project_archived_no_modules_empty_state_description": "Para ordenar tu proyecto, archiva los módulos completados o cancelados. Encuéntralos aquí una vez archivados.", + + "project_view_empty_state_title": "Guarda vistas filtradas para tu proyecto. Crea tantas como necesites", + "project_view_empty_state_primary_button_text": "Crea tu primera vista", + "project_view_empty_state_primary_button_comic_title": "Las vistas funcionan sobre las propiedades de los Problemas.", + "project_view_empty_state_primary_button_comic_description": "Puedes crear una vista desde aquí con tantas propiedades como filtros como consideres adecuado.", + + "project_page_empty_state_title": "Escribe una nota, un documento o una base de conocimiento completa. Obtén ayuda de Galileo, el asistente de IA de Plane, para comenzar", + "project_page_empty_state_description": "Las páginas son espacios para plasmar pensamientos en Plane. Toma notas de reuniones, dales formato fácilmente, incorpora problemas, organízalos usando una biblioteca de componentes y mantenlos todos en el contexto de tu proyecto. Para hacer un trabajo rápido de cualquier documento, invoca a Galileo, la IA de Plane, con un atajo o el clic de un botón.", + "project_page_empty_state_primary_button_text": "Crea tu primera página", + + "project_page_private_empty_state_title": "Aún no hay páginas privadas", + "project_page_private_empty_state_description": "Mantén tus pensamientos privados aquí. Cuando estés listo para compartir, el equipo está a solo un clic de distancia.", + "project_page_private_empty_state_primary_button_text": "Crea tu primera página", + + "project_page_public_empty_state_title": "Aún no hay páginas públicas", + "project_page_public_empty_state_description": "Ve las páginas compartidas con todos en tu proyecto aquí mismo.", + "project_page_public_empty_state_primary_button_text": "Crea tu primera página", + + "project_page_archived_empty_state_title": "Aún no hay páginas archivadas", + "project_page_archived_empty_state_description": "Archiva las páginas que no estén en tu radar. Accede a ellas aquí cuando las necesites.", + + "workspace_page_empty_state_title": "Escribe una nota, un documento o una base de conocimiento completa. Obtén ayuda de Galileo, el asistente de IA de Plane, para comenzar", + "workspace_page_empty_state_description": "Las páginas son espacios para plasmar pensamientos en Plane. Toma notas de reuniones, dales formato fácilmente, incorpora problemas, organízalos usando una biblioteca de componentes y mantenlos todos en el contexto de tu proyecto. Para hacer un trabajo rápido de cualquier documento, invoca a Galileo, la IA de Plane, con un atajo o el clic de un botón.", + "workspace_page_empty_state_primary_button_text": "Crea tu primera página", + + "workspace_page_private_empty_state_title": "Aún no hay páginas privadas", + "workspace_page_private_empty_state_description": "Mantén tus pensamientos privados aquí. Cuando estés listo para compartir, el equipo está a solo un clic de distancia.", + "workspace_page_private_empty_state_primary_button_text": "Crea tu primera página", + + "command_k_search_empty_state_title": "No se encontraron resultados", + + "issue_relation_search_empty_state_title": "No se encontraron problemas coincidentes", + "issue_relation_empty_state_title": "No se encontraron problemas", + + "issue_comment_empty_state_title": "Aún no hay comentarios", + "issue_comment_empty_state_description": "Los comentarios pueden usarse como un espacio de discusión y seguimiento para los problemas", + + "notification_detail_empty_state_title": "Selecciona para ver detalles.", + + "notification_all_empty_state_title": "No hay problemas asignados", + "notification_all_empty_state_description": "Las actualizaciones de los problemas asignados a ti se pueden ver aquí", + + "notification_mentions_empty_state_title": "No hay problemas asignados", + "notification_mentions_empty_state_description": "Las actualizaciones de los problemas asignados a ti se pueden ver aquí", + + "active_cycle_progress_empty_state_title": "Añade problemas al ciclo para ver su progreso", + "active_cycle_chart_empty_state_title": "Añade problemas al ciclo para ver el gráfico de avance.", + "active_cycle_priority_issue_empty_state_title": "Observa los problemas de alta prioridad abordados en el ciclo de un vistazo.", + "active_cycle_assignee_empty_state_title": "Añade asignados a los problemas para ver un desglose del trabajo por asignados.", + "active_cycle_label_empty_state_title": "Añade etiquetas a los problemas para ver el desglose del trabajo por etiquetas.", + + "workspace_active_cycles_empty_state_title": "No hay ciclos activos", + "workspace_active_cycles_empty_state_description": "Ciclos de tus proyectos que incluyen cualquier período que abarque la fecha de hoy dentro de su rango. Encuentra el progreso y los detalles de todos tus ciclos activos aquí.", + + "disabled_project_inbox_empty_state_title": "La entrada no está habilitada para el proyecto.", + "disabled_project_inbox_empty_state_description": "La entrada te ayuda a gestionar las solicitudes entrantes a tu proyecto y agregarlas como problemas en tu flujo de trabajo. Habilita la entrada desde la configuración del proyecto para gestionar las solicitudes.", + "disabled_project_inbox_empty_state_primary_button_text": "Gestionar funciones" } diff --git a/packages/i18n/src/locales/fr/translations.json b/packages/i18n/src/locales/fr/translations.json index 0eee868e174..6007622bca2 100644 --- a/packages/i18n/src/locales/fr/translations.json +++ b/packages/i18n/src/locales/fr/translations.json @@ -316,5 +316,211 @@ "remove_parent_issue": "Supprimer le problème parent", "add_parent": "Ajouter un parent", "loading_members": "Chargement des membres...", - "inbox": "Boîte de réception" + "inbox": "Boîte de réception", + + "workspace_dashboard_empty_state_title": "Aperçu de vos projets, activités et métriques", + "workspace_dashboard_empty_state_description": "Bienvenue sur Plane, nous sommes ravis de vous accueillir. Créez votre premier projet et suivez vos problèmes, et cette page se transformera en un espace qui vous aide à progresser. Les administrateurs verront également les éléments qui aident leur équipe à progresser.", + "workspace_dashboard_empty_state_primary_button_text": "Créez votre premier projet", + "workspace_dashboard_empty_state_primary_button_comic_title": "Tout commence par un projet dans Plane", + "workspace_dashboard_empty_state_primary_button_comic_description": "Un projet peut être la feuille de route d'un produit, une campagne marketing ou le lancement d'une nouvelle voiture.", + + "workspace_analytics_empty_state_title": "Suivez les progrès, les charges de travail et les allocations. Repérez les tendances, supprimez les obstacles et accélérez le travail", + "workspace_analytics_empty_state_description": "Visualisez la portée par rapport à la demande, les estimations et la dérive de portée. Obtenez les performances par membres et équipes, et assurez-vous que votre projet respecte les délais.", + "workspace_analytics_empty_state_primary_button_text": "Commencez votre premier projet", + "workspace_analytics_empty_state_primary_button_comic_title": "L'analyse fonctionne mieux avec les Cycles + Modules", + "workspace_analytics_empty_state_primary_button_comic_description": "D'abord, limitez vos problèmes dans le temps en Cycles et, si possible, groupez les problèmes qui s'étendent sur plus d'un cycle en Modules. Découvrez les deux dans la navigation de gauche.", + + "workspace_projects_empty_state_title": "Aucun projet actif", + "workspace_projects_empty_state_description": "Considérez chaque projet comme le parent d'un travail orienté vers un objectif. Les projets sont l'endroit où vivent les Tâches, les Cycles et les Modules et, avec vos collègues, vous aident à atteindre cet objectif. Créez un nouveau projet ou filtrez les projets archivés.", + "workspace_projects_empty_state_primary_button_text": "Commencez votre premier projet", + "workspace_projects_empty_state_primary_button_comic_title": "Tout commence par un projet dans Plane", + "workspace_projects_empty_state_primary_button_comic_description": "Un projet peut être la feuille de route d'un produit, une campagne marketing ou le lancement d'une nouvelle voiture.", + + "workspace_all_issues_empty_state_title": "Aucun problème dans le projet", + "workspace_all_issues_empty_state_description": "Premier projet terminé ! Maintenant, découpez votre travail en morceaux suivables avec des problèmes. Allons-y !", + "workspace_all_issues_empty_state_primary_button_text": "Créer un nouveau problème", + + "workspace_assigned_empty_state_title": "Aucun problème pour le moment", + "workspace_assigned_empty_state_description": "Les problèmes qui vous sont assignés peuvent être suivis ici.", + "workspace_assigned_empty_state_primary_button_text": "Créer un nouveau problème", + + "workspace_created_empty_state_title": "Aucun problème pour le moment", + "workspace_created_empty_state_description": "Tous les problèmes que vous créez arrivent ici, suivez-les directement ici.", + "workspace_created_empty_state_primary_button_text": "Créer un nouveau problème", + + "workspace_subscribed_empty_state_title": "Aucun problème pour le moment", + "workspace_subscribed_empty_state_description": "Abonnez-vous aux problèmes qui vous intéressent, suivez-les tous ici.", + + "workspace_custom_view_empty_state_title": "Aucun problème pour le moment", + "workspace_custom_view_empty_state_description": "Problèmes qui correspondent aux filtres, suivez-les tous ici.", + + "workspace_project_not_found_empty_state_title": "Ce projet n'existe pas", + "workspace_project_not_found_empty_state_description": "Pour créer des problèmes ou gérer votre travail, vous devez créer un projet ou faire partie d'un projet.", + "workspace_project_not_found_empty_state_primary_button_text": "Créer un projet", + "workspace_project_not_found_empty_state_primary_button_comic_title": "Tout commence par un projet dans Plane", + "workspace_project_not_found_empty_state_primary_button_comic_description": "Un projet peut être la feuille de route d'un produit, une campagne marketing ou le lancement d'une nouvelle voiture.", + + "workspace_no_projects_empty_state_title": "Aucun projet", + "workspace_no_projects_empty_state_description": "Pour créer des problèmes ou gérer votre travail, vous devez créer un projet ou faire partie d'un projet.", + "workspace_no_projects_empty_state_primary_button_text": "Commencez votre premier projet", + "workspace_no_projects_empty_state_primary_button_comic_title": "Tout commence par un projet dans Plane", + "workspace_no_projects_empty_state_primary_button_comic_description": "Un projet peut être la feuille de route d'un produit, une campagne marketing ou le lancement d'une nouvelle voiture.", + + "workspace_settings_api_tokens_empty_state_title": "Aucun jeton API créé", + "workspace_settings_api_tokens_empty_state_description": "Les APIs de Plane peuvent être utilisées pour intégrer vos données dans Plane avec n'importe quel système externe. Créez un jeton pour commencer.", + + "workspace_settings_webhooks_empty_state_title": "Aucun webhook ajouté", + "workspace_settings_webhooks_empty_state_description": "Créez des webhooks pour recevoir des mises à jour en temps réel et automatiser des actions.", + + "workspace_settings_export_empty_state_title": "Aucune exportation précédente", + "workspace_settings_export_empty_state_description": "Chaque fois que vous exportez, vous aurez également une copie ici pour référence.", + + "workspace_settings_import_empty_state_title": "Aucune importation précédente", + "workspace_settings_import_empty_state_description": "Trouvez toutes vos importations précédentes ici et téléchargez-les.", + + "profile_activity_empty_state_title": "Aucune activité pour le moment", + "profile_activity_empty_state_description": "Commencez par créer un nouveau problème ! Ajoutez-y des détails et des propriétés. Explorez davantage dans Plane pour voir votre activité.", + + "profile_assigned_empty_state_title": "Aucun problème ne vous est assigné", + "profile_assigned_empty_state_description": "Les problèmes qui vous sont assignés peuvent être suivis ici.", + + "profile_created_empty_state_title": "Aucun problème pour le moment", + "profile_created_empty_state_description": "Tous les problèmes que vous créez arrivent ici, suivez-les directement ici.", + + "profile_subscribed_empty_state_title": "Aucun problème pour le moment", + "profile_subscribed_empty_state_description": "Abonnez-vous aux problèmes qui vous intéressent, suivez-les tous ici.", + + "project_settings_labels_empty_state_title": "Aucune étiquette pour le moment", + "project_settings_labels_empty_state_description": "Créez des étiquettes pour aider à organiser et filtrer les problèmes dans votre projet.", + + "project_settings_integrations_empty_state_title": "Aucune intégration configurée", + "project_settings_integrations_empty_state_description": "Configurez GitHub et d'autres intégrations pour synchroniser vos problèmes de projet.", + + "project_settings_estimate_empty_state_title": "Aucune estimation ajoutée", + "project_settings_estimate_empty_state_description": "Créez un ensemble d'estimations pour communiquer la quantité de travail par problème.", + + "project_cycles_empty_state_title": "Groupez et limitez dans le temps votre travail en Cycles.", + "project_cycles_empty_state_description": "Décomposez le travail en morceaux limités dans le temps, travaillez à rebours depuis la date limite de votre projet pour définir les dates, et faites des progrès tangibles en équipe.", + "project_cycles_empty_state_primary_button_text": "Définissez votre premier cycle", + "project_cycles_empty_state_primary_button_comic_title": "Les Cycles sont des boîtes de temps répétitives.", + "project_cycles_empty_state_primary_button_comic_description": "Un sprint, une itération, ou tout autre terme que vous utilisez pour le suivi hebdomadaire ou bimensuel du travail est un cycle.", + + "project_cycle_no_issues_empty_state_title": "Aucun problème ajouté au cycle", + "project_cycle_no_issues_empty_state_description": "Ajoutez ou créez des problèmes que vous souhaitez limiter dans le temps et livrer dans ce cycle", + "project_cycle_no_issues_empty_state_primary_button_text": "Créer un nouveau problème", + "project_cycle_no_issues_empty_state_secondary_button_text": "Ajouter un problème existant", + + "project_cycle_active_empty_state_title": "Aucun cycle actif", + "project_cycle_active_empty_state_description": "Un cycle actif inclut toute période qui englobe la date d'aujourd'hui dans sa plage. Trouvez ici les progrès et les détails du cycle actif.", + + "project_cycle_completed_no_issues_empty_state_title": "Aucun problème dans le cycle", + "project_cycle_completed_no_issues_empty_state_description": "Aucun problème dans le cycle. Les problèmes sont soit transférés soit masqués. Pour voir les problèmes masqués s'il y en a, mettez à jour vos propriétés d'affichage en conséquence.", + + "project_archived_no_cycles_empty_state_title": "Aucun cycle archivé pour le moment", + "project_archived_no_cycles_empty_state_description": "Pour ranger votre projet, archivez les cycles terminés. Retrouvez-les ici une fois archivés.", + + "project_cycle_all_empty_state_title": "Aucun cycle", + "project_cycle_all_empty_state_description": "Un cycle actif inclut toute période qui englobe la date d'aujourd'hui dans sa plage. Trouvez ici les progrès et les détails du cycle actif.", + + "project_empty_filter_empty_state_title": "Aucun problème trouvé correspondant aux filtres appliqués", + "project_empty_filter_empty_state_secondary_button_text": "Effacer tous les filtres", + + "project_archived_empty_filter_empty_state_title": "Aucun problème trouvé correspondant aux filtres appliqués", + "project_archived_empty_filter_empty_state_secondary_button_text": "Effacer tous les filtres", + + "project_draft_empty_filter_empty_state_title": "Aucun problème trouvé correspondant aux filtres appliqués", + "project_draft_empty_filter_empty_state_secondary_button_text": "Effacer tous les filtres", + + "project_no_issues_empty_state_title": "Créez un problème et assignez-le à quelqu'un, même à vous-même", + "project_no_issues_empty_state_description": "Pensez aux problèmes comme des tâches, du travail, ou des JTBD. Ce que nous aimons. Un problème et ses sous-problèmes sont généralement des actions basées sur le temps assignées aux membres de votre équipe. Votre équipe crée, assigne et complète des problèmes pour faire avancer votre projet vers son objectif.", + "project_no_issues_empty_state_primary_button_text": "Créez votre premier problème", + "project_no_issues_empty_state_primary_button_comic_title": "Les problèmes sont les blocs de construction dans Plane.", + "project_no_issues_empty_state_primary_button_comic_description": "Refaire le design de l'interface Plane, Renouveler l'image de marque de l'entreprise, ou Lancer le nouveau système d'injection de carburant sont des exemples de problèmes qui ont probablement des sous-problèmes.", + + "project_archived_no_issues_empty_state_title": "Aucun problème archivé pour le moment", + "project_archived_no_issues_empty_state_description": "Manuellement ou par automatisation, vous pouvez archiver les problèmes terminés ou annulés. Retrouvez-les ici une fois archivés.", + "project_archived_no_issues_empty_state_primary_button_text": "Configurer l'automatisation", + + "project_draft_no_issues_empty_state_title": "Aucun problème en brouillon pour le moment", + "project_draft_no_issues_empty_state_description": "Vous partez rapidement mais voulez garder votre place ? Pas de souci – enregistrez un brouillon maintenant. Vos problèmes seront là à vous attendre.", + + "views_empty_search_empty_state_title": "Aucune vue correspondante", + "views_empty_search_empty_state_description": "Aucune vue ne correspond aux critères de recherche. Créez plutôt une nouvelle vue.", + + "projects_empty_search_empty_state_title": "Aucun projet correspondant", + "projects_empty_search_empty_state_description": "Aucun projet détecté avec les critères correspondants. Créez plutôt un nouveau projet.", + + "members_empty_search_empty_state_title": "Aucun membre correspondant", + "members_empty_search_empty_state_description": "Ajoutez-les au projet s'ils font déjà partie de l'espace de travail", + + "project_module_issues_empty_state_title": "Aucun problème dans le module", + "project_module_issues_empty_state_description": "Créez ou ajoutez des problèmes que vous souhaitez accomplir dans le cadre de ce module", + "project_module_issues_empty_state_primary_button_text": "Créer un nouveau problème", + "project_module_issues_empty_state_secondary_button_text": "Ajouter un problème existant", + + "project_module_empty_state_title": "Associez les jalons de votre projet à des modules et suivez facilement le travail agrégé.", + "project_module_empty_state_description": "Un groupe de problèmes appartenant à un parent logique et hiérarchique forme un module. Pensez-y comme un moyen de suivre le travail par jalons de projet. Ils ont leurs propres périodes et échéances ainsi que des analyses pour vous aider à voir à quel point vous êtes proche ou éloigné d'un jalon.", + "project_module_empty_state_primary_button_text": "Construisez votre premier module", + "project_module_empty_state_primary_button_comic_title": "Les modules aident à regrouper le travail par hiérarchie.", + "project_module_empty_state_primary_button_comic_description": "Un module de chariot, un module de châssis et un module d'entrepôt sont de bons exemples de ce regroupement.", + + "project_archived_no_modules_empty_state_title": "Aucun module archivé pour l'instant", + "project_archived_no_modules_empty_state_description": "Pour organiser votre projet, archivez les modules terminés ou annulés. Retrouvez-les ici une fois archivés.", + + "project_view_empty_state_title": "Enregistrez des vues filtrées pour votre projet. Créez-en autant que vous en avez besoin.", + "project_view_empty_state_primary_button_text": "Créez votre première vue", + "project_view_empty_state_primary_button_comic_title": "Les vues fonctionnent sur les propriétés des problèmes.", + "project_view_empty_state_primary_button_comic_description": "Vous pouvez créer une vue à partir d'ici avec autant de propriétés et de filtres que vous le souhaitez.", + + "project_page_empty_state_title": "Écrivez une note, un document ou une base de connaissances complète. Demandez à Galileo, l'assistant IA de Plane, de vous aider à démarrer.", + "project_page_empty_state_description": "Les pages sont des espaces de réflexion dans Plane. Prenez des notes de réunion, mettez-les en forme facilement, intégrez des problèmes, organisez-les à l'aide d'une bibliothèque de composants, et gardez-les dans le contexte de votre projet. Pour simplifier tout document, invoquez Galileo, l'IA de Plane, avec un raccourci ou un simple clic.", + "project_page_empty_state_primary_button_text": "Créez votre première page", + + "project_page_private_empty_state_title": "Aucune page privée pour l'instant", + "project_page_private_empty_state_description": "Gardez vos réflexions privées ici. Lorsque vous êtes prêt à les partager, l'équipe est à un clic de vous.", + "project_page_private_empty_state_primary_button_text": "Créez votre première page", + + "project_page_public_empty_state_title": "Aucune page publique pour l'instant", + "project_page_public_empty_state_description": "Consultez ici les pages partagées avec tout le monde dans votre projet.", + "project_page_public_empty_state_primary_button_text": "Créez votre première page", + + "project_page_archived_empty_state_title": "Aucune page archivée pour l'instant", + "project_page_archived_empty_state_description": "Archivez les pages qui ne sont plus sur votre radar. Accédez-y ici au besoin.", + + "workspace_page_empty_state_title": "Écrivez une note, un document ou une base de connaissances complète. Demandez à Galileo, l'assistant IA de Plane, de vous aider à démarrer.", + "workspace_page_empty_state_description": "Les pages sont des espaces de réflexion dans Plane. Prenez des notes de réunion, mettez-les en forme facilement, intégrez des problèmes, organisez-les à l'aide d'une bibliothèque de composants, et gardez-les dans le contexte de votre projet. Pour simplifier tout document, invoquez Galileo, l'IA de Plane, avec un raccourci ou un simple clic.", + "workspace_page_empty_state_primary_button_text": "Créez votre première page", + + "workspace_page_private_empty_state_title": "Aucune page privée pour l'instant", + "workspace_page_private_empty_state_description": "Gardez vos réflexions privées ici. Lorsque vous êtes prêt à les partager, l'équipe est à un clic de vous.", + "workspace_page_private_empty_state_primary_button_text": "Créez votre première page", + + "command_k_search_empty_state_title": "Aucun résultat trouvé", + + "issue_relation_search_empty_state_title": "Aucun problème correspondant trouvé", + "issue_relation_empty_state_title": "Aucun problème trouvé", + + "issue_comment_empty_state_title": "Pas encore de commentaires", + "issue_comment_empty_state_description": "Les commentaires peuvent être utilisés comme espace de discussion et de suivi pour les problèmes.", + + "notification_detail_empty_state_title": "Sélectionnez pour voir les détails.", + + "notification_all_empty_state_title": "Aucun problème assigné", + "notification_all_empty_state_description": "Les mises à jour des problèmes qui vous sont assignés sont visibles ici.", + + "notification_mentions_empty_state_title": "Aucun problème assigné", + "notification_mentions_empty_state_description": "Les mises à jour des problèmes qui vous sont assignés sont visibles ici.", + + "active_cycle_progress_empty_state_title": "Ajoutez des problèmes au cycle pour voir sa progression.", + "active_cycle_chart_empty_state_title": "Ajoutez des problèmes au cycle pour voir le graphique d'avancement.", + "active_cycle_priority_issue_empty_state_title": "Observez d'un coup d'œil les problèmes prioritaires traités dans le cycle.", + "active_cycle_assignee_empty_state_title": "Ajoutez des assignés aux problèmes pour voir une répartition du travail par assignés.", + "active_cycle_label_empty_state_title": "Ajoutez des étiquettes aux problèmes pour voir une répartition du travail par étiquettes.", + + "workspace_active_cycles_empty_state_title": "Aucun cycle actif", + "workspace_active_cycles_empty_state_description": "Les cycles de vos projets incluent toute période couvrant la date d'aujourd'hui dans sa plage. Trouvez ici la progression et les détails de tous vos cycles actifs.", + + "disabled_project_inbox_empty_state_title": "La réception n'est pas activée pour le projet.", + "disabled_project_inbox_empty_state_description": "La réception vous aide à gérer les demandes entrantes pour votre projet et à les ajouter comme problèmes dans votre flux de travail. Activez la réception dans les paramètres du projet pour gérer les demandes.", + "disabled_project_inbox_empty_state_primary_button_text": "Gérer les fonctionnalités" } diff --git a/packages/i18n/src/locales/ja/translations.json b/packages/i18n/src/locales/ja/translations.json index fa2b244cc5e..289a11734d1 100644 --- a/packages/i18n/src/locales/ja/translations.json +++ b/packages/i18n/src/locales/ja/translations.json @@ -316,5 +316,211 @@ "remove_parent_issue": "親問題を削除", "add_parent": "親問題を追加", "loading_members": "メンバーを読み込んでいます...", - "inbox": "受信箱" + "inbox": "受信箱", + + "workspace_dashboard_empty_state_title": "プロジェクト、アクティビティ、メトリクスの概要", + "workspace_dashboard_empty_state_description": "Planeへようこそ。最初のプロジェクトを作成し、課題を追跡すると、このページが進捗を助けるスペースに変わります。管理者はチームの進捗を助ける項目も表示されます。", + "workspace_dashboard_empty_state_primary_button_text": "最初のプロジェクトを作成する", + "workspace_dashboard_empty_state_primary_button_comic_title": "Planeではすべてがプロジェクトから始まります", + "workspace_dashboard_empty_state_primary_button_comic_description": "プロジェクトは、製品のロードマップ、マーケティングキャンペーン、または新車の発売などです。", + + "workspace_analytics_empty_state_title": "進捗、作業負荷、割り当てを追跡する。傾向を見つけ、障害を取り除き、作業を迅速化する", + "workspace_analytics_empty_state_description": "スコープと需要、見積もり、スコープの増加を確認します。チームメンバーやチームごとのパフォーマンスを把握し、プロジェクトを予定通り進行させます。", + "workspace_analytics_empty_state_primary_button_text": "最初のプロジェクトを開始する", + "workspace_analytics_empty_state_primary_button_comic_title": "サイクル+モジュールで分析が最適化されます", + "workspace_analytics_empty_state_primary_button_comic_description": "最初に課題をサイクルにタイムボックス化し、可能であればサイクルを超える課題をモジュールにグループ化します。左のナビで両方をチェックしてください。", + + "workspace_projects_empty_state_title": "アクティブなプロジェクトがありません", + "workspace_projects_empty_state_description": "各プロジェクトを目標指向の作業の親として考えてください。プロジェクトは、ジョブ、サイクル、モジュールが存在し、同僚と一緒にその目標を達成するのに役立ちます。新しいプロジェクトを作成するか、アーカイブされたプロジェクトをフィルタリングしてください。", + "workspace_projects_empty_state_primary_button_text": "最初のプロジェクトを開始する", + "workspace_projects_empty_state_primary_button_comic_title": "Planeではすべてがプロジェクトから始まります", + "workspace_projects_empty_state_primary_button_comic_description": "プロジェクトは、製品のロードマップ、マーケティングキャンペーン、または新車の発売などです。", + + "workspace_all_issues_empty_state_title": "プロジェクトに課題がありません", + "workspace_all_issues_empty_state_description": "最初のプロジェクト完了!今度は作業を追跡可能な部分に分割して課題を作成しましょう。", + "workspace_all_issues_empty_state_primary_button_text": "新しい課題を作成する", + + "workspace_assigned_empty_state_title": "まだ課題がありません", + "workspace_assigned_empty_state_description": "あなたに割り当てられた課題をここから追跡できます。", + "workspace_assigned_empty_state_primary_button_text": "新しい課題を作成する", + + "workspace_created_empty_state_title": "まだ課題がありません", + "workspace_created_empty_state_description": "あなたが作成したすべての課題がここに集まります。ここで直接追跡してください。", + "workspace_created_empty_state_primary_button_text": "新しい課題を作成する", + + "workspace_subscribed_empty_state_title": "まだ課題がありません", + "workspace_subscribed_empty_state_description": "興味のある課題を購読し、すべてをここで追跡してください。", + + "workspace_custom_view_empty_state_title": "まだ課題がありません", + "workspace_custom_view_empty_state_description": "フィルターに適用された課題を追跡し、すべてをここで確認してください。", + + "workspace_project_not_found_empty_state_title": "そのようなプロジェクトは存在しません", + "workspace_project_not_found_empty_state_description": "課題を作成したり作業を管理したりするには、プロジェクトを作成するか、その一部になる必要があります。", + "workspace_project_not_found_empty_state_primary_button_text": "プロジェクトを作成する", + "workspace_project_not_found_empty_state_primary_button_comic_title": "Planeではすべてがプロジェクトから始まります", + "workspace_project_not_found_empty_state_primary_button_comic_description": "プロジェクトは、製品のロードマップ、マーケティングキャンペーン、または新車の発売などです。", + + "workspace_no_projects_empty_state_title": "プロジェクトがありません", + "workspace_no_projects_empty_state_description": "課題を作成したり作業を管理したりするには、プロジェクトを作成するか、その一部になる必要があります。", + "workspace_no_projects_empty_state_primary_button_text": "最初のプロジェクトを開始する", + "workspace_no_projects_empty_state_primary_button_comic_title": "Planeではすべてがプロジェクトから始まります", + "workspace_no_projects_empty_state_primary_button_comic_description": "プロジェクトは、製品のロードマップ、マーケティングキャンペーン、または新車の発売などです。", + + "workspace_settings_api_tokens_empty_state_title": "APIトークンが作成されていません", + "workspace_settings_api_tokens_empty_state_description": "Plane APIを使用して、Plane内のデータを外部システムと統合できます。トークンを作成して開始してください。", + + "workspace_settings_webhooks_empty_state_title": "Webhookが追加されていません", + "workspace_settings_webhooks_empty_state_description": "リアルタイム更新を受け取ったりアクションを自動化したりするためにWebhookを作成してください。", + + "workspace_settings_export_empty_state_title": "過去のエクスポートがありません", + "workspace_settings_export_empty_state_description": "エクスポートするたびに、ここにコピーが保存されます。", + + "workspace_settings_import_empty_state_title": "過去のインポートがありません", + "workspace_settings_import_empty_state_description": "過去のインポートをすべてここで確認し、ダウンロードできます。", + + "profile_activity_empty_state_title": "まだアクティビティがありません", + "profile_activity_empty_state_description": "新しい課題を作成して始めてください!詳細とプロパティを追加します。Planeの他の機能を探索して、アクティビティを確認してください。", + + "profile_assigned_empty_state_title": "あなたに割り当てられた課題がありません", + "profile_assigned_empty_state_description": "あなたに割り当てられた課題をここから追跡できます。", + + "profile_created_empty_state_title": "まだ課題がありません", + "profile_created_empty_state_description": "あなたが作成したすべての課題がここに集まります。ここで直接追跡してください。", + + "profile_subscribed_empty_state_title": "まだ課題がありません", + "profile_subscribed_empty_state_description": "興味のある課題を購読し、すべてをここで追跡してください。", + + "project_settings_labels_empty_state_title": "ラベルがまだありません", + "project_settings_labels_empty_state_description": "課題を整理してプロジェクト内でフィルタリングするためのラベルを作成してください。", + + "project_settings_integrations_empty_state_title": "統合が設定されていません", + "project_settings_integrations_empty_state_description": "GitHubや他の統合を設定して、プロジェクトの課題を同期してください。", + + "project_settings_estimate_empty_state_title": "見積もりがまだ追加されていません", + "project_settings_estimate_empty_state_description": "課題ごとの作業量を伝えるための見積もりを作成してください。", + + "project_cycles_empty_state_title": "サイクルで作業をグループ化してタイムボックス化する。", + "project_cycles_empty_state_description": "作業をタイムボックス化されたチャンクに分解し、プロジェクトの締め切りから逆算して日付を設定し、チームとして具体的な進捗を達成します。", + "project_cycles_empty_state_primary_button_text": "最初のサイクルを設定する", + "project_cycles_empty_state_primary_button_comic_title": "サイクルは反復的なタイムボックスです。", + "project_cycles_empty_state_primary_button_comic_description": "スプリント、イテレーション、または週次や隔週での作業追跡に使用する他の用語がサイクルです。", + + "project_cycle_no_issues_empty_state_title": "サイクルに課題が追加されていません", + "project_cycle_no_issues_empty_state_description": "タイムボックス化してこのサイクル内で達成したい課題を追加または作成してください", + "project_cycle_no_issues_empty_state_primary_button_text": "新しい課題を作成する", + "project_cycle_no_issues_empty_state_secondary_button_text": "既存の課題を追加する", + + "project_cycle_active_empty_state_title": "アクティブなサイクルはありません", + "project_cycle_active_empty_state_description": "アクティブなサイクルには、現在の日付が含まれる期間が含まれます。ここでアクティブなサイクルの進捗や詳細を確認できます。", + + "project_cycle_completed_no_issues_empty_state_title": "サイクルに課題がありません", + "project_cycle_completed_no_issues_empty_state_description": "サイクルに課題はありません。課題は移動されたか、非表示になっています。非表示の課題を確認するには、表示プロパティを更新してください。", + + "project_archived_no_cycles_empty_state_title": "まだアーカイブされたサイクルはありません", + "project_archived_no_cycles_empty_state_description": "プロジェクトを整理するために、完了したサイクルをアーカイブします。一度アーカイブされると、ここに表示されます。", + + "project_cycle_all_empty_state_title": "サイクルがありません", + "project_cycle_all_empty_state_description": "アクティブなサイクルには、現在の日付が含まれる期間が含まれます。ここでアクティブなサイクルの進捗や詳細を確認できます。", + + "project_empty_filter_empty_state_title": "適用されたフィルターに一致する課題は見つかりません", + "project_empty_filter_empty_state_secondary_button_text": "すべてのフィルターをクリア", + + "project_archived_empty_filter_empty_state_title": "適用されたフィルターに一致する課題は見つかりません", + "project_archived_empty_filter_empty_state_secondary_button_text": "すべてのフィルターをクリア", + + "project_draft_empty_filter_empty_state_title": "適用されたフィルターに一致する課題は見つかりません", + "project_draft_empty_filter_empty_state_secondary_button_text": "すべてのフィルターをクリア", + + "project_no_issues_empty_state_title": "課題を作成し、自分自身または他の人に割り当ててください", + "project_no_issues_empty_state_description": "課題は仕事、タスク、作業、またはJTBDと考えられます。課題とそのサブ課題は通常、チームメンバーに割り当てられた時間ベースのアクション項目です。チームは課題を作成、割り当て、完了させることでプロジェクトを目標に向かって進めます。", + "project_no_issues_empty_state_primary_button_text": "最初の課題を作成する", + "project_no_issues_empty_state_primary_button_comic_title": "課題はPlaneの基本構成要素です。", + "project_no_issues_empty_state_primary_button_comic_description": "Plane UIの再設計、会社のリブランディング、新しい燃料噴射システムの導入は、サブ課題を含む課題の例です。", + + "project_archived_no_issues_empty_state_title": "まだアーカイブされた課題はありません", + "project_archived_no_issues_empty_state_description": "手動または自動化により、完了またはキャンセルされた課題をアーカイブできます。一度アーカイブされると、ここに表示されます。", + "project_archived_no_issues_empty_state_primary_button_text": "自動化を設定する", + + "project_draft_no_issues_empty_state_title": "まだドラフトの課題はありません", + "project_draft_no_issues_empty_state_description": "すぐに離れる必要がある場合でも心配いりません – 今すぐドラフトを保存してください。課題はここで待っています。", + + "views_empty_search_empty_state_title": "一致するビューはありません", + "views_empty_search_empty_state_description": "検索条件に一致するビューはありません。代わりに新しいビューを作成してください。", + + "projects_empty_search_empty_state_title": "一致するプロジェクトはありません", + "projects_empty_search_empty_state_description": "一致する条件のプロジェクトは見つかりませんでした。代わりに新しいプロジェクトを作成してください。", + + "members_empty_search_empty_state_title": "一致するメンバーはありません", + "members_empty_search_empty_state_description": "すでにワークスペースの一員である場合、プロジェクトに追加してください。", + + "project_module_issues_empty_state_title": "モジュール内に課題がありません", + "project_module_issues_empty_state_description": "このモジュールの一部として達成したい課題を作成または追加してください。", + "project_module_issues_empty_state_primary_button_text": "新しい課題を作成する", + "project_module_issues_empty_state_secondary_button_text": "既存の課題を追加する", + + "project_module_empty_state_title": "モジュールにプロジェクトのマイルストーンをマッピングし、集約された作業を簡単に追跡します。", + "project_module_empty_state_description": "論理的で階層的な親に属する課題のグループがモジュールを形成します。プロジェクトのマイルストーンごとに作業を追跡するための方法と考えてください。それぞれのモジュールには独自の期間と期限があり、マイルストーンへの進捗を把握するための分析が備わっています。", + "project_module_empty_state_primary_button_text": "最初のモジュールを構築する", + "project_module_empty_state_primary_button_comic_title": "モジュールは階層別に作業をグループ化します。", + "project_module_empty_state_primary_button_comic_description": "カートモジュール、シャーシモジュール、倉庫モジュールは、このグループ化の良い例です。", + + "project_archived_no_modules_empty_state_title": "まだアーカイブされたモジュールはありません", + "project_archived_no_modules_empty_state_description": "プロジェクトを整理するために、完了またはキャンセルされたモジュールをアーカイブします。一度アーカイブされると、ここに表示されます。", + + "project_view_empty_state_title": "プロジェクトのフィルタリングされたビューを保存します。必要なだけ作成できます。", + "project_view_empty_state_primary_button_text": "最初のビューを作成する", + "project_view_empty_state_primary_button_comic_title": "ビューは課題のプロパティに基づいて動作します。", + "project_view_empty_state_primary_button_comic_description": "ここからプロパティをいくつでもフィルターとして追加してビューを作成できます。", + + "project_page_empty_state_title": "メモ、ドキュメント、または完全なナレッジベースを書きます。PlaneのAIアシスタントであるガリレオが開始をお手伝いします。", + "project_page_empty_state_description": "ページはPlaneでアイデアを記録するスペースです。会議のメモを取ったり、簡単にフォーマットしたり、課題を埋め込んだり、コンポーネントのライブラリを使用してレイアウトしたりして、すべてをプロジェクトの文脈に保ちます。どんなドキュメントでも簡単に作成するには、ショートカットやボタンをクリックしてガリレオを呼び出してください。", + "project_page_empty_state_primary_button_text": "最初のページを作成する", + + "project_page_private_empty_state_title": "まだプライベートページはありません", + "project_page_private_empty_state_description": "ここで個人的な考えを記録してください。共有する準備ができたら、チームとワンクリックで共有できます。", + "project_page_private_empty_state_primary_button_text": "最初のページを作成する", + + "project_page_public_empty_state_title": "まだ公開されたページはありません", + "project_page_public_empty_state_description": "プロジェクト内のすべての人と共有されたページをここで確認してください。", + "project_page_public_empty_state_primary_button_text": "最初のページを作成する", + + "project_page_archived_empty_state_title": "まだアーカイブされたページはありません", + "project_page_archived_empty_state_description": "レーダーに載っていないページをアーカイブします。必要に応じてここからアクセスできます。", + + "workspace_page_empty_state_title": "メモ、ドキュメント、または完全なナレッジベースを書きます。PlaneのAIアシスタントであるガリレオが開始をお手伝いします。", + "workspace_page_empty_state_description": "ページはPlaneでアイデアを記録するスペースです。会議のメモを取ったり、簡単にフォーマットしたり、課題を埋め込んだり、コンポーネントのライブラリを使用してレイアウトしたりして、すべてをプロジェクトの文脈に保ちます。どんなドキュメントでも簡単に作成するには、ショートカットやボタンをクリックしてガリレオを呼び出してください。", + "workspace_page_empty_state_primary_button_text": "最初のページを作成する", + + "workspace_page_private_empty_state_title": "まだプライベートページはありません", + "workspace_page_private_empty_state_description": "ここで個人的な考えを記録してください。共有する準備ができたら、チームとワンクリックで共有できます。", + "workspace_page_private_empty_state_primary_button_text": "最初のページを作成する", + + "command_k_search_empty_state_title": "結果が見つかりません", + + "issue_relation_search_empty_state_title": "一致する課題が見つかりません", + "issue_relation_empty_state_title": "課題が見つかりません", + + "issue_comment_empty_state_title": "まだコメントがありません", + "issue_comment_empty_state_description": "コメントは課題に関する議論やフォローアップの場として活用できます", + + "notification_detail_empty_state_title": "詳細を表示するには選択してください。", + + "notification_all_empty_state_title": "割り当てられた課題はありません", + "notification_all_empty_state_description": "あなたに割り当てられた課題の更新はここで確認できます", + + "notification_mentions_empty_state_title": "割り当てられた課題はありません", + "notification_mentions_empty_state_description": "あなたに割り当てられた課題の更新はここで確認できます", + + "active_cycle_progress_empty_state_title": "課題をサイクルに追加して進捗を確認してください", + "active_cycle_chart_empty_state_title": "課題をサイクルに追加してバーンダウンチャートを表示してください。", + "active_cycle_priority_issue_empty_state_title": "サイクル内で対応された高優先度の課題を一目で確認できます。", + "active_cycle_assignee_empty_state_title": "課題に担当者を追加して、担当者別の作業の内訳を確認してください。", + "active_cycle_label_empty_state_title": "課題にラベルを追加して、ラベル別の作業の内訳を確認してください。", + + "workspace_active_cycles_empty_state_title": "アクティブなサイクルはありません", + "workspace_active_cycles_empty_state_description": "現在の日付を範囲に含むプロジェクトのサイクルです。すべてのアクティブなサイクルの進捗と詳細をここで確認してください。", + + "disabled_project_inbox_empty_state_title": "このプロジェクトではインテークが有効になっていません。", + "disabled_project_inbox_empty_state_description": "インテークは、プロジェクトへのリクエストを管理し、それらをワークフロー内の課題として追加するのに役立ちます。プロジェクト設定からインテークを有効にしてリクエストを管理してください。", + "disabled_project_inbox_empty_state_primary_button_text": "機能を管理" } From ce42651182f69bce8db1ad7fbb3721ce614dda62 Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia Date: Thu, 16 Jan 2025 13:12:38 +0530 Subject: [PATCH 05/26] chore: new empty state implementation --- .../(projects)/analytics/page.tsx | 43 ++++++++++++----- .../page-views/workspace-dashboard.tsx | 46 +++++++++++++++---- web/core/components/project/card-list.tsx | 43 +++++++++++++---- .../layouts/auth-layout/project-wrapper.tsx | 38 +++++++++++---- 4 files changed, 130 insertions(+), 40 deletions(-) diff --git a/web/app/[workspaceSlug]/(projects)/analytics/page.tsx b/web/app/[workspaceSlug]/(projects)/analytics/page.tsx index 3193efa0301..36b21e9fcc0 100644 --- a/web/app/[workspaceSlug]/(projects)/analytics/page.tsx +++ b/web/app/[workspaceSlug]/(projects)/analytics/page.tsx @@ -5,16 +5,17 @@ import { observer } from "mobx-react"; import { useSearchParams } from "next/navigation"; import { Tab } from "@headlessui/react"; // plane package imports -import { ANALYTICS_TABS } from "@plane/constants"; +import { ANALYTICS_TABS, EUserPermissionsLevel } from "@plane/constants"; import { Header, EHeaderVariant } from "@plane/ui"; // components import { CustomAnalytics, ScopeAndDemand } from "@/components/analytics"; import { PageHead } from "@/components/core"; -import { EmptyState } from "@/components/empty-state"; -// constants -import { EmptyStateType } from "@/constants/empty-state"; +import { ComicBoxButton, DetailedEmptyState } from "@/components/empty-state"; // hooks -import { useCommandPalette, useEventTracker, useProject, useWorkspace } from "@/hooks/store"; +import { useCommandPalette, useEventTracker, useProject, useUserPermissions, useWorkspace } from "@/hooks/store"; +import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; +// plane web +import { EUserPermissions } from "@/plane-web/constants"; const AnalyticsPage = observer(() => { const searchParams = useSearchParams(); @@ -24,9 +25,19 @@ const AnalyticsPage = observer(() => { const { setTrackElement } = useEventTracker(); const { workspaceProjectIds, loader } = useProject(); const { currentWorkspace } = useWorkspace(); + const { allowPermissions } = useUserPermissions(); + + // helper hooks + const resolvedPath = useResolvedAssetPath({ basePath: "/empty-state/onboarding/analytics" }); // derived values const pageTitle = currentWorkspace?.name ? `${currentWorkspace?.name} - Analytics` : undefined; + // permissions + const canPerformEmptyStateActions = allowPermissions( + [EUserPermissions.ADMIN, EUserPermissions.MEMBER], + EUserPermissionsLevel.WORKSPACE + ); + // TODO: refactor loader implementation return ( <> @@ -67,12 +78,22 @@ const AnalyticsPage = observer(() => { ) : ( - { - setTrackElement("Analytics empty state"); - toggleCreateProjectModal(true); - }} + { + setTrackElement("Analytics empty state"); + toggleCreateProjectModal(true); + }} + disabled={!canPerformEmptyStateActions} + /> + } /> )} diff --git a/web/core/components/page-views/workspace-dashboard.tsx b/web/core/components/page-views/workspace-dashboard.tsx index f4df757cd8b..a3f6d3a28d7 100644 --- a/web/core/components/page-views/workspace-dashboard.tsx +++ b/web/core/components/page-views/workspace-dashboard.tsx @@ -1,21 +1,31 @@ import { useEffect } from "react"; import { observer } from "mobx-react"; import { useParams } from "next/navigation"; +import { EUserPermissionsLevel } from "@plane/constants"; // components import { ContentWrapper } from "@plane/ui"; import { DashboardWidgets } from "@/components/dashboard"; -import { EmptyState } from "@/components/empty-state"; +import { ComicBoxButton, DetailedEmptyState } from "@/components/empty-state"; import { IssuePeekOverview } from "@/components/issues"; import { TourRoot } from "@/components/onboarding"; import { UserGreetingsView } from "@/components/user"; // constants -import { EmptyStateType } from "@/constants/empty-state"; import { PRODUCT_TOUR_COMPLETED } from "@/constants/event-tracker"; // helpers import { cn } from "@/helpers/common.helper"; // hooks -import { useCommandPalette, useUserProfile, useEventTracker, useDashboard, useProject, useUser } from "@/hooks/store"; +import { + useCommandPalette, + useUserProfile, + useEventTracker, + useDashboard, + useProject, + useUser, + useUserPermissions, +} from "@/hooks/store"; +import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; import useSize from "@/hooks/use-window-size"; +import { EUserPermissions } from "@/plane-web/constants"; export const WorkspaceDashboardView = observer(() => { // store hooks @@ -30,8 +40,11 @@ export const WorkspaceDashboardView = observer(() => { const { captureEvent } = useEventTracker(); const { homeDashboardId, fetchHomeDashboardWidgets } = useDashboard(); const { joinedProjectIds, loader } = useProject(); + const { allowPermissions } = useUserPermissions(); + // helper hooks const [windowWidth] = useSize(); + const resolvedPath = useResolvedAssetPath({ basePath: "/empty-state/onboarding/dashboard" }); const handleTourCompleted = () => { updateTourCompleted() @@ -53,6 +66,11 @@ export const WorkspaceDashboardView = observer(() => { fetchHomeDashboardWidgets(workspaceSlug?.toString()); }, [fetchHomeDashboardWidgets, workspaceSlug]); + const canPerformEmptyStateActions = allowPermissions( + [EUserPermissions.ADMIN, EUserPermissions.MEMBER], + EUserPermissionsLevel.WORKSPACE + ); + // TODO: refactor loader implementation return ( <> @@ -77,12 +95,22 @@ export const WorkspaceDashboardView = observer(() => { ) : ( - { - setTrackElement("Dashboard empty state"); - toggleCreateProjectModal(true); - }} + { + setTrackElement("Dashboard empty state"); + toggleCreateProjectModal(true); + }} + disabled={!canPerformEmptyStateActions} + /> + } /> )} diff --git a/web/core/components/project/card-list.tsx b/web/core/components/project/card-list.tsx index ff98c188c55..60155c82865 100644 --- a/web/core/components/project/card-list.tsx +++ b/web/core/components/project/card-list.tsx @@ -1,14 +1,16 @@ import { observer } from "mobx-react"; import Image from "next/image"; +import { EUserPermissionsLevel } from "@plane/constants"; // components import { ContentWrapper } from "@plane/ui"; -import { EmptyState } from "@/components/empty-state"; +import { ComicBoxButton, DetailedEmptyState } from "@/components/empty-state"; import { ProjectCard } from "@/components/project"; import { ProjectsLoader } from "@/components/ui"; -// constants -import { EmptyStateType } from "@/constants/empty-state"; // hooks -import { useCommandPalette, useEventTracker, useProject, useProjectFilter } from "@/hooks/store"; +import { useCommandPalette, useEventTracker, useProject, useProjectFilter, useUserPermissions } from "@/hooks/store"; +import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; +// plane-web +import { EUserPermissions } from "@/plane-web/constants"; // assets import AllFiltersImage from "@/public/empty-state/project/all-filters.svg"; import NameFilterImage from "@/public/empty-state/project/name-filter.svg"; @@ -30,20 +32,41 @@ export const ProjectCardList = observer((props: TProjectCardListProps) => { loader, } = useProject(); const { searchQuery, currentWorkspaceDisplayFilters } = useProjectFilter(); + const { allowPermissions } = useUserPermissions(); + + // helper hooks + const resolvedPath = useResolvedAssetPath({ basePath: "/empty-state/onboarding/projects" }); + // derived values const workspaceProjectIds = totalProjectIdsProps ?? storeWorkspaceProjectIds; const filteredProjectIds = filteredProjectIdsProps ?? storeFilteredProjectIds; + // permissions + const canPerformEmptyStateActions = allowPermissions( + [EUserPermissions.ADMIN, EUserPermissions.MEMBER], + EUserPermissionsLevel.WORKSPACE + ); + if (!filteredProjectIds || !workspaceProjectIds || loader) return ; if (workspaceProjectIds?.length === 0 && !currentWorkspaceDisplayFilters?.archived_projects) return ( - { - setTrackElement("Project empty state"); - toggleCreateProjectModal(true); - }} + { + setTrackElement("Project empty state"); + toggleCreateProjectModal(true); + }} + disabled={!canPerformEmptyStateActions} + /> + } /> ); diff --git a/web/core/layouts/auth-layout/project-wrapper.tsx b/web/core/layouts/auth-layout/project-wrapper.tsx index dcba2a8fef2..fe8a367e3c9 100644 --- a/web/core/layouts/auth-layout/project-wrapper.tsx +++ b/web/core/layouts/auth-layout/project-wrapper.tsx @@ -8,10 +8,8 @@ import useSWR from "swr"; // components import { JoinProject } from "@/components/auth-screens"; import { LogoSpinner } from "@/components/common"; -import { EmptyState } from "@/components/empty-state"; +import { ComicBoxButton, DetailedEmptyState } from "@/components/empty-state"; import { ETimeLineTypeType } from "@/components/gantt-chart/contexts"; -//constants -import { EmptyStateType } from "@/constants/empty-state"; // hooks import { useCommandPalette, @@ -26,6 +24,7 @@ import { useProjectView, useUserPermissions, } from "@/hooks/store"; +import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; import { useTimeLineChart } from "@/hooks/use-timeline-chart"; // local import { persistence } from "@/local-db/storage.sqlite"; @@ -56,6 +55,10 @@ export const ProjectAuthWrapper: FC = observer((props) => { const { fetchProjectStates, fetchProjectStateTransitions } = useProjectState(); const { fetchProjectLabels } = useLabel(); const { getProjectEstimates } = useProjectEstimates(); + + // helper hooks + const resolvedPath = useResolvedAssetPath({ basePath: "/empty-state/onboarding/projects" }); + // derived values const projectExists = projectId ? getProjectById(projectId.toString()) : null; const projectMemberInfo = projectUserInfo?.[workspaceSlug?.toString()]?.[projectId?.toString()]; @@ -151,6 +154,12 @@ export const ProjectAuthWrapper: FC = observer((props) => { { revalidateIfStale: false, revalidateOnFocus: false } ); + // permissions + const canPerformEmptyStateActions = allowPermissions( + [EUserPermissions.ADMIN, EUserPermissions.MEMBER], + EUserPermissionsLevel.WORKSPACE + ); + // check if the project member apis is loading if (isParentLoading || (!projectMemberInfo && projectId && hasPermissionToCurrentProject === null)) return ( @@ -168,13 +177,22 @@ export const ProjectAuthWrapper: FC = observer((props) => { if (!loader && !projectExists && projectId && !!hasPermissionToCurrentProject === false) return (
- { - setTrackElement("Projects page empty state"); - toggleCreateProjectModal(true); - }} + { + setTrackElement("Project empty state"); + toggleCreateProjectModal(true); + }} + disabled={!canPerformEmptyStateActions} + /> + } />
); From 86f5398d209ce5adf8ce169eb41cdbdfaa961cff Mon Sep 17 00:00:00 2001 From: Prateek Shourya Date: Thu, 16 Jan 2025 13:59:06 +0530 Subject: [PATCH 06/26] improvement: add more translations --- .../i18n/src/locales/en/translations.json | 33 ++++++++++++++++++- .../i18n/src/locales/es/translations.json | 33 ++++++++++++++++++- .../i18n/src/locales/fr/translations.json | 33 ++++++++++++++++++- .../i18n/src/locales/ja/translations.json | 33 ++++++++++++++++++- 4 files changed, 128 insertions(+), 4 deletions(-) diff --git a/packages/i18n/src/locales/en/translations.json b/packages/i18n/src/locales/en/translations.json index 9857a013d31..538edcc1236 100644 --- a/packages/i18n/src/locales/en/translations.json +++ b/packages/i18n/src/locales/en/translations.json @@ -522,5 +522,36 @@ "disabled_project_inbox_empty_state_title": "Intake is not enabled for the project.", "disabled_project_inbox_empty_state_description": "Intake helps you manage incoming requests to your project and add them as issues in your workflow. Enable intake from project settings to manage requests.", - "disabled_project_inbox_empty_state_primary_button_text": "Manage features" + "disabled_project_inbox_empty_state_primary_button_text": "Manage features", + + "disabled_project_cycle_empty_state_title": "Cycles is not enabled for this project.", + "disabled_project_cycle_empty_state_description": "Break work down by timeboxed chunks, work backwards from your project deadline to set dates, and make tangible progress as a team. Enable the cycles feature for your project to start using them.", + "disabled_project_cycle_empty_state_primary_button_text": "Manage features", + + "disabled_project_module_empty_state_title": "Modules are not enabled for the project.", + "disabled_project_module_empty_state_description": "A group of issues that belong to a logical, hierarchical parent form a module. Think of them as a way to track work by project milestones. Enable modules from project settings.", + "disabled_project_module_empty_state_primary_button_text": "Manage features", + + "disabled_project_page_empty_state_title": "Pages are not enabled for the project.", + "disabled_project_page_empty_state_description": "Pages are thought spotting space in Plane. Take down meeting notes, format them easily, embed issues, lay them out using a library of components, and keep them all in your project's context. Enable the pages feature to start creating them in your project.", + "disabled_project_page_empty_state_primary_button_text": "Manage features", + + "disabled_project_view_empty_state_title": "Views is not enabled for this project.", + "disabled_project_view_empty_state_description": "Views are a set of saved filters that you use frequently or want easy access to. All your colleagues in a project can see everyone's views and choose whichever suits their needs best. Enable views in the project settings to start using them.", + "disabled_project_view_empty_state_primary_button_text": "Manage features", + + "inbox_sidebar_open_tab_empty_state_title": "No open issues", + "inbox_sidebar_open_tab_empty_state_description": "Find open issues here. Create new issue.", + + "inbox_sidebar_closed_tab_empty_state_title": "No closed issues", + "inbox_sidebar_closed_tab_empty_state_description": "All the issues whether accepted or declined can be found here.", + + "inbox_sidebar_filter_empty_state_title": "No matching issues", + "inbox_sidebar_filter_empty_state_description": "No issue matches filter applied in intake. Create a new issue.", + + "inbox_detail_empty_state_title": "Select an issue to view its details.", + + "workspace_draft_issues_empty_state_title": "Half-written issues, and soon, comments will show up here.", + "workspace_draft_issues_empty_state_description": "To try this out, start adding an issue and leave it mid-way or create your first draft below. 😉", + "workspace_draft_issues_empty_state_primary_button_text": "Create your first draft" } diff --git a/packages/i18n/src/locales/es/translations.json b/packages/i18n/src/locales/es/translations.json index 4f2b15c32b5..f56b85a6e3f 100644 --- a/packages/i18n/src/locales/es/translations.json +++ b/packages/i18n/src/locales/es/translations.json @@ -521,5 +521,36 @@ "disabled_project_inbox_empty_state_title": "La entrada no está habilitada para el proyecto.", "disabled_project_inbox_empty_state_description": "La entrada te ayuda a gestionar las solicitudes entrantes a tu proyecto y agregarlas como problemas en tu flujo de trabajo. Habilita la entrada desde la configuración del proyecto para gestionar las solicitudes.", - "disabled_project_inbox_empty_state_primary_button_text": "Gestionar funciones" + "disabled_project_inbox_empty_state_primary_button_text": "Gestionar funciones", + + "disabled_project_cycle_empty_state_title": "Los ciclos no están habilitados para este proyecto.", + "disabled_project_cycle_empty_state_description": "Divide el trabajo en partes temporales, trabaja hacia atrás desde la fecha límite del proyecto para establecer fechas y realiza avances tangibles como equipo. Habilita la función de ciclos para tu proyecto para comenzar a usarlos.", + "disabled_project_cycle_empty_state_primary_button_text": "Gestionar características", + + "disabled_project_module_empty_state_title": "Los módulos no están habilitados para el proyecto.", + "disabled_project_module_empty_state_description": "Un grupo de problemas que pertenecen a un padre lógico y jerárquico forma un módulo. Piénsalo como una forma de realizar un seguimiento del trabajo por los hitos del proyecto. Habilita los módulos desde la configuración del proyecto.", + "disabled_project_module_empty_state_primary_button_text": "Gestionar características", + + "disabled_project_page_empty_state_title": "Las páginas no están habilitadas para el proyecto.", + "disabled_project_page_empty_state_description": "Las páginas son espacios de anotación en Plane. Toma notas de reuniones, formatearlas fácilmente, incrustar problemas, organizarlas utilizando una biblioteca de componentes y mantenerlas dentro del contexto de tu proyecto. Habilita la función de páginas para empezar a crearlas en tu proyecto.", + "disabled_project_page_empty_state_primary_button_text": "Gestionar características", + + "disabled_project_view_empty_state_title": "Las vistas no están habilitadas para este proyecto.", + "disabled_project_view_empty_state_description": "Las vistas son un conjunto de filtros guardados que usas con frecuencia o que deseas tener acceso fácilmente. Todos tus compañeros de proyecto pueden ver las vistas de todos y elegir la que mejor se adapte a sus necesidades. Habilita las vistas en la configuración del proyecto para comenzar a usarlas.", + "disabled_project_view_empty_state_primary_button_text": "Gestionar características", + + "inbox_sidebar_open_tab_empty_state_title": "No hay problemas abiertos", + "inbox_sidebar_open_tab_empty_state_description": "Encuentra los problemas abiertos aquí. Crea un nuevo problema.", + + "inbox_sidebar_closed_tab_empty_state_title": "No hay problemas cerrados", + "inbox_sidebar_closed_tab_empty_state_description": "Aquí puedes encontrar todos los problemas, ya sean aceptados o rechazados.", + + "inbox_sidebar_filter_empty_state_title": "No hay problemas que coincidan", + "inbox_sidebar_filter_empty_state_description": "Ningún problema coincide con el filtro aplicado en la recepción. Crea un nuevo problema.", + + "inbox_detail_empty_state_title": "Selecciona un problema para ver sus detalles.", + + "workspace_draft_issues_empty_state_title": "Problemas a medio escribir, y pronto, comentarios aparecerán aquí.", + "workspace_draft_issues_empty_state_description": "Para probarlo, comienza a agregar un problema y déjalo a medias o crea tu primer borrador a continuación. 😉", + "workspace_draft_issues_empty_state_primary_button_text": "Crea tu primer borrador" } diff --git a/packages/i18n/src/locales/fr/translations.json b/packages/i18n/src/locales/fr/translations.json index 6007622bca2..b1f7cd4ec40 100644 --- a/packages/i18n/src/locales/fr/translations.json +++ b/packages/i18n/src/locales/fr/translations.json @@ -522,5 +522,36 @@ "disabled_project_inbox_empty_state_title": "La réception n'est pas activée pour le projet.", "disabled_project_inbox_empty_state_description": "La réception vous aide à gérer les demandes entrantes pour votre projet et à les ajouter comme problèmes dans votre flux de travail. Activez la réception dans les paramètres du projet pour gérer les demandes.", - "disabled_project_inbox_empty_state_primary_button_text": "Gérer les fonctionnalités" + "disabled_project_inbox_empty_state_primary_button_text": "Gérer les fonctionnalités", + + "disabled_project_cycle_empty_state_title": "Les cycles ne sont pas activés pour ce projet.", + "disabled_project_cycle_empty_state_description": "Divisez le travail en morceaux temporels, travaillez à partir de la date limite du projet pour définir des dates et faites des progrès tangibles en équipe. Activez la fonction des cycles pour votre projet afin de commencer à les utiliser.", + "disabled_project_cycle_empty_state_primary_button_text": "Gérer les fonctionnalités", + + "disabled_project_module_empty_state_title": "Les modules ne sont pas activés pour le projet.", + "disabled_project_module_empty_state_description": "Un groupe de problèmes appartenant à un parent logique et hiérarchique forme un module. Considérez-les comme un moyen de suivre le travail par jalons du projet. Activez les modules depuis les paramètres du projet.", + "disabled_project_module_empty_state_primary_button_text": "Gérer les fonctionnalités", + + "disabled_project_page_empty_state_title": "Les pages ne sont pas activées pour le projet.", + "disabled_project_page_empty_state_description": "Les pages sont des espaces de prise de notes dans Plane. Prenez des notes lors des réunions, formatez-les facilement, intégrez des problèmes, organisez-les à l’aide d’une bibliothèque de composants et gardez-les dans le contexte de votre projet. Activez la fonction des pages pour commencer à les créer dans votre projet.", + "disabled_project_page_empty_state_primary_button_text": "Gérer les fonctionnalités", + + "disabled_project_view_empty_state_title": "Les vues ne sont pas activées pour ce projet.", + "disabled_project_view_empty_state_description": "Les vues sont un ensemble de filtres enregistrés que vous utilisez fréquemment ou auxquels vous voulez un accès facile. Tous vos collègues du projet peuvent voir les vues de chacun et choisir celle qui correspond le mieux à leurs besoins. Activez les vues dans les paramètres du projet pour commencer à les utiliser.", + "disabled_project_view_empty_state_primary_button_text": "Gérer les fonctionnalités", + + "inbox_sidebar_open_tab_empty_state_title": "Pas de problèmes ouverts", + "inbox_sidebar_open_tab_empty_state_description": "Trouvez ici les problèmes ouverts. Créez un nouveau problème.", + + "inbox_sidebar_closed_tab_empty_state_title": "Pas de problèmes fermés", + "inbox_sidebar_closed_tab_empty_state_description": "Tous les problèmes, qu'ils soient acceptés ou rejetés, peuvent être trouvés ici.", + + "inbox_sidebar_filter_empty_state_title": "Aucun problème ne correspond", + "inbox_sidebar_filter_empty_state_description": "Aucun problème ne correspond au filtre appliqué dans la réception. Créez un nouveau problème.", + + "inbox_detail_empty_state_title": "Sélectionnez un problème pour voir ses détails.", + + "workspace_draft_issues_empty_state_title": "Problèmes inachevés, et bientôt, des commentaires apparaîtront ici.", + "workspace_draft_issues_empty_state_description": "Pour essayer cela, commencez à ajouter un problème et laissez-le inachevé ou créez votre premier brouillon ci-dessous. 😉", + "workspace_draft_issues_empty_state_primary_button_text": "Créez votre premier brouillon" } diff --git a/packages/i18n/src/locales/ja/translations.json b/packages/i18n/src/locales/ja/translations.json index 289a11734d1..5b0c474e528 100644 --- a/packages/i18n/src/locales/ja/translations.json +++ b/packages/i18n/src/locales/ja/translations.json @@ -522,5 +522,36 @@ "disabled_project_inbox_empty_state_title": "このプロジェクトではインテークが有効になっていません。", "disabled_project_inbox_empty_state_description": "インテークは、プロジェクトへのリクエストを管理し、それらをワークフロー内の課題として追加するのに役立ちます。プロジェクト設定からインテークを有効にしてリクエストを管理してください。", - "disabled_project_inbox_empty_state_primary_button_text": "機能を管理" + "disabled_project_inbox_empty_state_primary_button_text": "機能を管理", + + "disabled_project_cycle_empty_state_title": "このプロジェクトではサイクルが有効になっていません。", + "disabled_project_cycle_empty_state_description": "作業を時間枠で区切り、プロジェクトの期限から逆算して日付を設定し、チームとして具体的な進捗を遂げます。サイクル機能をプロジェクトで有効にして使用を開始してください。", + "disabled_project_cycle_empty_state_primary_button_text": "機能を管理", + + "disabled_project_module_empty_state_title": "このプロジェクトではモジュールが有効になっていません。", + "disabled_project_module_empty_state_description": "論理的かつ階層的な親に属する課題のグループがモジュールを形成します。それらは、プロジェクトのマイルストーンごとに作業を追跡する方法として考えられます。プロジェクト設定からモジュールを有効にしてください。", + "disabled_project_module_empty_state_primary_button_text": "機能を管理", + + "disabled_project_page_empty_state_title": "このプロジェクトではページが有効になっていません。", + "disabled_project_page_empty_state_description": "ページはPlaneのノート取り用スペースです。会議のメモを取り、簡単にフォーマットし、課題を埋め込み、コンポーネントのライブラリを使ってレイアウトし、プロジェクトの文脈内でそれらを保管します。ページ機能を有効にしてプロジェクト内で作成を開始してください。", + "disabled_project_page_empty_state_primary_button_text": "機能を管理", + + "disabled_project_view_empty_state_title": "このプロジェクトではビューが有効になっていません。", + "disabled_project_view_empty_state_description": "ビューは頻繁に使用するフィルターのセットで、簡単にアクセスできるようにしたいものです。プロジェクト内のすべての同僚は、他の人のビューを見て、ニーズに合ったものを選択できます。プロジェクト設定からビューを有効にして、使用を開始してください。", + "disabled_project_view_empty_state_primary_button_text": "機能を管理", + + "inbox_sidebar_open_tab_empty_state_title": "開いている課題はありません", + "inbox_sidebar_open_tab_empty_state_description": "ここで開いている課題を見つけてください。新しい課題を作成します。", + + "inbox_sidebar_closed_tab_empty_state_title": "閉じた課題はありません", + "inbox_sidebar_closed_tab_empty_state_description": "すべての課題は、承認されたものも拒否されたものもここで見つけることができます。", + + "inbox_sidebar_filter_empty_state_title": "一致する課題はありません", + "inbox_sidebar_filter_empty_state_description": "インテークで適用したフィルターに一致する課題はありません。新しい課題を作成してください。", + + "inbox_detail_empty_state_title": "課題を選択してその詳細を表示してください。", + + "workspace_draft_issues_empty_state_title": "未完成の課題、そしてすぐにコメントがここに表示されます。", + "workspace_draft_issues_empty_state_description": "これを試すために、課題を追加して途中で中断するか、下に最初のドラフトを作成してください。😉", + "workspace_draft_issues_empty_state_primary_button_text": "最初のドラフトを作成" } From 239f79b129cc63861cb285a49a058327191eba42 Mon Sep 17 00:00:00 2001 From: Prateek Shourya Date: Thu, 16 Jan 2025 14:03:18 +0530 Subject: [PATCH 07/26] improvement: user permissions and workspace draft empty state --- .../issues/workspace-draft/empty-state.tsx | 36 ++++++++++++++----- web/core/store/user/permissions.store.ts | 9 +++-- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/web/core/components/issues/workspace-draft/empty-state.tsx b/web/core/components/issues/workspace-draft/empty-state.tsx index 7a2893abd98..34d98a3ffc0 100644 --- a/web/core/components/issues/workspace-draft/empty-state.tsx +++ b/web/core/components/issues/workspace-draft/empty-state.tsx @@ -2,15 +2,27 @@ import { FC, Fragment, useState } from "react"; // components -import { EIssuesStoreType } from "@plane/constants"; -import { EmptyState } from "@/components/empty-state"; +import { observer } from "mobx-react"; +import { EIssuesStoreType, EUserPermissionsLevel, EUserWorkspaceRoles } from "@plane/constants"; +import { useTranslation } from "@plane/i18n"; +import { DetailedEmptyState } from "@/components/empty-state"; import { CreateUpdateIssueModal } from "@/components/issues"; // constants -import { EmptyStateType } from "@/constants/empty-state"; +import { useUserPermissions } from "@/hooks/store"; +import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; -export const WorkspaceDraftEmptyState: FC = () => { +export const WorkspaceDraftEmptyState: FC = observer(() => { // state const [isDraftIssueModalOpen, setIsDraftIssueModalOpen] = useState(false); + // store hooks + const { t } = useTranslation(); + const { allowPermissions } = useUserPermissions(); + // derived values + const canPerformEmptyStateActions = allowPermissions( + [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER], + EUserPermissionsLevel.WORKSPACE + ); + const resolvedPath = useResolvedAssetPath({ basePath: "/empty-state/onboarding/cycles" }); return ( @@ -21,13 +33,19 @@ export const WorkspaceDraftEmptyState: FC = () => { isDraft />
- { - setIsDraftIssueModalOpen(true); + { + setIsDraftIssueModalOpen(true); + }, + disabled: !canPerformEmptyStateActions }} />
); -}; +}); diff --git a/web/core/store/user/permissions.store.ts b/web/core/store/user/permissions.store.ts index ba1211b0f1a..2c745e6bc2d 100644 --- a/web/core/store/user/permissions.store.ts +++ b/web/core/store/user/permissions.store.ts @@ -3,6 +3,7 @@ import unset from "lodash/unset"; import { action, makeObservable, observable, runInAction } from "mobx"; import { computedFn } from "mobx-utils"; // types +import { EUserProjectRoles, EUserWorkspaceRoles } from "@plane/constants"; import { IProjectMember, IUserProjectsRole, IWorkspaceMemberMe } from "@plane/types"; // plane web types import { @@ -22,6 +23,8 @@ import { CoreRootStore } from "@/store/root.store"; // derived services const workspaceService = new WorkspaceService(); +type ETempUserRole = TUserPermissions | EUserWorkspaceRoles | EUserProjectRoles; // TODO: Remove this once we have migrated user permissions to enums to plane constants package + export interface IUserPermissionStore { loader: boolean; // observables @@ -36,7 +39,7 @@ export interface IUserPermissionStore { projectId: string ) => TUserPermissions | undefined; allowPermissions: ( - allowPermissions: TUserPermissions[], + allowPermissions: ETempUserRole[], level: TUserPermissionsLevel, workspaceSlug?: string, projectId?: string, @@ -115,7 +118,7 @@ export class UserPermissionStore implements IUserPermissionStore { * @returns { boolean } */ allowPermissions = ( - allowPermissions: TUserPermissions[], + allowPermissions: ETempUserRole[], level: TUserPermissionsLevel, workspaceSlug?: string, projectId?: string, @@ -140,7 +143,7 @@ export class UserPermissionStore implements IUserPermissionStore { this.projectPermissionsByWorkspaceSlugAndProjectId(workspaceSlug, projectId)) as EUserPermissions | undefined; } - if (currentUserRole && allowPermissions.includes(currentUserRole)) { + if (currentUserRole && allowPermissions.includes(currentUserRole as TUserPermissions)) { if (onPermissionAllowed) { return onPermissionAllowed(); } else { From bb2542bf4f075b9dce3e9b4fed2f957cb953ae95 Mon Sep 17 00:00:00 2001 From: Prateek Shourya Date: Thu, 16 Jan 2025 19:37:36 +0530 Subject: [PATCH 08/26] chore: update translation structure --- .../i18n/src/locales/en/translations.json | 312 ++++++++++++------ .../i18n/src/locales/es/translations.json | 309 +++++++++++------ .../i18n/src/locales/fr/translations.json | 309 +++++++++++------ .../i18n/src/locales/ja/translations.json | 309 +++++++++++------ web/app/profile/notifications/page.tsx | 2 +- web/app/profile/page.tsx | 2 +- .../issues/workspace-draft/empty-state.tsx | 6 +- .../components/workspace/sidebar/dropdown.tsx | 2 +- web/core/constants/empty-state.ts | 83 ----- 9 files changed, 834 insertions(+), 500 deletions(-) diff --git a/packages/i18n/src/locales/en/translations.json b/packages/i18n/src/locales/en/translations.json index 538edcc1236..6df36c44b41 100644 --- a/packages/i18n/src/locales/en/translations.json +++ b/packages/i18n/src/locales/en/translations.json @@ -38,7 +38,6 @@ "deactivate_account_description": "When deactivating an account, all of the data and resources within that account will be permanently removed and cannot be recovered.", "profile_settings": "Profile settings", "your_account": "Your account", - "profile": "Profile", "security": "Security", "activity": "Activity", "appearance": "Appearance", @@ -155,7 +154,6 @@ "stay_ahead_of_blockers_description": "Spot challenges from one project to another and see inter-cycle dependencies that aren't obvious from any other view.", "analytics": "Analytics", "workspace_invites": "Workspace invites", - "workspace_settings": "Workspace settings", "enter_god_mode": "Enter god mode", "workspace_logo": "Workspace logo", "new_issue": "New issue", @@ -318,110 +316,208 @@ "add_parent": "Add parent", "loading_members": "Loading members...", - "workspace_dashboard_empty_state_title": "Overview of your projects, activity, and metrics", - "workspace_dashboard_empty_state_description": "Welcome to Plane, we are excited to have you here. Create your first project and track your issues, and this page will transform into a space that helps you progress. Admins will also see items which help their team progress.", - "workspace_dashboard_empty_state_primary_button_text": "Build your first project", - "workspace_dashboard_empty_state_primary_button_comic_title": "Everything starts with a project in Plane", - "workspace_dashboard_empty_state_primary_button_comic_description": "A project could be a product's roadmap, a marketing campaign, or launching a new car.", - - "workspace_analytics_empty_state_title": "Track progress, workloads, and allocations. Spot trends, remove blockers, and move work faster", - "workspace_analytics_empty_state_description": "See scope versus demand, estimates, and scope creep. Get performance by team members and teams, and make sure your project runs on time.", - "workspace_analytics_empty_state_primary_button_text": "Start your first project", - "workspace_analytics_empty_state_primary_button_comic_title": "Analytics works best with Cycles + Modules", - "workspace_analytics_empty_state_primary_button_comic_description": "First, timebox your issues into Cycles and, if you can, group issues that span more than a cycle into Modules. Check out both on the left nav.", - - "workspace_projects_empty_state_title": "No active projects", - "workspace_projects_empty_state_description": "Think of each project as the parent for goal-oriented work. Projects are where Jobs, Cycles, and Modules live and, along with your colleagues, help you achieve that goal. Create a new project or filter for archived projects.", - "workspace_projects_empty_state_primary_button_text": "Start your first project", - "workspace_projects_empty_state_primary_button_comic_title": "Everything starts with a project in Plane", - "workspace_projects_empty_state_primary_button_comic_description": "A project could be a product's roadmap, a marketing campaign, or launching a new car.", - - "workspace_all_issues_empty_state_title": "No issues in the project", - "workspace_all_issues_empty_state_description": "First project done! Now, slice your work into trackable pieces with issues. Let's go!", - "workspace_all_issues_empty_state_primary_button_text": "Create new issue", - - "workspace_assigned_empty_state_title": "No issues yet", - "workspace_assigned_empty_state_description": "Issues assigned to you can be tracked from here.", - "workspace_assigned_empty_state_primary_button_text": "Create new issue", - - "workspace_created_empty_state_title": "No issues yet", - "workspace_created_empty_state_description": "All issues created by you come here, track them here directly.", - "workspace_created_empty_state_primary_button_text": "Create new issue", - - "workspace_subscribed_empty_state_title": "No issues yet", - "workspace_subscribed_empty_state_description": "Subscribe to issues you are interested in, track all of them here.", - - "workspace_custom_view_empty_state_title": "No issues yet", - "workspace_custom_view_empty_state_description": "Issues that applies to the filters, track all of them here.", - - "workspace_project_not_found_empty_state_title": "No such project exists", - "workspace_project_not_found_empty_state_description": "To create issues or manage your work, you need to create a project or be a part of one.", - "workspace_project_not_found_empty_state_primary_button_text": "Create Project", - "workspace_project_not_found_empty_state_primary_button_comic_title": "Everything starts with a project in Plane", - "workspace_project_not_found_empty_state_primary_button_comic_description": "A project could be a product's roadmap, a marketing campaign, or launching a new car.", - - "workspace_no_projects_empty_state_title": "No project", - "workspace_no_projects_empty_state_description": "To create issues or manage your work, you need to create a project or be a part of one.", - "workspace_no_projects_empty_state_primary_button_text": "Start your first project", - "workspace_no_projects_empty_state_primary_button_comic_title": "Everything starts with a project in Plane", - "workspace_no_projects_empty_state_primary_button_comic_description": "A project could be a product's roadmap, a marketing campaign, or launching a new car.", - - "workspace_settings_api_tokens_empty_state_title": "No API tokens created", - "workspace_settings_api_tokens_empty_state_description": "Plane APIs can be used to integrate your data in Plane with any external system. Create a token to get started.", - - "workspace_settings_webhooks_empty_state_title": "No webhooks added", - "workspace_settings_webhooks_empty_state_description": "Create webhooks to receive real-time updates and automate actions.", - - "workspace_settings_export_empty_state_title": "No previous exports yet", - "workspace_settings_export_empty_state_description": "Anytime you export, you will also have a copy here for reference.", - - "workspace_settings_import_empty_state_title": "No previous imports yet", - "workspace_settings_import_empty_state_description": "Find all your previous imports here and download them.", - - "profile_activity_empty_state_title": "No activities yet", - "profile_activity_empty_state_description": "Get started by creating a new issue! Add details and properties to it. Explore more in Plane to see your activity.", - - "profile_assigned_empty_state_title": "No issues are assigned to you", - "profile_assigned_empty_state_description": "Issues assigned to you can be tracked from here.", - - "profile_created_empty_state_title": "No issues yet", - "profile_created_empty_state_description": "All issues created by you come here, track them here directly.", - - "profile_subscribed_empty_state_title": "No issues yet", - "profile_subscribed_empty_state_description": "Subscribe to issues you are interested in, track all of them here.", - - "project_settings_labels_empty_state_title": "No labels yet", - "project_settings_labels_empty_state_description": "Create labels to help organize and filter issues in you project.", - - "project_settings_integrations_empty_state_title": "No integrations configured", - "project_settings_integrations_empty_state_description": "Configure GitHub and other integrations to sync your project issues.", - - "project_settings_estimate_empty_state_title": "No estimates added", - "project_settings_estimate_empty_state_description": "Create a set of estimates to communicate the amount of work per issue.", - - "project_cycles_empty_state_title": "Group and timebox your work in Cycles.", - "project_cycles_empty_state_description": "Break work down by timeboxed chunks, work backwards from your project deadline to set dates, and make tangible progress as a team.", - "project_cycles_empty_state_primary_button_text": "Set your first cycle", - "project_cycles_empty_state_primary_button_comic_title": "Cycles are repetitive time-boxes.", - "project_cycles_empty_state_primary_button_comic_description": "A sprint, an iteration, and or any other term you use for weekly or fortnightly tracking of work is a cycle.", - - "project_cycle_no_issues_empty_state_title": "No issues added to the cycle", - "project_cycle_no_issues_empty_state_description": "Add or create issues you wish to timebox and deliver within this cycle", - "project_cycle_no_issues_empty_state_primary_button_text": "Create new issue", - "project_cycle_no_issues_empty_state_secondary_button_text": "Add an existing issue", - - "project_cycle_active_empty_state_title": "No active cycle", - "project_cycle_active_empty_state_description": "An active cycle includes any period that encompasses today's date within its range. Find the progress and details of the active cycle here.", - - "project_cycle_completed_no_issues_empty_state_title": "No issues in the cycle", - "project_cycle_completed_no_issues_empty_state_description": "No issues in the cycle. Issues are either transferred or hidden. To see hidden issues if any, update your display properties accordingly.", + "workspace_dashboard": { + "empty_state": { + "title": "Overview of your projects, activity, and metrics", + "description": "Welcome to Plane, we are excited to have you here. Create your first project and track your issues, and this page will transform into a space that helps you progress. Admins will also see items which help their team progress.", + "primary_button": { + "text": "Build your first project", + "comic": { + "title": "Everything starts with a project in Plane", + "description": "A project could be a product's roadmap, a marketing campaign, or launching a new car." + } + } + } + }, + + "workspace_analytics": { + "empty_state": { + "title": "Track progress, workloads, and allocations. Spot trends, remove blockers, and move work faster", + "description": "See scope versus demand, estimates, and scope creep. Get performance by team members and teams, and make sure your project runs on time.", + "primary_button": { + "text": "Start your first project", + "comic": { + "title": "Analytics works best with Cycles + Modules", + "description": "First, timebox your issues into Cycles and, if you can, group issues that span more than a cycle into Modules. Check out both on the left nav." + } + } + } + }, + + "workspace_projects": { + "empty_state": { + "general": { + "title": "No active projects", + "description": "Think of each project as the parent for goal-oriented work. Projects are where Jobs, Cycles, and Modules live and, along with your colleagues, help you achieve that goal. Create a new project or filter for archived projects.", + "primary_button": { + "text": "Start your first project", + "comic": { + "title": "Everything starts with a project in Plane", + "description": "A project could be a product's roadmap, a marketing campaign, or launching a new car." + } + } + }, + "not_found": { + "title": "No such project exists", + "description": "To create issues or manage your work, you need to create a project or be a part of one.", + "primary_button": { + "text": "Create Project", + "comic": { + "title": "Everything starts with a project in Plane", + "description": "A project could be a product's roadmap, a marketing campaign, or launching a new car." + } + } + }, + "no_projects": { + "title": "No project", + "description": "To create issues or manage your work, you need to create a project or be a part of one.", + "primary_button": { + "text": "Start your first project", + "comic": { + "title": "Everything starts with a project in Plane", + "description": "A project could be a product's roadmap, a marketing campaign, or launching a new car." + } + } + } + } + }, + + "workspace_issues": { + "empty_state": { + "all_issues": { + "title": "No issues in the project", + "description": "First project done! Now, slice your work into trackable pieces with issues. Let's go!", + "primary_button": { + "text": "Create new issue" + } + }, + "assigned": { + "title": "No issues yet", + "description": "Issues assigned to you can be tracked from here.", + "primary_button": { + "text": "Create new issue" + } + }, + "created": { + "title": "No issues yet", + "description": "All issues created by you come here, track them here directly.", + "primary_button": { + "text": "Create new issue" + } + }, + "subscribed": { + "title": "No issues yet", + "description": "Subscribe to issues you are interested in, track all of them here." + }, + "custom_view": { + "title": "No issues yet", + "description": "Issues that applies to the filters, track all of them here." + } + } + }, + + "workspace_settings": { + "name": "Workspace settings", + "empty_state": { + "api_tokens": { + "title": "No API tokens created", + "description": "Plane APIs can be used to integrate your data in Plane with any external system. Create a token to get started." + }, + "webhooks": { + "title": "No webhooks added", + "description": "Create webhooks to receive real-time updates and automate actions." + }, + "exports": { + "title": "No exports yet", + "description": "Anytime you export, you will also have a copy here for reference." + }, + "imports": { + "title": "No imports yet", + "description": "Find all your previous imports here and download them." + } + } + }, + + "profile": { + "name": "Profile", + "empty_state": { + "activity": { + "title": "No activities yet", + "description": "Get started by creating a new issue! Add details and properties to it. Explore more in Plane to see your activity." + }, + "assigned": { + "title": "No issues are assigned to you", + "description": "Issues assigned to you can be tracked from here." + }, + "created": { + "title": "No issues yet", + "description": "All issues created by you come here, track them here directly." + }, + "subscribed": { + "title": "No issues yet", + "description": "Subscribe to issues you are interested in, track all of them here." + } + } + }, + + "project_settings": { + "empty_state": { + "labels": { + "title": "No labels yet", + "description": "Create labels to help organize and filter issues in you project." + }, + "integerations": { + "title": "No integrations configured", + "description": "Configure GitHub and other integrations to sync your project issues." + }, + "estimates": { + "title": "No estimates added", + "description": "Create a set of estimates to communicate the amount of work per issue." + } + } + }, + + "project_cycles": { + "empty_state": { + "general": { + "title": "Group and timebox your work in Cycles.", + "description": "Break work down by timeboxed chunks, work backwards from your project deadline to set dates, and make tangible progress as a team.", + "primary_button": { + "text": "Set your first cycle", + "comic": { + "title": "Cycles are repetitive time-boxes.", + "description": "A sprint, an iteration, and or any other term you use for weekly or fortnightly tracking of work is a cycle." + } + } + }, + "all": { + "title": "No cycles", + "description": "An active cycle includes any period that encompasses today's date within its range. Find the progress and details of the active cycle here." + }, + "no_issues": { + "title": "No issues added to the cycle", + "description": "Add or create issues you wish to timebox and deliver within this cycle", + "primary_button": { + "text": "Create new issue" + }, + "secondary_button": { + "text": "Add existing issue" + } + }, + "active": { + "title": "No active cycle", + "description": "An active cycle includes any period that encompasses today's date within its range. Find the progress and details of the active cycle here." + }, + "completed": { + "title": "No issues in the cycle", + "description": "No issues in the cycle. Issues are either transferred or hidden. To see hidden issues if any, update your display properties accordingly." + } + } + }, "project_archived_no_cycles_empty_state_title": "No archived cycles yet", "project_archived_no_cycles_empty_state_description": "To tidy up your project, archive completed cycles. Find them here once archived.", - "project_cycle_all_empty_state_title": "No cycles", - "project_cycle_all_empty_state_description": "An active cycle includes any period that encompasses today's date within its range. Find the progress and details of the active cycle here.", - "project_empty_filter_empty_state_title": "No issues found matching the filters applied", "project_empty_filter_empty_state_secondary_button_text": "Clear all filters", @@ -551,7 +647,13 @@ "inbox_detail_empty_state_title": "Select an issue to view its details.", - "workspace_draft_issues_empty_state_title": "Half-written issues, and soon, comments will show up here.", - "workspace_draft_issues_empty_state_description": "To try this out, start adding an issue and leave it mid-way or create your first draft below. 😉", - "workspace_draft_issues_empty_state_primary_button_text": "Create your first draft" + "workspace_draft_issues": { + "empty_state": { + "title": "Half-written issues, and soon, comments will show up here.", + "description": "To try this out, start adding an issue and leave it mid-way or create your first draft below. 😉", + "primary_button": { + "text": "Create your first draft" + } + } + } } diff --git a/packages/i18n/src/locales/es/translations.json b/packages/i18n/src/locales/es/translations.json index f56b85a6e3f..9e6260c6a6d 100644 --- a/packages/i18n/src/locales/es/translations.json +++ b/packages/i18n/src/locales/es/translations.json @@ -38,7 +38,6 @@ "deactivate_account_description": "Al desactivar una cuenta, todos los datos y recursos dentro de esa cuenta se eliminarán permanentemente y no se podrán recuperar.", "profile_settings": "Configuración de perfil", "your_account": "Tu cuenta", - "profile": "Perfil", "security": "Seguridad", "activity": "Actividad", "appearance": "Apariencia", @@ -153,7 +152,6 @@ "stay_ahead_of_blockers_description": "Detecta desafíos de un proyecto a otro y ve dependencias entre ciclos que no son obvias desde ninguna otra vista.", "analytics": "Analítica", "workspace_invites": "Invitaciones al espacio de trabajo", - "workspace_settings": "Configuración del espacio de trabajo", "enter_god_mode": "Entrar en modo dios", "workspace_logo": "Logo del espacio de trabajo", "new_issue": "Nuevo problema", @@ -317,103 +315,204 @@ "loading_members": "Cargando miembros...", "inbox": "bandeja de entrada", - "workspace_dashboard_empty_state_title": "Resumen de tus proyectos, actividad y métricas", - "workspace_dashboard_empty_state_description": "Bienvenido a Plane, estamos emocionados de tenerte aquí. Crea tu primer proyecto y realiza un seguimiento de tus problemas, y esta página se transformará en un espacio que te ayuda a progresar. Los administradores también verán elementos que ayudan a su equipo a progresar.", - "workspace_dashboard_empty_state_primary_button_text": "Construye tu primer proyecto", - "workspace_dashboard_empty_state_primary_button_comic_title": "Todo comienza con un proyecto en Plane", - "workspace_dashboard_empty_state_primary_button_comic_description": "Un proyecto podría ser la hoja de ruta de un producto, una campaña de marketing o el lanzamiento de un nuevo automóvil.", - - "workspace_analytics_empty_state_title": "Rastrea el progreso, las cargas de trabajo y las asignaciones. Identifica tendencias, elimina obstáculos y mueve el trabajo más rápido", - "workspace_analytics_empty_state_description": "Observa el alcance versus la demanda, las estimaciones y el aumento del alcance. Obtén el rendimiento por miembros del equipo y equipos, y asegúrate de que tu proyecto se ejecute a tiempo.", - "workspace_analytics_empty_state_primary_button_text": "Comienza tu primer proyecto", - "workspace_analytics_empty_state_primary_button_comic_title": "El análisis funciona mejor con Ciclos + Módulos", - "workspace_analytics_empty_state_primary_button_comic_description": "Primero, limita en el tiempo tus problemas en Ciclos y, si puedes, agrupa los problemas que abarcan más de un ciclo en Módulos. Revisa ambos en la navegación izquierda.", - - "workspace_projects_empty_state_title": "No hay proyectos activos", - "workspace_projects_empty_state_description": "Piensa en cada proyecto como el padre del trabajo orientado a objetivos. Los proyectos son donde viven los Trabajos, Ciclos y Módulos y, junto con tus colegas, te ayudan a alcanzar ese objetivo. Crea un nuevo proyecto o filtra proyectos archivados.", - "workspace_projects_empty_state_primary_button_text": "Comienza tu primer proyecto", - "workspace_projects_empty_state_primary_button_comic_title": "Todo comienza con un proyecto en Plane", - "workspace_projects_empty_state_primary_button_comic_description": "Un proyecto podría ser la hoja de ruta de un producto, una campaña de marketing o el lanzamiento de un nuevo automóvil.", - - "workspace_all_issues_empty_state_title": "No hay problemas en el proyecto", - "workspace_all_issues_empty_state_description": "¡Primer proyecto completado! Ahora, divide tu trabajo en piezas rastreables con problemas. ¡Vamos!", - "workspace_all_issues_empty_state_primary_button_text": "Crear nuevo problema", - - "workspace_assigned_empty_state_title": "No hay problemas aún", - "workspace_assigned_empty_state_description": "Los problemas asignados a ti pueden ser rastreados desde aquí.", - "workspace_assigned_empty_state_primary_button_text": "Crear nuevo problema", - - "workspace_created_empty_state_title": "No hay problemas aún", - "workspace_created_empty_state_description": "Todos los problemas creados por ti vienen aquí, rastréalos aquí directamente.", - "workspace_created_empty_state_primary_button_text": "Crear nuevo problema", - - "workspace_subscribed_empty_state_title": "No hay problemas aún", - "workspace_subscribed_empty_state_description": "Suscríbete a problemas que te interesen, rastréalos todos aquí.", - - "workspace_custom_view_empty_state_title": "No hay problemas aún", - "workspace_custom_view_empty_state_description": "Problemas que aplican a los filtros, rastréalos todos aquí.", - - "workspace_project_not_found_empty_state_title": "No existe tal proyecto", - "workspace_project_not_found_empty_state_description": "Para crear problemas o gestionar tu trabajo, necesitas crear un proyecto o ser parte de uno.", - "workspace_project_not_found_empty_state_primary_button_text": "Crear Proyecto", - "workspace_project_not_found_empty_state_primary_button_comic_title": "Todo comienza con un proyecto en Plane", - "workspace_project_not_found_empty_state_primary_button_comic_description": "Un proyecto podría ser la hoja de ruta de un producto, una campaña de marketing o el lanzamiento de un nuevo automóvil.", - - "workspace_no_projects_empty_state_title": "No hay proyecto", - "workspace_no_projects_empty_state_description": "Para crear problemas o gestionar tu trabajo, necesitas crear un proyecto o ser parte de uno.", - "workspace_no_projects_empty_state_primary_button_text": "Comienza tu primer proyecto", - "workspace_no_projects_empty_state_primary_button_comic_title": "Todo comienza con un proyecto en Plane", - "workspace_no_projects_empty_state_primary_button_comic_description": "Un proyecto podría ser la hoja de ruta de un producto, una campaña de marketing o el lanzamiento de un nuevo automóvil.", - - "workspace_settings_api_tokens_empty_state_title": "No se han creado tokens API", - "workspace_settings_api_tokens_empty_state_description": "Las APIs de Plane pueden usarse para integrar tus datos en Plane con cualquier sistema externo. Crea un token para comenzar.", - - "workspace_settings_webhooks_empty_state_title": "No se han añadido webhooks", - "workspace_settings_webhooks_empty_state_description": "Crea webhooks para recibir actualizaciones en tiempo real y automatizar acciones.", - - "workspace_settings_export_empty_state_title": "No hay exportaciones previas aún", - "workspace_settings_export_empty_state_description": "Cada vez que exportes, también tendrás una copia aquí para referencia.", - - "workspace_settings_import_empty_state_title": "No hay importaciones previas aún", - "workspace_settings_import_empty_state_description": "Encuentra todas tus importaciones previas aquí y descárgalas.", - - "profile_activity_empty_state_title": "No hay actividades aún", - "profile_activity_empty_state_description": "¡Comienza creando un nuevo problema! Añade detalles y propiedades. Explora más en Plane para ver tu actividad.", - - "profile_assigned_empty_state_title": "No hay problemas asignados a ti", - "profile_assigned_empty_state_description": "Los problemas asignados a ti pueden ser rastreados desde aquí.", - - "profile_created_empty_state_title": "No hay problemas aún", - "profile_created_empty_state_description": "Todos los problemas creados por ti vienen aquí, rastréalos aquí directamente.", - - "profile_subscribed_empty_state_title": "No hay problemas aún", - "profile_subscribed_empty_state_description": "Suscríbete a problemas que te interesen, rastréalos todos aquí.", - - "project_settings_labels_empty_state_title": "No hay etiquetas aún", - "project_settings_labels_empty_state_description": "Crea etiquetas para ayudar a organizar y filtrar problemas en tu proyecto.", - - "project_settings_integrations_empty_state_title": "No hay integraciones configuradas", - "project_settings_integrations_empty_state_description": "Configura GitHub y otras integraciones para sincronizar los problemas de tu proyecto.", - - "project_settings_estimate_empty_state_title": "No se han añadido estimaciones", - "project_settings_estimate_empty_state_description": "Crea un conjunto de estimaciones para comunicar la cantidad de trabajo por problema.", - - "project_cycles_empty_state_title": "Agrupa y limita en el tiempo tu trabajo en Ciclos.", - "project_cycles_empty_state_description": "Divide el trabajo en fragmentos limitados en el tiempo, trabaja hacia atrás desde la fecha límite de tu proyecto para establecer fechas y haz progreso tangible como equipo.", - "project_cycles_empty_state_primary_button_text": "Establece tu primer ciclo", - "project_cycles_empty_state_primary_button_comic_title": "Los Ciclos son cajas de tiempo repetitivas.", - "project_cycles_empty_state_primary_button_comic_description": "Un sprint, una iteración, o cualquier otro término que uses para el seguimiento semanal o quincenal del trabajo es un ciclo.", - - "project_cycle_no_issues_empty_state_title": "No se han añadido problemas al ciclo", - "project_cycle_no_issues_empty_state_description": "Añade o crea problemas que desees limitar en el tiempo y entregar dentro de este ciclo", - "project_cycle_no_issues_empty_state_primary_button_text": "Crear nuevo problema", - "project_cycle_no_issues_empty_state_secondary_button_text": "Añadir un problema existente", - - "project_cycle_active_empty_state_title": "No hay ciclo activo", - "project_cycle_active_empty_state_description": "Un ciclo activo incluye cualquier período que abarque la fecha de hoy dentro de su rango. Encuentra el progreso y los detalles del ciclo activo aquí.", - - "project_cycle_completed_no_issues_empty_state_title": "No hay problemas en el ciclo", - "project_cycle_completed_no_issues_empty_state_description": "No hay problemas en el ciclo. Los problemas están transferidos u ocultos. Para ver problemas ocultos si los hay, actualiza tus propiedades de visualización en consecuencia.", + "workspace_dashboard": { + "empty_state": { + "title": "Resumen de tus proyectos, actividad y métricas", + "description": "Bienvenido a Plane, estamos emocionados de tenerte aquí. Crea tu primer proyecto y rastrea tus problemas, y esta página se transformará en un espacio que te ayudará a avanzar. Los administradores también verán elementos que ayudan a su equipo a progresar.", + "primary_button": { + "text": "Construye tu primer proyecto", + "comic": { + "title": "Todo comienza con un proyecto en Plane", + "description": "Un proyecto podría ser la hoja de ruta de un producto, una campaña de marketing o el lanzamiento de un nuevo coche." + } + } + } + }, + + "workspace_analytics": { + "empty_state": { + "title": "Rastrea el progreso, cargas de trabajo y asignaciones. Detecta tendencias, elimina bloqueos y acelera el trabajo", + "description": "Consulta el alcance frente a la demanda, estimaciones y desbordamiento del alcance. Obtén el rendimiento por miembros del equipo y equipos, y asegúrate de que tu proyecto termine a tiempo.", + "primary_button": { + "text": "Comienza tu primer proyecto", + "comic": { + "title": "La analítica funciona mejor con Ciclos + Módulos", + "description": "Primero, organiza tus problemas en ciclos y, si puedes, agrupa problemas que abarquen más de un ciclo en módulos. Consulta ambos en el menú de navegación a la izquierda." + } + } + } + }, + + "workspace_projects": { + "empty_state": { + "general": { + "title": "No hay proyectos activos", + "description": "Piensa en cada proyecto como el contenedor para trabajo orientado a objetivos. Los proyectos son donde viven Trabajos, Ciclos y Módulos y, junto con tus colegas, te ayudan a lograr ese objetivo. Crea un nuevo proyecto o filtra por proyectos archivados.", + "primary_button": { + "text": "Comienza tu primer proyecto", + "comic": { + "title": "Todo comienza con un proyecto en Plane", + "description": "Un proyecto podría ser la hoja de ruta de un producto, una campaña de marketing o el lanzamiento de un nuevo coche." + } + } + }, + "not_found": { + "title": "No existe tal proyecto", + "description": "Para crear problemas o gestionar tu trabajo, necesitas crear un proyecto o ser parte de uno.", + "primary_button": { + "text": "Crear proyecto", + "comic": { + "title": "Todo comienza con un proyecto en Plane", + "description": "Un proyecto podría ser la hoja de ruta de un producto, una campaña de marketing o el lanzamiento de un nuevo coche." + } + } + }, + "no_projects": { + "title": "Sin proyectos", + "description": "Para crear problemas o gestionar tu trabajo, necesitas crear un proyecto o ser parte de uno.", + "primary_button": { + "text": "Comienza tu primer proyecto", + "comic": { + "title": "Todo comienza con un proyecto en Plane", + "description": "Un proyecto podría ser la hoja de ruta de un producto, una campaña de marketing o el lanzamiento de un nuevo coche." + } + } + } + } + }, + + "workspace_issues": { + "empty_state": { + "all_issues": { + "title": "No hay problemas en el proyecto", + "description": "¡Primer proyecto terminado! Ahora, divide tu trabajo en piezas rastreables con problemas. ¡Vamos!", + "primary_button": { + "text": "Crear nuevo problema" + } + }, + "assigned": { + "title": "Aún no hay problemas", + "description": "Los problemas asignados a ti se pueden rastrear desde aquí.", + "primary_button": { + "text": "Crear nuevo problema" + } + }, + "created": { + "title": "Aún no hay problemas", + "description": "Todos los problemas creados por ti aparecen aquí. Rastréalos directamente.", + "primary_button": { + "text": "Crear nuevo problema" + } + }, + "subscribed": { + "title": "Aún no hay problemas", + "description": "Suscríbete a los problemas que te interesan y rastrea todos ellos aquí." + }, + "custom_view": { + "title": "Aún no hay problemas", + "description": "Los problemas que se aplican a los filtros se rastrean aquí." + } + } + }, + + "workspace_settings": { + "name": "Configuración del espacio de trabajo", + "empty_state": { + "api_tokens": { + "title": "No se han creado tokens API", + "description": "Las APIs de Plane pueden ser usadas para integrar tus datos en Plane con cualquier sistema externo. Crea un token para comenzar." + }, + "webhooks": { + "title": "No se han agregado webhooks", + "description": "Crea webhooks para recibir actualizaciones en tiempo real y automatizar acciones." + }, + "exports": { + "title": "Aún no hay exportaciones", + "description": "Cada vez que exportes, también tendrás una copia aquí para referencia." + }, + "imports": { + "title": "Aún no hay importaciones", + "description": "Encuentra todas tus importaciones previas aquí y descárgalas." + } + } + }, + + "profile": { + "name": "Perfil", + "empty_state": { + "activity": { + "title": "Aún no hay actividades", + "description": "¡Comienza creando un nuevo problema! Añade detalles y propiedades a él. Explora más en Plane para ver tu actividad." + }, + "assigned": { + "title": "No tienes problemas asignados", + "description": "Los problemas asignados a ti se pueden rastrear desde aquí." + }, + "created": { + "title": "Aún no hay problemas", + "description": "Todos los problemas creados por ti aparecen aquí. Rastréalos directamente." + }, + "subscribed": { + "title": "Aún no hay problemas", + "description": "Suscríbete a los problemas que te interesan y rastrea todos ellos aquí." + } + } + }, + + "project_settings": { + "empty_state": { + "labels": { + "title": "Aún no hay etiquetas", + "description": "Crea etiquetas para ayudar a organizar y filtrar problemas en tu proyecto." + }, + "integerations": { + "title": "No se han configurado integraciones", + "description": "Configura GitHub y otras integraciones para sincronizar los problemas de tu proyecto." + }, + "estimates": { + "title": "Aún no hay estimaciones", + "description": "Crea un conjunto de estimaciones para comunicar la cantidad de trabajo por problema." + } + } + }, + + "project_cycles": { + "empty_state": { + "general": { + "title": "Agrupa y organiza tu trabajo en Ciclos.", + "description": "Divide el trabajo en partes organizadas por plazos, retrocede desde la fecha límite de tu proyecto para establecer fechas y haz un progreso tangible como equipo.", + "primary_button": { + "text": "Configura tu primer ciclo", + "comic": { + "title": "Los ciclos son bloques de tiempo repetitivos.", + "description": "Un sprint, una iteración o cualquier otro término que uses para el seguimiento semanal o quincenal del trabajo es un ciclo." + } + } + }, + "all": { + "title": "Sin ciclos", + "description": "Un ciclo activo incluye cualquier período que abarque la fecha de hoy dentro de su rango. Encuentra el progreso y los detalles del ciclo activo aquí." + }, + "no_issues": { + "title": "No hay problemas añadidos al ciclo", + "description": "Añade o crea problemas que desees organizar y entregar dentro de este ciclo", + "primary_button": { + "text": "Crear nuevo problema" + }, + "secondary_button": { + "text": "Añadir problema existente" + } + }, + "active": { + "title": "Sin ciclo activo", + "description": "Un ciclo activo incluye cualquier período que abarque la fecha de hoy dentro de su rango. Encuentra el progreso y los detalles del ciclo activo aquí." + }, + "completed": { + "title": "No hay problemas en el ciclo", + "description": "No hay problemas en el ciclo. Los problemas se transfirieron o están ocultos. Para ver los problemas ocultos, si los hay, actualiza tus propiedades de visualización según sea necesario." + } + } + }, "project_archived_no_cycles_empty_state_title": "No hay ciclos archivados aún", "project_archived_no_cycles_empty_state_description": "Para ordenar tu proyecto, archiva los ciclos completados. Encuéntralos aquí una vez archivados.", @@ -550,7 +649,13 @@ "inbox_detail_empty_state_title": "Selecciona un problema para ver sus detalles.", - "workspace_draft_issues_empty_state_title": "Problemas a medio escribir, y pronto, comentarios aparecerán aquí.", - "workspace_draft_issues_empty_state_description": "Para probarlo, comienza a agregar un problema y déjalo a medias o crea tu primer borrador a continuación. 😉", - "workspace_draft_issues_empty_state_primary_button_text": "Crea tu primer borrador" + "workspace_draft_issues": { + "empty_state": { + "title": "Los problemas a medio escribir, y pronto, los comentarios aparecerán aquí.", + "description": "Para probar esto, comienza a agregar un problema y déjalo a medias o crea tu primer borrador abajo. 😉", + "primary_button": { + "text": "Crea tu primer borrador" + } + } + } } diff --git a/packages/i18n/src/locales/fr/translations.json b/packages/i18n/src/locales/fr/translations.json index b1f7cd4ec40..25900bca010 100644 --- a/packages/i18n/src/locales/fr/translations.json +++ b/packages/i18n/src/locales/fr/translations.json @@ -38,7 +38,6 @@ "deactivate_account_description": "Lors de la désactivation d'un compte, toutes les données et ressources de ce compte seront définitivement supprimées et ne pourront pas être récupérées.", "profile_settings": "Paramètres du profil", "your_account": "Votre compte", - "profile": "Profil", "security": " Sécurité", "activity": "Activité", "appearance": "Apparence", @@ -154,7 +153,6 @@ "stay_ahead_of_blockers_description": "Repérez les défis d'un projet à l'autre et identifiez les dépendances entre cycles qui ne sont pas évidentes depuis d'autres vues.", "analytics": "Analyse", "workspace_invites": "Invitations de l'espace de travail", - "workspace_settings": "Paramètres de l'espace de travail", "enter_god_mode": "Entrer en mode dieu", "workspace_logo": "Logo de l'espace de travail", "new_issue": "Nouveau problème", @@ -318,103 +316,204 @@ "loading_members": "Chargement des membres...", "inbox": "Boîte de réception", - "workspace_dashboard_empty_state_title": "Aperçu de vos projets, activités et métriques", - "workspace_dashboard_empty_state_description": "Bienvenue sur Plane, nous sommes ravis de vous accueillir. Créez votre premier projet et suivez vos problèmes, et cette page se transformera en un espace qui vous aide à progresser. Les administrateurs verront également les éléments qui aident leur équipe à progresser.", - "workspace_dashboard_empty_state_primary_button_text": "Créez votre premier projet", - "workspace_dashboard_empty_state_primary_button_comic_title": "Tout commence par un projet dans Plane", - "workspace_dashboard_empty_state_primary_button_comic_description": "Un projet peut être la feuille de route d'un produit, une campagne marketing ou le lancement d'une nouvelle voiture.", - - "workspace_analytics_empty_state_title": "Suivez les progrès, les charges de travail et les allocations. Repérez les tendances, supprimez les obstacles et accélérez le travail", - "workspace_analytics_empty_state_description": "Visualisez la portée par rapport à la demande, les estimations et la dérive de portée. Obtenez les performances par membres et équipes, et assurez-vous que votre projet respecte les délais.", - "workspace_analytics_empty_state_primary_button_text": "Commencez votre premier projet", - "workspace_analytics_empty_state_primary_button_comic_title": "L'analyse fonctionne mieux avec les Cycles + Modules", - "workspace_analytics_empty_state_primary_button_comic_description": "D'abord, limitez vos problèmes dans le temps en Cycles et, si possible, groupez les problèmes qui s'étendent sur plus d'un cycle en Modules. Découvrez les deux dans la navigation de gauche.", - - "workspace_projects_empty_state_title": "Aucun projet actif", - "workspace_projects_empty_state_description": "Considérez chaque projet comme le parent d'un travail orienté vers un objectif. Les projets sont l'endroit où vivent les Tâches, les Cycles et les Modules et, avec vos collègues, vous aident à atteindre cet objectif. Créez un nouveau projet ou filtrez les projets archivés.", - "workspace_projects_empty_state_primary_button_text": "Commencez votre premier projet", - "workspace_projects_empty_state_primary_button_comic_title": "Tout commence par un projet dans Plane", - "workspace_projects_empty_state_primary_button_comic_description": "Un projet peut être la feuille de route d'un produit, une campagne marketing ou le lancement d'une nouvelle voiture.", - - "workspace_all_issues_empty_state_title": "Aucun problème dans le projet", - "workspace_all_issues_empty_state_description": "Premier projet terminé ! Maintenant, découpez votre travail en morceaux suivables avec des problèmes. Allons-y !", - "workspace_all_issues_empty_state_primary_button_text": "Créer un nouveau problème", - - "workspace_assigned_empty_state_title": "Aucun problème pour le moment", - "workspace_assigned_empty_state_description": "Les problèmes qui vous sont assignés peuvent être suivis ici.", - "workspace_assigned_empty_state_primary_button_text": "Créer un nouveau problème", - - "workspace_created_empty_state_title": "Aucun problème pour le moment", - "workspace_created_empty_state_description": "Tous les problèmes que vous créez arrivent ici, suivez-les directement ici.", - "workspace_created_empty_state_primary_button_text": "Créer un nouveau problème", - - "workspace_subscribed_empty_state_title": "Aucun problème pour le moment", - "workspace_subscribed_empty_state_description": "Abonnez-vous aux problèmes qui vous intéressent, suivez-les tous ici.", - - "workspace_custom_view_empty_state_title": "Aucun problème pour le moment", - "workspace_custom_view_empty_state_description": "Problèmes qui correspondent aux filtres, suivez-les tous ici.", - - "workspace_project_not_found_empty_state_title": "Ce projet n'existe pas", - "workspace_project_not_found_empty_state_description": "Pour créer des problèmes ou gérer votre travail, vous devez créer un projet ou faire partie d'un projet.", - "workspace_project_not_found_empty_state_primary_button_text": "Créer un projet", - "workspace_project_not_found_empty_state_primary_button_comic_title": "Tout commence par un projet dans Plane", - "workspace_project_not_found_empty_state_primary_button_comic_description": "Un projet peut être la feuille de route d'un produit, une campagne marketing ou le lancement d'une nouvelle voiture.", - - "workspace_no_projects_empty_state_title": "Aucun projet", - "workspace_no_projects_empty_state_description": "Pour créer des problèmes ou gérer votre travail, vous devez créer un projet ou faire partie d'un projet.", - "workspace_no_projects_empty_state_primary_button_text": "Commencez votre premier projet", - "workspace_no_projects_empty_state_primary_button_comic_title": "Tout commence par un projet dans Plane", - "workspace_no_projects_empty_state_primary_button_comic_description": "Un projet peut être la feuille de route d'un produit, une campagne marketing ou le lancement d'une nouvelle voiture.", - - "workspace_settings_api_tokens_empty_state_title": "Aucun jeton API créé", - "workspace_settings_api_tokens_empty_state_description": "Les APIs de Plane peuvent être utilisées pour intégrer vos données dans Plane avec n'importe quel système externe. Créez un jeton pour commencer.", - - "workspace_settings_webhooks_empty_state_title": "Aucun webhook ajouté", - "workspace_settings_webhooks_empty_state_description": "Créez des webhooks pour recevoir des mises à jour en temps réel et automatiser des actions.", - - "workspace_settings_export_empty_state_title": "Aucune exportation précédente", - "workspace_settings_export_empty_state_description": "Chaque fois que vous exportez, vous aurez également une copie ici pour référence.", - - "workspace_settings_import_empty_state_title": "Aucune importation précédente", - "workspace_settings_import_empty_state_description": "Trouvez toutes vos importations précédentes ici et téléchargez-les.", - - "profile_activity_empty_state_title": "Aucune activité pour le moment", - "profile_activity_empty_state_description": "Commencez par créer un nouveau problème ! Ajoutez-y des détails et des propriétés. Explorez davantage dans Plane pour voir votre activité.", - - "profile_assigned_empty_state_title": "Aucun problème ne vous est assigné", - "profile_assigned_empty_state_description": "Les problèmes qui vous sont assignés peuvent être suivis ici.", - - "profile_created_empty_state_title": "Aucun problème pour le moment", - "profile_created_empty_state_description": "Tous les problèmes que vous créez arrivent ici, suivez-les directement ici.", - - "profile_subscribed_empty_state_title": "Aucun problème pour le moment", - "profile_subscribed_empty_state_description": "Abonnez-vous aux problèmes qui vous intéressent, suivez-les tous ici.", - - "project_settings_labels_empty_state_title": "Aucune étiquette pour le moment", - "project_settings_labels_empty_state_description": "Créez des étiquettes pour aider à organiser et filtrer les problèmes dans votre projet.", - - "project_settings_integrations_empty_state_title": "Aucune intégration configurée", - "project_settings_integrations_empty_state_description": "Configurez GitHub et d'autres intégrations pour synchroniser vos problèmes de projet.", - - "project_settings_estimate_empty_state_title": "Aucune estimation ajoutée", - "project_settings_estimate_empty_state_description": "Créez un ensemble d'estimations pour communiquer la quantité de travail par problème.", - - "project_cycles_empty_state_title": "Groupez et limitez dans le temps votre travail en Cycles.", - "project_cycles_empty_state_description": "Décomposez le travail en morceaux limités dans le temps, travaillez à rebours depuis la date limite de votre projet pour définir les dates, et faites des progrès tangibles en équipe.", - "project_cycles_empty_state_primary_button_text": "Définissez votre premier cycle", - "project_cycles_empty_state_primary_button_comic_title": "Les Cycles sont des boîtes de temps répétitives.", - "project_cycles_empty_state_primary_button_comic_description": "Un sprint, une itération, ou tout autre terme que vous utilisez pour le suivi hebdomadaire ou bimensuel du travail est un cycle.", - - "project_cycle_no_issues_empty_state_title": "Aucun problème ajouté au cycle", - "project_cycle_no_issues_empty_state_description": "Ajoutez ou créez des problèmes que vous souhaitez limiter dans le temps et livrer dans ce cycle", - "project_cycle_no_issues_empty_state_primary_button_text": "Créer un nouveau problème", - "project_cycle_no_issues_empty_state_secondary_button_text": "Ajouter un problème existant", - - "project_cycle_active_empty_state_title": "Aucun cycle actif", - "project_cycle_active_empty_state_description": "Un cycle actif inclut toute période qui englobe la date d'aujourd'hui dans sa plage. Trouvez ici les progrès et les détails du cycle actif.", - - "project_cycle_completed_no_issues_empty_state_title": "Aucun problème dans le cycle", - "project_cycle_completed_no_issues_empty_state_description": "Aucun problème dans le cycle. Les problèmes sont soit transférés soit masqués. Pour voir les problèmes masqués s'il y en a, mettez à jour vos propriétés d'affichage en conséquence.", + "workspace_dashboard": { + "empty_state": { + "title": "Vue d'ensemble de vos projets, activités et métriques", + "description": "Bienvenue sur Plane, nous sommes ravis de vous accueillir. Créez votre premier projet et suivez vos tâches, et cette page se transformera en un espace qui vous aidera à progresser. Les administrateurs verront également des éléments pour aider leur équipe à progresser.", + "primary_button": { + "text": "Créez votre premier projet", + "comic": { + "title": "Tout commence par un projet sur Plane", + "description": "Un projet peut être une feuille de route produit, une campagne marketing ou le lancement d'une nouvelle voiture." + } + } + } + }, + + "workspace_analytics": { + "empty_state": { + "title": "Suivez les progrès, les charges de travail et les allocations. Repérez les tendances, éliminez les obstacles et accélérez le travail", + "description": "Visualisez l'étendue par rapport à la demande, les estimations et l'expansion des objectifs. Obtenez des performances par membre et par équipe, et assurez-vous que votre projet respecte les délais.", + "primary_button": { + "text": "Commencez votre premier projet", + "comic": { + "title": "Les analyses fonctionnent mieux avec Cycles + Modules", + "description": "D'abord, cadrez vos tâches dans des Cycles et, si possible, regroupez les tâches qui s'étendent sur plus d'un cycle dans des Modules. Consultez-les dans la navigation à gauche." + } + } + } + }, + + "workspace_projects": { + "empty_state": { + "general": { + "title": "Aucun projet actif", + "description": "Considérez chaque projet comme le parent des travaux orientés vers un objectif. Les projets sont l'endroit où vivent les tâches, les Cycles et les Modules, et avec vos collègues, ils vous aident à atteindre cet objectif. Créez un nouveau projet ou filtrez les projets archivés.", + "primary_button": { + "text": "Commencez votre premier projet", + "comic": { + "title": "Tout commence par un projet sur Plane", + "description": "Un projet peut être une feuille de route produit, une campagne marketing ou le lancement d'une nouvelle voiture." + } + } + }, + "not_found": { + "title": "Aucun projet correspondant", + "description": "Pour créer des tâches ou gérer votre travail, vous devez créer un projet ou en faire partie.", + "primary_button": { + "text": "Créer un projet", + "comic": { + "title": "Tout commence par un projet sur Plane", + "description": "Un projet peut être une feuille de route produit, une campagne marketing ou le lancement d'une nouvelle voiture." + } + } + }, + "no_projects": { + "title": "Aucun projet", + "description": "Pour créer des tâches ou gérer votre travail, vous devez créer un projet ou en faire partie.", + "primary_button": { + "text": "Commencez votre premier projet", + "comic": { + "title": "Tout commence par un projet sur Plane", + "description": "Un projet peut être une feuille de route produit, une campagne marketing ou le lancement d'une nouvelle voiture." + } + } + } + } + }, + + "workspace_issues": { + "empty_state": { + "all_issues": { + "title": "Aucune tâche dans le projet", + "description": "Premier projet terminé ! Maintenant, divisez votre travail en morceaux traçables avec des tâches. Allons-y !", + "primary_button": { + "text": "Créer une nouvelle tâche" + } + }, + "assigned": { + "title": "Aucune tâche assignée", + "description": "Les tâches qui vous sont assignées peuvent être suivies ici.", + "primary_button": { + "text": "Créer une nouvelle tâche" + } + }, + "created": { + "title": "Aucune tâche créée", + "description": "Toutes les tâches que vous avez créées se trouvent ici. Suivez-les directement ici.", + "primary_button": { + "text": "Créer une nouvelle tâche" + } + }, + "subscribed": { + "title": "Aucune tâche suivie", + "description": "Abonnez-vous aux tâches qui vous intéressent, suivez-les toutes ici." + }, + "custom_view": { + "title": "Aucune tâche trouvée", + "description": "Les tâches correspondant aux filtres sont affichées ici. Suivez-les toutes ici." + } + } + }, + + "workspace_settings": { + "name": "Paramètres de l'espace de travail", + "empty_state": { + "api_tokens": { + "title": "Aucun jeton API créé", + "description": "Les API Plane peuvent être utilisées pour intégrer vos données dans Plane avec n'importe quel système externe. Créez un jeton pour commencer." + }, + "webhooks": { + "title": "Aucun webhook ajouté", + "description": "Créez des webhooks pour recevoir des mises à jour en temps réel et automatiser des actions." + }, + "exports": { + "title": "Aucune exportation pour le moment", + "description": "Chaque fois que vous exportez, une copie sera également disponible ici pour référence." + }, + "imports": { + "title": "Aucune importation pour le moment", + "description": "Retrouvez toutes vos importations précédentes ici et téléchargez-les." + } + } + }, + + "profile": { + "name": "Profil", + "empty_state": { + "activity": { + "title": "Aucune activité pour le moment", + "description": "Commencez par créer une nouvelle tâche ! Ajoutez des détails et des propriétés à celle-ci. Explorez davantage Plane pour voir votre activité." + }, + "assigned": { + "title": "Aucune tâche assignée", + "description": "Les tâches qui vous sont assignées peuvent être suivies ici." + }, + "created": { + "title": "Aucune tâche créée", + "description": "Toutes les tâches que vous avez créées se trouvent ici. Suivez-les directement ici." + }, + "subscribed": { + "title": "Aucune tâche suivie", + "description": "Abonnez-vous aux tâches qui vous intéressent, suivez-les toutes ici." + } + } + }, + + "project_settings": { + "empty_state": { + "labels": { + "title": "Aucune étiquette pour le moment", + "description": "Créez des étiquettes pour organiser et filtrer les tâches de votre projet." + }, + "integerations": { + "title": "Aucune intégration configurée", + "description": "Configurez GitHub et d'autres intégrations pour synchroniser les tâches de votre projet." + }, + "estimates": { + "title": "Aucune estimation ajoutée", + "description": "Créez un ensemble d'estimations pour communiquer la quantité de travail par tâche." + } + } + }, + + "project_cycles": { + "empty_state": { + "general": { + "title": "Groupez et cadrez votre travail en cycles.", + "description": "Décomposez le travail en périodes définies, travaillez à rebours à partir de votre date limite pour fixer des échéances, et réalisez des progrès tangibles en équipe.", + "primary_button": { + "text": "Définir votre premier cycle", + "comic": { + "title": "Les cycles sont des périodes répétitives.", + "description": "Un sprint, une itération ou tout autre terme que vous utilisez pour le suivi hebdomadaire ou bi-hebdomadaire du travail est un cycle." + } + } + }, + "all": { + "title": "Aucun cycle", + "description": "Un cycle actif inclut toute période qui englobe la date d'aujourd'hui dans sa plage. Trouvez les progrès et les détails du cycle actif ici." + }, + "no_issues": { + "title": "Aucune tâche ajoutée au cycle", + "description": "Ajoutez ou créez des tâches que vous souhaitez cadencer et livrer dans ce cycle", + "primary_button": { + "text": "Créer une nouvelle tâche" + }, + "secondary_button": { + "text": "Ajouter une tâche existante" + } + }, + "active": { + "title": "Aucun cycle actif", + "description": "Un cycle actif inclut toute période qui englobe la date d'aujourd'hui dans sa plage. Trouvez les progrès et les détails du cycle actif ici." + }, + "completed": { + "title": "Aucune tâche dans le cycle", + "description": "Aucune tâche dans le cycle. Les tâches sont soit transférées, soit masquées. Pour voir les tâches masquées, si elles existent, mettez à jour vos propriétés d'affichage en conséquence." + } + } + }, "project_archived_no_cycles_empty_state_title": "Aucun cycle archivé pour le moment", "project_archived_no_cycles_empty_state_description": "Pour ranger votre projet, archivez les cycles terminés. Retrouvez-les ici une fois archivés.", @@ -551,7 +650,13 @@ "inbox_detail_empty_state_title": "Sélectionnez un problème pour voir ses détails.", - "workspace_draft_issues_empty_state_title": "Problèmes inachevés, et bientôt, des commentaires apparaîtront ici.", - "workspace_draft_issues_empty_state_description": "Pour essayer cela, commencez à ajouter un problème et laissez-le inachevé ou créez votre premier brouillon ci-dessous. 😉", - "workspace_draft_issues_empty_state_primary_button_text": "Créez votre premier brouillon" + "workspace_draft_issues": { + "empty_state": { + "title": "Les problèmes à moitié rédigés, et bientôt, les commentaires apparaîtront ici.", + "description": "Pour essayer cela, commencez à rédiger un problème et laissez-le en suspens ou créez votre premier brouillon ci-dessous. 😉", + "primary_button": { + "text": "Créez votre premier brouillon" + } + } + } } diff --git a/packages/i18n/src/locales/ja/translations.json b/packages/i18n/src/locales/ja/translations.json index 5b0c474e528..57bf6443ae8 100644 --- a/packages/i18n/src/locales/ja/translations.json +++ b/packages/i18n/src/locales/ja/translations.json @@ -38,7 +38,6 @@ "deactivate_account_description": "アカウントを無効化すると、そのアカウント内のすべてのデータとリソースが完全に削除され、復元することはできません。", "profile_settings": "プロフィール設定", "your_account": "アカウント", - "profile": "プロフィール", "security": "セキュリティ", "activity": "アクティビティ", "appearance": "アピアンス", @@ -154,7 +153,6 @@ "stay_ahead_of_blockers_description": "プロジェクト間の課題を見つけ、他のビューからは明らかでないサイクル間の依存関係を確認します。", "analytics": "分析", "workspace_invites": "ワークスペースの招待", - "workspace_settings": "ワークスペース設定", "enter_god_mode": "ゴッドモードに入る", "workspace_logo": "ワークスペースロゴ", "new_issue": "新しい問題", @@ -318,103 +316,204 @@ "loading_members": "メンバーを読み込んでいます...", "inbox": "受信箱", - "workspace_dashboard_empty_state_title": "プロジェクト、アクティビティ、メトリクスの概要", - "workspace_dashboard_empty_state_description": "Planeへようこそ。最初のプロジェクトを作成し、課題を追跡すると、このページが進捗を助けるスペースに変わります。管理者はチームの進捗を助ける項目も表示されます。", - "workspace_dashboard_empty_state_primary_button_text": "最初のプロジェクトを作成する", - "workspace_dashboard_empty_state_primary_button_comic_title": "Planeではすべてがプロジェクトから始まります", - "workspace_dashboard_empty_state_primary_button_comic_description": "プロジェクトは、製品のロードマップ、マーケティングキャンペーン、または新車の発売などです。", - - "workspace_analytics_empty_state_title": "進捗、作業負荷、割り当てを追跡する。傾向を見つけ、障害を取り除き、作業を迅速化する", - "workspace_analytics_empty_state_description": "スコープと需要、見積もり、スコープの増加を確認します。チームメンバーやチームごとのパフォーマンスを把握し、プロジェクトを予定通り進行させます。", - "workspace_analytics_empty_state_primary_button_text": "最初のプロジェクトを開始する", - "workspace_analytics_empty_state_primary_button_comic_title": "サイクル+モジュールで分析が最適化されます", - "workspace_analytics_empty_state_primary_button_comic_description": "最初に課題をサイクルにタイムボックス化し、可能であればサイクルを超える課題をモジュールにグループ化します。左のナビで両方をチェックしてください。", - - "workspace_projects_empty_state_title": "アクティブなプロジェクトがありません", - "workspace_projects_empty_state_description": "各プロジェクトを目標指向の作業の親として考えてください。プロジェクトは、ジョブ、サイクル、モジュールが存在し、同僚と一緒にその目標を達成するのに役立ちます。新しいプロジェクトを作成するか、アーカイブされたプロジェクトをフィルタリングしてください。", - "workspace_projects_empty_state_primary_button_text": "最初のプロジェクトを開始する", - "workspace_projects_empty_state_primary_button_comic_title": "Planeではすべてがプロジェクトから始まります", - "workspace_projects_empty_state_primary_button_comic_description": "プロジェクトは、製品のロードマップ、マーケティングキャンペーン、または新車の発売などです。", - - "workspace_all_issues_empty_state_title": "プロジェクトに課題がありません", - "workspace_all_issues_empty_state_description": "最初のプロジェクト完了!今度は作業を追跡可能な部分に分割して課題を作成しましょう。", - "workspace_all_issues_empty_state_primary_button_text": "新しい課題を作成する", - - "workspace_assigned_empty_state_title": "まだ課題がありません", - "workspace_assigned_empty_state_description": "あなたに割り当てられた課題をここから追跡できます。", - "workspace_assigned_empty_state_primary_button_text": "新しい課題を作成する", - - "workspace_created_empty_state_title": "まだ課題がありません", - "workspace_created_empty_state_description": "あなたが作成したすべての課題がここに集まります。ここで直接追跡してください。", - "workspace_created_empty_state_primary_button_text": "新しい課題を作成する", - - "workspace_subscribed_empty_state_title": "まだ課題がありません", - "workspace_subscribed_empty_state_description": "興味のある課題を購読し、すべてをここで追跡してください。", - - "workspace_custom_view_empty_state_title": "まだ課題がありません", - "workspace_custom_view_empty_state_description": "フィルターに適用された課題を追跡し、すべてをここで確認してください。", - - "workspace_project_not_found_empty_state_title": "そのようなプロジェクトは存在しません", - "workspace_project_not_found_empty_state_description": "課題を作成したり作業を管理したりするには、プロジェクトを作成するか、その一部になる必要があります。", - "workspace_project_not_found_empty_state_primary_button_text": "プロジェクトを作成する", - "workspace_project_not_found_empty_state_primary_button_comic_title": "Planeではすべてがプロジェクトから始まります", - "workspace_project_not_found_empty_state_primary_button_comic_description": "プロジェクトは、製品のロードマップ、マーケティングキャンペーン、または新車の発売などです。", - - "workspace_no_projects_empty_state_title": "プロジェクトがありません", - "workspace_no_projects_empty_state_description": "課題を作成したり作業を管理したりするには、プロジェクトを作成するか、その一部になる必要があります。", - "workspace_no_projects_empty_state_primary_button_text": "最初のプロジェクトを開始する", - "workspace_no_projects_empty_state_primary_button_comic_title": "Planeではすべてがプロジェクトから始まります", - "workspace_no_projects_empty_state_primary_button_comic_description": "プロジェクトは、製品のロードマップ、マーケティングキャンペーン、または新車の発売などです。", - - "workspace_settings_api_tokens_empty_state_title": "APIトークンが作成されていません", - "workspace_settings_api_tokens_empty_state_description": "Plane APIを使用して、Plane内のデータを外部システムと統合できます。トークンを作成して開始してください。", - - "workspace_settings_webhooks_empty_state_title": "Webhookが追加されていません", - "workspace_settings_webhooks_empty_state_description": "リアルタイム更新を受け取ったりアクションを自動化したりするためにWebhookを作成してください。", - - "workspace_settings_export_empty_state_title": "過去のエクスポートがありません", - "workspace_settings_export_empty_state_description": "エクスポートするたびに、ここにコピーが保存されます。", - - "workspace_settings_import_empty_state_title": "過去のインポートがありません", - "workspace_settings_import_empty_state_description": "過去のインポートをすべてここで確認し、ダウンロードできます。", - - "profile_activity_empty_state_title": "まだアクティビティがありません", - "profile_activity_empty_state_description": "新しい課題を作成して始めてください!詳細とプロパティを追加します。Planeの他の機能を探索して、アクティビティを確認してください。", - - "profile_assigned_empty_state_title": "あなたに割り当てられた課題がありません", - "profile_assigned_empty_state_description": "あなたに割り当てられた課題をここから追跡できます。", - - "profile_created_empty_state_title": "まだ課題がありません", - "profile_created_empty_state_description": "あなたが作成したすべての課題がここに集まります。ここで直接追跡してください。", - - "profile_subscribed_empty_state_title": "まだ課題がありません", - "profile_subscribed_empty_state_description": "興味のある課題を購読し、すべてをここで追跡してください。", - - "project_settings_labels_empty_state_title": "ラベルがまだありません", - "project_settings_labels_empty_state_description": "課題を整理してプロジェクト内でフィルタリングするためのラベルを作成してください。", - - "project_settings_integrations_empty_state_title": "統合が設定されていません", - "project_settings_integrations_empty_state_description": "GitHubや他の統合を設定して、プロジェクトの課題を同期してください。", - - "project_settings_estimate_empty_state_title": "見積もりがまだ追加されていません", - "project_settings_estimate_empty_state_description": "課題ごとの作業量を伝えるための見積もりを作成してください。", - - "project_cycles_empty_state_title": "サイクルで作業をグループ化してタイムボックス化する。", - "project_cycles_empty_state_description": "作業をタイムボックス化されたチャンクに分解し、プロジェクトの締め切りから逆算して日付を設定し、チームとして具体的な進捗を達成します。", - "project_cycles_empty_state_primary_button_text": "最初のサイクルを設定する", - "project_cycles_empty_state_primary_button_comic_title": "サイクルは反復的なタイムボックスです。", - "project_cycles_empty_state_primary_button_comic_description": "スプリント、イテレーション、または週次や隔週での作業追跡に使用する他の用語がサイクルです。", - - "project_cycle_no_issues_empty_state_title": "サイクルに課題が追加されていません", - "project_cycle_no_issues_empty_state_description": "タイムボックス化してこのサイクル内で達成したい課題を追加または作成してください", - "project_cycle_no_issues_empty_state_primary_button_text": "新しい課題を作成する", - "project_cycle_no_issues_empty_state_secondary_button_text": "既存の課題を追加する", - - "project_cycle_active_empty_state_title": "アクティブなサイクルはありません", - "project_cycle_active_empty_state_description": "アクティブなサイクルには、現在の日付が含まれる期間が含まれます。ここでアクティブなサイクルの進捗や詳細を確認できます。", - - "project_cycle_completed_no_issues_empty_state_title": "サイクルに課題がありません", - "project_cycle_completed_no_issues_empty_state_description": "サイクルに課題はありません。課題は移動されたか、非表示になっています。非表示の課題を確認するには、表示プロパティを更新してください。", + "workspace_dashboard": { + "empty_state": { + "title": "プロジェクト、アクティビティ、指標の概要", + "description": "Planeへようこそ!私たちはあなたを迎えることができて嬉しいです。最初のプロジェクトを作成してタスクを追跡し、このページが進捗を助けるスペースに変わります。管理者は、チームを前進させるための要素も見ることができます。", + "primary_button": { + "text": "最初のプロジェクトを作成", + "comic": { + "title": "すべてはPlaneでのプロジェクトから始まります", + "description": "プロジェクトは製品ロードマップ、マーケティングキャンペーン、新車の発売など、さまざまなものになります。" + } + } + } + }, + + "workspace_analytics": { + "empty_state": { + "title": "進捗、作業負荷、割り当てを追跡します。傾向を見つけ、障害を取り除き、作業を加速させます", + "description": "需要に対するスコープ、見積もり、目標の進展を視覚化します。メンバーやチームごとのパフォーマンスを確認し、プロジェクトが期限内に進むことを確認します。", + "primary_button": { + "text": "最初のプロジェクトを開始", + "comic": { + "title": "分析はサイクル+モジュールでより効果的に機能します", + "description": "まず、タスクをサイクルにフレーム化し、可能であれば複数のサイクルにまたがるタスクをモジュールにグループ化します。左側のナビゲーションで確認してください。" + } + } + } + }, + + "workspace_projects": { + "empty_state": { + "general": { + "title": "アクティブなプロジェクトがありません", + "description": "各プロジェクトは目標志向の作業の親と見なされます。プロジェクトはタスク、サイクル、モジュールが存在する場所であり、同僚とともに目標を達成するのに役立ちます。新しいプロジェクトを作成するか、アーカイブされたプロジェクトをフィルタリングしてください。", + "primary_button": { + "text": "最初のプロジェクトを開始", + "comic": { + "title": "すべてはPlaneでのプロジェクトから始まります", + "description": "プロジェクトは製品ロードマップ、マーケティングキャンペーン、新車の発売など、さまざまなものになります。" + } + } + }, + "not_found": { + "title": "一致するプロジェクトがありません", + "description": "タスクを作成したり作業を管理するには、プロジェクトを作成するか、その一部である必要があります。", + "primary_button": { + "text": "プロジェクトを作成", + "comic": { + "title": "すべてはPlaneでのプロジェクトから始まります", + "description": "プロジェクトは製品ロードマップ、マーケティングキャンペーン、新車の発売など、さまざまなものになります。" + } + } + }, + "no_projects": { + "title": "プロジェクトがありません", + "description": "タスクを作成したり作業を管理するには、プロジェクトを作成するか、その一部である必要があります。", + "primary_button": { + "text": "最初のプロジェクトを開始", + "comic": { + "title": "すべてはPlaneでのプロジェクトから始まります", + "description": "プロジェクトは製品ロードマップ、マーケティングキャンペーン、新車の発売など、さまざまなものになります。" + } + } + } + } + }, + + "workspace_issues": { + "empty_state": { + "all_issues": { + "title": "プロジェクトにタスクがありません", + "description": "最初のプロジェクトが完了しました!次に、追跡可能なチャンクに分割してタスクを作成します。始めましょう!", + "primary_button": { + "text": "新しいタスクを作成" + } + }, + "assigned": { + "title": "割り当てられたタスクがありません", + "description": "割り当てられたタスクをここで追跡できます。", + "primary_button": { + "text": "新しいタスクを作成" + } + }, + "created": { + "title": "作成されたタスクがありません", + "description": "作成したすべてのタスクはここにあります。直接ここで追跡してください。", + "primary_button": { + "text": "新しいタスクを作成" + } + }, + "subscribed": { + "title": "フォローしているタスクがありません", + "description": "興味のあるタスクをフォローして、すべてここで追跡してください。" + }, + "custom_view": { + "title": "タスクが見つかりません", + "description": "フィルタに一致するタスクがここに表示されます。すべてここで追跡してください。" + } + } + }, + + "workspace_settings": { + "name": "ワークスペース設定", + "empty_state": { + "api_tokens": { + "title": "APIトークンが作成されていません", + "description": "Plane APIは、外部システムでPlaneデータを統合するために使用できます。トークンを作成して始めましょう。" + }, + "webhooks": { + "title": "Webhookが追加されていません", + "description": "リアルタイム更新を受け取り、アクションを自動化するためにWebhookを作成します。" + }, + "exports": { + "title": "エクスポートはまだありません", + "description": "エクスポートするたびに、コピーがここにも参照用として利用可能になります。" + }, + "imports": { + "title": "インポートはまだありません", + "description": "過去のインポート履歴をすべてここで確認し、ダウンロードできます。" + } + } + }, + + "profile": { + "name": "プロフィール", + "empty_state": { + "activity": { + "title": "まだアクティビティがありません", + "description": "新しいタスクを作成することから始めましょう!詳細やプロパティを追加してください。Planeをさらに探索して、アクティビティを確認してください。" + }, + "assigned": { + "title": "割り当てられたタスクがありません", + "description": "割り当てられたタスクをここで追跡できます。" + }, + "created": { + "title": "作成されたタスクがありません", + "description": "作成したすべてのタスクはここにあります。直接ここで追跡してください。" + }, + "subscribed": { + "title": "フォローしているタスクがありません", + "description": "興味のあるタスクをフォローして、すべてここで追跡してください。" + } + } + }, + + "project_settings": { + "empty_state": { + "labels": { + "title": "ラベルがありません", + "description": "ラベルを作成して、プロジェクトのタスクを整理し、フィルタリングします。" + }, + "integerations": { + "title": "設定済みの統合がありません", + "description": "GitHubやその他の統合を設定して、プロジェクトのタスクを同期します。" + }, + "estimates": { + "title": "見積もりが追加されていません", + "description": "タスクごとの作業量を伝えるために、見積もりセットを作成します。" + } + } + }, + + "project_cycles": { + "empty_state": { + "general": { + "title": "作業をサイクルにまとめ、フレーム化します。", + "description": "作業を定義された期間に分割し、期限から逆算して締め切りを設定し、チームで具体的な進捗を達成します。", + "primary_button": { + "text": "最初のサイクルを設定", + "comic": { + "title": "サイクルは繰り返し期間です。", + "description": "スプリント、イテレーション、または週次・隔週の作業追跡に使用するその他の用語がサイクルです。" + } + } + }, + "all": { + "title": "サイクルがありません", + "description": "アクティブなサイクルは、今日の日付を範囲内に含む期間を指します。アクティブなサイクルの進捗と詳細をここで確認してください。" + }, + "no_issues": { + "title": "サイクルに追加されたタスクがありません", + "description": "このサイクル内でタイムフレーム化し、配信したいタスクを追加または作成してください。", + "primary_button": { + "text": "新しいタスクを作成" + }, + "secondary_button": { + "text": "既存のタスクを追加" + } + }, + "active": { + "title": "アクティブなサイクルがありません", + "description": "アクティブなサイクルは、今日の日付を範囲内に含む期間を指します。アクティブなサイクルの進捗と詳細をここで確認してください。" + }, + "completed": { + "title": "サイクルにタスクがありません", + "description": "サイクルにタスクがありません。タスクは移行されるか、非表示になっています。存在する場合は、表示プロパティを更新して非表示のタスクを確認してください。" + } + } + }, "project_archived_no_cycles_empty_state_title": "まだアーカイブされたサイクルはありません", "project_archived_no_cycles_empty_state_description": "プロジェクトを整理するために、完了したサイクルをアーカイブします。一度アーカイブされると、ここに表示されます。", @@ -551,7 +650,13 @@ "inbox_detail_empty_state_title": "課題を選択してその詳細を表示してください。", - "workspace_draft_issues_empty_state_title": "未完成の課題、そしてすぐにコメントがここに表示されます。", - "workspace_draft_issues_empty_state_description": "これを試すために、課題を追加して途中で中断するか、下に最初のドラフトを作成してください。😉", - "workspace_draft_issues_empty_state_primary_button_text": "最初のドラフトを作成" + "workspace_draft_issues": { + "empty_state": { + "title": "書きかけの課題や、もうすぐコメントもここに表示されます。", + "description": "これを試すには、課題の作成を始めて途中で中断するか、下に最初の下書きを作成してください。😉", + "primary_button": { + "text": "最初の下書きを作成" + } + } + } } diff --git a/web/app/profile/notifications/page.tsx b/web/app/profile/notifications/page.tsx index cbdcd147d73..6eb27954aec 100644 --- a/web/app/profile/notifications/page.tsx +++ b/web/app/profile/notifications/page.tsx @@ -25,7 +25,7 @@ export default function ProfileNotificationPage() { return ( <> - + { return ( <> - + diff --git a/web/core/components/issues/workspace-draft/empty-state.tsx b/web/core/components/issues/workspace-draft/empty-state.tsx index 34d98a3ffc0..1c0b51fbb1d 100644 --- a/web/core/components/issues/workspace-draft/empty-state.tsx +++ b/web/core/components/issues/workspace-draft/empty-state.tsx @@ -34,11 +34,11 @@ export const WorkspaceDraftEmptyState: FC = observer(() => { />
{ setIsDraftIssueModalOpen(true); }, diff --git a/web/core/components/workspace/sidebar/dropdown.tsx b/web/core/components/workspace/sidebar/dropdown.tsx index 93eb92bc08e..3aac24254e4 100644 --- a/web/core/components/workspace/sidebar/dropdown.tsx +++ b/web/core/components/workspace/sidebar/dropdown.tsx @@ -41,7 +41,7 @@ export const SidebarDropdown = observer(() => { }, { key: "settings", - name: t("workspace_settings"), + name: t("workspace_settings.name"), href: `/${workspaceSlug}/settings`, icon: Settings, access: [EUserPermissions.ADMIN], diff --git a/web/core/constants/empty-state.ts b/web/core/constants/empty-state.ts index 7ba5a19255c..63f2eecd46d 100644 --- a/web/core/constants/empty-state.ts +++ b/web/core/constants/empty-state.ts @@ -113,15 +113,6 @@ export enum EmptyStateType { INBOX_SIDEBAR_CLOSED_TAB = "inbox-sidebar-closed-tab", INBOX_SIDEBAR_FILTER_EMPTY_STATE = "inbox-sidebar-filter-empty-state", INBOX_DETAIL_EMPTY_STATE = "inbox-detail-empty-state", - - WORKSPACE_DRAFT_ISSUES = "workspace-draft-issues", - - PROJECT_NO_EPICS = "project-no-epics", - // Teams - TEAM_NO_ISSUES = "team-no-issues", - TEAM_EMPTY_FILTER = "team-empty-filter", - TEAM_VIEW = "team-view", - TEAM_PAGE = "team-page", } const emptyStateDetails = { @@ -838,80 +829,6 @@ const emptyStateDetails = { title: "Select an issue to view its details.", path: "/empty-state/intake/issue-detail", }, - [EmptyStateType.WORKSPACE_DRAFT_ISSUES]: { - key: EmptyStateType.WORKSPACE_DRAFT_ISSUES, - title: "Half-written issues, and soon, comments will show up here.", - description: "To try this out, start adding an issue and leave it mid-way or create your first draft below. 😉", - path: "/empty-state/workspace-draft/issue", - primaryButton: { - text: "Create your first draft", - }, - accessType: "workspace", - access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER], - }, - [EmptyStateType.PROJECT_NO_EPICS]: { - key: EmptyStateType.PROJECT_NO_EPICS, - title: "Create an epic and assign it to someone, even yourself", - description: - "For larger bodies of work that span several cycles and can live across modules, create an epic. Link issues and sub-issues in a project to an epic and jump into an issue from the overview.", - path: "/empty-state/onboarding/issues", - primaryButton: { - text: "Create an Epic", - }, - accessType: "project", - access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER], - }, - // Teams - [EmptyStateType.TEAM_NO_ISSUES]: { - key: EmptyStateType.TEAM_NO_ISSUES, - title: "Create an issue in your team projects and assign it to someone, even yourself", - description: - "Think of issues as jobs, tasks, work, or JTBD. Which we like. An issue and its sub-issues are usually time-based actionables assigned to members of your team. Your team creates, assigns, and completes issues to move your project towards its goal.", - path: "/empty-state/onboarding/issues", - primaryButton: { - text: "Create your first issue", - comicBox: { - title: "Issues are building blocks in Plane.", - description: - "Redesign the Plane UI, Rebrand the company, or Launch the new fuel injection system are examples of issues that likely have sub-issues.", - }, - }, - accessType: "workspace", - access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER], - }, - [EmptyStateType.TEAM_EMPTY_FILTER]: { - key: EmptyStateType.TEAM_EMPTY_FILTER, - title: "No issues found matching the filters applied", - path: "/empty-state/empty-filters/", - secondaryButton: { - text: "Clear all filters", - }, - accessType: "workspace", - access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER], - }, - [EmptyStateType.TEAM_VIEW]: { - key: EmptyStateType.TEAM_VIEW, - title: "Save filtered views for your team. Create as many as you need", - description: - "Views are a set of saved filters that you use frequently or want easy access to. All your colleagues in a team can see everyone’s views and choose whichever suits their needs best.", - path: "/empty-state/onboarding/views", - primaryButton: { - text: "Create your first view", - comicBox: { - title: "Views work atop Issue properties.", - description: "You can create a view from here with as many properties as filters as you see fit.", - }, - }, - accessType: "workspace", - access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER], - }, - [EmptyStateType.TEAM_PAGE]: { - key: EmptyStateType.TEAM_PAGE, - title: "Team pages are coming soon!", - description: - "Write a note, a doc, or a full knowledge base. Get Galileo, Plane’s AI assistant, to help you get started. Pages are thoughts potting space in Plane. Take down meeting notes, format them easily, embed issues, lay them out using a library of components, and keep them all in your project’s context. To make short work of any doc, invoke Galileo, Plane’s AI, with a shortcut or the click of a button.", - path: "/empty-state/onboarding/pages", - }, } as const; export const EMPTY_STATE_DETAILS: Record = emptyStateDetails; From 7f6ad5f20c0d18618d495cf0692ce3f2766a668d Mon Sep 17 00:00:00 2001 From: Prateek Shourya Date: Thu, 16 Jan 2025 20:16:26 +0530 Subject: [PATCH 09/26] chore: inbox empty states --- .../i18n/src/locales/en/translations.json | 31 +++++++----- .../i18n/src/locales/es/translations.json | 31 +++++++----- .../i18n/src/locales/fr/translations.json | 31 +++++++----- .../i18n/src/locales/ja/translations.json | 31 +++++++----- web/core/components/inbox/root.tsx | 13 +++-- web/core/components/inbox/sidebar/root.tsx | 47 +++++++++++++------ .../workspace/sidebar/user-menu.tsx | 2 +- web/core/constants/empty-state.ts | 30 +----------- 8 files changed, 123 insertions(+), 93 deletions(-) diff --git a/packages/i18n/src/locales/en/translations.json b/packages/i18n/src/locales/en/translations.json index 6df36c44b41..292aca1987f 100644 --- a/packages/i18n/src/locales/en/translations.json +++ b/packages/i18n/src/locales/en/translations.json @@ -42,7 +42,6 @@ "activity": "Activity", "appearance": "Appearance", "notifications": "Notifications", - "inbox": "Inbox", "workspaces": "Workspaces", "create_workspace": "Create workspace", "invitations": "Invitations", @@ -636,16 +635,26 @@ "disabled_project_view_empty_state_description": "Views are a set of saved filters that you use frequently or want easy access to. All your colleagues in a project can see everyone's views and choose whichever suits their needs best. Enable views in the project settings to start using them.", "disabled_project_view_empty_state_primary_button_text": "Manage features", - "inbox_sidebar_open_tab_empty_state_title": "No open issues", - "inbox_sidebar_open_tab_empty_state_description": "Find open issues here. Create new issue.", - - "inbox_sidebar_closed_tab_empty_state_title": "No closed issues", - "inbox_sidebar_closed_tab_empty_state_description": "All the issues whether accepted or declined can be found here.", - - "inbox_sidebar_filter_empty_state_title": "No matching issues", - "inbox_sidebar_filter_empty_state_description": "No issue matches filter applied in intake. Create a new issue.", - - "inbox_detail_empty_state_title": "Select an issue to view its details.", + "inbox": { + "name": "Inbox", + "empty_state": { + "sidebar_open_tab": { + "title": "No open issues", + "description": "Find open issues here. Create new issue." + }, + "sidebar_closed_tab": { + "title": "No closed issues", + "description": "All the issues whether accepted or declined can be found here." + }, + "sidebar_filter": { + "title": "No matching issues", + "description": "No issue matches filter applied in intake. Create a new issue." + }, + "detail": { + "title": "Select an issue to view its details." + } + } + }, "workspace_draft_issues": { "empty_state": { diff --git a/packages/i18n/src/locales/es/translations.json b/packages/i18n/src/locales/es/translations.json index 9e6260c6a6d..e9d017d0da3 100644 --- a/packages/i18n/src/locales/es/translations.json +++ b/packages/i18n/src/locales/es/translations.json @@ -313,7 +313,6 @@ "remove_parent_issue": "Eliminar problema padre", "add_parent": "Agregar padre", "loading_members": "Cargando miembros...", - "inbox": "bandeja de entrada", "workspace_dashboard": { "empty_state": { @@ -638,16 +637,26 @@ "disabled_project_view_empty_state_description": "Las vistas son un conjunto de filtros guardados que usas con frecuencia o que deseas tener acceso fácilmente. Todos tus compañeros de proyecto pueden ver las vistas de todos y elegir la que mejor se adapte a sus necesidades. Habilita las vistas en la configuración del proyecto para comenzar a usarlas.", "disabled_project_view_empty_state_primary_button_text": "Gestionar características", - "inbox_sidebar_open_tab_empty_state_title": "No hay problemas abiertos", - "inbox_sidebar_open_tab_empty_state_description": "Encuentra los problemas abiertos aquí. Crea un nuevo problema.", - - "inbox_sidebar_closed_tab_empty_state_title": "No hay problemas cerrados", - "inbox_sidebar_closed_tab_empty_state_description": "Aquí puedes encontrar todos los problemas, ya sean aceptados o rechazados.", - - "inbox_sidebar_filter_empty_state_title": "No hay problemas que coincidan", - "inbox_sidebar_filter_empty_state_description": "Ningún problema coincide con el filtro aplicado en la recepción. Crea un nuevo problema.", - - "inbox_detail_empty_state_title": "Selecciona un problema para ver sus detalles.", + "inbox": { + "name": "Bandeja de entrada", + "empty_state": { + "sidebar_open_tab": { + "title": "No hay problemas abiertos", + "description": "Encuentra los problemas abiertos aquí. Crea un nuevo problema." + }, + "sidebar_closed_tab": { + "title": "No hay problemas cerrados", + "description": "Todos los problemas, ya sean aceptados o rechazados, se pueden encontrar aquí." + }, + "sidebar_filter": { + "title": "No hay problemas coincidentes", + "description": "Ningún problema coincide con el filtro aplicado en la entrada. Crea un nuevo problema." + }, + "detail": { + "title": "Selecciona un problema para ver sus detalles." + } + } + }, "workspace_draft_issues": { "empty_state": { diff --git a/packages/i18n/src/locales/fr/translations.json b/packages/i18n/src/locales/fr/translations.json index 25900bca010..fde720b4cfa 100644 --- a/packages/i18n/src/locales/fr/translations.json +++ b/packages/i18n/src/locales/fr/translations.json @@ -314,7 +314,6 @@ "remove_parent_issue": "Supprimer le problème parent", "add_parent": "Ajouter un parent", "loading_members": "Chargement des membres...", - "inbox": "Boîte de réception", "workspace_dashboard": { "empty_state": { @@ -639,16 +638,26 @@ "disabled_project_view_empty_state_description": "Les vues sont un ensemble de filtres enregistrés que vous utilisez fréquemment ou auxquels vous voulez un accès facile. Tous vos collègues du projet peuvent voir les vues de chacun et choisir celle qui correspond le mieux à leurs besoins. Activez les vues dans les paramètres du projet pour commencer à les utiliser.", "disabled_project_view_empty_state_primary_button_text": "Gérer les fonctionnalités", - "inbox_sidebar_open_tab_empty_state_title": "Pas de problèmes ouverts", - "inbox_sidebar_open_tab_empty_state_description": "Trouvez ici les problèmes ouverts. Créez un nouveau problème.", - - "inbox_sidebar_closed_tab_empty_state_title": "Pas de problèmes fermés", - "inbox_sidebar_closed_tab_empty_state_description": "Tous les problèmes, qu'ils soient acceptés ou rejetés, peuvent être trouvés ici.", - - "inbox_sidebar_filter_empty_state_title": "Aucun problème ne correspond", - "inbox_sidebar_filter_empty_state_description": "Aucun problème ne correspond au filtre appliqué dans la réception. Créez un nouveau problème.", - - "inbox_detail_empty_state_title": "Sélectionnez un problème pour voir ses détails.", + "inbox": { + "name": "Boîte de réception", + "empty_state": { + "sidebar_open_tab": { + "title": "Aucun problème ouvert", + "description": "Trouvez ici les problèmes ouverts. Créez un nouveau problème." + }, + "sidebar_closed_tab": { + "title": "Aucun problème fermé", + "description": "Tous les problèmes, qu'ils soient acceptés ou refusés, se trouvent ici." + }, + "sidebar_filter": { + "title": "Aucun problème correspondant", + "description": "Aucun problème ne correspond au filtre appliqué dans l'entrée. Créez un nouveau problème." + }, + "detail": { + "title": "Sélectionnez un problème pour voir ses détails." + } + } + }, "workspace_draft_issues": { "empty_state": { diff --git a/packages/i18n/src/locales/ja/translations.json b/packages/i18n/src/locales/ja/translations.json index 57bf6443ae8..dd1a456d1c9 100644 --- a/packages/i18n/src/locales/ja/translations.json +++ b/packages/i18n/src/locales/ja/translations.json @@ -314,7 +314,6 @@ "remove_parent_issue": "親問題を削除", "add_parent": "親問題を追加", "loading_members": "メンバーを読み込んでいます...", - "inbox": "受信箱", "workspace_dashboard": { "empty_state": { @@ -639,16 +638,26 @@ "disabled_project_view_empty_state_description": "ビューは頻繁に使用するフィルターのセットで、簡単にアクセスできるようにしたいものです。プロジェクト内のすべての同僚は、他の人のビューを見て、ニーズに合ったものを選択できます。プロジェクト設定からビューを有効にして、使用を開始してください。", "disabled_project_view_empty_state_primary_button_text": "機能を管理", - "inbox_sidebar_open_tab_empty_state_title": "開いている課題はありません", - "inbox_sidebar_open_tab_empty_state_description": "ここで開いている課題を見つけてください。新しい課題を作成します。", - - "inbox_sidebar_closed_tab_empty_state_title": "閉じた課題はありません", - "inbox_sidebar_closed_tab_empty_state_description": "すべての課題は、承認されたものも拒否されたものもここで見つけることができます。", - - "inbox_sidebar_filter_empty_state_title": "一致する課題はありません", - "inbox_sidebar_filter_empty_state_description": "インテークで適用したフィルターに一致する課題はありません。新しい課題を作成してください。", - - "inbox_detail_empty_state_title": "課題を選択してその詳細を表示してください。", + "inbox": { + "name": "受信トレイ", + "empty_state": { + "sidebar_open_tab": { + "title": "未解決の課題はありません", + "description": "ここに未解決の課題が表示されます。新しい課題を作成してください。" + }, + "sidebar_closed_tab": { + "title": "完了した課題はありません", + "description": "受け入れ済みまたは却下済みのすべての課題がここに表示されます。" + }, + "sidebar_filter": { + "title": "一致する課題はありません", + "description": "入力で適用されたフィルターに一致する課題はありません。新しい課題を作成してください。" + }, + "detail": { + "title": "詳細を表示するには課題を選択してください。" + } + } + }, "workspace_draft_issues": { "empty_state": { diff --git a/web/core/components/inbox/root.tsx b/web/core/components/inbox/root.tsx index 5d5617bb394..cea33743e6a 100644 --- a/web/core/components/inbox/root.tsx +++ b/web/core/components/inbox/root.tsx @@ -1,18 +1,19 @@ import { FC, useEffect, useState } from "react"; import { observer } from "mobx-react"; import { PanelLeft } from "lucide-react"; +// plane imports +import { useTranslation } from "@plane/i18n"; import { Intake } from "@plane/ui"; // components -import { EmptyState } from "@/components/empty-state"; +import { SimpleEmptyState } from "@/components/empty-state"; import { InboxSidebar, InboxContentRoot } from "@/components/inbox"; import { InboxLayoutLoader } from "@/components/ui"; -// constants -import { EmptyStateType } from "@/constants/empty-state"; // helpers import { cn } from "@/helpers/common.helper"; import { EInboxIssueCurrentTab } from "@/helpers/inbox.helper"; // hooks import { useProjectInbox } from "@/hooks/store"; +import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; type TInboxIssueRoot = { workspaceSlug: string; @@ -26,8 +27,12 @@ export const InboxIssueRoot: FC = observer((props) => { const { workspaceSlug, projectId, inboxIssueId, inboxAccessible, navigationTab } = props; // states const [isMobileSidebar, setIsMobileSidebar] = useState(true); + // plane hooks + const { t } = useTranslation(); // hooks const { loader, error, currentTab, handleCurrentTab, fetchInboxIssues } = useProjectInbox(); + // derived values + const resolvedPath = useResolvedAssetPath({ basePath: "/empty-state/intake/issue-detail" }); useEffect(() => { if (!inboxAccessible || !workspaceSlug || !projectId) return; @@ -96,7 +101,7 @@ export const InboxIssueRoot: FC = observer((props) => { /> ) : (
- +
)}
diff --git a/web/core/components/inbox/sidebar/root.tsx b/web/core/components/inbox/sidebar/root.tsx index b8c86e0dee5..ea85b5dd4b6 100644 --- a/web/core/components/inbox/sidebar/root.tsx +++ b/web/core/components/inbox/sidebar/root.tsx @@ -2,14 +2,14 @@ import { FC, useCallback, useEffect, useRef, useState } from "react"; import { observer } from "mobx-react"; +// plane imports +import { useTranslation } from "@plane/i18n"; import { TInboxIssueCurrentTab } from "@plane/types"; import { Header, Loader, EHeaderVariant } from "@plane/ui"; // components -import { EmptyState } from "@/components/empty-state"; +import { SimpleEmptyState } from "@/components/empty-state"; import { FiltersRoot, InboxIssueAppliedFilters, InboxIssueList } from "@/components/inbox"; import { InboxSidebarLoader } from "@/components/ui"; -// constants -import { EmptyStateType } from "@/constants/empty-state"; // helpers import { cn } from "@/helpers/common.helper"; import { EInboxIssueCurrentTab } from "@/helpers/inbox.helper"; @@ -17,6 +17,7 @@ import { EInboxIssueCurrentTab } from "@/helpers/inbox.helper"; import { useProject, useProjectInbox } from "@/hooks/store"; import { useAppRouter } from "@/hooks/use-app-router"; import { useIntersectionObserver } from "@/hooks/use-intersection-observer"; +import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; type IInboxSidebarProps = { workspaceSlug: string; @@ -38,9 +39,13 @@ const tabNavigationOptions: { key: TInboxIssueCurrentTab; label: string }[] = [ export const InboxSidebar: FC = observer((props) => { const { workspaceSlug, projectId, inboxIssueId, setIsMobileSidebar } = props; + // router + const router = useAppRouter(); // ref const containerRef = useRef(null); const [elementRef, setElementRef] = useState(null); + // plane hooks + const { t } = useTranslation(); // store const { currentProjectDetails } = useProject(); const { @@ -52,8 +57,11 @@ export const InboxSidebar: FC = observer((props) => { fetchInboxPaginationIssues, getAppliedFiltersCount, } = useProjectInbox(); - - const router = useAppRouter(); + // derived values + const sidebarAssetPath = useResolvedAssetPath({ basePath: "/empty-state/intake/intake-issue" }); + const sidebarFilterAssetPath = useResolvedAssetPath({ + basePath: "/empty-state/intake/filter-issue", + }); const fetchNextPages = useCallback(() => { if (!workspaceSlug || !projectId) return; @@ -128,16 +136,25 @@ export const InboxSidebar: FC = observer((props) => { /> ) : (
- 0 - ? EmptyStateType.INBOX_SIDEBAR_FILTER_EMPTY_STATE - : currentTab === EInboxIssueCurrentTab.OPEN - ? EmptyStateType.INBOX_SIDEBAR_OPEN_TAB - : EmptyStateType.INBOX_SIDEBAR_CLOSED_TAB - } - layout="screen-simple" - /> + {getAppliedFiltersCount > 0 ? ( + + ) : currentTab === EInboxIssueCurrentTab.OPEN ? ( + + ) : ( + + )}
)}
diff --git a/web/core/components/workspace/sidebar/user-menu.tsx b/web/core/components/workspace/sidebar/user-menu.tsx index e412fc7b65a..089d26c69e6 100644 --- a/web/core/components/workspace/sidebar/user-menu.tsx +++ b/web/core/components/workspace/sidebar/user-menu.tsx @@ -37,7 +37,7 @@ export const SidebarUserMenu = observer(() => { }, { key: "notifications", - labelTranslationKey: "inbox", + labelTranslationKey: "inbox.name", href: `/${workspaceSlug.toString()}/notifications/`, access: [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER, EUserWorkspaceRoles.GUEST], Icon: Inbox, diff --git a/web/core/constants/empty-state.ts b/web/core/constants/empty-state.ts index 63f2eecd46d..a0cd526781b 100644 --- a/web/core/constants/empty-state.ts +++ b/web/core/constants/empty-state.ts @@ -108,11 +108,6 @@ export enum EmptyStateType { DISABLED_PROJECT_MODULE = "disabled-project-module", DISABLED_PROJECT_VIEW = "disabled-project-view", DISABLED_PROJECT_PAGE = "disabled-project-page", - - INBOX_SIDEBAR_OPEN_TAB = "inbox-sidebar-open-tab", - INBOX_SIDEBAR_CLOSED_TAB = "inbox-sidebar-closed-tab", - INBOX_SIDEBAR_FILTER_EMPTY_STATE = "inbox-sidebar-filter-empty-state", - INBOX_DETAIL_EMPTY_STATE = "inbox-detail-empty-state", } const emptyStateDetails = { @@ -661,7 +656,7 @@ const emptyStateDetails = { }, [EmptyStateType.NOTIFICATION_DETAIL_EMPTY_STATE]: { - key: EmptyStateType.INBOX_DETAIL_EMPTY_STATE, + key: EmptyStateType.NOTIFICATION_DETAIL_EMPTY_STATE, title: "Select to view details.", path: "/empty-state/intake/issue-detail", }, @@ -806,29 +801,6 @@ const emptyStateDetails = { text: "Manage features", }, }, - [EmptyStateType.INBOX_SIDEBAR_OPEN_TAB]: { - key: EmptyStateType.INBOX_SIDEBAR_OPEN_TAB, - title: "No open issues", - description: "Find open issues here. Create new issue.", - path: "/empty-state/intake/intake-issue", - }, - [EmptyStateType.INBOX_SIDEBAR_CLOSED_TAB]: { - key: EmptyStateType.INBOX_SIDEBAR_CLOSED_TAB, - title: "No closed issues", - description: "All the issues whether accepted or \n declined can be found here.", - path: "/empty-state/intake/intake-issue", - }, - [EmptyStateType.INBOX_SIDEBAR_FILTER_EMPTY_STATE]: { - key: EmptyStateType.INBOX_SIDEBAR_FILTER_EMPTY_STATE, - title: "No matching issues", - description: "No issue matches filter applied in intake. \n Create a new issue.", - path: "/empty-state/intake/filter-issue", - }, - [EmptyStateType.INBOX_DETAIL_EMPTY_STATE]: { - key: EmptyStateType.INBOX_DETAIL_EMPTY_STATE, - title: "Select an issue to view its details.", - path: "/empty-state/intake/issue-detail", - }, } as const; export const EMPTY_STATE_DETAILS: Record = emptyStateDetails; From a09271948d1bbbc6aa5383bc69db735c3fa629f8 Mon Sep 17 00:00:00 2001 From: Prateek Shourya Date: Thu, 16 Jan 2025 21:20:12 +0530 Subject: [PATCH 10/26] chore: disabled project features empty state --- .../i18n/src/locales/en/translations.json | 58 +++++++++++------ .../i18n/src/locales/es/translations.json | 58 +++++++++++------ .../i18n/src/locales/fr/translations.json | 58 +++++++++++------ .../i18n/src/locales/ja/translations.json | 58 +++++++++++------ .../[projectId]/cycles/(list)/page.tsx | 30 +++++++-- .../(detail)/[projectId]/inbox/page.tsx | 35 +++++++--- .../[projectId]/modules/(list)/page.tsx | 31 +++++++-- .../[projectId]/pages/(list)/page.tsx | 32 ++++++--- .../[projectId]/views/(list)/page.tsx | 29 +++++++-- web/core/constants/empty-state.tsx | 65 ------------------- 10 files changed, 276 insertions(+), 178 deletions(-) diff --git a/packages/i18n/src/locales/en/translations.json b/packages/i18n/src/locales/en/translations.json index 292aca1987f..83a3396b78e 100644 --- a/packages/i18n/src/locales/en/translations.json +++ b/packages/i18n/src/locales/en/translations.json @@ -615,25 +615,45 @@ "workspace_active_cycles_empty_state_title": "No active cycles", "workspace_active_cycles_empty_state_description": "Cycles of your projects that includes any period that encompasses today's date within its range. Find the progress and details of all your active cycle here.", - "disabled_project_inbox_empty_state_title": "Intake is not enabled for the project.", - "disabled_project_inbox_empty_state_description": "Intake helps you manage incoming requests to your project and add them as issues in your workflow. Enable intake from project settings to manage requests.", - "disabled_project_inbox_empty_state_primary_button_text": "Manage features", - - "disabled_project_cycle_empty_state_title": "Cycles is not enabled for this project.", - "disabled_project_cycle_empty_state_description": "Break work down by timeboxed chunks, work backwards from your project deadline to set dates, and make tangible progress as a team. Enable the cycles feature for your project to start using them.", - "disabled_project_cycle_empty_state_primary_button_text": "Manage features", - - "disabled_project_module_empty_state_title": "Modules are not enabled for the project.", - "disabled_project_module_empty_state_description": "A group of issues that belong to a logical, hierarchical parent form a module. Think of them as a way to track work by project milestones. Enable modules from project settings.", - "disabled_project_module_empty_state_primary_button_text": "Manage features", - - "disabled_project_page_empty_state_title": "Pages are not enabled for the project.", - "disabled_project_page_empty_state_description": "Pages are thought spotting space in Plane. Take down meeting notes, format them easily, embed issues, lay them out using a library of components, and keep them all in your project's context. Enable the pages feature to start creating them in your project.", - "disabled_project_page_empty_state_primary_button_text": "Manage features", - - "disabled_project_view_empty_state_title": "Views is not enabled for this project.", - "disabled_project_view_empty_state_description": "Views are a set of saved filters that you use frequently or want easy access to. All your colleagues in a project can see everyone's views and choose whichever suits their needs best. Enable views in the project settings to start using them.", - "disabled_project_view_empty_state_primary_button_text": "Manage features", + "disabled_project": { + "empty_state": { + "inbox": { + "title": "Intake is not enabled for the project.", + "description": "Intake helps you manage incoming requests to your project and add them as issues in your workflow. Enable intake from project settings to manage requests.", + "primary_button": { + "text": "Manage features" + } + }, + "cycle": { + "title": "Cycles is not enabled for this project.", + "description": "Break work down by timeboxed chunks, work backwards from your project deadline to set dates, and make tangible progress as a team. Enable the cycles feature for your project to start using them.", + "primary_button": { + "text": "Manage features" + } + }, + "module": { + "title": "Modules are not enabled for the project.", + "description": "Modules are the building blocks of your project. Enable modules from project settings to start using them.", + "primary_button": { + "text": "Manage features" + } + }, + "page": { + "title": "Pages are not enabled for the project.", + "description": "Pages are the building blocks of your project. Enable pages from project settings to start using them.", + "primary_button": { + "text": "Manage features" + } + }, + "view": { + "title": "Views are not enabled for the project.", + "description": "Views are the building blocks of your project. Enable views from project settings to start using them.", + "primary_button": { + "text": "Manage features" + } + } + } + }, "inbox": { "name": "Inbox", diff --git a/packages/i18n/src/locales/es/translations.json b/packages/i18n/src/locales/es/translations.json index e9d017d0da3..b9e16974e65 100644 --- a/packages/i18n/src/locales/es/translations.json +++ b/packages/i18n/src/locales/es/translations.json @@ -617,25 +617,45 @@ "workspace_active_cycles_empty_state_title": "No hay ciclos activos", "workspace_active_cycles_empty_state_description": "Ciclos de tus proyectos que incluyen cualquier período que abarque la fecha de hoy dentro de su rango. Encuentra el progreso y los detalles de todos tus ciclos activos aquí.", - "disabled_project_inbox_empty_state_title": "La entrada no está habilitada para el proyecto.", - "disabled_project_inbox_empty_state_description": "La entrada te ayuda a gestionar las solicitudes entrantes a tu proyecto y agregarlas como problemas en tu flujo de trabajo. Habilita la entrada desde la configuración del proyecto para gestionar las solicitudes.", - "disabled_project_inbox_empty_state_primary_button_text": "Gestionar funciones", - - "disabled_project_cycle_empty_state_title": "Los ciclos no están habilitados para este proyecto.", - "disabled_project_cycle_empty_state_description": "Divide el trabajo en partes temporales, trabaja hacia atrás desde la fecha límite del proyecto para establecer fechas y realiza avances tangibles como equipo. Habilita la función de ciclos para tu proyecto para comenzar a usarlos.", - "disabled_project_cycle_empty_state_primary_button_text": "Gestionar características", - - "disabled_project_module_empty_state_title": "Los módulos no están habilitados para el proyecto.", - "disabled_project_module_empty_state_description": "Un grupo de problemas que pertenecen a un padre lógico y jerárquico forma un módulo. Piénsalo como una forma de realizar un seguimiento del trabajo por los hitos del proyecto. Habilita los módulos desde la configuración del proyecto.", - "disabled_project_module_empty_state_primary_button_text": "Gestionar características", - - "disabled_project_page_empty_state_title": "Las páginas no están habilitadas para el proyecto.", - "disabled_project_page_empty_state_description": "Las páginas son espacios de anotación en Plane. Toma notas de reuniones, formatearlas fácilmente, incrustar problemas, organizarlas utilizando una biblioteca de componentes y mantenerlas dentro del contexto de tu proyecto. Habilita la función de páginas para empezar a crearlas en tu proyecto.", - "disabled_project_page_empty_state_primary_button_text": "Gestionar características", - - "disabled_project_view_empty_state_title": "Las vistas no están habilitadas para este proyecto.", - "disabled_project_view_empty_state_description": "Las vistas son un conjunto de filtros guardados que usas con frecuencia o que deseas tener acceso fácilmente. Todos tus compañeros de proyecto pueden ver las vistas de todos y elegir la que mejor se adapte a sus necesidades. Habilita las vistas en la configuración del proyecto para comenzar a usarlas.", - "disabled_project_view_empty_state_primary_button_text": "Gestionar características", + "disabled_project": { + "empty_state": { + "inbox": { + "title": "La entrada no está habilitada para el proyecto.", + "description": "La entrada te ayuda a gestionar las solicitudes entrantes para tu proyecto y agregarlas como problemas en tu flujo de trabajo. Habilita la entrada desde la configuración del proyecto para gestionar solicitudes.", + "primary_button": { + "text": "Gestionar funciones" + } + }, + "cycle": { + "title": "Los ciclos no están habilitados para este proyecto.", + "description": "Divide el trabajo en bloques de tiempo, trabaja hacia atrás desde la fecha límite de tu proyecto para establecer fechas y logra avances tangibles como equipo. Habilita la función de ciclos para tu proyecto para comenzar a usarlos.", + "primary_button": { + "text": "Gestionar funciones" + } + }, + "module": { + "title": "Los módulos no están habilitados para el proyecto.", + "description": "Los módulos son los bloques de construcción de tu proyecto. Habilita módulos desde la configuración del proyecto para comenzar a usarlos.", + "primary_button": { + "text": "Gestionar funciones" + } + }, + "page": { + "title": "Las páginas no están habilitadas para el proyecto.", + "description": "Las páginas son los bloques de construcción de tu proyecto. Habilita páginas desde la configuración del proyecto para comenzar a usarlas.", + "primary_button": { + "text": "Gestionar funciones" + } + }, + "view": { + "title": "Las vistas no están habilitadas para el proyecto.", + "description": "Las vistas son los bloques de construcción de tu proyecto. Habilita vistas desde la configuración del proyecto para comenzar a usarlas.", + "primary_button": { + "text": "Gestionar funciones" + } + } + } + }, "inbox": { "name": "Bandeja de entrada", diff --git a/packages/i18n/src/locales/fr/translations.json b/packages/i18n/src/locales/fr/translations.json index fde720b4cfa..b2d3341e4d6 100644 --- a/packages/i18n/src/locales/fr/translations.json +++ b/packages/i18n/src/locales/fr/translations.json @@ -618,25 +618,45 @@ "workspace_active_cycles_empty_state_title": "Aucun cycle actif", "workspace_active_cycles_empty_state_description": "Les cycles de vos projets incluent toute période couvrant la date d'aujourd'hui dans sa plage. Trouvez ici la progression et les détails de tous vos cycles actifs.", - "disabled_project_inbox_empty_state_title": "La réception n'est pas activée pour le projet.", - "disabled_project_inbox_empty_state_description": "La réception vous aide à gérer les demandes entrantes pour votre projet et à les ajouter comme problèmes dans votre flux de travail. Activez la réception dans les paramètres du projet pour gérer les demandes.", - "disabled_project_inbox_empty_state_primary_button_text": "Gérer les fonctionnalités", - - "disabled_project_cycle_empty_state_title": "Les cycles ne sont pas activés pour ce projet.", - "disabled_project_cycle_empty_state_description": "Divisez le travail en morceaux temporels, travaillez à partir de la date limite du projet pour définir des dates et faites des progrès tangibles en équipe. Activez la fonction des cycles pour votre projet afin de commencer à les utiliser.", - "disabled_project_cycle_empty_state_primary_button_text": "Gérer les fonctionnalités", - - "disabled_project_module_empty_state_title": "Les modules ne sont pas activés pour le projet.", - "disabled_project_module_empty_state_description": "Un groupe de problèmes appartenant à un parent logique et hiérarchique forme un module. Considérez-les comme un moyen de suivre le travail par jalons du projet. Activez les modules depuis les paramètres du projet.", - "disabled_project_module_empty_state_primary_button_text": "Gérer les fonctionnalités", - - "disabled_project_page_empty_state_title": "Les pages ne sont pas activées pour le projet.", - "disabled_project_page_empty_state_description": "Les pages sont des espaces de prise de notes dans Plane. Prenez des notes lors des réunions, formatez-les facilement, intégrez des problèmes, organisez-les à l’aide d’une bibliothèque de composants et gardez-les dans le contexte de votre projet. Activez la fonction des pages pour commencer à les créer dans votre projet.", - "disabled_project_page_empty_state_primary_button_text": "Gérer les fonctionnalités", - - "disabled_project_view_empty_state_title": "Les vues ne sont pas activées pour ce projet.", - "disabled_project_view_empty_state_description": "Les vues sont un ensemble de filtres enregistrés que vous utilisez fréquemment ou auxquels vous voulez un accès facile. Tous vos collègues du projet peuvent voir les vues de chacun et choisir celle qui correspond le mieux à leurs besoins. Activez les vues dans les paramètres du projet pour commencer à les utiliser.", - "disabled_project_view_empty_state_primary_button_text": "Gérer les fonctionnalités", + "disabled_project": { + "empty_state": { + "inbox": { + "title": "La collecte n'est pas activée pour le projet.", + "description": "La collecte vous aide à gérer les demandes entrantes pour votre projet et à les ajouter en tant que problèmes dans votre flux de travail. Activez la collecte dans les paramètres du projet pour gérer les demandes.", + "primary_button": { + "text": "Gérer les fonctionnalités" + } + }, + "cycle": { + "title": "Les cycles ne sont pas activés pour ce projet.", + "description": "Divisez le travail en segments limités dans le temps, travaillez à rebours depuis la date limite de votre projet pour fixer des dates et progressez concrètement en équipe. Activez la fonctionnalité des cycles pour votre projet afin de commencer à les utiliser.", + "primary_button": { + "text": "Gérer les fonctionnalités" + } + }, + "module": { + "title": "Les modules ne sont pas activés pour le projet.", + "description": "Les modules sont les éléments constitutifs de votre projet. Activez les modules dans les paramètres du projet pour commencer à les utiliser.", + "primary_button": { + "text": "Gérer les fonctionnalités" + } + }, + "page": { + "title": "Les pages ne sont pas activées pour le projet.", + "description": "Les pages sont les éléments constitutifs de votre projet. Activez les pages dans les paramètres du projet pour commencer à les utiliser.", + "primary_button": { + "text": "Gérer les fonctionnalités" + } + }, + "view": { + "title": "Les vues ne sont pas activées pour le projet.", + "description": "Les vues sont les éléments constitutifs de votre projet. Activez les vues dans les paramètres du projet pour commencer à les utiliser.", + "primary_button": { + "text": "Gérer les fonctionnalités" + } + } + } + }, "inbox": { "name": "Boîte de réception", diff --git a/packages/i18n/src/locales/ja/translations.json b/packages/i18n/src/locales/ja/translations.json index dd1a456d1c9..5949083a2f9 100644 --- a/packages/i18n/src/locales/ja/translations.json +++ b/packages/i18n/src/locales/ja/translations.json @@ -618,25 +618,45 @@ "workspace_active_cycles_empty_state_title": "アクティブなサイクルはありません", "workspace_active_cycles_empty_state_description": "現在の日付を範囲に含むプロジェクトのサイクルです。すべてのアクティブなサイクルの進捗と詳細をここで確認してください。", - "disabled_project_inbox_empty_state_title": "このプロジェクトではインテークが有効になっていません。", - "disabled_project_inbox_empty_state_description": "インテークは、プロジェクトへのリクエストを管理し、それらをワークフロー内の課題として追加するのに役立ちます。プロジェクト設定からインテークを有効にしてリクエストを管理してください。", - "disabled_project_inbox_empty_state_primary_button_text": "機能を管理", - - "disabled_project_cycle_empty_state_title": "このプロジェクトではサイクルが有効になっていません。", - "disabled_project_cycle_empty_state_description": "作業を時間枠で区切り、プロジェクトの期限から逆算して日付を設定し、チームとして具体的な進捗を遂げます。サイクル機能をプロジェクトで有効にして使用を開始してください。", - "disabled_project_cycle_empty_state_primary_button_text": "機能を管理", - - "disabled_project_module_empty_state_title": "このプロジェクトではモジュールが有効になっていません。", - "disabled_project_module_empty_state_description": "論理的かつ階層的な親に属する課題のグループがモジュールを形成します。それらは、プロジェクトのマイルストーンごとに作業を追跡する方法として考えられます。プロジェクト設定からモジュールを有効にしてください。", - "disabled_project_module_empty_state_primary_button_text": "機能を管理", - - "disabled_project_page_empty_state_title": "このプロジェクトではページが有効になっていません。", - "disabled_project_page_empty_state_description": "ページはPlaneのノート取り用スペースです。会議のメモを取り、簡単にフォーマットし、課題を埋め込み、コンポーネントのライブラリを使ってレイアウトし、プロジェクトの文脈内でそれらを保管します。ページ機能を有効にしてプロジェクト内で作成を開始してください。", - "disabled_project_page_empty_state_primary_button_text": "機能を管理", - - "disabled_project_view_empty_state_title": "このプロジェクトではビューが有効になっていません。", - "disabled_project_view_empty_state_description": "ビューは頻繁に使用するフィルターのセットで、簡単にアクセスできるようにしたいものです。プロジェクト内のすべての同僚は、他の人のビューを見て、ニーズに合ったものを選択できます。プロジェクト設定からビューを有効にして、使用を開始してください。", - "disabled_project_view_empty_state_primary_button_text": "機能を管理", + "disabled_project": { + "empty_state": { + "inbox": { + "title": "プロジェクトにインテークが有効化されていません。", + "description": "インテークは、プロジェクトへのリクエストを管理し、それらをワークフローの課題として追加するのに役立ちます。プロジェクト設定からインテークを有効化してリクエストを管理してください。", + "primary_button": { + "text": "機能を管理" + } + }, + "cycle": { + "title": "このプロジェクトでサイクルが有効化されていません。", + "description": "作業をタイムボックス化されたチャンクに分割し、プロジェクトの期限から逆算して日程を設定し、チームとして具体的な進捗を実現します。プロジェクトでサイクル機能を有効化して利用を開始してください。", + "primary_button": { + "text": "機能を管理" + } + }, + "module": { + "title": "プロジェクトにモジュールが有効化されていません。", + "description": "モジュールはプロジェクトの構成要素です。プロジェクト設定からモジュールを有効化して利用を開始してください。", + "primary_button": { + "text": "機能を管理" + } + }, + "page": { + "title": "プロジェクトにページが有効化されていません。", + "description": "ページはプロジェクトの構成要素です。プロジェクト設定からページを有効化して利用を開始してください。", + "primary_button": { + "text": "機能を管理" + } + }, + "view": { + "title": "プロジェクトにビューが有効化されていません。", + "description": "ビューはプロジェクトの構成要素です。プロジェクト設定からビューを有効化して利用を開始してください。", + "primary_button": { + "text": "機能を管理" + } + } + } + }, "inbox": { "name": "受信トレイ", diff --git a/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/cycles/(list)/page.tsx b/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/cycles/(list)/page.tsx index 5b1793d5d1f..ac0b9974977 100644 --- a/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/cycles/(list)/page.tsx +++ b/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/cycles/(list)/page.tsx @@ -3,20 +3,24 @@ import { useState } from "react"; import { observer } from "mobx-react"; import { useParams } from "next/navigation"; -// types +// plane imports +import { EUserPermissionsLevel, EUserWorkspaceRoles } from "@plane/constants"; +import { useTranslation } from "@plane/i18n"; import { TCycleFilters } from "@plane/types"; // components import { Header, EHeaderVariant } from "@plane/ui"; import { PageHead } from "@/components/core"; import { CyclesView, CycleCreateUpdateModal, CycleAppliedFiltersList } from "@/components/cycles"; -import { EmptyState } from "@/components/empty-state"; +import { DetailedEmptyState, EmptyState } from "@/components/empty-state"; import { CycleModuleListLayout } from "@/components/ui"; // constants import { EmptyStateType } from "@/constants/empty-state"; // helpers import { calculateTotalFilters } from "@/helpers/filter.helper"; // hooks -import { useEventTracker, useCycle, useProject, useCycleFilter } from "@/hooks/store"; +import { useEventTracker, useCycle, useProject, useCycleFilter, useUserPermissions } from "@/hooks/store"; +import { useAppRouter } from "@/hooks/use-app-router"; +import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; const ProjectCyclesPage = observer(() => { // states @@ -26,13 +30,19 @@ const ProjectCyclesPage = observer(() => { const { currentProjectCycleIds, loader } = useCycle(); const { getProjectById, currentProjectDetails } = useProject(); // router + const router = useAppRouter(); const { workspaceSlug, projectId } = useParams(); + // plane hooks + const { t } = useTranslation(); // cycle filters hook const { clearAllFilters, currentProjectFilters, updateFilters } = useCycleFilter(); + const { allowPermissions } = useUserPermissions(); // derived values const totalCycles = currentProjectCycleIds?.length ?? 0; const project = projectId ? getProjectById(projectId?.toString()) : undefined; const pageTitle = project?.name ? `${project?.name} - Cycles` : undefined; + const canPerformEmptyStateActions = allowPermissions([EUserWorkspaceRoles.ADMIN], EUserPermissionsLevel.PROJECT); + const resolvedPath = useResolvedAssetPath({ basePath: "/empty-state/disabled-feature/cycles" }); const handleRemoveFilter = (key: keyof TCycleFilters, value: string | null) => { if (!projectId) return; @@ -50,9 +60,17 @@ const ProjectCyclesPage = observer(() => { if (currentProjectDetails?.cycle_view === false) return (
- { + router.push(`/${workspaceSlug}/projects/${projectId}/settings/features`); + }, + disabled: !canPerformEmptyStateActions, + }} />
); diff --git a/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/inbox/page.tsx b/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/inbox/page.tsx index 36aa37e302c..2d53d57ddd6 100644 --- a/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/inbox/page.tsx +++ b/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/inbox/page.tsx @@ -2,35 +2,50 @@ import { observer } from "mobx-react"; // components import { useParams, useSearchParams } from "next/navigation"; +import { EUserWorkspaceRoles } from "@plane/constants/src/user"; +import { useTranslation } from "@plane/i18n"; import { PageHead } from "@/components/core"; -import { EmptyState } from "@/components/empty-state"; +import { DetailedEmptyState } from "@/components/empty-state"; import { InboxIssueRoot } from "@/components/inbox"; -// constants -import { EmptyStateType } from "@/constants/empty-state"; // helpers import { EInboxIssueCurrentTab } from "@/helpers/inbox.helper"; // hooks -import { useProject } from "@/hooks/store"; +import { useProject, useUserPermissions } from "@/hooks/store"; +import { useAppRouter } from "@/hooks/use-app-router"; +import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; +import { EUserPermissionsLevel } from "@/plane-web/constants/user-permissions"; const ProjectInboxPage = observer(() => { /// router + const router = useAppRouter(); const { workspaceSlug, projectId } = useParams(); - const searchParams = useSearchParams(); - const navigationTab = searchParams.get("currentTab"); const inboxIssueId = searchParams.get("inboxIssueId"); - + // plane hooks + const { t } = useTranslation(); // hooks const { currentProjectDetails } = useProject(); + const { allowPermissions } = useUserPermissions(); + // derived values + const canPerformEmptyStateActions = allowPermissions([EUserWorkspaceRoles.ADMIN], EUserPermissionsLevel.PROJECT); + const resolvedPath = useResolvedAssetPath({ basePath: "/empty-state/disabled-feature/intake" }); // No access to inbox if (currentProjectDetails?.inbox_view === false) return (
- { + router.push(`/${workspaceSlug}/projects/${projectId}/settings/features`); + }, + disabled: !canPerformEmptyStateActions, + }} />
); diff --git a/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/modules/(list)/page.tsx b/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/modules/(list)/page.tsx index 9417016e385..2066b77b0f5 100644 --- a/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/modules/(list)/page.tsx +++ b/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/modules/(list)/page.tsx @@ -4,27 +4,36 @@ import { useCallback } from "react"; import { observer } from "mobx-react"; import { useParams } from "next/navigation"; // types +import { EUserPermissionsLevel, EUserWorkspaceRoles } from "@plane/constants"; +import { useTranslation } from "@plane/i18n"; import { TModuleFilters } from "@plane/types"; // components import { PageHead } from "@/components/core"; -import { EmptyState } from "@/components/empty-state"; +import { DetailedEmptyState } from "@/components/empty-state"; import { ModuleAppliedFiltersList, ModulesListView } from "@/components/modules"; -// constants -import { EmptyStateType } from "@/constants/empty-state"; // helpers import { calculateTotalFilters } from "@/helpers/filter.helper"; // hooks -import { useModuleFilter, useProject } from "@/hooks/store"; +import { useModuleFilter, useProject, useUserPermissions } from "@/hooks/store"; +import { useAppRouter } from "@/hooks/use-app-router"; +import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; const ProjectModulesPage = observer(() => { + // router + const router = useAppRouter(); const { workspaceSlug, projectId } = useParams(); + // plane hooks + const { t } = useTranslation(); // store const { getProjectById, currentProjectDetails } = useProject(); const { currentProjectFilters, currentProjectDisplayFilters, clearAllFilters, updateFilters, updateDisplayFilters } = useModuleFilter(); + const { allowPermissions } = useUserPermissions(); // derived values const project = projectId ? getProjectById(projectId.toString()) : undefined; const pageTitle = project?.name ? `${project?.name} - Modules` : undefined; + const canPerformEmptyStateActions = allowPermissions([EUserWorkspaceRoles.ADMIN], EUserPermissionsLevel.PROJECT); + const resolvedPath = useResolvedAssetPath({ basePath: "/empty-state/disabled-feature/modules" }); const handleRemoveFilter = useCallback( (key: keyof TModuleFilters, value: string | null) => { @@ -45,9 +54,17 @@ const ProjectModulesPage = observer(() => { if (currentProjectDetails?.module_view === false) return (
- { + router.push(`/${workspaceSlug}/projects/${projectId}/settings/features`); + }, + disabled: !canPerformEmptyStateActions, + }} />
); diff --git a/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/pages/(list)/page.tsx b/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/pages/(list)/page.tsx index 93f37ea83b0..6db2f570ab0 100644 --- a/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/pages/(list)/page.tsx +++ b/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/pages/(list)/page.tsx @@ -2,27 +2,35 @@ import { observer } from "mobx-react"; import { useParams, useSearchParams } from "next/navigation"; -// types +// plane imports +import { EUserPermissionsLevel, EUserWorkspaceRoles } from "@plane/constants"; +import { useTranslation } from "@plane/i18n"; import { TPageNavigationTabs } from "@plane/types"; // components import { PageHead } from "@/components/core"; -import { EmptyState } from "@/components/empty-state"; +import { DetailedEmptyState } from "@/components/empty-state"; import { PagesListRoot, PagesListView } from "@/components/pages"; -// constants -import { EmptyStateType } from "@/constants/empty-state"; // hooks -import { useProject } from "@/hooks/store"; +import { useProject, useUserPermissions } from "@/hooks/store"; +import { useAppRouter } from "@/hooks/use-app-router"; +import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; const ProjectPagesPage = observer(() => { // router + const router = useAppRouter(); const searchParams = useSearchParams(); const type = searchParams.get("type"); const { workspaceSlug, projectId } = useParams(); + // plane hooks + const { t } = useTranslation(); // store hooks const { getProjectById, currentProjectDetails } = useProject(); + const { allowPermissions } = useUserPermissions(); // derived values const project = projectId ? getProjectById(projectId.toString()) : undefined; const pageTitle = project?.name ? `${project?.name} - Pages` : undefined; + const canPerformEmptyStateActions = allowPermissions([EUserWorkspaceRoles.ADMIN], EUserPermissionsLevel.PROJECT); + const resolvedPath = useResolvedAssetPath({ basePath: "/empty-state/disabled-feature/pages" }); const currentPageType = (): TPageNavigationTabs => { const pageType = type?.toString(); @@ -37,9 +45,17 @@ const ProjectPagesPage = observer(() => { if (currentProjectDetails?.page_view === false) return (
- { + router.push(`/${workspaceSlug}/projects/${projectId}/settings/features`); + }, + disabled: !canPerformEmptyStateActions, + }} />
); diff --git a/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/views/(list)/page.tsx b/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/views/(list)/page.tsx index 387f6e5b423..820617561bc 100644 --- a/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/views/(list)/page.tsx +++ b/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/views/(list)/page.tsx @@ -4,29 +4,38 @@ import { useCallback } from "react"; import { observer } from "mobx-react"; import { useParams } from "next/navigation"; // components +import { EUserPermissionsLevel, EUserWorkspaceRoles } from "@plane/constants"; +import { useTranslation } from "@plane/i18n"; import { TViewFilterProps } from "@plane/types"; import { Header, EHeaderVariant } from "@plane/ui"; import { PageHead } from "@/components/core"; -import { EmptyState } from "@/components/empty-state"; +import { DetailedEmptyState } from "@/components/empty-state"; import { ProjectViewsList } from "@/components/views"; import { ViewAppliedFiltersList } from "@/components/views/applied-filters"; -import { EmptyStateType } from "@/constants/empty-state"; // constants import { EViewAccess } from "@/constants/views"; // helpers import { calculateTotalFilters } from "@/helpers/filter.helper"; // hooks -import { useProject, useProjectView } from "@/hooks/store"; +import { useProject, useProjectView, useUserPermissions } from "@/hooks/store"; +import { useAppRouter } from "@/hooks/use-app-router"; +import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; const ProjectViewsPage = observer(() => { // router + const router = useAppRouter(); const { workspaceSlug, projectId } = useParams(); + // plane hooks + const { t } = useTranslation(); // store const { getProjectById, currentProjectDetails } = useProject(); const { filters, updateFilters, clearAllFilters } = useProjectView(); + const { allowPermissions } = useUserPermissions(); // derived values const project = projectId ? getProjectById(projectId.toString()) : undefined; const pageTitle = project?.name ? `${project?.name} - Views` : undefined; + const canPerformEmptyStateActions = allowPermissions([EUserWorkspaceRoles.ADMIN], EUserPermissionsLevel.PROJECT); + const resolvedPath = useResolvedAssetPath({ basePath: "/empty-state/disabled-feature/views" }); const handleRemoveFilter = useCallback( (key: keyof TViewFilterProps, value: string | EViewAccess | null) => { @@ -53,9 +62,17 @@ const ProjectViewsPage = observer(() => { if (currentProjectDetails?.issue_views_view === false) return (
- { + router.push(`/${workspaceSlug}/projects/${projectId}/settings/features`); + }, + disabled: !canPerformEmptyStateActions, + }} />
); diff --git a/web/core/constants/empty-state.tsx b/web/core/constants/empty-state.tsx index dbbd32782e6..b795332d816 100644 --- a/web/core/constants/empty-state.tsx +++ b/web/core/constants/empty-state.tsx @@ -104,11 +104,6 @@ export enum EmptyStateType { ACTIVE_CYCLE_LABEL_EMPTY_STATE = "active-cycle-label-empty-state", WORKSPACE_ACTIVE_CYCLES = "workspace-active-cycles", - DISABLED_PROJECT_INBOX = "disabled-project-inbox", - DISABLED_PROJECT_CYCLE = "disabled-project-cycle", - DISABLED_PROJECT_MODULE = "disabled-project-module", - DISABLED_PROJECT_VIEW = "disabled-project-view", - DISABLED_PROJECT_PAGE = "disabled-project-page", // stickies STICKIES = "stickies", STICKIES_SEARCH = "stickies-search", @@ -747,66 +742,6 @@ const emptyStateDetails: Record = { "Cycles of your projects that includes any period that encompasses today's date within its range. Find the progress and details of all your active cycle here.", path: "/empty-state/onboarding/workspace-active-cycles", }, - [EmptyStateType.DISABLED_PROJECT_INBOX]: { - key: EmptyStateType.DISABLED_PROJECT_INBOX, - title: "Intake is not enabled for the project.", - description: - "Intake helps you manage incoming requests to your project and add them as issues in your workflow. Enable intake \n from project settings to manage requests.", - accessType: "project", - access: [EUserPermissions.ADMIN], - path: "/empty-state/disabled-feature/intake", - primaryButton: { - text: "Manage features", - }, - }, - [EmptyStateType.DISABLED_PROJECT_CYCLE]: { - key: EmptyStateType.DISABLED_PROJECT_CYCLE, - title: "Cycles is not enabled for this project.", - description: - "Break work down by timeboxed chunks, work backwards from your project deadline to set dates, and make tangible progress as a team. Enable the cycles feature for your project to start using them.", - accessType: "project", - access: [EUserPermissions.ADMIN], - path: "/empty-state/disabled-feature/cycles", - primaryButton: { - text: "Manage features", - }, - }, - [EmptyStateType.DISABLED_PROJECT_MODULE]: { - key: EmptyStateType.DISABLED_PROJECT_MODULE, - title: "Modules are not enabled for the project.", - description: - "A group of issues that belong to a logical, hierarchical parent form a module. Think of them as a way to track work by project milestones. Enable modules from project settings.", - accessType: "project", - access: [EUserPermissions.ADMIN], - path: "/empty-state/disabled-feature/modules", - primaryButton: { - text: "Manage features", - }, - }, - [EmptyStateType.DISABLED_PROJECT_PAGE]: { - key: EmptyStateType.DISABLED_PROJECT_PAGE, - title: "Pages are not enabled for the project.", - description: - "Pages are thought spotting space in Plane. Take down meeting notes, format them easily, embed issues, lay them out using a library of components, and keep them all in your project’s context. Enable the pages feature to start creating them in your project.", - accessType: "project", - access: [EUserPermissions.ADMIN], - path: "/empty-state/disabled-feature/pages", - primaryButton: { - text: "Manage features", - }, - }, - [EmptyStateType.DISABLED_PROJECT_VIEW]: { - key: EmptyStateType.DISABLED_PROJECT_VIEW, - title: "Views is not enabled for this project.", - description: - "Views are a set of saved filters that you use frequently or want easy access to. All your colleagues in a project can see everyone’s views and choose whichever suits their needs best. Enable views in the project settings to start using them.", - accessType: "project", - access: [EUserPermissions.ADMIN], - path: "/empty-state/disabled-feature/views", - primaryButton: { - text: "Manage features", - }, - }, [EmptyStateType.STICKIES]: { key: EmptyStateType.STICKIES, title: "Stickies are quick notes and to-dos you take down on the fly.", From f7274e454bb4000e9150ef4e01bde3800323ffa9 Mon Sep 17 00:00:00 2001 From: Prateek Shourya Date: Thu, 16 Jan 2025 21:59:48 +0530 Subject: [PATCH 11/26] chore: active cycle progress empty state --- .../i18n/src/locales/en/translations.json | 27 ++++++++---- .../i18n/src/locales/es/translations.json | 27 ++++++++---- .../i18n/src/locales/fr/translations.json | 27 ++++++++---- .../i18n/src/locales/ja/translations.json | 27 ++++++++---- .../cycles/active-cycle/cycle-stats.tsx | 35 +++++++++------- .../cycles/active-cycle/productivity.tsx | 15 ++++--- .../cycles/active-cycle/progress.tsx | 12 +++--- web/core/constants/empty-state.tsx | 41 ------------------- 8 files changed, 112 insertions(+), 99 deletions(-) diff --git a/packages/i18n/src/locales/en/translations.json b/packages/i18n/src/locales/en/translations.json index 83a3396b78e..bc851518d79 100644 --- a/packages/i18n/src/locales/en/translations.json +++ b/packages/i18n/src/locales/en/translations.json @@ -606,14 +606,25 @@ "notification_mentions_empty_state_title": "No issues assigned", "notification_mentions_empty_state_description": "Updates for issues assigned to you can be seen here", - "active_cycle_progress_empty_state_title": "Add issues to the cycle to view it's progress", - "active_cycle_chart_empty_state_title": "Add issues to the cycle to view the burndown chart.", - "active_cycle_priority_issue_empty_state_title": "Observe high priority issues tackled in the cycle at a glance.", - "active_cycle_assignee_empty_state_title": "Add assignees to issues to see a breakdown of work by assignees.", - "active_cycle_label_empty_state_title": "Add labels to issues to see the breakdown of work by labels.", - - "workspace_active_cycles_empty_state_title": "No active cycles", - "workspace_active_cycles_empty_state_description": "Cycles of your projects that includes any period that encompasses today's date within its range. Find the progress and details of all your active cycle here.", + "active_cycle": { + "empty_state": { + "progress": { + "title": "Add issues to the cycle to view it's progress" + }, + "chart": { + "title": "Add issues to the cycle to view the burndown chart." + }, + "priority_issue": { + "title": "Observe high priority issues tackled in the cycle at a glance." + }, + "assignee": { + "title": "Add assignees to issues to see a breakdown of work by assignees." + }, + "label": { + "title": "Add labels to issues to see the breakdown of work by labels." + } + } + }, "disabled_project": { "empty_state": { diff --git a/packages/i18n/src/locales/es/translations.json b/packages/i18n/src/locales/es/translations.json index b9e16974e65..f605f19d67d 100644 --- a/packages/i18n/src/locales/es/translations.json +++ b/packages/i18n/src/locales/es/translations.json @@ -608,14 +608,25 @@ "notification_mentions_empty_state_title": "No hay problemas asignados", "notification_mentions_empty_state_description": "Las actualizaciones de los problemas asignados a ti se pueden ver aquí", - "active_cycle_progress_empty_state_title": "Añade problemas al ciclo para ver su progreso", - "active_cycle_chart_empty_state_title": "Añade problemas al ciclo para ver el gráfico de avance.", - "active_cycle_priority_issue_empty_state_title": "Observa los problemas de alta prioridad abordados en el ciclo de un vistazo.", - "active_cycle_assignee_empty_state_title": "Añade asignados a los problemas para ver un desglose del trabajo por asignados.", - "active_cycle_label_empty_state_title": "Añade etiquetas a los problemas para ver el desglose del trabajo por etiquetas.", - - "workspace_active_cycles_empty_state_title": "No hay ciclos activos", - "workspace_active_cycles_empty_state_description": "Ciclos de tus proyectos que incluyen cualquier período que abarque la fecha de hoy dentro de su rango. Encuentra el progreso y los detalles de todos tus ciclos activos aquí.", + "active_cycle": { + "empty_state": { + "progress": { + "title": "Agrega problemas al ciclo para ver su progreso." + }, + "chart": { + "title": "Agrega problemas al ciclo para ver el gráfico de burndown." + }, + "priority_issue": { + "title": "Observa de un vistazo los problemas de alta prioridad abordados en el ciclo." + }, + "assignee": { + "title": "Asigna responsables a los problemas para ver un desglose del trabajo por responsables." + }, + "label": { + "title": "Agrega etiquetas a los problemas para ver el desglose del trabajo por etiquetas." + } + } + }, "disabled_project": { "empty_state": { diff --git a/packages/i18n/src/locales/fr/translations.json b/packages/i18n/src/locales/fr/translations.json index b2d3341e4d6..45d3c74a49b 100644 --- a/packages/i18n/src/locales/fr/translations.json +++ b/packages/i18n/src/locales/fr/translations.json @@ -609,14 +609,25 @@ "notification_mentions_empty_state_title": "Aucun problème assigné", "notification_mentions_empty_state_description": "Les mises à jour des problèmes qui vous sont assignés sont visibles ici.", - "active_cycle_progress_empty_state_title": "Ajoutez des problèmes au cycle pour voir sa progression.", - "active_cycle_chart_empty_state_title": "Ajoutez des problèmes au cycle pour voir le graphique d'avancement.", - "active_cycle_priority_issue_empty_state_title": "Observez d'un coup d'œil les problèmes prioritaires traités dans le cycle.", - "active_cycle_assignee_empty_state_title": "Ajoutez des assignés aux problèmes pour voir une répartition du travail par assignés.", - "active_cycle_label_empty_state_title": "Ajoutez des étiquettes aux problèmes pour voir une répartition du travail par étiquettes.", - - "workspace_active_cycles_empty_state_title": "Aucun cycle actif", - "workspace_active_cycles_empty_state_description": "Les cycles de vos projets incluent toute période couvrant la date d'aujourd'hui dans sa plage. Trouvez ici la progression et les détails de tous vos cycles actifs.", + "active_cycle": { + "empty_state": { + "progress": { + "title": "Ajoutez des problèmes au cycle pour voir sa progression." + }, + "chart": { + "title": "Ajoutez des problèmes au cycle pour voir le graphique d'avancement." + }, + "priority_issue": { + "title": "Observez d'un coup d'œil les problèmes prioritaires traités dans le cycle." + }, + "assignee": { + "title": "Ajoutez des responsables aux problèmes pour voir la répartition du travail par responsable." + }, + "label": { + "title": "Ajoutez des étiquettes aux problèmes pour voir la répartition du travail par étiquette." + } + } + }, "disabled_project": { "empty_state": { diff --git a/packages/i18n/src/locales/ja/translations.json b/packages/i18n/src/locales/ja/translations.json index 5949083a2f9..cd7c7167fca 100644 --- a/packages/i18n/src/locales/ja/translations.json +++ b/packages/i18n/src/locales/ja/translations.json @@ -609,14 +609,25 @@ "notification_mentions_empty_state_title": "割り当てられた課題はありません", "notification_mentions_empty_state_description": "あなたに割り当てられた課題の更新はここで確認できます", - "active_cycle_progress_empty_state_title": "課題をサイクルに追加して進捗を確認してください", - "active_cycle_chart_empty_state_title": "課題をサイクルに追加してバーンダウンチャートを表示してください。", - "active_cycle_priority_issue_empty_state_title": "サイクル内で対応された高優先度の課題を一目で確認できます。", - "active_cycle_assignee_empty_state_title": "課題に担当者を追加して、担当者別の作業の内訳を確認してください。", - "active_cycle_label_empty_state_title": "課題にラベルを追加して、ラベル別の作業の内訳を確認してください。", - - "workspace_active_cycles_empty_state_title": "アクティブなサイクルはありません", - "workspace_active_cycles_empty_state_description": "現在の日付を範囲に含むプロジェクトのサイクルです。すべてのアクティブなサイクルの進捗と詳細をここで確認してください。", + "active_cycle": { + "empty_state": { + "progress": { + "title": "サイクルに課題を追加して進捗を確認してください。" + }, + "chart": { + "title": "サイクルに課題を追加してバーンダウンチャートを確認してください。" + }, + "priority_issue": { + "title": "サイクル内で処理された高優先度の課題を一目で把握できます。" + }, + "assignee": { + "title": "課題に担当者を追加して、担当者ごとの作業の内訳を確認してください。" + }, + "label": { + "title": "課題にラベルを追加して、ラベルごとの作業の内訳を確認してください。" + } + } + }, "disabled_project": { "empty_state": { diff --git a/web/core/components/cycles/active-cycle/cycle-stats.tsx b/web/core/components/cycles/active-cycle/cycle-stats.tsx index 44d7b595f48..b9cf267a62f 100644 --- a/web/core/components/cycles/active-cycle/cycle-stats.tsx +++ b/web/core/components/cycles/active-cycle/cycle-stats.tsx @@ -6,17 +6,16 @@ import { observer } from "mobx-react"; import { CalendarCheck } from "lucide-react"; // headless ui import { Tab } from "@headlessui/react"; -// types +// plane imports import { EIssuesStoreType } from "@plane/constants"; +import { useTranslation } from "@plane/i18n"; import { ICycle, IIssueFilterOptions } from "@plane/types"; // ui import { Tooltip, Loader, PriorityIcon, Avatar } from "@plane/ui"; // components import { SingleProgressStats } from "@/components/core"; import { StateDropdown } from "@/components/dropdowns"; -import { EmptyState } from "@/components/empty-state"; -// constants -import { EmptyStateType } from "@/constants/empty-state"; +import { SimpleEmptyState } from "@/components/empty-state"; // helpers import { cn } from "@/helpers/common.helper"; import { renderFormattedDate, renderFormattedDateWithoutYear } from "@/helpers/date-time.helper"; @@ -26,6 +25,7 @@ import { useIssueDetail, useIssues } from "@/hooks/store"; import { useIntersectionObserver } from "@/hooks/use-intersection-observer"; import useLocalStorage from "@/hooks/use-local-storage"; // plane web components +import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; import { IssueIdentifier } from "@/plane-web/components/issues"; // store import { ActiveCycleIssueDetails } from "@/store/issue/cycle"; @@ -41,11 +41,18 @@ export type ActiveCycleStatsProps = { export const ActiveCycleStats: FC = observer((props) => { const { workspaceSlug, projectId, cycle, cycleId, handleFiltersUpdate, cycleIssueDetails } = props; - + // local storage const { storedValue: tab, setValue: setTab } = useLocalStorage("activeCycleTab", "Assignees"); - + // refs const issuesContainerRef = useRef(null); + // states const [issuesLoaderElement, setIssueLoaderElement] = useState(null); + // plane hooks + const { t } = useTranslation(); + // derived values + const priorityResolvedPath = useResolvedAssetPath({ basePath: "/empty-state/active-cycle/priority" }); + const assigneesResolvedPath = useResolvedAssetPath({ basePath: "/empty-state/active-cycle/assignee" }); + const labelsResolvedPath = useResolvedAssetPath({ basePath: "/empty-state/active-cycle/label" }); const currentValue = (tab: string | null) => { switch (tab) { @@ -231,10 +238,9 @@ export const ActiveCycleStats: FC = observer((props) => { ) : (
-
) @@ -293,10 +299,9 @@ export const ActiveCycleStats: FC = observer((props) => { }) ) : (
-
) @@ -336,7 +341,7 @@ export const ActiveCycleStats: FC = observer((props) => { )) ) : (
- +
) ) : ( diff --git a/web/core/components/cycles/active-cycle/productivity.tsx b/web/core/components/cycles/active-cycle/productivity.tsx index 74957af03c7..859c3015435 100644 --- a/web/core/components/cycles/active-cycle/productivity.tsx +++ b/web/core/components/cycles/active-cycle/productivity.tsx @@ -1,16 +1,17 @@ import { FC, Fragment } from "react"; import { observer } from "mobx-react"; import Link from "next/link"; +// plane imports +import { useTranslation } from "@plane/i18n"; import { ICycle, TCycleEstimateType } from "@plane/types"; import { Loader } from "@plane/ui"; // components import ProgressChart from "@/components/core/sidebar/progress-chart"; -import { EmptyState } from "@/components/empty-state"; +import { SimpleEmptyState } from "@/components/empty-state"; // constants -import { EmptyStateType } from "@/constants/empty-state"; -import { useCycle, useProjectEstimates } from "@/hooks/store"; +import { useCycle } from "@/hooks/store"; // plane web constants -import { EEstimateSystem } from "@/plane-web/constants/estimates"; +import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; import { EstimateTypeDropdown } from "../dropdowns/estimate-type-dropdown"; export type ActiveCycleProductivityProps = { @@ -21,11 +22,13 @@ export type ActiveCycleProductivityProps = { export const ActiveCycleProductivity: FC = observer((props) => { const { workspaceSlug, projectId, cycle } = props; + // plane hooks + const { t } = useTranslation(); // hooks const { getEstimateTypeByCycleId, setEstimateType } = useCycle(); - // derived values const estimateType: TCycleEstimateType = (cycle && getEstimateTypeByCycleId(cycle.id)) || "issues"; + const resolvedPath = useResolvedAssetPath({ basePath: "/empty-state/active-cycle/chart" }); const onChange = async (value: TCycleEstimateType) => { if (!workspaceSlug || !projectId || !cycle || !cycle.id) return; @@ -95,7 +98,7 @@ export const ActiveCycleProductivity: FC = observe ) : ( <>
- +
)} diff --git a/web/core/components/cycles/active-cycle/progress.tsx b/web/core/components/cycles/active-cycle/progress.tsx index 0dffff5c757..0f2c5a419aa 100644 --- a/web/core/components/cycles/active-cycle/progress.tsx +++ b/web/core/components/cycles/active-cycle/progress.tsx @@ -4,14 +4,14 @@ import { FC } from "react"; import { observer } from "mobx-react"; // plane package imports import { PROGRESS_STATE_GROUPS_DETAILS } from "@plane/constants"; +import { useTranslation } from "@plane/i18n"; import { ICycle, IIssueFilterOptions } from "@plane/types"; import { LinearProgressIndicator, Loader } from "@plane/ui"; // components -import { EmptyState } from "@/components/empty-state"; -// constants -import { EmptyStateType } from "@/constants/empty-state"; +import { SimpleEmptyState } from "@/components/empty-state"; // hooks import { useProjectState } from "@/hooks/store"; +import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; export type ActiveCycleProgressProps = { cycle: ICycle | null; @@ -22,9 +22,10 @@ export type ActiveCycleProgressProps = { export const ActiveCycleProgress: FC = observer((props) => { const { handleFiltersUpdate, cycle } = props; + // plane hooks + const { t } = useTranslation(); // store hooks const { groupedProjectStates } = useProjectState(); - // derived values const progressIndicatorData = PROGRESS_STATE_GROUPS_DETAILS.map((group, index) => ({ id: index, @@ -40,6 +41,7 @@ export const ActiveCycleProgress: FC = observer((props backlog: cycle?.backlog_issues, } : {}; + const resolvedPath = useResolvedAssetPath({ basePath: "/empty-state/active-cycle/progress" }); return cycle && cycle.hasOwnProperty("started_issues") ? (
@@ -101,7 +103,7 @@ export const ActiveCycleProgress: FC = observer((props
) : (
- +
)}
diff --git a/web/core/constants/empty-state.tsx b/web/core/constants/empty-state.tsx index b795332d816..70295c11e1f 100644 --- a/web/core/constants/empty-state.tsx +++ b/web/core/constants/empty-state.tsx @@ -96,14 +96,6 @@ export enum EmptyStateType { NOTIFICATION_ARCHIVED_EMPTY_STATE = "notification-archived-empty-state", NOTIFICATION_SNOOZED_EMPTY_STATE = "notification-snoozed-empty-state", NOTIFICATION_UNREAD_EMPTY_STATE = "notification-unread-empty-state", - - ACTIVE_CYCLE_PROGRESS_EMPTY_STATE = "active-cycle-progress-empty-state", - ACTIVE_CYCLE_CHART_EMPTY_STATE = "active-cycle-chart-empty-state", - ACTIVE_CYCLE_PRIORITY_ISSUE_EMPTY_STATE = "active-cycle-priority-issue-empty-state", - ACTIVE_CYCLE_ASSIGNEE_EMPTY_STATE = "active-cycle-assignee-empty-state", - ACTIVE_CYCLE_LABEL_EMPTY_STATE = "active-cycle-label-empty-state", - - WORKSPACE_ACTIVE_CYCLES = "workspace-active-cycles", // stickies STICKIES = "stickies", STICKIES_SEARCH = "stickies-search", @@ -709,39 +701,6 @@ const emptyStateDetails: Record = { description: "Any notification you archive will be \n available here to help you focus", path: "/empty-state/search/archive", }, - - [EmptyStateType.ACTIVE_CYCLE_PROGRESS_EMPTY_STATE]: { - key: EmptyStateType.ACTIVE_CYCLE_PROGRESS_EMPTY_STATE, - title: "Add issues to the cycle to view it's \n progress", - path: "/empty-state/active-cycle/progress", - }, - [EmptyStateType.ACTIVE_CYCLE_CHART_EMPTY_STATE]: { - key: EmptyStateType.ACTIVE_CYCLE_CHART_EMPTY_STATE, - title: "Add issues to the cycle to view the \n burndown chart.", - path: "/empty-state/active-cycle/chart", - }, - [EmptyStateType.ACTIVE_CYCLE_PRIORITY_ISSUE_EMPTY_STATE]: { - key: EmptyStateType.ACTIVE_CYCLE_PRIORITY_ISSUE_EMPTY_STATE, - title: "Observe high priority issues tackled in \n the cycle at a glance.", - path: "/empty-state/active-cycle/priority", - }, - [EmptyStateType.ACTIVE_CYCLE_ASSIGNEE_EMPTY_STATE]: { - key: EmptyStateType.ACTIVE_CYCLE_ASSIGNEE_EMPTY_STATE, - title: "Add assignees to issues to see a \n breakdown of work by assignees.", - path: "/empty-state/active-cycle/assignee", - }, - [EmptyStateType.ACTIVE_CYCLE_LABEL_EMPTY_STATE]: { - key: EmptyStateType.ACTIVE_CYCLE_LABEL_EMPTY_STATE, - title: "Add labels to issues to see the \n breakdown of work by labels.", - path: "/empty-state/active-cycle/label", - }, - [EmptyStateType.WORKSPACE_ACTIVE_CYCLES]: { - key: EmptyStateType.WORKSPACE_ACTIVE_CYCLES, - title: "No active cycles", - description: - "Cycles of your projects that includes any period that encompasses today's date within its range. Find the progress and details of all your active cycle here.", - path: "/empty-state/onboarding/workspace-active-cycles", - }, [EmptyStateType.STICKIES]: { key: EmptyStateType.STICKIES, title: "Stickies are quick notes and to-dos you take down on the fly.", From bafa6ac3b374b75f30e93ae3ebca957a49f6b622 Mon Sep 17 00:00:00 2001 From: Prateek Shourya Date: Thu, 16 Jan 2025 22:20:07 +0530 Subject: [PATCH 12/26] chore: notification empty state --- .../i18n/src/locales/en/translations.json | 22 ++-- .../i18n/src/locales/es/translations.json | 16 +++ .../i18n/src/locales/fr/translations.json | 16 +++ .../i18n/src/locales/ja/translations.json | 16 +++ .../(projects)/notifications/page.tsx | 12 +- .../sidebar/empty-state.tsx | 29 ++++- web/core/constants/empty-state.tsx | 110 ------------------ 7 files changed, 94 insertions(+), 127 deletions(-) diff --git a/packages/i18n/src/locales/en/translations.json b/packages/i18n/src/locales/en/translations.json index bc851518d79..71952b05685 100644 --- a/packages/i18n/src/locales/en/translations.json +++ b/packages/i18n/src/locales/en/translations.json @@ -598,13 +598,21 @@ "issue_comment_empty_state_title": "No comments yet", "issue_comment_empty_state_description": "Comments can be used as a discussion and follow-up space for the issues", - "notification_detail_empty_state_title": "Select to view details.", - - "notification_all_empty_state_title": "No issues assigned", - "notification_all_empty_state_description": "Updates for issues assigned to you can be seen here", - - "notification_mentions_empty_state_title": "No issues assigned", - "notification_mentions_empty_state_description": "Updates for issues assigned to you can be seen here", + "notification": { + "empty_state": { + "detail": { + "title": "Select to view details." + }, + "all": { + "title": "No issues assigned", + "description": "Updates for issues assigned to you can be \n seen here" + }, + "mentions": { + "title": "No issues assigned", + "description": "Updates for issues assigned to you can be \n seen here" + } + } + }, "active_cycle": { "empty_state": { diff --git a/packages/i18n/src/locales/es/translations.json b/packages/i18n/src/locales/es/translations.json index f605f19d67d..1066771efe6 100644 --- a/packages/i18n/src/locales/es/translations.json +++ b/packages/i18n/src/locales/es/translations.json @@ -608,6 +608,22 @@ "notification_mentions_empty_state_title": "No hay problemas asignados", "notification_mentions_empty_state_description": "Las actualizaciones de los problemas asignados a ti se pueden ver aquí", + "notification": { + "empty_state": { + "detail": { + "title": "Selecciona para ver los detalles." + }, + "all": { + "title": "No hay problemas asignados", + "description": "Las actualizaciones de los problemas asignados a ti se \n pueden ver aquí" + }, + "mentions": { + "title": "No hay problemas asignados", + "description": "Las actualizaciones de los problemas asignados a ti se \n pueden ver aquí" + } + } + }, + "active_cycle": { "empty_state": { "progress": { diff --git a/packages/i18n/src/locales/fr/translations.json b/packages/i18n/src/locales/fr/translations.json index 45d3c74a49b..c9144e8ae5b 100644 --- a/packages/i18n/src/locales/fr/translations.json +++ b/packages/i18n/src/locales/fr/translations.json @@ -609,6 +609,22 @@ "notification_mentions_empty_state_title": "Aucun problème assigné", "notification_mentions_empty_state_description": "Les mises à jour des problèmes qui vous sont assignés sont visibles ici.", + "notification": { + "empty_state": { + "detail": { + "title": "Sélectionnez pour voir les détails." + }, + "all": { + "title": "Aucune tâche assignée", + "description": "Les mises à jour des problèmes qui vous sont assignés peuvent être \n vues ici." + }, + "mentions": { + "title": "Aucune tâche assignée", + "description": "Les mises à jour des problèmes qui vous sont assignés peuvent être \n vues ici." + } + } + }, + "active_cycle": { "empty_state": { "progress": { diff --git a/packages/i18n/src/locales/ja/translations.json b/packages/i18n/src/locales/ja/translations.json index cd7c7167fca..b4d4937f648 100644 --- a/packages/i18n/src/locales/ja/translations.json +++ b/packages/i18n/src/locales/ja/translations.json @@ -609,6 +609,22 @@ "notification_mentions_empty_state_title": "割り当てられた課題はありません", "notification_mentions_empty_state_description": "あなたに割り当てられた課題の更新はここで確認できます", + "notification": { + "empty_state": { + "detail": { + "title": "詳細を表示するには選択してください。" + }, + "all": { + "title": "割り当てられた問題はありません", + "description": "あなたに割り当てられた問題の更新情報はここで確認できます。" + }, + "mentions": { + "title": "割り当てられた問題はありません", + "description": "あなたに割り当てられた問題の更新情報はここで確認できます。" + } + } + }, + "active_cycle": { "empty_state": { "progress": { diff --git a/web/app/[workspaceSlug]/(projects)/notifications/page.tsx b/web/app/[workspaceSlug]/(projects)/notifications/page.tsx index 4ea0c8e4258..3074acbf8ce 100644 --- a/web/app/[workspaceSlug]/(projects)/notifications/page.tsx +++ b/web/app/[workspaceSlug]/(projects)/notifications/page.tsx @@ -4,21 +4,24 @@ import { useCallback, useEffect } from "react"; import { observer } from "mobx-react"; import { useParams } from "next/navigation"; import useSWR from "swr"; +// plane imports +import { useTranslation } from "@plane/i18n"; // components import { LogoSpinner } from "@/components/common"; import { PageHead } from "@/components/core"; -import { EmptyState } from "@/components/empty-state"; +import { SimpleEmptyState } from "@/components/empty-state"; import { InboxContentRoot } from "@/components/inbox"; import { IssuePeekOverview } from "@/components/issues"; -// constants -import { EmptyStateType } from "@/constants/empty-state"; import { ENotificationLoader, ENotificationQueryParamType } from "@/constants/notification"; // hooks import { useIssueDetail, useUserPermissions, useWorkspace, useWorkspaceNotifications } from "@/hooks/store"; +import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; import { useWorkspaceIssueProperties } from "@/hooks/use-workspace-issue-properties"; const WorkspaceDashboardPage = observer(() => { const { workspaceSlug } = useParams(); + // plane hooks + const { t } = useTranslation(); // hooks const { currentWorkspace } = useWorkspace(); const { @@ -34,6 +37,7 @@ const WorkspaceDashboardPage = observer(() => { const pageTitle = currentWorkspace?.name ? `${currentWorkspace?.name} - Inbox` : undefined; const { workspace_slug, project_id, issue_id, is_inbox_issue } = notificationLiteByNotificationId(currentSelectedNotificationId); + const resolvedPath = useResolvedAssetPath({ basePath: "/empty-state/intake/issue-detail" }); // fetching workspace issue properties useWorkspaceIssueProperties(workspaceSlug); @@ -82,7 +86,7 @@ const WorkspaceDashboardPage = observer(() => {
{!currentSelectedNotificationId ? (
- +
) : ( <> diff --git a/web/core/components/workspace-notifications/sidebar/empty-state.tsx b/web/core/components/workspace-notifications/sidebar/empty-state.tsx index 3b2b0c0f546..687e0c38c73 100644 --- a/web/core/components/workspace-notifications/sidebar/empty-state.tsx +++ b/web/core/components/workspace-notifications/sidebar/empty-state.tsx @@ -3,16 +3,33 @@ import { FC } from "react"; import { observer } from "mobx-react"; // components -import { EmptyState } from "@/components/empty-state"; +import { useTranslation } from "@plane/i18n"; +import { SimpleEmptyState } from "@/components/empty-state"; // constants -import { EmptyStateType } from "@/constants/empty-state"; import { ENotificationTab } from "@/constants/notification"; +import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; export const NotificationEmptyState: FC = observer(() => { + // plane imports + const { t } = useTranslation(); // derived values - const currentTabEmptyState = ENotificationTab.ALL - ? EmptyStateType.NOTIFICATION_ALL_EMPTY_STATE - : EmptyStateType.NOTIFICATION_MENTIONS_EMPTY_STATE; + const resolvedPath = useResolvedAssetPath({ basePath: "/empty-state/search/notification" }); - return ; + return ( + <> + {ENotificationTab.ALL ? ( + + ) : ( + + )} + + ); }); diff --git a/web/core/constants/empty-state.tsx b/web/core/constants/empty-state.tsx index 70295c11e1f..d2bb26b9e7a 100644 --- a/web/core/constants/empty-state.tsx +++ b/web/core/constants/empty-state.tsx @@ -30,9 +30,6 @@ export enum EmptyStateType { WORKSPACE_DASHBOARD = "workspace-dashboard", WORKSPACE_ANALYTICS = "workspace-analytics", WORKSPACE_PROJECTS = "workspace-projects", - WORKSPACE_TEAMS = "workspace-teams", - WORKSPACE_INITIATIVES = "workspace-initiatives", - WORKSPACE_INITIATIVES_EMPTY_SEARCH = "workspace-initiatives-empty-search", WORKSPACE_ALL_ISSUES = "workspace-all-issues", WORKSPACE_ASSIGNED = "workspace-assigned", WORKSPACE_CREATED = "workspace-created", @@ -84,18 +81,6 @@ export enum EmptyStateType { ISSUE_RELATION_EMPTY_STATE = "issue-relation-empty-state", ISSUE_COMMENT_EMPTY_STATE = "issue-comment-empty-state", - EPIC_RELATION_SEARCH_EMPTY_STATE = "epic-relation-search-empty-state", - EPIC_RELATION_EMPTY_STATE = "epic-relation-empty-state", - - NOTIFICATION_DETAIL_EMPTY_STATE = "notification-detail-empty-state", - NOTIFICATION_ALL_EMPTY_STATE = "notification-all-empty-state", - NOTIFICATION_MENTIONS_EMPTY_STATE = "notification-mentions-empty-state", - NOTIFICATION_MY_ISSUE_EMPTY_STATE = "notification-my-issues-empty-state", - NOTIFICATION_CREATED_EMPTY_STATE = "notification-created-empty-state", - NOTIFICATION_SUBSCRIBED_EMPTY_STATE = "notification-subscribed-empty-state", - NOTIFICATION_ARCHIVED_EMPTY_STATE = "notification-archived-empty-state", - NOTIFICATION_SNOOZED_EMPTY_STATE = "notification-snoozed-empty-state", - NOTIFICATION_UNREAD_EMPTY_STATE = "notification-unread-empty-state", // stickies STICKIES = "stickies", STICKIES_SEARCH = "stickies-search", @@ -156,35 +141,6 @@ const emptyStateDetails: Record = { accessType: "workspace", access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER], }, - [EmptyStateType.WORKSPACE_TEAMS]: { - key: EmptyStateType.WORKSPACE_TEAMS, - title: "Teams", - description: "Teams are groups of people who collaborate on projects. Create a team to get started.", - path: "/empty-state/teams/teams", - primaryButton: { - text: "Create new team", - }, - accessType: "workspace", - access: [EUserPermissions.ADMIN], - }, - [EmptyStateType.WORKSPACE_INITIATIVES]: { - key: EmptyStateType.WORKSPACE_INITIATIVES, - title: "Organize work at the highest level with Initiatives", - description: - "When you need to organize work spanning several projects and teams, Initiatives come in handy. Connect projects and epics to initiatives, see automatically rolled up updates, and see the forests before you get to the trees.", - path: "/empty-state/initiatives/initiatives", - primaryButton: { - text: "Create an initiative", - }, - accessType: "workspace", - access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER], - }, - [EmptyStateType.WORKSPACE_INITIATIVES_EMPTY_SEARCH]: { - key: EmptyStateType.WORKSPACE_INITIATIVES_EMPTY_SEARCH, - title: "No matching initiatives", - description: "No initiatives detected with the matching criteria. \n Create a new initiative instead.", - path: "/empty-state/search/project", - }, // all-issues [EmptyStateType.WORKSPACE_ALL_ISSUES]: { key: EmptyStateType.WORKSPACE_ALL_ISSUES, @@ -629,78 +585,12 @@ const emptyStateDetails: Record = { title: "No issues found", path: "/empty-state/search/issues", }, - - [EmptyStateType.EPIC_RELATION_SEARCH_EMPTY_STATE]: { - key: EmptyStateType.EPIC_RELATION_SEARCH_EMPTY_STATE, - title: "No matching epics found", - path: "/empty-state/search/search", - }, - [EmptyStateType.EPIC_RELATION_EMPTY_STATE]: { - key: EmptyStateType.EPIC_RELATION_EMPTY_STATE, - title: "No epics found", - path: "/empty-state/search/issues", - }, - [EmptyStateType.ISSUE_COMMENT_EMPTY_STATE]: { key: EmptyStateType.ISSUE_COMMENT_EMPTY_STATE, title: "No comments yet", description: "Comments can be used as a discussion and \n follow-up space for the issues", path: "/empty-state/search/comments", }, - - [EmptyStateType.NOTIFICATION_DETAIL_EMPTY_STATE]: { - key: EmptyStateType.NOTIFICATION_DETAIL_EMPTY_STATE, - title: "Select to view details.", - path: "/empty-state/intake/issue-detail", - }, - [EmptyStateType.NOTIFICATION_ALL_EMPTY_STATE]: { - key: EmptyStateType.NOTIFICATION_ALL_EMPTY_STATE, - title: "No issues assigned", - description: "Updates for issues assigned to you can be \n seen here", - path: "/empty-state/search/notification", - }, - [EmptyStateType.NOTIFICATION_MENTIONS_EMPTY_STATE]: { - key: EmptyStateType.NOTIFICATION_MENTIONS_EMPTY_STATE, - title: "No issues assigned", - description: "Updates for issues assigned to you can be \n seen here", - path: "/empty-state/search/notification", - }, - [EmptyStateType.NOTIFICATION_MY_ISSUE_EMPTY_STATE]: { - key: EmptyStateType.NOTIFICATION_MY_ISSUE_EMPTY_STATE, - title: "No issues assigned", - description: "Updates for issues assigned to you can be \n seen here", - path: "/empty-state/search/notification", - }, - [EmptyStateType.NOTIFICATION_CREATED_EMPTY_STATE]: { - key: EmptyStateType.NOTIFICATION_CREATED_EMPTY_STATE, - title: "No updates to issues", - description: "Updates to issues created by you can be \n seen here", - path: "/empty-state/search/notification", - }, - [EmptyStateType.NOTIFICATION_SUBSCRIBED_EMPTY_STATE]: { - key: EmptyStateType.NOTIFICATION_SUBSCRIBED_EMPTY_STATE, - title: "No updates to issues", - description: "Updates to any issue you are \n subscribed to can be seen here", - path: "/empty-state/search/notification", - }, - [EmptyStateType.NOTIFICATION_UNREAD_EMPTY_STATE]: { - key: EmptyStateType.NOTIFICATION_UNREAD_EMPTY_STATE, - title: "No unread notifications", - description: "Congratulations, you are up-to-date \n with everything happening in the issues \n you care about", - path: "/empty-state/search/notification", - }, - [EmptyStateType.NOTIFICATION_SNOOZED_EMPTY_STATE]: { - key: EmptyStateType.NOTIFICATION_SNOOZED_EMPTY_STATE, - title: "No snoozed notifications yet", - description: "Any notification you snooze for later will \n be available here to act upon", - path: "/empty-state/search/snooze", - }, - [EmptyStateType.NOTIFICATION_ARCHIVED_EMPTY_STATE]: { - key: EmptyStateType.NOTIFICATION_ARCHIVED_EMPTY_STATE, - title: "No archived notifications yet", - description: "Any notification you archive will be \n available here to help you focus", - path: "/empty-state/search/archive", - }, [EmptyStateType.STICKIES]: { key: EmptyStateType.STICKIES, title: "Stickies are quick notes and to-dos you take down on the fly.", From 38927c1abb401100aca098f616e89d2e130db944 Mon Sep 17 00:00:00 2001 From: Prateek Shourya Date: Fri, 17 Jan 2025 13:06:43 +0530 Subject: [PATCH 13/26] chore: connections translation --- packages/i18n/src/locales/en/translations.json | 1 + packages/i18n/src/locales/es/translations.json | 1 + packages/i18n/src/locales/fr/translations.json | 1 + packages/i18n/src/locales/ja/translations.json | 1 + 4 files changed, 4 insertions(+) diff --git a/packages/i18n/src/locales/en/translations.json b/packages/i18n/src/locales/en/translations.json index 71952b05685..4c35af84ccf 100644 --- a/packages/i18n/src/locales/en/translations.json +++ b/packages/i18n/src/locales/en/translations.json @@ -314,6 +314,7 @@ "remove_parent_issue": "Remove parent issue", "add_parent": "Add parent", "loading_members": "Loading members...", + "connections" : "Connections", "workspace_dashboard": { "empty_state": { diff --git a/packages/i18n/src/locales/es/translations.json b/packages/i18n/src/locales/es/translations.json index 1066771efe6..e773c53a928 100644 --- a/packages/i18n/src/locales/es/translations.json +++ b/packages/i18n/src/locales/es/translations.json @@ -313,6 +313,7 @@ "remove_parent_issue": "Eliminar problema padre", "add_parent": "Agregar padre", "loading_members": "Cargando miembros...", + "connections": "Conexiones", "workspace_dashboard": { "empty_state": { diff --git a/packages/i18n/src/locales/fr/translations.json b/packages/i18n/src/locales/fr/translations.json index c9144e8ae5b..4154663432c 100644 --- a/packages/i18n/src/locales/fr/translations.json +++ b/packages/i18n/src/locales/fr/translations.json @@ -314,6 +314,7 @@ "remove_parent_issue": "Supprimer le problème parent", "add_parent": "Ajouter un parent", "loading_members": "Chargement des membres...", + "connections": "Connexions", "workspace_dashboard": { "empty_state": { diff --git a/packages/i18n/src/locales/ja/translations.json b/packages/i18n/src/locales/ja/translations.json index b4d4937f648..819c4915161 100644 --- a/packages/i18n/src/locales/ja/translations.json +++ b/packages/i18n/src/locales/ja/translations.json @@ -314,6 +314,7 @@ "remove_parent_issue": "親問題を削除", "add_parent": "親問題を追加", "loading_members": "メンバーを読み込んでいます...", + "connections": "接続", "workspace_dashboard": { "empty_state": { From 3fe907720fc73c20961bcc7ee140edf9c52fd203 Mon Sep 17 00:00:00 2001 From: Prateek Shourya Date: Fri, 17 Jan 2025 13:53:17 +0530 Subject: [PATCH 14/26] chore: issue comment, relation, bulk delete, and command k empty state translation --- .../i18n/src/locales/en/translations.json | 30 ++++++++++--- .../i18n/src/locales/es/translations.json | 38 ++++++++++------ .../i18n/src/locales/fr/translations.json | 38 ++++++++++------ .../i18n/src/locales/ja/translations.json | 38 ++++++++++------ .../command-palette/command-modal.tsx | 37 +++++++--------- .../core/modals/bulk-delete-issues-modal.tsx | 33 +++++++------- .../modals/issue-search-modal-empty-state.tsx | 44 ++++++++++++------- .../inbox/modals/select-duplicate.tsx | 40 ++++++++--------- .../issue-activity/comments/root.tsx | 19 +++++--- web/core/constants/empty-state.tsx | 27 ------------ 10 files changed, 193 insertions(+), 151 deletions(-) diff --git a/packages/i18n/src/locales/en/translations.json b/packages/i18n/src/locales/en/translations.json index 4c35af84ccf..4d40b00e6c7 100644 --- a/packages/i18n/src/locales/en/translations.json +++ b/packages/i18n/src/locales/en/translations.json @@ -591,13 +591,33 @@ "workspace_page_private_empty_state_description": "Keep your private thoughts here. When you're ready to share, the team's just a click away.", "workspace_page_private_empty_state_primary_button_text": "Create your first page", - "command_k_search_empty_state_title": "No results found", + "command_k": { + "empty_state": { + "search": { + "title": "No results found" + } + } + }, - "issue_relation_search_empty_state_title": "No matching issues found", - "issue_relation_empty_state_title": "No issues found", + "issue_relation": { + "empty_state": { + "search": { + "title": "No matching issues found" + }, + "no_issues": { + "title": "No issues found" + } + } + }, - "issue_comment_empty_state_title": "No comments yet", - "issue_comment_empty_state_description": "Comments can be used as a discussion and follow-up space for the issues", + "issue_comment": { + "empty_state": { + "general": { + "title": "No comments yet", + "description": "Comments can be used as a discussion and follow-up space for the issues" + } + } + }, "notification": { "empty_state": { diff --git a/packages/i18n/src/locales/es/translations.json b/packages/i18n/src/locales/es/translations.json index e773c53a928..0eb6236d8d2 100644 --- a/packages/i18n/src/locales/es/translations.json +++ b/packages/i18n/src/locales/es/translations.json @@ -593,21 +593,33 @@ "workspace_page_private_empty_state_description": "Mantén tus pensamientos privados aquí. Cuando estés listo para compartir, el equipo está a solo un clic de distancia.", "workspace_page_private_empty_state_primary_button_text": "Crea tu primera página", - "command_k_search_empty_state_title": "No se encontraron resultados", - - "issue_relation_search_empty_state_title": "No se encontraron problemas coincidentes", - "issue_relation_empty_state_title": "No se encontraron problemas", - - "issue_comment_empty_state_title": "Aún no hay comentarios", - "issue_comment_empty_state_description": "Los comentarios pueden usarse como un espacio de discusión y seguimiento para los problemas", - - "notification_detail_empty_state_title": "Selecciona para ver detalles.", + "command_k": { + "empty_state": { + "search": { + "title": "No se encontraron resultados" + } + } + }, - "notification_all_empty_state_title": "No hay problemas asignados", - "notification_all_empty_state_description": "Las actualizaciones de los problemas asignados a ti se pueden ver aquí", + "issue_relation": { + "empty_state": { + "search": { + "title": "No se encontraron problemas coincidentes" + }, + "general": { + "title": "No se encontraron problemas" + } + } + }, - "notification_mentions_empty_state_title": "No hay problemas asignados", - "notification_mentions_empty_state_description": "Las actualizaciones de los problemas asignados a ti se pueden ver aquí", + "issue_comment": { + "empty_state": { + "general": { + "title": "Aún no hay comentarios", + "description": "Los comentarios pueden usarse como un espacio de discusión y seguimiento para los problemas" + } + } + }, "notification": { "empty_state": { diff --git a/packages/i18n/src/locales/fr/translations.json b/packages/i18n/src/locales/fr/translations.json index 4154663432c..3f26a5bfc8f 100644 --- a/packages/i18n/src/locales/fr/translations.json +++ b/packages/i18n/src/locales/fr/translations.json @@ -594,21 +594,33 @@ "workspace_page_private_empty_state_description": "Gardez vos réflexions privées ici. Lorsque vous êtes prêt à les partager, l'équipe est à un clic de vous.", "workspace_page_private_empty_state_primary_button_text": "Créez votre première page", - "command_k_search_empty_state_title": "Aucun résultat trouvé", - - "issue_relation_search_empty_state_title": "Aucun problème correspondant trouvé", - "issue_relation_empty_state_title": "Aucun problème trouvé", - - "issue_comment_empty_state_title": "Pas encore de commentaires", - "issue_comment_empty_state_description": "Les commentaires peuvent être utilisés comme espace de discussion et de suivi pour les problèmes.", - - "notification_detail_empty_state_title": "Sélectionnez pour voir les détails.", + "command_k": { + "empty_state": { + "search": { + "title": "Aucun résultat trouvé" + } + } + }, - "notification_all_empty_state_title": "Aucun problème assigné", - "notification_all_empty_state_description": "Les mises à jour des problèmes qui vous sont assignés sont visibles ici.", + "issue_relation": { + "empty_state": { + "search": { + "title": "Aucun problème correspondant trouvé" + }, + "general": { + "title": "Aucun problème trouvé" + } + } + }, - "notification_mentions_empty_state_title": "Aucun problème assigné", - "notification_mentions_empty_state_description": "Les mises à jour des problèmes qui vous sont assignés sont visibles ici.", + "issue_comment": { + "empty_state": { + "general": { + "title": "Pas encore de commentaires", + "description": "Les commentaires peuvent être utilisés comme un espace de discussion et de suivi pour les problèmes" + } + } + }, "notification": { "empty_state": { diff --git a/packages/i18n/src/locales/ja/translations.json b/packages/i18n/src/locales/ja/translations.json index 819c4915161..284b7adb9b0 100644 --- a/packages/i18n/src/locales/ja/translations.json +++ b/packages/i18n/src/locales/ja/translations.json @@ -594,21 +594,33 @@ "workspace_page_private_empty_state_description": "ここで個人的な考えを記録してください。共有する準備ができたら、チームとワンクリックで共有できます。", "workspace_page_private_empty_state_primary_button_text": "最初のページを作成する", - "command_k_search_empty_state_title": "結果が見つかりません", - - "issue_relation_search_empty_state_title": "一致する課題が見つかりません", - "issue_relation_empty_state_title": "課題が見つかりません", - - "issue_comment_empty_state_title": "まだコメントがありません", - "issue_comment_empty_state_description": "コメントは課題に関する議論やフォローアップの場として活用できます", - - "notification_detail_empty_state_title": "詳細を表示するには選択してください。", + "command_k": { + "empty_state": { + "search": { + "title": "結果が見つかりません" + } + } + }, - "notification_all_empty_state_title": "割り当てられた課題はありません", - "notification_all_empty_state_description": "あなたに割り当てられた課題の更新はここで確認できます", + "issue_relation": { + "empty_state": { + "search": { + "title": "一致する課題が見つかりませんでした" + }, + "general": { + "title": "課題が見つかりません" + } + } + }, - "notification_mentions_empty_state_title": "割り当てられた課題はありません", - "notification_mentions_empty_state_description": "あなたに割り当てられた課題の更新はここで確認できます", + "issue_comment": { + "empty_state": { + "general": { + "title": "まだコメントはありません", + "description": "コメントは課題の議論やフォローアップスペースとして使用できます" + } + } + }, "notification": { "empty_state": { diff --git a/web/core/components/command-palette/command-modal.tsx b/web/core/components/command-palette/command-modal.tsx index b80b0dfe145..c6e8cb90951 100644 --- a/web/core/components/command-palette/command-modal.tsx +++ b/web/core/components/command-palette/command-modal.tsx @@ -2,14 +2,15 @@ import React, { useEffect, useState } from "react"; import { Command } from "cmdk"; +import { EUserPermissions, EUserPermissionsLevel } from "ee/constants/user-permissions"; import { observer } from "mobx-react"; import { useParams } from "next/navigation"; import useSWR from "swr"; import { FolderPlus, Search, Settings } from "lucide-react"; import { Dialog, Transition } from "@headlessui/react"; -// types +// plane imports +import { useTranslation } from "@plane/i18n"; import { IWorkspaceSearchResults } from "@plane/types"; -// ui import { LayersIcon, Loader, ToggleSwitch, Tooltip } from "@plane/ui"; // components import { @@ -23,9 +24,7 @@ import { CommandPaletteThemeActions, CommandPaletteWorkspaceSettingsActions, } from "@/components/command-palette"; -import { EmptyState } from "@/components/empty-state"; -// constants -import { EmptyStateType } from "@/constants/empty-state"; +import { SimpleEmptyState } from "@/components/empty-state"; // fetch-keys import { ISSUE_DETAILS } from "@/constants/fetch-keys"; // helpers @@ -36,21 +35,20 @@ import { useAppRouter } from "@/hooks/use-app-router"; import useDebounce from "@/hooks/use-debounce"; import { usePlatformOS } from "@/hooks/use-platform-os"; // plane web components +import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; import { IssueIdentifier } from "@/plane-web/components/issues"; // plane web services import { WorkspaceService } from "@/plane-web/services"; // services import { IssueService } from "@/services/issue"; -import { EUserPermissions, EUserPermissionsLevel } from "ee/constants/user-permissions"; const workspaceService = new WorkspaceService(); const issueService = new IssueService(); export const CommandModal: React.FC = observer(() => { - // hooks - const { workspaceProjectIds } = useProject(); - const { isMobile } = usePlatformOS(); - const { canPerformAnyCreateAction } = useUser(); + // router + const router = useAppRouter(); + const { workspaceSlug, projectId, issueId } = useParams(); // states const [placeholder, setPlaceholder] = useState("Type a command or search..."); const [resultsCount, setResultsCount] = useState(0); @@ -70,26 +68,25 @@ export const CommandModal: React.FC = observer(() => { }); const [isWorkspaceLevel, setIsWorkspaceLevel] = useState(false); const [pages, setPages] = useState([]); + // plane hooks + const { t } = useTranslation(); + // hooks + const { workspaceProjectIds } = useProject(); + const { isMobile } = usePlatformOS(); + const { canPerformAnyCreateAction } = useUser(); const { isCommandPaletteOpen, toggleCommandPaletteModal, toggleCreateIssueModal, toggleCreateProjectModal } = useCommandPalette(); const { allowPermissions } = useUserPermissions(); const { setTrackElement } = useEventTracker(); - - // router - const router = useAppRouter(); - // router params - const { workspaceSlug, projectId, issueId } = useParams(); - + // derived values const page = pages[pages.length - 1]; - const debouncedSearchTerm = useDebounce(searchTerm, 500); - const { baseTabIndex } = getTabIndex(undefined, isMobile); - const canPerformWorkspaceActions = allowPermissions( [EUserPermissions.ADMIN, EUserPermissions.MEMBER], EUserPermissionsLevel.WORKSPACE ); + const resolvedPath = useResolvedAssetPath({ basePath: "/empty-state/search/search" }); // TODO: update this to mobx store const { data: issueDetails } = useSWR( @@ -268,7 +265,7 @@ export const CommandModal: React.FC = observer(() => { {!isLoading && resultsCount === 0 && searchTerm !== "" && debouncedSearchTerm !== "" && (
- +
)} diff --git a/web/core/components/core/modals/bulk-delete-issues-modal.tsx b/web/core/components/core/modals/bulk-delete-issues-modal.tsx index aec70262ab1..73dd37a231a 100644 --- a/web/core/components/core/modals/bulk-delete-issues-modal.tsx +++ b/web/core/components/core/modals/bulk-delete-issues-modal.tsx @@ -6,19 +6,18 @@ import { useParams } from "next/navigation"; import { SubmitHandler, useForm } from "react-hook-form"; import { Search } from "lucide-react"; import { Combobox, Dialog, Transition } from "@headlessui/react"; +// plane imports import { EIssuesStoreType } from "@plane/constants"; -// types +import { useTranslation } from "@plane/i18n"; import { ISearchIssueResponse, IUser } from "@plane/types"; -// ui import { Button, Loader, TOAST_TYPE, setToast } from "@plane/ui"; // components -import { EmptyState } from "@/components/empty-state"; -// constants -import { EmptyStateType } from "@/constants/empty-state"; +import { SimpleEmptyState } from "@/components/empty-state"; // hooks import { useIssues } from "@/hooks/store"; import useDebounce from "@/hooks/use-debounce"; // services +import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; import { ProjectService } from "@/services/project"; // local components import { BulkDeleteIssuesModalItem } from "./bulk-delete-issues-modal-item"; @@ -39,16 +38,19 @@ export const BulkDeleteIssuesModal: React.FC = observer((props) => { const { isOpen, onClose } = props; // router params const { workspaceSlug, projectId } = useParams(); - // hooks - const { - issues: { removeBulkIssues }, - } = useIssues(EIssuesStoreType.PROJECT); // states const [query, setQuery] = useState(""); const [issues, setIssues] = useState([]); const [isSearching, setIsSearching] = useState(false); - + // hooks + const { + issues: { removeBulkIssues }, + } = useIssues(EIssuesStoreType.PROJECT); + const { t } = useTranslation(); + // derived values const debouncedSearchTerm: string = useDebounce(query, 500); + const searchResolvedPath = useResolvedAssetPath({ basePath: "/empty-state/search/search" }); + const issuesResolvedPath = useResolvedAssetPath({ basePath: "/empty-state/search/issues" }); useEffect(() => { if (!isOpen || !workspaceSlug || !projectId) return; @@ -131,12 +133,11 @@ export const BulkDeleteIssuesModal: React.FC = observer((props) => { ) : (
- + {query === "" ? ( + + ) : ( + + )}
); diff --git a/web/core/components/core/modals/issue-search-modal-empty-state.tsx b/web/core/components/core/modals/issue-search-modal-empty-state.tsx index 578d39a60fc..20646efb182 100644 --- a/web/core/components/core/modals/issue-search-modal-empty-state.tsx +++ b/web/core/components/core/modals/issue-search-modal-empty-state.tsx @@ -1,10 +1,10 @@ import React from "react"; -// components +// plane imports +import { useTranslation } from "@plane/i18n"; import { ISearchIssueResponse } from "@plane/types"; -import { EmptyState } from "@/components/empty-state"; -// types -import { EmptyStateType } from "@/constants/empty-state"; -// constants +// components +import { SimpleEmptyState } from "@/components/empty-state"; +import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; interface EmptyStateProps { issues: ISearchIssueResponse[]; @@ -19,18 +19,28 @@ export const IssueSearchModalEmptyState: React.FC = ({ debouncedSearchTerm, isSearching, }) => { - const renderEmptyState = (type: EmptyStateType) => ( -
- -
- ); + // plane hooks + const { t } = useTranslation(); + // derived values + const searchResolvedPath = useResolvedAssetPath({ basePath: "/empty-state/search/search" }); + const issuesResolvedPath = useResolvedAssetPath({ basePath: "/empty-state/search/issues" }); - const emptyState = - issues.length === 0 && searchTerm !== "" && debouncedSearchTerm !== "" && !isSearching - ? renderEmptyState(EmptyStateType.ISSUE_RELATION_SEARCH_EMPTY_STATE) - : issues.length === 0 - ? renderEmptyState(EmptyStateType.ISSUE_RELATION_EMPTY_STATE) - : null; + const EmptyStateContainer = ({ children }: { children: React.ReactNode }) => ( +
{children}
+ ); - return emptyState; + if (issues.length === 0 && searchTerm !== "" && debouncedSearchTerm !== "" && !isSearching) { + return ( + + + + ); + } else if (issues.length === 0) { + return ( + + + + ); + } + return null; }; diff --git a/web/core/components/inbox/modals/select-duplicate.tsx b/web/core/components/inbox/modals/select-duplicate.tsx index 9bcefad490a..ccd95593148 100644 --- a/web/core/components/inbox/modals/select-duplicate.tsx +++ b/web/core/components/inbox/modals/select-duplicate.tsx @@ -4,18 +4,16 @@ import React, { useEffect, useState } from "react"; import { useParams } from "next/navigation"; import { Search } from "lucide-react"; import { Combobox, Dialog, Transition } from "@headlessui/react"; -// icons -// components -// types +// plane imports +import { useTranslation } from "@plane/i18n"; import { ISearchIssueResponse } from "@plane/types"; -// ui import { Loader, TOAST_TYPE, setToast } from "@plane/ui"; -import { EmptyState } from "@/components/empty-state"; -// constants -import { EmptyStateType } from "@/constants/empty-state"; +// components +import { SimpleEmptyState } from "@/components/empty-state"; // hooks import { useProject } from "@/hooks/store"; import useDebounce from "@/hooks/use-debounce"; +import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; // services import { ProjectService } from "@/services/project"; @@ -30,18 +28,19 @@ const projectService = new ProjectService(); export const SelectDuplicateInboxIssueModal: React.FC = (props) => { const { isOpen, onClose, onSubmit, value } = props; - - const [query, setQuery] = useState(""); - + // router const { workspaceSlug, projectId, issueId } = useParams(); - - // hooks - const { getProjectById } = useProject(); - + // states + const [query, setQuery] = useState(""); const [issues, setIssues] = useState([]); const [isSearching, setIsSearching] = useState(false); - + // hooks + const { getProjectById } = useProject(); + const { t } = useTranslation(); + // derived values const debouncedSearchTerm: string = useDebounce(query, 500); + const searchResolvedPath = useResolvedAssetPath({ basePath: "/empty-state/search/search" }); + const issuesResolvedPath = useResolvedAssetPath({ basePath: "/empty-state/search/issues" }); useEffect(() => { if (!isOpen || !workspaceSlug || !projectId) return; @@ -110,12 +109,11 @@ export const SelectDuplicateInboxIssueModal: React.FC = (props) => { ) : (
- + {query === "" ? ( + + ) : ( + + )}
); diff --git a/web/core/components/issues/issue-detail/issue-activity/comments/root.tsx b/web/core/components/issues/issue-detail/issue-activity/comments/root.tsx index 7b481af355b..8a7e9210845 100644 --- a/web/core/components/issues/issue-detail/issue-activity/comments/root.tsx +++ b/web/core/components/issues/issue-detail/issue-activity/comments/root.tsx @@ -1,15 +1,15 @@ import { FC } from "react"; import { observer } from "mobx-react"; +// plane imports +import { useTranslation } from "@plane/i18n"; // components -import { EmptyState } from "@/components/empty-state"; -// hooks -import { EmptyStateType } from "@/constants/empty-state"; +import { SimpleEmptyState } from "@/components/empty-state"; // hooks import { useIssueDetail } from "@/hooks/store"; -// components +import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; +// local components import { TActivityOperations } from "../root"; import { IssueCommentCard } from "./comment-card"; -// types type TIssueCommentRoot = { projectId: string; @@ -26,6 +26,9 @@ export const IssueCommentRoot: FC = observer((props) => { const { comment: { getCommentsByIssueId }, } = useIssueDetail(); + const { t } = useTranslation(); + // derived values + const resolvedPath = useResolvedAssetPath({ basePath: "/empty-state/search/comments" }); const commentIds = getCommentsByIssueId(issueId); if (!commentIds) return <>; @@ -48,7 +51,11 @@ export const IssueCommentRoot: FC = observer((props) => { )) ) : (
- +
)}
diff --git a/web/core/constants/empty-state.tsx b/web/core/constants/empty-state.tsx index d2bb26b9e7a..d3a573893d0 100644 --- a/web/core/constants/empty-state.tsx +++ b/web/core/constants/empty-state.tsx @@ -76,11 +76,6 @@ export enum EmptyStateType { WORKSPACE_PAGE_PUBLIC = "workspace-page-public", WORKSPACE_PAGE_ARCHIVED = "workspace-page-archived", - COMMAND_K_SEARCH_EMPTY_STATE = "command-k-search-empty-state", - ISSUE_RELATION_SEARCH_EMPTY_STATE = "issue-relation-search-empty-state", - ISSUE_RELATION_EMPTY_STATE = "issue-relation-empty-state", - ISSUE_COMMENT_EMPTY_STATE = "issue-comment-empty-state", - // stickies STICKIES = "stickies", STICKIES_SEARCH = "stickies-search", @@ -569,28 +564,6 @@ const emptyStateDetails: Record = { description: "Archive pages not on your radar. Access them here when needed.", path: "/empty-state/pages/archived", }, - - [EmptyStateType.COMMAND_K_SEARCH_EMPTY_STATE]: { - key: EmptyStateType.COMMAND_K_SEARCH_EMPTY_STATE, - title: "No results found", - path: "/empty-state/search/search", - }, - [EmptyStateType.ISSUE_RELATION_SEARCH_EMPTY_STATE]: { - key: EmptyStateType.ISSUE_RELATION_SEARCH_EMPTY_STATE, - title: "No matching issues found", - path: "/empty-state/search/search", - }, - [EmptyStateType.ISSUE_RELATION_EMPTY_STATE]: { - key: EmptyStateType.ISSUE_RELATION_EMPTY_STATE, - title: "No issues found", - path: "/empty-state/search/issues", - }, - [EmptyStateType.ISSUE_COMMENT_EMPTY_STATE]: { - key: EmptyStateType.ISSUE_COMMENT_EMPTY_STATE, - title: "No comments yet", - description: "Comments can be used as a discussion and \n follow-up space for the issues", - path: "/empty-state/search/comments", - }, [EmptyStateType.STICKIES]: { key: EmptyStateType.STICKIES, title: "Stickies are quick notes and to-dos you take down on the fly.", From 2611105468204a860542cf67906fc72acbcaf5a2 Mon Sep 17 00:00:00 2001 From: Prateek Shourya Date: Fri, 17 Jan 2025 15:13:26 +0530 Subject: [PATCH 15/26] chore: project pages empty state and translations --- .../i18n/src/locales/en/translations.json | 53 ++++++----- .../i18n/src/locales/es/translations.json | 51 ++++++----- .../i18n/src/locales/fr/translations.json | 51 ++++++----- .../i18n/src/locales/ja/translations.json | 51 ++++++----- .../pages/pages-list-main-content.tsx | 81 +++++++++++++---- web/core/constants/empty-state.tsx | 89 ------------------- 6 files changed, 180 insertions(+), 196 deletions(-) diff --git a/packages/i18n/src/locales/en/translations.json b/packages/i18n/src/locales/en/translations.json index 4d40b00e6c7..ede8689dc12 100644 --- a/packages/i18n/src/locales/en/translations.json +++ b/packages/i18n/src/locales/en/translations.json @@ -314,7 +314,7 @@ "remove_parent_issue": "Remove parent issue", "add_parent": "Add parent", "loading_members": "Loading members...", - "connections" : "Connections", + "connections": "Connections", "workspace_dashboard": { "empty_state": { @@ -568,28 +568,35 @@ "project_view_empty_state_primary_button_comic_title": "Views work atop Issue properties.", "project_view_empty_state_primary_button_comic_description": "You can create a view from here with as many properties as filters as you see fit.", - "project_page_empty_state_title": "Write a note, a doc, or a full knowledge base. Get Galileo, Plane's AI assistant, to help you get started", - "project_page_empty_state_description": "Pages are thoughts potting space in Plane. Take down meeting notes, format them easily, embed issues, lay them out using a library of components, and keep them all in your project's context. To make short work of any doc, invoke Galileo, Plane's AI, with a shortcut or the click of a button.", - "project_page_empty_state_primary_button_text": "Create your first page", - - "project_page_private_empty_state_title": "No private pages yet", - "project_page_private_empty_state_description": "Keep your private thoughts here. When you're ready to share, the team's just a click away.", - "project_page_private_empty_state_primary_button_text": "Create your first page", - - "project_page_public_empty_state_title": "No public pages yet", - "project_page_public_empty_state_description": "See pages shared with everyone in your project right here.", - "project_page_public_empty_state_primary_button_text": "Create your first page", - - "project_page_archived_empty_state_title": "No archived pages yet", - "project_page_archived_empty_state_description": "Archive pages not on your radar. Access them here when needed.", - - "workspace_page_empty_state_title": "Write a note, a doc, or a full knowledge base. Get Galileo, Plane's AI assistant, to help you get started", - "workspace_page_empty_state_description": "Pages are thoughts potting space in Plane. Take down meeting notes, format them easily, embed issues, lay them out using a library of components, and keep them all in your project's context. To make short work of any doc, invoke Galileo, Plane's AI, with a shortcut or the click of a button.", - "workspace_page_empty_state_primary_button_text": "Create your first page", - - "workspace_page_private_empty_state_title": "No private pages yet", - "workspace_page_private_empty_state_description": "Keep your private thoughts here. When you're ready to share, the team's just a click away.", - "workspace_page_private_empty_state_primary_button_text": "Create your first page", + "project_page": { + "empty_state": { + "general": { + "title": "Write a note, a doc, or a full knowledge base. Get Galileo, Plane's AI assistant, to help you get started", + "description": "Pages are thoughts potting space in Plane. Take down meeting notes, format them easily, embed issues, lay them out using a library of components, and keep them all in your project's context. To make short work of any doc, invoke Galileo, Plane's AI, with a shortcut or the click of a button.", + "primary_button": { + "text": "Create your first page" + } + }, + "private": { + "title": "No private pages yet", + "description": "Keep your private thoughts here. When you're ready to share, the team's just a click away.", + "primary_button": { + "text": "Create your first page" + } + }, + "public": { + "title": "No public pages yet", + "description": "See pages shared with everyone in your project right here.", + "primary_button": { + "text": "Create your first page" + } + }, + "archived": { + "title": "No archived pages yet", + "description": "Archive pages not on your radar. Access them here when needed." + } + } + }, "command_k": { "empty_state": { diff --git a/packages/i18n/src/locales/es/translations.json b/packages/i18n/src/locales/es/translations.json index 0eb6236d8d2..a85fc91be96 100644 --- a/packages/i18n/src/locales/es/translations.json +++ b/packages/i18n/src/locales/es/translations.json @@ -570,28 +570,35 @@ "project_view_empty_state_primary_button_comic_title": "Las vistas funcionan sobre las propiedades de los Problemas.", "project_view_empty_state_primary_button_comic_description": "Puedes crear una vista desde aquí con tantas propiedades como filtros como consideres adecuado.", - "project_page_empty_state_title": "Escribe una nota, un documento o una base de conocimiento completa. Obtén ayuda de Galileo, el asistente de IA de Plane, para comenzar", - "project_page_empty_state_description": "Las páginas son espacios para plasmar pensamientos en Plane. Toma notas de reuniones, dales formato fácilmente, incorpora problemas, organízalos usando una biblioteca de componentes y mantenlos todos en el contexto de tu proyecto. Para hacer un trabajo rápido de cualquier documento, invoca a Galileo, la IA de Plane, con un atajo o el clic de un botón.", - "project_page_empty_state_primary_button_text": "Crea tu primera página", - - "project_page_private_empty_state_title": "Aún no hay páginas privadas", - "project_page_private_empty_state_description": "Mantén tus pensamientos privados aquí. Cuando estés listo para compartir, el equipo está a solo un clic de distancia.", - "project_page_private_empty_state_primary_button_text": "Crea tu primera página", - - "project_page_public_empty_state_title": "Aún no hay páginas públicas", - "project_page_public_empty_state_description": "Ve las páginas compartidas con todos en tu proyecto aquí mismo.", - "project_page_public_empty_state_primary_button_text": "Crea tu primera página", - - "project_page_archived_empty_state_title": "Aún no hay páginas archivadas", - "project_page_archived_empty_state_description": "Archiva las páginas que no estén en tu radar. Accede a ellas aquí cuando las necesites.", - - "workspace_page_empty_state_title": "Escribe una nota, un documento o una base de conocimiento completa. Obtén ayuda de Galileo, el asistente de IA de Plane, para comenzar", - "workspace_page_empty_state_description": "Las páginas son espacios para plasmar pensamientos en Plane. Toma notas de reuniones, dales formato fácilmente, incorpora problemas, organízalos usando una biblioteca de componentes y mantenlos todos en el contexto de tu proyecto. Para hacer un trabajo rápido de cualquier documento, invoca a Galileo, la IA de Plane, con un atajo o el clic de un botón.", - "workspace_page_empty_state_primary_button_text": "Crea tu primera página", - - "workspace_page_private_empty_state_title": "Aún no hay páginas privadas", - "workspace_page_private_empty_state_description": "Mantén tus pensamientos privados aquí. Cuando estés listo para compartir, el equipo está a solo un clic de distancia.", - "workspace_page_private_empty_state_primary_button_text": "Crea tu primera página", + "project_page": { + "empty_state": { + "general": { + "title": "Escribe una nota, un documento o una base de conocimiento completa. Deja que Galileo, el asistente de IA de Plane, te ayude a empezar", + "description": "Las páginas son un espacio para capturar ideas en Plane. Toma notas de reuniones, formatearlas fácilmente, incrusta problemas, organiza usando una biblioteca de componentes y mantén todo en el contexto de tu proyecto. Para simplificar cualquier documento, invoca a Galileo, la IA de Plane, con un atajo o un clic.", + "primary_button": { + "text": "Crea tu primera página" + } + }, + "private": { + "title": "Aún no hay páginas privadas", + "description": "Guarda aquí tus pensamientos privados. Cuando estés listo para compartirlos, el equipo está a un clic de distancia.", + "primary_button": { + "text": "Crea tu primera página" + } + }, + "public": { + "title": "Aún no hay páginas públicas", + "description": "Consulta aquí las páginas compartidas con todos en tu proyecto.", + "primary_button": { + "text": "Crea tu primera página" + } + }, + "archived": { + "title": "Aún no hay páginas archivadas", + "description": "Archiva las páginas que no están en tu radar. Accede a ellas aquí cuando las necesites." + } + } + }, "command_k": { "empty_state": { diff --git a/packages/i18n/src/locales/fr/translations.json b/packages/i18n/src/locales/fr/translations.json index 3f26a5bfc8f..7d78806534f 100644 --- a/packages/i18n/src/locales/fr/translations.json +++ b/packages/i18n/src/locales/fr/translations.json @@ -571,28 +571,35 @@ "project_view_empty_state_primary_button_comic_title": "Les vues fonctionnent sur les propriétés des problèmes.", "project_view_empty_state_primary_button_comic_description": "Vous pouvez créer une vue à partir d'ici avec autant de propriétés et de filtres que vous le souhaitez.", - "project_page_empty_state_title": "Écrivez une note, un document ou une base de connaissances complète. Demandez à Galileo, l'assistant IA de Plane, de vous aider à démarrer.", - "project_page_empty_state_description": "Les pages sont des espaces de réflexion dans Plane. Prenez des notes de réunion, mettez-les en forme facilement, intégrez des problèmes, organisez-les à l'aide d'une bibliothèque de composants, et gardez-les dans le contexte de votre projet. Pour simplifier tout document, invoquez Galileo, l'IA de Plane, avec un raccourci ou un simple clic.", - "project_page_empty_state_primary_button_text": "Créez votre première page", - - "project_page_private_empty_state_title": "Aucune page privée pour l'instant", - "project_page_private_empty_state_description": "Gardez vos réflexions privées ici. Lorsque vous êtes prêt à les partager, l'équipe est à un clic de vous.", - "project_page_private_empty_state_primary_button_text": "Créez votre première page", - - "project_page_public_empty_state_title": "Aucune page publique pour l'instant", - "project_page_public_empty_state_description": "Consultez ici les pages partagées avec tout le monde dans votre projet.", - "project_page_public_empty_state_primary_button_text": "Créez votre première page", - - "project_page_archived_empty_state_title": "Aucune page archivée pour l'instant", - "project_page_archived_empty_state_description": "Archivez les pages qui ne sont plus sur votre radar. Accédez-y ici au besoin.", - - "workspace_page_empty_state_title": "Écrivez une note, un document ou une base de connaissances complète. Demandez à Galileo, l'assistant IA de Plane, de vous aider à démarrer.", - "workspace_page_empty_state_description": "Les pages sont des espaces de réflexion dans Plane. Prenez des notes de réunion, mettez-les en forme facilement, intégrez des problèmes, organisez-les à l'aide d'une bibliothèque de composants, et gardez-les dans le contexte de votre projet. Pour simplifier tout document, invoquez Galileo, l'IA de Plane, avec un raccourci ou un simple clic.", - "workspace_page_empty_state_primary_button_text": "Créez votre première page", - - "workspace_page_private_empty_state_title": "Aucune page privée pour l'instant", - "workspace_page_private_empty_state_description": "Gardez vos réflexions privées ici. Lorsque vous êtes prêt à les partager, l'équipe est à un clic de vous.", - "workspace_page_private_empty_state_primary_button_text": "Créez votre première page", + "project_page": { + "empty_state": { + "general": { + "title": "Écrivez une note, un document ou une base de connaissances complète. Laissez Galileo, l'assistant IA de Plane, vous aider à démarrer", + "description": "Les pages sont un espace pour capturer des idées dans Plane. Prenez des notes de réunion, formatez-les facilement, intégrez des problèmes, organisez-les en utilisant une bibliothèque de composants et gardez-les toutes dans le contexte de votre projet. Pour simplifier tout document, invoquez Galileo, l'IA de Plane, avec un raccourci ou en cliquant sur un bouton.", + "primary_button": { + "text": "Créez votre première page" + } + }, + "private": { + "title": "Aucune page privée pour le moment", + "description": "Conservez vos pensées privées ici. Lorsque vous êtes prêt à les partager, votre équipe n'est qu'à un clic.", + "primary_button": { + "text": "Créez votre première page" + } + }, + "public": { + "title": "Aucune page publique pour le moment", + "description": "Consultez ici les pages partagées avec tout le monde dans votre projet.", + "primary_button": { + "text": "Créez votre première page" + } + }, + "archived": { + "title": "Aucune page archivée pour le moment", + "description": "Archivez les pages qui ne sont pas sur votre radar. Accédez-y ici en cas de besoin." + } + } + }, "command_k": { "empty_state": { diff --git a/packages/i18n/src/locales/ja/translations.json b/packages/i18n/src/locales/ja/translations.json index 284b7adb9b0..e9095bbc241 100644 --- a/packages/i18n/src/locales/ja/translations.json +++ b/packages/i18n/src/locales/ja/translations.json @@ -571,28 +571,35 @@ "project_view_empty_state_primary_button_comic_title": "ビューは課題のプロパティに基づいて動作します。", "project_view_empty_state_primary_button_comic_description": "ここからプロパティをいくつでもフィルターとして追加してビューを作成できます。", - "project_page_empty_state_title": "メモ、ドキュメント、または完全なナレッジベースを書きます。PlaneのAIアシスタントであるガリレオが開始をお手伝いします。", - "project_page_empty_state_description": "ページはPlaneでアイデアを記録するスペースです。会議のメモを取ったり、簡単にフォーマットしたり、課題を埋め込んだり、コンポーネントのライブラリを使用してレイアウトしたりして、すべてをプロジェクトの文脈に保ちます。どんなドキュメントでも簡単に作成するには、ショートカットやボタンをクリックしてガリレオを呼び出してください。", - "project_page_empty_state_primary_button_text": "最初のページを作成する", - - "project_page_private_empty_state_title": "まだプライベートページはありません", - "project_page_private_empty_state_description": "ここで個人的な考えを記録してください。共有する準備ができたら、チームとワンクリックで共有できます。", - "project_page_private_empty_state_primary_button_text": "最初のページを作成する", - - "project_page_public_empty_state_title": "まだ公開されたページはありません", - "project_page_public_empty_state_description": "プロジェクト内のすべての人と共有されたページをここで確認してください。", - "project_page_public_empty_state_primary_button_text": "最初のページを作成する", - - "project_page_archived_empty_state_title": "まだアーカイブされたページはありません", - "project_page_archived_empty_state_description": "レーダーに載っていないページをアーカイブします。必要に応じてここからアクセスできます。", - - "workspace_page_empty_state_title": "メモ、ドキュメント、または完全なナレッジベースを書きます。PlaneのAIアシスタントであるガリレオが開始をお手伝いします。", - "workspace_page_empty_state_description": "ページはPlaneでアイデアを記録するスペースです。会議のメモを取ったり、簡単にフォーマットしたり、課題を埋め込んだり、コンポーネントのライブラリを使用してレイアウトしたりして、すべてをプロジェクトの文脈に保ちます。どんなドキュメントでも簡単に作成するには、ショートカットやボタンをクリックしてガリレオを呼び出してください。", - "workspace_page_empty_state_primary_button_text": "最初のページを作成する", - - "workspace_page_private_empty_state_title": "まだプライベートページはありません", - "workspace_page_private_empty_state_description": "ここで個人的な考えを記録してください。共有する準備ができたら、チームとワンクリックで共有できます。", - "workspace_page_private_empty_state_primary_button_text": "最初のページを作成する", + "project_page": { + "empty_state": { + "general": { + "title": "メモ、ドキュメント、または完全なナレッジベースを書きましょう。PlaneのAIアシスタントGalileoがスタートをサポートします", + "description": "ページはPlaneでアイデアをまとめるスペースです。会議のメモを取る、簡単にフォーマットする、課題を埋め込む、コンポーネントライブラリを使用してレイアウトするなど、すべてをプロジェクトのコンテキスト内に保ちます。どんなドキュメントでも簡単にするために、ショートカットやボタンのクリックでPlaneのAIであるGalileoを呼び出してください。", + "primary_button": { + "text": "最初のページを作成" + } + }, + "private": { + "title": "まだプライベートページはありません", + "description": "プライベートな考えをここに保存します。共有する準備ができたら、チームはすぐそばにいます。", + "primary_button": { + "text": "最初のページを作成" + } + }, + "public": { + "title": "まだ公開ページはありません", + "description": "プロジェクト内のすべての人と共有されているページをここで確認してください。", + "primary_button": { + "text": "最初のページを作成" + } + }, + "archived": { + "title": "まだアーカイブされたページはありません", + "description": "レーダーに載っていないページをアーカイブします。必要なときにここからアクセスしてください。" + } + } + }, "command_k": { "empty_state": { diff --git a/web/core/components/pages/pages-list-main-content.tsx b/web/core/components/pages/pages-list-main-content.tsx index a0b4b356591..4600f90406a 100644 --- a/web/core/components/pages/pages-list-main-content.tsx +++ b/web/core/components/pages/pages-list-main-content.tsx @@ -1,15 +1,16 @@ import { observer } from "mobx-react"; import Image from "next/image"; -// types +// plane imports +import { EUserPermissionsLevel, EUserWorkspaceRoles } from "@plane/constants"; +import { useTranslation } from "@plane/i18n"; import { TPageNavigationTabs } from "@plane/types"; // components -import { EmptyState } from "@/components/empty-state"; +import { DetailedEmptyState } from "@/components/empty-state"; import { PageLoader } from "@/components/pages"; -// constants -import { EmptyStateType } from "@/constants/empty-state"; // hooks import { EPageAccess } from "@/constants/page"; -import { useCommandPalette, useProjectPages } from "@/hooks/store"; +import { useCommandPalette, useProjectPages, useUserPermissions } from "@/hooks/store"; +import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; // assets import AllFiltersImage from "@/public/empty-state/pages/all-filters.svg"; import NameFilterImage from "@/public/empty-state/pages/name-filter.svg"; @@ -21,46 +22,90 @@ type Props = { export const PagesListMainContent: React.FC = observer((props) => { const { children, pageType } = props; + // plane hooks + const { t } = useTranslation(); // store hooks const { loader, isAnyPageAvailable, getCurrentProjectFilteredPageIds, getCurrentProjectPageIds, filters } = useProjectPages(); const { toggleCreatePageModal } = useCommandPalette(); + const { allowPermissions } = useUserPermissions(); // derived values const pageIds = getCurrentProjectPageIds(pageType); const filteredPageIds = getCurrentProjectFilteredPageIds(pageType); + const canPerformEmptyStateActions = allowPermissions( + [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER], + EUserPermissionsLevel.WORKSPACE + ); + const generalPageResolvedPath = useResolvedAssetPath({ + basePath: "/empty-state/onboarding/pages", + }); + const publicPageResolvedPath = useResolvedAssetPath({ + basePath: "/empty-state/pages/public", + }); + const privatePageResolvedPath = useResolvedAssetPath({ + basePath: "/empty-state/pages/private", + }); + const archivedPageResolvedPath = useResolvedAssetPath({ + basePath: "/empty-state/pages/archived", + }); if (loader === "init-loader") return ; // if no pages exist in the active page type if (!isAnyPageAvailable || pageIds?.length === 0) { if (!isAnyPageAvailable) { return ( - { - toggleCreatePageModal({ isOpen: true }); + { + toggleCreatePageModal({ isOpen: true }); + }, + disabled: !canPerformEmptyStateActions, }} /> ); } if (pageType === "public") return ( - { - toggleCreatePageModal({ isOpen: true, pageAccess: EPageAccess.PUBLIC }); + { + toggleCreatePageModal({ isOpen: true, pageAccess: EPageAccess.PUBLIC }); + }, + disabled: !canPerformEmptyStateActions, }} /> ); if (pageType === "private") return ( - { - toggleCreatePageModal({ isOpen: true, pageAccess: EPageAccess.PRIVATE }); + { + toggleCreatePageModal({ isOpen: true, pageAccess: EPageAccess.PRIVATE }); + }, + disabled: !canPerformEmptyStateActions, }} /> ); - if (pageType === "archived") return ; + if (pageType === "archived") + return ( + + ); } // if no pages match the filter criteria if (filteredPageIds?.length === 0) diff --git a/web/core/constants/empty-state.tsx b/web/core/constants/empty-state.tsx index d3a573893d0..df347952a8d 100644 --- a/web/core/constants/empty-state.tsx +++ b/web/core/constants/empty-state.tsx @@ -67,14 +67,6 @@ export enum EmptyStateType { PROJECT_MODULE = "project-module", PROJECT_ARCHIVED_NO_MODULES = "project-archived-no-modules", PROJECT_VIEW = "project-view", - PROJECT_PAGE = "project-page", - PROJECT_PAGE_PRIVATE = "project-page-private", - PROJECT_PAGE_PUBLIC = "project-page-public", - PROJECT_PAGE_ARCHIVED = "project-page-archived", - WORKSPACE_PAGE = "workspace-page", - WORKSPACE_PAGE_PRIVATE = "workspace-page-private", - WORKSPACE_PAGE_PUBLIC = "workspace-page-public", - WORKSPACE_PAGE_ARCHIVED = "workspace-page-archived", // stickies STICKIES = "stickies", @@ -483,87 +475,6 @@ const emptyStateDetails: Record = { accessType: "project", access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER, EUserPermissions.GUEST], }, - // project pages - [EmptyStateType.PROJECT_PAGE]: { - key: EmptyStateType.PROJECT_PAGE, - title: "Write a note, a doc, or a full knowledge base. Get Galileo, Plane’s AI assistant, to help you get started", - description: - "Pages are thoughts potting space in Plane. Take down meeting notes, format them easily, embed issues, lay them out using a library of components, and keep them all in your project’s context. To make short work of any doc, invoke Galileo, Plane’s AI, with a shortcut or the click of a button.", - path: "/empty-state/onboarding/pages", - primaryButton: { - text: "Create your first page", - }, - accessType: "project", - access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER], - }, - [EmptyStateType.PROJECT_PAGE_PRIVATE]: { - key: EmptyStateType.PROJECT_PAGE_PRIVATE, - title: "No private pages yet", - description: "Keep your private thoughts here. When you're ready to share, the team's just a click away.", - path: "/empty-state/pages/private", - primaryButton: { - text: "Create your first page", - }, - accessType: "project", - access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER], - }, - [EmptyStateType.PROJECT_PAGE_PUBLIC]: { - key: EmptyStateType.PROJECT_PAGE_PUBLIC, - title: "No public pages yet", - description: "See pages shared with everyone in your project right here.", - path: "/empty-state/pages/public", - primaryButton: { - text: "Create your first page", - }, - accessType: "project", - access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER], - }, - [EmptyStateType.PROJECT_PAGE_ARCHIVED]: { - key: EmptyStateType.PROJECT_PAGE_ARCHIVED, - title: "No archived pages yet", - description: "Archive pages not on your radar. Access them here when needed.", - path: "/empty-state/pages/archived", - }, - [EmptyStateType.WORKSPACE_PAGE]: { - key: EmptyStateType.WORKSPACE_PAGE, - title: "Write a note, a doc, or a full knowledge base. Get Galileo, Plane’s AI assistant, to help you get started", - description: - "Pages are thoughts potting space in Plane. Take down meeting notes, format them easily, embed issues, lay them out using a library of components, and keep them all in your project’s context. To make short work of any doc, invoke Galileo, Plane’s AI, with a shortcut or the click of a button.", - path: "/empty-state/onboarding/pages", - primaryButton: { - text: "Create your first page", - }, - accessType: "workspace", - access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER], - }, - [EmptyStateType.WORKSPACE_PAGE_PRIVATE]: { - key: EmptyStateType.WORKSPACE_PAGE_PRIVATE, - title: "No private pages yet", - description: "Keep your private thoughts here. When you're ready to share, the team's just a click away.", - path: "/empty-state/pages/private", - primaryButton: { - text: "Create your first page", - }, - accessType: "workspace", - access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER], - }, - [EmptyStateType.WORKSPACE_PAGE_PUBLIC]: { - key: EmptyStateType.WORKSPACE_PAGE_PUBLIC, - title: "No public pages yet", - description: "See pages shared with everyone in your workspace right here.", - path: "/empty-state/pages/public", - primaryButton: { - text: "Create your first page", - }, - accessType: "workspace", - access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER], - }, - [EmptyStateType.WORKSPACE_PAGE_ARCHIVED]: { - key: EmptyStateType.WORKSPACE_PAGE_ARCHIVED, - title: "No archived pages yet", - description: "Archive pages not on your radar. Access them here when needed.", - path: "/empty-state/pages/archived", - }, [EmptyStateType.STICKIES]: { key: EmptyStateType.STICKIES, title: "Stickies are quick notes and to-dos you take down on the fly.", From 77a48335d57523fde8d9f5f3ba4f62e04cc7f488 Mon Sep 17 00:00:00 2001 From: Prateek Shourya Date: Fri, 17 Jan 2025 16:45:34 +0530 Subject: [PATCH 16/26] chore: project module and view related empty state --- .../i18n/src/locales/en/translations.json | 98 +++++++++++++------ .../i18n/src/locales/es/translations.json | 98 +++++++++++++------ .../i18n/src/locales/fr/translations.json | 98 +++++++++++++------ .../i18n/src/locales/ja/translations.json | 98 +++++++++++++------ .../[projectId]/cycles/(list)/page.tsx | 4 +- .../(detail)/[projectId]/inbox/page.tsx | 4 +- .../[projectId]/modules/(list)/page.tsx | 4 +- .../[projectId]/pages/(list)/page.tsx | 4 +- .../[projectId]/views/(list)/page.tsx | 4 +- web/app/profile/notifications/page.tsx | 2 +- web/app/profile/page.tsx | 2 +- .../issue-layouts/empty-states/module.tsx | 90 +++++++++++------ .../modules/archived-modules/root.tsx | 18 ++-- .../components/modules/modules-list-view.tsx | 41 ++++++-- .../pages/pages-list-main-content.tsx | 6 +- .../project/project-feature-update.tsx | 2 +- web/core/components/views/views-list.tsx | 36 ++++++- .../components/workspace/sidebar/dropdown.tsx | 2 +- .../workspace/sidebar/user-menu.tsx | 2 +- web/core/constants/empty-state.tsx | 59 ----------- 20 files changed, 427 insertions(+), 245 deletions(-) diff --git a/packages/i18n/src/locales/en/translations.json b/packages/i18n/src/locales/en/translations.json index ede8689dc12..756f7857805 100644 --- a/packages/i18n/src/locales/en/translations.json +++ b/packages/i18n/src/locales/en/translations.json @@ -220,7 +220,6 @@ "join_the_project_to_rearrange": "Join the project to rearrange", "drag_to_rearrange": "Drag to rearrange", "congrats": "Congrats!", - "project": "Project", "open_project": "Open project", "issues": "Issues", "cycles": "Cycles", @@ -417,7 +416,7 @@ }, "workspace_settings": { - "name": "Workspace settings", + "label": "Workspace settings", "empty_state": { "api_tokens": { "title": "No API tokens created", @@ -439,7 +438,7 @@ }, "profile": { - "name": "Profile", + "label": "Profile", "empty_state": { "activity": { "title": "No activities yet", @@ -518,21 +517,12 @@ "project_archived_no_cycles_empty_state_title": "No archived cycles yet", "project_archived_no_cycles_empty_state_description": "To tidy up your project, archive completed cycles. Find them here once archived.", - "project_empty_filter_empty_state_title": "No issues found matching the filters applied", - "project_empty_filter_empty_state_secondary_button_text": "Clear all filters", - "project_archived_empty_filter_empty_state_title": "No issues found matching the filters applied", "project_archived_empty_filter_empty_state_secondary_button_text": "Clear all filters", "project_draft_empty_filter_empty_state_title": "No issues found matching the filters applied", "project_draft_empty_filter_empty_state_secondary_button_text": "Clear all filters", - "project_no_issues_empty_state_title": "Create an issue and assign it to someone, even yourself", - "project_no_issues_empty_state_description": "Think of issues as jobs, tasks, work, or JTBD. Which we like. An issue and its sub-issues are usually time-based actionables assigned to members of your team. Your team creates, assigns, and completes issues to move your project towards its goal.", - "project_no_issues_empty_state_primary_button_text": "Create your first issue", - "project_no_issues_empty_state_primary_button_comic_title": "Issues are building blocks in Plane.", - "project_no_issues_empty_state_primary_button_comic_description": "Redesign the Plane UI, Rebrand the company, or Launch the new fuel injection system are examples of issues that likely have sub-issues.", - "project_archived_no_issues_empty_state_title": "No archived issues yet", "project_archived_no_issues_empty_state_description": "Manually or through automation, you can archive issues that are completed or cancelled. Find them here once archived.", "project_archived_no_issues_empty_state_primary_button_text": "Set automation", @@ -549,24 +539,74 @@ "members_empty_search_empty_state_title": "No matching members", "members_empty_search_empty_state_description": "Add them to the project if they are already a part of the workspace", - "project_module_issues_empty_state_title": "No issues in the module", - "project_module_issues_empty_state_description": "Create or add issues which you want to accomplish as part of this module", - "project_module_issues_empty_state_primary_button_text": "Create new issue", - "project_module_issues_empty_state_secondary_button_text": "Add an existing issue", - - "project_module_empty_state_title": "Map your project milestones to Modules and track aggregated work easily.", - "project_module_empty_state_description": "A group of issues that belong to a logical, hierarchical parent form a module. Think of them as a way to track work by project milestones. They have their own periods and deadlines as well as analytics to help you see how close or far you are from a milestone.", - "project_module_empty_state_primary_button_text": "Build your first module", - "project_module_empty_state_primary_button_comic_title": "Modules help group work by hierarchy.", - "project_module_empty_state_primary_button_comic_description": "A cart module, a chassis module, and a warehouse module are all good example of this grouping.", + "project": { + "label": "Project", + "empty_state": { + "no_issues": { + "title": "Create an issue and assign it to someone, even yourself", + "description": "Think of issues as jobs, tasks, work, or JTBD. Which we like. An issue and its sub-issues are usually time-based actionables assigned to members of your team. Your team creates, assigns, and completes issues to move your project towards its goal.", + "primary_button": { + "text": "Create your first issue", + "comic": { + "title": "Issues are building blocks in Plane.", + "description": "Redesign the Plane UI, Rebrand the company, or Launch the new fuel injection system are examples of issues that likely have sub-issues." + } + } + }, + "issues_empty_filter": { + "title": "No issues found matching the filters applied", + "secondary_button": { + "text": "Clear all filters" + } + } + } + }, - "project_archived_no_modules_empty_state_title": "No archived Modules yet", - "project_archived_no_modules_empty_state_description": "To tidy up your project, archive completed or cancelled modules. Find them here once archived.", + "project_module": { + "empty_state": { + "general": { + "title": "Map your project milestones to Modules and track aggregated work easily.", + "description": "A group of issues that belong to a logical, hierarchical parent form a module. Think of them as a way to track work by project milestones. They have their own periods and deadlines as well as analytics to help you see how close or far you are from a milestone.", + "primary_button": { + "text": "Build your first module", + "comic": { + "title": "Modules help group work by hierarchy.", + "description": "A cart module, a chassis module, and a warehouse module are all good example of this grouping." + } + } + }, + "no_issues": { + "title": "No issues in the module", + "description": "Create or add issues which you want to accomplish as part of this module", + "primary_button": { + "text": "Create new issue" + }, + "secondary_button": { + "text": "Add an existing issue" + } + }, + "archived": { + "title": "No archived Modules yet", + "description": "To tidy up your project, archive completed or cancelled modules. Find them here once archived." + } + } + }, - "project_view_empty_state_title": "Save filtered views for your project. Create as many as you need", - "project_view_empty_state_primary_button_text": "Create your first view", - "project_view_empty_state_primary_button_comic_title": "Views work atop Issue properties.", - "project_view_empty_state_primary_button_comic_description": "You can create a view from here with as many properties as filters as you see fit.", + "project_view": { + "empty_state": { + "general": { + "title": "Save filtered views for your project. Create as many as you need", + "description": "Views are a set of saved filters that you use frequently or want easy access to. All your colleagues in a project can see everyone’s views and choose whichever suits their needs best.", + "primary_button": { + "text": "Create your first view", + "comic": { + "title": "Views work atop Issue properties.", + "description": "You can create a view from here with as many properties as filters as you see fit." + } + } + } + } + }, "project_page": { "empty_state": { @@ -703,7 +743,7 @@ }, "inbox": { - "name": "Inbox", + "label": "Inbox", "empty_state": { "sidebar_open_tab": { "title": "No open issues", diff --git a/packages/i18n/src/locales/es/translations.json b/packages/i18n/src/locales/es/translations.json index a85fc91be96..12702c8ece2 100644 --- a/packages/i18n/src/locales/es/translations.json +++ b/packages/i18n/src/locales/es/translations.json @@ -219,7 +219,6 @@ "join_the_project_to_rearrange": "Únete al proyecto para reordenar", "drag_to_rearrange": "Arrastra para reordenar", "congrats": "¡Felicitaciones!", - "project": "Proyecto", "open_project": "Abrir proyecto", "issues": "Problemas", "cycles": "Ciclos", @@ -416,7 +415,7 @@ }, "workspace_settings": { - "name": "Configuración del espacio de trabajo", + "label": "Configuración del espacio de trabajo", "empty_state": { "api_tokens": { "title": "No se han creado tokens API", @@ -438,7 +437,7 @@ }, "profile": { - "name": "Perfil", + "label": "Perfil", "empty_state": { "activity": { "title": "Aún no hay actividades", @@ -520,21 +519,12 @@ "project_cycle_all_empty_state_title": "No hay ciclos", "project_cycle_all_empty_state_description": "Un ciclo activo incluye cualquier período que abarque la fecha de hoy dentro de su rango. Encuentra el progreso y los detalles del ciclo activo aquí.", - "project_empty_filter_empty_state_title": "No se encontraron problemas que coincidan con los filtros aplicados", - "project_empty_filter_empty_state_secondary_button_text": "Limpiar todos los filtros", - "project_archived_empty_filter_empty_state_title": "No se encontraron problemas que coincidan con los filtros aplicados", "project_archived_empty_filter_empty_state_secondary_button_text": "Limpiar todos los filtros", "project_draft_empty_filter_empty_state_title": "No se encontraron problemas que coincidan con los filtros aplicados", "project_draft_empty_filter_empty_state_secondary_button_text": "Limpiar todos los filtros", - "project_no_issues_empty_state_title": "Crea un problema y asígnalo a alguien, incluso a ti mismo", - "project_no_issues_empty_state_description": "Piensa en los problemas como trabajos, tareas, trabajo o JTBD. Que nos gusta. Un problema y sus sub-problemas son generalmente acciones basadas en tiempo asignadas a miembros de tu equipo. Tu equipo crea, asigna y completa problemas para mover tu proyecto hacia su objetivo.", - "project_no_issues_empty_state_primary_button_text": "Crea tu primer problema", - "project_no_issues_empty_state_primary_button_comic_title": "Los problemas son bloques de construcción en Plane.", - "project_no_issues_empty_state_primary_button_comic_description": "Rediseñar la interfaz de usuario de Plane, Cambiar la marca de la empresa o Lanzar el nuevo sistema de inyección de combustible son ejemplos de problemas que probablemente tengan sub-problemas.", - "project_archived_no_issues_empty_state_title": "No hay problemas archivados aún", "project_archived_no_issues_empty_state_description": "Manual o mediante automatización, puedes archivar problemas que están completados o cancelados. Encuéntralos aquí una vez archivados.", "project_archived_no_issues_empty_state_primary_button_text": "Establecer automatización", @@ -551,24 +541,74 @@ "members_empty_search_empty_state_title": "No hay miembros coincidentes", "members_empty_search_empty_state_description": "Añádelos al proyecto si ya son parte del espacio de trabajo", - "project_module_issues_empty_state_title": "No hay problemas en el módulo", - "project_module_issues_empty_state_description": "Crea o añade problemas que quieras realizar como parte de este módulo", - "project_module_issues_empty_state_primary_button_text": "Crear nuevo problema", - "project_module_issues_empty_state_secondary_button_text": "Añadir un problema existente", - - "project_module_empty_state_title": "Mapea los hitos de tu proyecto a Módulos y rastrea el trabajo agregado fácilmente.", - "project_module_empty_state_description": "Un grupo de problemas que pertenecen a un padre lógico y jerárquico forman un módulo. Piensa en ellos como una forma de rastrear el trabajo por hitos del proyecto. Tienen sus propios períodos y fechas límite, así como análisis para ayudarte a ver qué tan cerca o lejos estás de un hito.", - "project_module_empty_state_primary_button_text": "Construye tu primer módulo", - "project_module_empty_state_primary_button_comic_title": "Los Módulos ayudan a agrupar el trabajo por jerarquía.", - "project_module_empty_state_primary_button_comic_description": "Un módulo de carrito, un módulo de chasis y un módulo de almacén son todos buenos ejemplos de esta agrupación.", + "project": { + "label": "Proyecto", + "empty_state": { + "no_issues": { + "title": "Crea un problema y asígnalo a alguien, incluso a ti mismo", + "description": "Piensa en los problemas como trabajos, tareas, acciones, o JTBD (trabajos por hacer). Nos gusta eso. Un problema y sus subproblemas suelen ser acciones basadas en el tiempo asignadas a los miembros de tu equipo. Tu equipo crea, asigna y completa problemas para avanzar el proyecto hacia su objetivo.", + "primary_button": { + "text": "Crea tu primer problema", + "comic": { + "title": "Los problemas son bloques de construcción en Plane.", + "description": "Rediseñar la interfaz de Plane, Rebrandear la empresa o Lanzar el nuevo sistema de inyección de combustible son ejemplos de problemas que probablemente tengan subproblemas." + } + } + }, + "issues_empty_filter": { + "title": "No se encontraron problemas que coincidan con los filtros aplicados", + "secondary_button": { + "text": "Borrar todos los filtros" + } + } + } + }, - "project_archived_no_modules_empty_state_title": "Aún no hay Módulos archivados", - "project_archived_no_modules_empty_state_description": "Para ordenar tu proyecto, archiva los módulos completados o cancelados. Encuéntralos aquí una vez archivados.", + "project_module": { + "empty_state": { + "no_issues": { + "title": "No hay problemas en el módulo", + "description": "Crea o agrega problemas que deseas lograr como parte de este módulo", + "primary_button": { + "text": "Crear nuevo problema" + }, + "secondary_button": { + "text": "Agregar un problema existente" + } + }, + "general": { + "title": "Mapea los hitos de tu proyecto a Módulos y sigue el trabajo agregado fácilmente.", + "description": "Un grupo de problemas que pertenecen a un padre lógico y jerárquico forma un módulo. Piénsalos como una forma de rastrear el trabajo por hitos del proyecto. Tienen sus propios períodos y plazos, así como análisis para ayudarte a ver qué tan cerca o lejos estás de un hito.", + "primary_button": { + "text": "Construye tu primer módulo", + "comic": { + "title": "Los módulos ayudan a agrupar el trabajo por jerarquía.", + "description": "Un módulo de carrito, un módulo de chasis y un módulo de almacén son buenos ejemplos de esta agrupación." + } + } + }, + "archived": { + "title": "Aún no hay módulos archivados", + "description": "Para organizar tu proyecto, archiva módulos completados o cancelados. Encuéntralos aquí una vez archivados." + } + } + }, - "project_view_empty_state_title": "Guarda vistas filtradas para tu proyecto. Crea tantas como necesites", - "project_view_empty_state_primary_button_text": "Crea tu primera vista", - "project_view_empty_state_primary_button_comic_title": "Las vistas funcionan sobre las propiedades de los Problemas.", - "project_view_empty_state_primary_button_comic_description": "Puedes crear una vista desde aquí con tantas propiedades como filtros como consideres adecuado.", + "project_view": { + "empty_state": { + "general": { + "title": "Guarda vistas filtradas para tu proyecto. Crea tantas como necesites", + "description": "Las vistas son un conjunto de filtros guardados que usas con frecuencia o a los que deseas tener acceso fácil. Todos tus colegas en un proyecto pueden ver las vistas de todos y elegir la que mejor se adapte a sus necesidades.", + "primary_button": { + "text": "Crea tu primera vista", + "comic": { + "title": "Las vistas funcionan sobre las propiedades de los problemas.", + "description": "Puedes crear una vista desde aquí con tantas propiedades como filtros que consideres necesarios." + } + } + } + } + }, "project_page": { "empty_state": { @@ -705,7 +745,7 @@ }, "inbox": { - "name": "Bandeja de entrada", + "label": "Bandeja de entrada", "empty_state": { "sidebar_open_tab": { "title": "No hay problemas abiertos", diff --git a/packages/i18n/src/locales/fr/translations.json b/packages/i18n/src/locales/fr/translations.json index 7d78806534f..0025d74a629 100644 --- a/packages/i18n/src/locales/fr/translations.json +++ b/packages/i18n/src/locales/fr/translations.json @@ -220,7 +220,6 @@ "join_the_project_to_rearrange": "Rejoindre le projet pour réorganiser", "drag_to_rearrange": "Glisser pour réorganiser", "congrats": "Félicitations !", - "project": "Projet", "open_project": "Ouvrir le projet", "issues": "Problèmes", "cycles": "Cycles", @@ -417,7 +416,7 @@ }, "workspace_settings": { - "name": "Paramètres de l'espace de travail", + "label": "Paramètres de l'espace de travail", "empty_state": { "api_tokens": { "title": "Aucun jeton API créé", @@ -439,7 +438,7 @@ }, "profile": { - "name": "Profil", + "label": "Profil", "empty_state": { "activity": { "title": "Aucune activité pour le moment", @@ -521,21 +520,12 @@ "project_cycle_all_empty_state_title": "Aucun cycle", "project_cycle_all_empty_state_description": "Un cycle actif inclut toute période qui englobe la date d'aujourd'hui dans sa plage. Trouvez ici les progrès et les détails du cycle actif.", - "project_empty_filter_empty_state_title": "Aucun problème trouvé correspondant aux filtres appliqués", - "project_empty_filter_empty_state_secondary_button_text": "Effacer tous les filtres", - "project_archived_empty_filter_empty_state_title": "Aucun problème trouvé correspondant aux filtres appliqués", "project_archived_empty_filter_empty_state_secondary_button_text": "Effacer tous les filtres", "project_draft_empty_filter_empty_state_title": "Aucun problème trouvé correspondant aux filtres appliqués", "project_draft_empty_filter_empty_state_secondary_button_text": "Effacer tous les filtres", - "project_no_issues_empty_state_title": "Créez un problème et assignez-le à quelqu'un, même à vous-même", - "project_no_issues_empty_state_description": "Pensez aux problèmes comme des tâches, du travail, ou des JTBD. Ce que nous aimons. Un problème et ses sous-problèmes sont généralement des actions basées sur le temps assignées aux membres de votre équipe. Votre équipe crée, assigne et complète des problèmes pour faire avancer votre projet vers son objectif.", - "project_no_issues_empty_state_primary_button_text": "Créez votre premier problème", - "project_no_issues_empty_state_primary_button_comic_title": "Les problèmes sont les blocs de construction dans Plane.", - "project_no_issues_empty_state_primary_button_comic_description": "Refaire le design de l'interface Plane, Renouveler l'image de marque de l'entreprise, ou Lancer le nouveau système d'injection de carburant sont des exemples de problèmes qui ont probablement des sous-problèmes.", - "project_archived_no_issues_empty_state_title": "Aucun problème archivé pour le moment", "project_archived_no_issues_empty_state_description": "Manuellement ou par automatisation, vous pouvez archiver les problèmes terminés ou annulés. Retrouvez-les ici une fois archivés.", "project_archived_no_issues_empty_state_primary_button_text": "Configurer l'automatisation", @@ -552,24 +542,74 @@ "members_empty_search_empty_state_title": "Aucun membre correspondant", "members_empty_search_empty_state_description": "Ajoutez-les au projet s'ils font déjà partie de l'espace de travail", - "project_module_issues_empty_state_title": "Aucun problème dans le module", - "project_module_issues_empty_state_description": "Créez ou ajoutez des problèmes que vous souhaitez accomplir dans le cadre de ce module", - "project_module_issues_empty_state_primary_button_text": "Créer un nouveau problème", - "project_module_issues_empty_state_secondary_button_text": "Ajouter un problème existant", - - "project_module_empty_state_title": "Associez les jalons de votre projet à des modules et suivez facilement le travail agrégé.", - "project_module_empty_state_description": "Un groupe de problèmes appartenant à un parent logique et hiérarchique forme un module. Pensez-y comme un moyen de suivre le travail par jalons de projet. Ils ont leurs propres périodes et échéances ainsi que des analyses pour vous aider à voir à quel point vous êtes proche ou éloigné d'un jalon.", - "project_module_empty_state_primary_button_text": "Construisez votre premier module", - "project_module_empty_state_primary_button_comic_title": "Les modules aident à regrouper le travail par hiérarchie.", - "project_module_empty_state_primary_button_comic_description": "Un module de chariot, un module de châssis et un module d'entrepôt sont de bons exemples de ce regroupement.", + "project": { + "label": "Projet", + "empty_state": { + "no_issues": { + "title": "Créez un problème et assignez-le à quelqu’un, même à vous-même", + "description": "Considérez les problèmes comme des emplois, des tâches, des actions ou JTBD (travaux à accomplir). Nous aimons ça. Un problème et ses sous-problèmes sont généralement des actions basées sur le temps assignées aux membres de votre équipe. Votre équipe crée, assigne et termine des problèmes pour faire avancer votre projet vers son objectif.", + "primary_button": { + "text": "Créez votre premier problème", + "comic": { + "title": "Les problèmes sont les éléments constitutifs de Plane.", + "description": "Redessiner l’interface utilisateur de Plane, Rebrander l’entreprise ou Lancer le nouveau système d’injection de carburant sont des exemples de problèmes qui comportent probablement des sous-problèmes." + } + } + }, + "issues_empty_filter": { + "title": "Aucun problème trouvé correspondant aux filtres appliqués", + "secondary_button": { + "text": "Effacer tous les filtres" + } + } + } + }, - "project_archived_no_modules_empty_state_title": "Aucun module archivé pour l'instant", - "project_archived_no_modules_empty_state_description": "Pour organiser votre projet, archivez les modules terminés ou annulés. Retrouvez-les ici une fois archivés.", + "project_module": { + "empty_state": { + "no_issues": { + "title": "Aucun problème dans le module", + "description": "Créez ou ajoutez des problèmes que vous souhaitez réaliser dans le cadre de ce module", + "primary_button": { + "text": "Créer un nouveau problème" + }, + "secondary_button": { + "text": "Ajouter un problème existant" + } + }, + "general": { + "title": "Associez les jalons de votre projet aux modules et suivez facilement le travail global.", + "description": "Un groupe de problèmes appartenant à un parent logique et hiérarchique forme un module. Pensez-y comme un moyen de suivre le travail par jalons de projet. Ils ont leurs propres périodes, échéances et analyses pour vous aider à voir votre progression vers un jalon.", + "primary_button": { + "text": "Construisez votre premier module", + "comic": { + "title": "Les modules aident à regrouper le travail par hiérarchie.", + "description": "Un module de panier, un module de châssis et un module d'entrepôt sont de bons exemples de ce regroupement." + } + } + }, + "archived": { + "title": "Aucun module archivé pour le moment", + "description": "Pour organiser votre projet, archivez les modules terminés ou annulés. Retrouvez-les ici une fois archivés." + } + } + }, - "project_view_empty_state_title": "Enregistrez des vues filtrées pour votre projet. Créez-en autant que vous en avez besoin.", - "project_view_empty_state_primary_button_text": "Créez votre première vue", - "project_view_empty_state_primary_button_comic_title": "Les vues fonctionnent sur les propriétés des problèmes.", - "project_view_empty_state_primary_button_comic_description": "Vous pouvez créer une vue à partir d'ici avec autant de propriétés et de filtres que vous le souhaitez.", + "project_view": { + "empty_state": { + "general": { + "title": "Enregistrez des vues filtrées pour votre projet. Créez-en autant que nécessaire", + "description": "Les vues sont un ensemble de filtres enregistrés que vous utilisez fréquemment ou auxquels vous souhaitez accéder facilement. Tous vos collègues dans un projet peuvent voir les vues de chacun et choisir celle qui correspond le mieux à leurs besoins.", + "primary_button": { + "text": "Créez votre première vue", + "comic": { + "title": "Les vues fonctionnent au-dessus des propriétés des problèmes.", + "description": "Vous pouvez créer une vue à partir d'ici avec autant de propriétés ou de filtres que vous le souhaitez." + } + } + } + } + }, "project_page": { "empty_state": { @@ -706,7 +746,7 @@ }, "inbox": { - "name": "Boîte de réception", + "label": "Boîte de réception", "empty_state": { "sidebar_open_tab": { "title": "Aucun problème ouvert", diff --git a/packages/i18n/src/locales/ja/translations.json b/packages/i18n/src/locales/ja/translations.json index e9095bbc241..78955e67b8a 100644 --- a/packages/i18n/src/locales/ja/translations.json +++ b/packages/i18n/src/locales/ja/translations.json @@ -220,7 +220,6 @@ "join_the_project_to_rearrange": "プロジェクトに参加して並べ替え", "drag_to_rearrange": "ドラッグして並べ替え", "congrats": "おめでとうございます!", - "project": "プロジェクト", "open_project": "プロジェクトを開く", "issues": "問題", "cycles": "サイクル", @@ -417,7 +416,7 @@ }, "workspace_settings": { - "name": "ワークスペース設定", + "label": "ワークスペース設定", "empty_state": { "api_tokens": { "title": "APIトークンが作成されていません", @@ -439,7 +438,7 @@ }, "profile": { - "name": "プロフィール", + "label": "プロフィール", "empty_state": { "activity": { "title": "まだアクティビティがありません", @@ -521,21 +520,12 @@ "project_cycle_all_empty_state_title": "サイクルがありません", "project_cycle_all_empty_state_description": "アクティブなサイクルには、現在の日付が含まれる期間が含まれます。ここでアクティブなサイクルの進捗や詳細を確認できます。", - "project_empty_filter_empty_state_title": "適用されたフィルターに一致する課題は見つかりません", - "project_empty_filter_empty_state_secondary_button_text": "すべてのフィルターをクリア", - "project_archived_empty_filter_empty_state_title": "適用されたフィルターに一致する課題は見つかりません", "project_archived_empty_filter_empty_state_secondary_button_text": "すべてのフィルターをクリア", "project_draft_empty_filter_empty_state_title": "適用されたフィルターに一致する課題は見つかりません", "project_draft_empty_filter_empty_state_secondary_button_text": "すべてのフィルターをクリア", - "project_no_issues_empty_state_title": "課題を作成し、自分自身または他の人に割り当ててください", - "project_no_issues_empty_state_description": "課題は仕事、タスク、作業、またはJTBDと考えられます。課題とそのサブ課題は通常、チームメンバーに割り当てられた時間ベースのアクション項目です。チームは課題を作成、割り当て、完了させることでプロジェクトを目標に向かって進めます。", - "project_no_issues_empty_state_primary_button_text": "最初の課題を作成する", - "project_no_issues_empty_state_primary_button_comic_title": "課題はPlaneの基本構成要素です。", - "project_no_issues_empty_state_primary_button_comic_description": "Plane UIの再設計、会社のリブランディング、新しい燃料噴射システムの導入は、サブ課題を含む課題の例です。", - "project_archived_no_issues_empty_state_title": "まだアーカイブされた課題はありません", "project_archived_no_issues_empty_state_description": "手動または自動化により、完了またはキャンセルされた課題をアーカイブできます。一度アーカイブされると、ここに表示されます。", "project_archived_no_issues_empty_state_primary_button_text": "自動化を設定する", @@ -552,24 +542,74 @@ "members_empty_search_empty_state_title": "一致するメンバーはありません", "members_empty_search_empty_state_description": "すでにワークスペースの一員である場合、プロジェクトに追加してください。", - "project_module_issues_empty_state_title": "モジュール内に課題がありません", - "project_module_issues_empty_state_description": "このモジュールの一部として達成したい課題を作成または追加してください。", - "project_module_issues_empty_state_primary_button_text": "新しい課題を作成する", - "project_module_issues_empty_state_secondary_button_text": "既存の課題を追加する", - - "project_module_empty_state_title": "モジュールにプロジェクトのマイルストーンをマッピングし、集約された作業を簡単に追跡します。", - "project_module_empty_state_description": "論理的で階層的な親に属する課題のグループがモジュールを形成します。プロジェクトのマイルストーンごとに作業を追跡するための方法と考えてください。それぞれのモジュールには独自の期間と期限があり、マイルストーンへの進捗を把握するための分析が備わっています。", - "project_module_empty_state_primary_button_text": "最初のモジュールを構築する", - "project_module_empty_state_primary_button_comic_title": "モジュールは階層別に作業をグループ化します。", - "project_module_empty_state_primary_button_comic_description": "カートモジュール、シャーシモジュール、倉庫モジュールは、このグループ化の良い例です。", + "project": { + "label": "プロジェクト", + "empty_state": { + "no_issues": { + "title": "課題を作成し、誰かに、または自分に割り当てましょう", + "description": "課題を仕事、タスク、行動、またはJTBD(やるべき仕事)と考えてください。それが私たちの好む方法です。課題とそのサブ課題は通常、チームメンバーに割り当てられる時間ベースのアクションです。チームは課題を作成し、割り当て、完了させることで、プロジェクトの目標に向かって進みます。", + "primary_button": { + "text": "最初の課題を作成", + "comic": { + "title": "課題はPlaneの構成要素です。", + "description": "Plane UIの再設計、会社のリブランド、新しい燃料噴射システムの開始は、サブ課題がある可能性のある課題の例です。" + } + } + }, + "issues_empty_filter": { + "title": "適用されたフィルターに一致する課題は見つかりませんでした", + "secondary_button": { + "text": "すべてのフィルターをクリア" + } + } + } + }, - "project_archived_no_modules_empty_state_title": "まだアーカイブされたモジュールはありません", - "project_archived_no_modules_empty_state_description": "プロジェクトを整理するために、完了またはキャンセルされたモジュールをアーカイブします。一度アーカイブされると、ここに表示されます。", + "project_module": { + "empty_state": { + "no_issues": { + "title": "モジュールに課題がありません", + "description": "このモジュールの一部として達成したい課題を作成または追加してください", + "primary_button": { + "text": "新しい課題を作成" + }, + "secondary_button": { + "text": "既存の課題を追加" + } + }, + "general": { + "title": "プロジェクトのマイルストーンをモジュールにマッピングし、集計された作業を簡単に追跡します。", + "description": "論理的で階層的な親に属する課題のグループがモジュールを形成します。それをプロジェクトのマイルストーンで作業を追跡する方法と考えてください。モジュールには独自の期間と締切があり、分析を通じてマイルストーンへの進捗状況を確認できます。", + "primary_button": { + "text": "最初のモジュールを構築", + "comic": { + "title": "モジュールは階層によって作業をグループ化します。", + "description": "カートモジュール、シャーシモジュール、倉庫モジュールは、このグループ化の良い例です。" + } + } + }, + "archived": { + "title": "まだアーカイブされたモジュールはありません", + "description": "プロジェクトを整理するために、完了またはキャンセルされたモジュールをアーカイブします。アーカイブされたモジュールはここで見つけることができます。" + } + } + }, - "project_view_empty_state_title": "プロジェクトのフィルタリングされたビューを保存します。必要なだけ作成できます。", - "project_view_empty_state_primary_button_text": "最初のビューを作成する", - "project_view_empty_state_primary_button_comic_title": "ビューは課題のプロパティに基づいて動作します。", - "project_view_empty_state_primary_button_comic_description": "ここからプロパティをいくつでもフィルターとして追加してビューを作成できます。", + "project_view": { + "empty_state": { + "general": { + "title": "プロジェクト用にフィルタされたビューを保存します。必要なだけ作成してください", + "description": "ビューは、頻繁に使用するか、簡単にアクセスしたい保存されたフィルターのセットです。プロジェクト内のすべての同僚が他の人のビューを確認し、自分のニーズに最適なものを選ぶことができます。", + "primary_button": { + "text": "最初のビューを作成", + "comic": { + "title": "ビューは課題プロパティの上に機能します。", + "description": "ここから必要に応じてプロパティをフィルターとして使用してビューを作成できます。" + } + } + } + } + }, "project_page": { "empty_state": { @@ -706,7 +746,7 @@ }, "inbox": { - "name": "受信トレイ", + "label": "受信トレイ", "empty_state": { "sidebar_open_tab": { "title": "未解決の課題はありません", diff --git a/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/cycles/(list)/page.tsx b/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/cycles/(list)/page.tsx index ac0b9974977..fd20d94275e 100644 --- a/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/cycles/(list)/page.tsx +++ b/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/cycles/(list)/page.tsx @@ -4,7 +4,7 @@ import { useState } from "react"; import { observer } from "mobx-react"; import { useParams } from "next/navigation"; // plane imports -import { EUserPermissionsLevel, EUserWorkspaceRoles } from "@plane/constants"; +import { EUserPermissionsLevel, EUserProjectRoles } from "@plane/constants"; import { useTranslation } from "@plane/i18n"; import { TCycleFilters } from "@plane/types"; // components @@ -41,7 +41,7 @@ const ProjectCyclesPage = observer(() => { const totalCycles = currentProjectCycleIds?.length ?? 0; const project = projectId ? getProjectById(projectId?.toString()) : undefined; const pageTitle = project?.name ? `${project?.name} - Cycles` : undefined; - const canPerformEmptyStateActions = allowPermissions([EUserWorkspaceRoles.ADMIN], EUserPermissionsLevel.PROJECT); + const canPerformEmptyStateActions = allowPermissions([EUserProjectRoles.ADMIN], EUserPermissionsLevel.PROJECT); const resolvedPath = useResolvedAssetPath({ basePath: "/empty-state/disabled-feature/cycles" }); const handleRemoveFilter = (key: keyof TCycleFilters, value: string | null) => { diff --git a/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/inbox/page.tsx b/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/inbox/page.tsx index 2d53d57ddd6..92d01aa25a9 100644 --- a/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/inbox/page.tsx +++ b/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/inbox/page.tsx @@ -2,7 +2,7 @@ import { observer } from "mobx-react"; // components import { useParams, useSearchParams } from "next/navigation"; -import { EUserWorkspaceRoles } from "@plane/constants/src/user"; +import { EUserProjectRoles } from "@plane/constants/src/user"; import { useTranslation } from "@plane/i18n"; import { PageHead } from "@/components/core"; import { DetailedEmptyState } from "@/components/empty-state"; @@ -28,7 +28,7 @@ const ProjectInboxPage = observer(() => { const { currentProjectDetails } = useProject(); const { allowPermissions } = useUserPermissions(); // derived values - const canPerformEmptyStateActions = allowPermissions([EUserWorkspaceRoles.ADMIN], EUserPermissionsLevel.PROJECT); + const canPerformEmptyStateActions = allowPermissions([EUserProjectRoles.ADMIN], EUserPermissionsLevel.PROJECT); const resolvedPath = useResolvedAssetPath({ basePath: "/empty-state/disabled-feature/intake" }); // No access to inbox diff --git a/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/modules/(list)/page.tsx b/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/modules/(list)/page.tsx index 2066b77b0f5..572cb3862f7 100644 --- a/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/modules/(list)/page.tsx +++ b/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/modules/(list)/page.tsx @@ -4,7 +4,7 @@ import { useCallback } from "react"; import { observer } from "mobx-react"; import { useParams } from "next/navigation"; // types -import { EUserPermissionsLevel, EUserWorkspaceRoles } from "@plane/constants"; +import { EUserPermissionsLevel, EUserProjectRoles } from "@plane/constants"; import { useTranslation } from "@plane/i18n"; import { TModuleFilters } from "@plane/types"; // components @@ -32,7 +32,7 @@ const ProjectModulesPage = observer(() => { // derived values const project = projectId ? getProjectById(projectId.toString()) : undefined; const pageTitle = project?.name ? `${project?.name} - Modules` : undefined; - const canPerformEmptyStateActions = allowPermissions([EUserWorkspaceRoles.ADMIN], EUserPermissionsLevel.PROJECT); + const canPerformEmptyStateActions = allowPermissions([EUserProjectRoles.ADMIN], EUserPermissionsLevel.PROJECT); const resolvedPath = useResolvedAssetPath({ basePath: "/empty-state/disabled-feature/modules" }); const handleRemoveFilter = useCallback( diff --git a/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/pages/(list)/page.tsx b/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/pages/(list)/page.tsx index 6db2f570ab0..547584f51a1 100644 --- a/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/pages/(list)/page.tsx +++ b/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/pages/(list)/page.tsx @@ -3,7 +3,7 @@ import { observer } from "mobx-react"; import { useParams, useSearchParams } from "next/navigation"; // plane imports -import { EUserPermissionsLevel, EUserWorkspaceRoles } from "@plane/constants"; +import { EUserPermissionsLevel, EUserProjectRoles } from "@plane/constants"; import { useTranslation } from "@plane/i18n"; import { TPageNavigationTabs } from "@plane/types"; // components @@ -29,7 +29,7 @@ const ProjectPagesPage = observer(() => { // derived values const project = projectId ? getProjectById(projectId.toString()) : undefined; const pageTitle = project?.name ? `${project?.name} - Pages` : undefined; - const canPerformEmptyStateActions = allowPermissions([EUserWorkspaceRoles.ADMIN], EUserPermissionsLevel.PROJECT); + const canPerformEmptyStateActions = allowPermissions([EUserProjectRoles.ADMIN], EUserPermissionsLevel.PROJECT); const resolvedPath = useResolvedAssetPath({ basePath: "/empty-state/disabled-feature/pages" }); const currentPageType = (): TPageNavigationTabs => { diff --git a/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/views/(list)/page.tsx b/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/views/(list)/page.tsx index 820617561bc..73e7e0d85e4 100644 --- a/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/views/(list)/page.tsx +++ b/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/views/(list)/page.tsx @@ -4,7 +4,7 @@ import { useCallback } from "react"; import { observer } from "mobx-react"; import { useParams } from "next/navigation"; // components -import { EUserPermissionsLevel, EUserWorkspaceRoles } from "@plane/constants"; +import { EUserPermissionsLevel, EUserProjectRoles } from "@plane/constants"; import { useTranslation } from "@plane/i18n"; import { TViewFilterProps } from "@plane/types"; import { Header, EHeaderVariant } from "@plane/ui"; @@ -34,7 +34,7 @@ const ProjectViewsPage = observer(() => { // derived values const project = projectId ? getProjectById(projectId.toString()) : undefined; const pageTitle = project?.name ? `${project?.name} - Views` : undefined; - const canPerformEmptyStateActions = allowPermissions([EUserWorkspaceRoles.ADMIN], EUserPermissionsLevel.PROJECT); + const canPerformEmptyStateActions = allowPermissions([EUserProjectRoles.ADMIN], EUserPermissionsLevel.PROJECT); const resolvedPath = useResolvedAssetPath({ basePath: "/empty-state/disabled-feature/views" }); const handleRemoveFilter = useCallback( diff --git a/web/app/profile/notifications/page.tsx b/web/app/profile/notifications/page.tsx index 6eb27954aec..5e154fdffc1 100644 --- a/web/app/profile/notifications/page.tsx +++ b/web/app/profile/notifications/page.tsx @@ -25,7 +25,7 @@ export default function ProfileNotificationPage() { return ( <> - + { return ( <> - + diff --git a/web/core/components/issues/issue-layouts/empty-states/module.tsx b/web/core/components/issues/issue-layouts/empty-states/module.tsx index 9e8a26955e6..3597636100b 100644 --- a/web/core/components/issues/issue-layouts/empty-states/module.tsx +++ b/web/core/components/issues/issue-layouts/empty-states/module.tsx @@ -4,31 +4,52 @@ import { useState } from "react"; import size from "lodash/size"; import { observer } from "mobx-react"; import { useParams } from "next/navigation"; -// types -import { EIssueFilterType, EIssuesStoreType } from "@plane/constants"; +// plane imports +import { EIssueFilterType, EIssuesStoreType, EUserPermissionsLevel, EUserProjectRoles } from "@plane/constants"; +import { useTranslation } from "@plane/i18n"; import { IIssueFilterOptions, ISearchIssueResponse } from "@plane/types"; -// ui import { TOAST_TYPE, setToast } from "@plane/ui"; // components import { ExistingIssuesListModal } from "@/components/core"; -import { EmptyState } from "@/components/empty-state"; -// constants -import { EmptyStateType } from "@/constants/empty-state"; +import { DetailedEmptyState } from "@/components/empty-state"; // hooks -import { useCommandPalette, useEventTracker, useIssues } from "@/hooks/store"; +import { useCommandPalette, useEventTracker, useIssues, useUserPermissions } from "@/hooks/store"; +import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; export const ModuleEmptyState: React.FC = observer(() => { // router const { workspaceSlug, projectId, moduleId } = useParams(); // states const [moduleIssuesListModal, setModuleIssuesListModal] = useState(false); + // plane hooks + const { t } = useTranslation(); // store hooks const { issues, issuesFilter } = useIssues(EIssuesStoreType.MODULE); const { toggleCreateIssueModal } = useCommandPalette(); const { setTrackElement } = useEventTracker(); - + const { allowPermissions } = useUserPermissions(); + // derived values const userFilters = issuesFilter?.issueFilters?.filters; const activeLayout = issuesFilter?.issueFilters?.displayFilters?.layout; + const issueFilterCount = size( + Object.fromEntries( + Object.entries(userFilters ?? {}).filter(([, value]) => value && Array.isArray(value) && value.length > 0) + ) + ); + const isEmptyFilters = issueFilterCount > 0; + const additionalPath = activeLayout ?? "list"; + const canPerformEmptyStateActions = allowPermissions( + [EUserProjectRoles.ADMIN, EUserProjectRoles.MEMBER], + EUserPermissionsLevel.PROJECT + ); + const emptyFilterResolvedPath = useResolvedAssetPath({ + basePath: "/empty-state/empty-filters/", + additionalPath: additionalPath, + }); + const moduleIssuesResolvedPath = useResolvedAssetPath({ + basePath: "/empty-state/module-issues/", + additionalPath: additionalPath, + }); const handleAddIssuesToModule = async (data: ISearchIssueResponse[]) => { if (!workspaceSlug || !projectId || !moduleId) return; @@ -52,12 +73,6 @@ export const ModuleEmptyState: React.FC = observer(() => { ); }; - const issueFilterCount = size( - Object.fromEntries( - Object.entries(userFilters ?? {}).filter(([, value]) => value && Array.isArray(value) && value.length > 0) - ) - ); - const handleClearAllFilters = () => { if (!workspaceSlug || !projectId || !moduleId) return; const newFilters: IIssueFilterOptions = {}; @@ -75,10 +90,6 @@ export const ModuleEmptyState: React.FC = observer(() => { ); }; - const isEmptyFilters = issueFilterCount > 0; - const emptyStateType = isEmptyFilters ? EmptyStateType.PROJECT_EMPTY_FILTER : EmptyStateType.PROJECT_MODULE_ISSUES; - const additionalPath = activeLayout ?? "list"; - return (
{ handleOnSubmit={handleAddIssuesToModule} />
- { - setTrackElement("Module issue empty state"); - toggleCreateIssueModal(true, EIssuesStoreType.MODULE); - } - } - secondaryButtonOnClick={isEmptyFilters ? handleClearAllFilters : () => setModuleIssuesListModal(true)} - /> + {isEmptyFilters ? ( + + ) : ( + { + setTrackElement("Module issue empty state"); + toggleCreateIssueModal(true, EIssuesStoreType.MODULE); + }, + disabled: !canPerformEmptyStateActions, + }} + secondaryButton={{ + text: t("project_module.empty_state.no_issues.secondary_button.text"), + onClick: () => setModuleIssuesListModal(true), + disabled: !canPerformEmptyStateActions, + }} + /> + )}
); diff --git a/web/core/components/modules/archived-modules/root.tsx b/web/core/components/modules/archived-modules/root.tsx index b74814add67..30ae74a5ce8 100644 --- a/web/core/components/modules/archived-modules/root.tsx +++ b/web/core/components/modules/archived-modules/root.tsx @@ -2,28 +2,30 @@ import React, { useCallback } from "react"; import { observer } from "mobx-react"; import { useParams } from "next/navigation"; import useSWR from "swr"; -// types +// plane imports +import { useTranslation } from "@plane/i18n"; import { TModuleFilters } from "@plane/types"; // components -import { EmptyState } from "@/components/empty-state"; +import { DetailedEmptyState } from "@/components/empty-state"; import { ArchivedModulesView, ModuleAppliedFiltersList } from "@/components/modules"; import { CycleModuleListLayout } from "@/components/ui"; -// constants -import { EmptyStateType } from "@/constants/empty-state"; // helpers import { calculateTotalFilters } from "@/helpers/filter.helper"; // hooks import { useModule, useModuleFilter } from "@/hooks/store"; +import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; export const ArchivedModuleLayoutRoot: React.FC = observer(() => { // router const { workspaceSlug, projectId } = useParams(); + // plane hooks + const { t } = useTranslation(); // hooks const { fetchArchivedModules, projectArchivedModuleIds, loader } = useModule(); - // module filters hook const { clearAllFilters, currentProjectArchivedFilters, updateFilters } = useModuleFilter(); // derived values const totalArchivedModules = projectArchivedModuleIds?.length ?? 0; + const resolvedPath = useResolvedAssetPath({ basePath: "/empty-state/archived/empty-modules" }); useSWR( workspaceSlug && projectId ? `ARCHIVED_MODULES_${workspaceSlug.toString()}_${projectId.toString()}` : null, @@ -69,7 +71,11 @@ export const ArchivedModuleLayoutRoot: React.FC = observer(() => { )} {totalArchivedModules === 0 ? (
- +
) : (
diff --git a/web/core/components/modules/modules-list-view.tsx b/web/core/components/modules/modules-list-view.tsx index 4b45879f7a2..4d8eac8d3c1 100644 --- a/web/core/components/modules/modules-list-view.tsx +++ b/web/core/components/modules/modules-list-view.tsx @@ -2,15 +2,16 @@ import { observer } from "mobx-react"; import Image from "next/image"; import { useParams, useSearchParams } from "next/navigation"; // components +import { EUserPermissionsLevel, EUserProjectRoles } from "@plane/constants"; +import { useTranslation } from "@plane/i18n"; import { ContentWrapper, Row, ERowVariant } from "@plane/ui"; import { ListLayout } from "@/components/core/list"; -import { EmptyState } from "@/components/empty-state"; +import { DetailedEmptyState, ComicBoxButton } from "@/components/empty-state"; import { ModuleCardItem, ModuleListItem, ModulePeekOverview, ModulesListGanttChartView } from "@/components/modules"; import { CycleModuleBoardLayout, CycleModuleListLayout, GanttLayoutLoader } from "@/components/ui"; -// constants -import { EmptyStateType } from "@/constants/empty-state"; // hooks -import { useCommandPalette, useEventTracker, useModule, useModuleFilter } from "@/hooks/store"; +import { useCommandPalette, useEventTracker, useModule, useModuleFilter, useUserPermissions } from "@/hooks/store"; +import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; import AllFiltersImage from "@/public/empty-state/module/all-filters.svg"; import NameFilterImage from "@/public/empty-state/module/name-filter.svg"; @@ -19,14 +20,24 @@ export const ModulesListView: React.FC = observer(() => { const { workspaceSlug, projectId } = useParams(); const searchParams = useSearchParams(); const peekModule = searchParams.get("peekModule"); + // plane hooks + const { t } = useTranslation(); // store hooks const { toggleCreateModuleModal } = useCommandPalette(); const { setTrackElement } = useEventTracker(); const { getProjectModuleIds, getFilteredModuleIds, loader } = useModule(); const { currentProjectDisplayFilters: displayFilters, searchQuery } = useModuleFilter(); + const { allowPermissions } = useUserPermissions(); // derived values const projectModuleIds = projectId ? getProjectModuleIds(projectId.toString()) : undefined; const filteredModuleIds = projectId ? getFilteredModuleIds(projectId.toString()) : undefined; + const canPerformEmptyStateActions = allowPermissions( + [EUserProjectRoles.ADMIN, EUserProjectRoles.MEMBER], + EUserPermissionsLevel.PROJECT + ); + const generalViewResolvedPath = useResolvedAssetPath({ + basePath: "/empty-state/onboarding/modules", + }); if (loader || !projectModuleIds || !filteredModuleIds) return ( @@ -39,12 +50,22 @@ export const ModulesListView: React.FC = observer(() => { if (projectModuleIds.length === 0) return ( - { - setTrackElement("Module empty state"); - toggleCreateModuleModal(true); - }} + { + setTrackElement("Module empty state"); + toggleCreateModuleModal(true); + }} + disabled={!canPerformEmptyStateActions} + /> + } /> ); diff --git a/web/core/components/pages/pages-list-main-content.tsx b/web/core/components/pages/pages-list-main-content.tsx index 4600f90406a..ec5ac519333 100644 --- a/web/core/components/pages/pages-list-main-content.tsx +++ b/web/core/components/pages/pages-list-main-content.tsx @@ -1,7 +1,7 @@ import { observer } from "mobx-react"; import Image from "next/image"; // plane imports -import { EUserPermissionsLevel, EUserWorkspaceRoles } from "@plane/constants"; +import { EUserPermissionsLevel, EUserProjectRoles } from "@plane/constants"; import { useTranslation } from "@plane/i18n"; import { TPageNavigationTabs } from "@plane/types"; // components @@ -33,8 +33,8 @@ export const PagesListMainContent: React.FC = observer((props) => { const pageIds = getCurrentProjectPageIds(pageType); const filteredPageIds = getCurrentProjectFilteredPageIds(pageType); const canPerformEmptyStateActions = allowPermissions( - [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER], - EUserPermissionsLevel.WORKSPACE + [EUserProjectRoles.ADMIN, EUserProjectRoles.MEMBER], + EUserPermissionsLevel.PROJECT ); const generalPageResolvedPath = useResolvedAssetPath({ basePath: "/empty-state/onboarding/pages", diff --git a/web/core/components/project/project-feature-update.tsx b/web/core/components/project/project-feature-update.tsx index 01752effc4c..1857c647dc8 100644 --- a/web/core/components/project/project-feature-update.tsx +++ b/web/core/components/project/project-feature-update.tsx @@ -35,7 +35,7 @@ export const ProjectFeatureUpdate: FC = observer((props) => {
- {t("congrats")}! {t("project")} {" "} + {t("congrats")}! {t("project.label")} {" "}

{currentProjectDetails.name}

{t("created").toLowerCase()}.
diff --git a/web/core/components/views/views-list.tsx b/web/core/components/views/views-list.tsx index 6b7d4117241..3d7fed6a1f8 100644 --- a/web/core/components/views/views-list.tsx +++ b/web/core/components/views/views-list.tsx @@ -1,24 +1,37 @@ import { observer } from "mobx-react"; import { useParams } from "next/navigation"; +// plane imports +import { EUserPermissionsLevel, EUserProjectRoles } from "@plane/constants"; +import { useTranslation } from "@plane/i18n"; // components import { ListLayout } from "@/components/core/list"; -import { EmptyState } from "@/components/empty-state"; +import { ComicBoxButton, DetailedEmptyState, EmptyState } from "@/components/empty-state"; import { ViewListLoader } from "@/components/ui"; import { ProjectViewListItem } from "@/components/views"; // constants import { EmptyStateType } from "@/constants/empty-state"; // hooks -import { useCommandPalette, useProjectView } from "@/hooks/store"; -// assets +import { useCommandPalette, useProjectView, useUserPermissions } from "@/hooks/store"; +import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; export const ProjectViewsList = observer(() => { const { projectId } = useParams(); + // plane hooks + const { t } = useTranslation(); // store hooks const { toggleCreateViewModal } = useCommandPalette(); const { getProjectViews, getFilteredProjectViews, loader } = useProjectView(); - + const { allowPermissions } = useUserPermissions(); + // derived values const projectViews = getProjectViews(projectId?.toString()); const filteredProjectViews = getFilteredProjectViews(projectId?.toString()); + const canPerformEmptyStateActions = allowPermissions( + [EUserProjectRoles.ADMIN, EUserProjectRoles.MEMBER, EUserProjectRoles.GUEST], + EUserPermissionsLevel.PROJECT + ); + const generalViewResolvedPath = useResolvedAssetPath({ + basePath: "/empty-state/onboarding/views", + }); if (loader || !projectViews || !filteredProjectViews) return ; @@ -43,7 +56,20 @@ export const ProjectViewsList = observer(() => {
) : ( - toggleCreateViewModal(true)} /> + toggleCreateViewModal(true)} + disabled={!canPerformEmptyStateActions} + /> + } + /> )} ); diff --git a/web/core/components/workspace/sidebar/dropdown.tsx b/web/core/components/workspace/sidebar/dropdown.tsx index 3aac24254e4..901dfcd65af 100644 --- a/web/core/components/workspace/sidebar/dropdown.tsx +++ b/web/core/components/workspace/sidebar/dropdown.tsx @@ -41,7 +41,7 @@ export const SidebarDropdown = observer(() => { }, { key: "settings", - name: t("workspace_settings.name"), + name: t("workspace_settings.label"), href: `/${workspaceSlug}/settings`, icon: Settings, access: [EUserPermissions.ADMIN], diff --git a/web/core/components/workspace/sidebar/user-menu.tsx b/web/core/components/workspace/sidebar/user-menu.tsx index 089d26c69e6..89e9cff3258 100644 --- a/web/core/components/workspace/sidebar/user-menu.tsx +++ b/web/core/components/workspace/sidebar/user-menu.tsx @@ -37,7 +37,7 @@ export const SidebarUserMenu = observer(() => { }, { key: "notifications", - labelTranslationKey: "inbox.name", + labelTranslationKey: "inbox.label", href: `/${workspaceSlug.toString()}/notifications/`, access: [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER, EUserWorkspaceRoles.GUEST], Icon: Inbox, diff --git a/web/core/constants/empty-state.tsx b/web/core/constants/empty-state.tsx index df347952a8d..71eab2f687d 100644 --- a/web/core/constants/empty-state.tsx +++ b/web/core/constants/empty-state.tsx @@ -63,11 +63,6 @@ export enum EmptyStateType { VIEWS_EMPTY_SEARCH = "views-empty-search", PROJECTS_EMPTY_SEARCH = "projects-empty-search", MEMBERS_EMPTY_SEARCH = "members-empty-search", - PROJECT_MODULE_ISSUES = "project-module-issues", - PROJECT_MODULE = "project-module", - PROJECT_ARCHIVED_NO_MODULES = "project-archived-no-modules", - PROJECT_VIEW = "project-view", - // stickies STICKIES = "stickies", STICKIES_SEARCH = "stickies-search", @@ -421,60 +416,6 @@ const emptyStateDetails: Record = { description: "Add them to the project if they are already a part of the workspace", path: "/empty-state/search/member", }, - // project module - [EmptyStateType.PROJECT_MODULE_ISSUES]: { - key: EmptyStateType.PROJECT_MODULE_ISSUES, - title: "No issues in the module", - description: "Create or add issues which you want to accomplish as part of this module", - path: "/empty-state/module-issues/", - primaryButton: { - text: "Create new issue ", - }, - secondaryButton: { - text: "Add an existing issue", - }, - accessType: "project", - access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER], - }, - [EmptyStateType.PROJECT_MODULE]: { - key: EmptyStateType.PROJECT_MODULE, - title: "Map your project milestones to Modules and track aggregated work easily.", - description: - "A group of issues that belong to a logical, hierarchical parent form a module. Think of them as a way to track work by project milestones. They have their own periods and deadlines as well as analytics to help you see how close or far you are from a milestone.", - path: "/empty-state/onboarding/modules", - primaryButton: { - text: "Build your first module", - comicBox: { - title: "Modules help group work by hierarchy.", - description: "A cart module, a chassis module, and a warehouse module are all good example of this grouping.", - }, - }, - accessType: "project", - access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER], - }, - [EmptyStateType.PROJECT_ARCHIVED_NO_MODULES]: { - key: EmptyStateType.PROJECT_ARCHIVED_NO_MODULES, - title: "No archived Modules yet", - description: "To tidy up your project, archive completed or cancelled modules. Find them here once archived.", - path: "/empty-state/archived/empty-modules", - }, - // project views - [EmptyStateType.PROJECT_VIEW]: { - key: EmptyStateType.PROJECT_VIEW, - title: "Save filtered views for your project. Create as many as you need", - description: - "Views are a set of saved filters that you use frequently or want easy access to. All your colleagues in a project can see everyone’s views and choose whichever suits their needs best.", - path: "/empty-state/onboarding/views", - primaryButton: { - text: "Create your first view", - comicBox: { - title: "Views work atop Issue properties.", - description: "You can create a view from here with as many properties as filters as you see fit.", - }, - }, - accessType: "project", - access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER, EUserPermissions.GUEST], - }, [EmptyStateType.STICKIES]: { key: EmptyStateType.STICKIES, title: "Stickies are quick notes and to-dos you take down on the fly.", From 90a8834be861ee09370914eb2713ff920ac9efdf Mon Sep 17 00:00:00 2001 From: Prateek Shourya Date: Fri, 17 Jan 2025 16:54:53 +0530 Subject: [PATCH 17/26] chore: remove project draft related empty state --- .../empty-states/draft-issues.tsx | 55 ++----------------- web/core/constants/empty-state.tsx | 19 ------- 2 files changed, 4 insertions(+), 70 deletions(-) diff --git a/web/core/components/issues/issue-layouts/empty-states/draft-issues.tsx b/web/core/components/issues/issue-layouts/empty-states/draft-issues.tsx index 1af3ca5a5c4..bb10176ae9f 100644 --- a/web/core/components/issues/issue-layouts/empty-states/draft-issues.tsx +++ b/web/core/components/issues/issue-layouts/empty-states/draft-issues.tsx @@ -1,53 +1,6 @@ -import size from "lodash/size"; import { observer } from "mobx-react"; -import { useParams } from "next/navigation"; -import { EIssueFilterType, EIssuesStoreType } from "@plane/constants"; -import { IIssueFilterOptions } from "@plane/types"; -// hooks -// components -import { EmptyState } from "@/components/empty-state"; -// constants -import { EmptyStateType } from "@/constants/empty-state"; -import { useIssues } from "@/hooks/store"; -// types -export const ProjectDraftEmptyState: React.FC = observer(() => { - // router - const { workspaceSlug, projectId } = useParams(); - // store hooks - const { issuesFilter } = useIssues(EIssuesStoreType.DRAFT); - - const userFilters = issuesFilter?.issueFilters?.filters; - const activeLayout = issuesFilter?.issueFilters?.displayFilters?.layout; - - const issueFilterCount = size( - Object.fromEntries( - Object.entries(userFilters ?? {}).filter(([, value]) => value && Array.isArray(value) && value.length > 0) - ) - ); - - const handleClearAllFilters = () => { - if (!workspaceSlug || !projectId) return; - const newFilters: IIssueFilterOptions = {}; - Object.keys(userFilters ?? {}).forEach((key) => { - newFilters[key as keyof IIssueFilterOptions] = []; - }); - issuesFilter.updateFilters(workspaceSlug.toString(), projectId.toString(), EIssueFilterType.FILTERS, { - ...newFilters, - }); - }; - - const emptyStateType = - issueFilterCount > 0 ? EmptyStateType.PROJECT_DRAFT_EMPTY_FILTER : EmptyStateType.PROJECT_DRAFT_NO_ISSUES; - const additionalPath = issueFilterCount > 0 ? activeLayout ?? "list" : undefined; - - return ( -
- 0 ? handleClearAllFilters : undefined} - /> -
- ); -}); +// FIXME: Project drafts is deprecated. Remove this component and all the related code. +export const ProjectDraftEmptyState: React.FC = observer(() => ( +
+)); diff --git a/web/core/constants/empty-state.tsx b/web/core/constants/empty-state.tsx index 71eab2f687d..e98efd2dc80 100644 --- a/web/core/constants/empty-state.tsx +++ b/web/core/constants/empty-state.tsx @@ -56,10 +56,8 @@ export enum EmptyStateType { PROJECT_ARCHIVED_NO_CYCLES = "project-archived-no-cycles", PROJECT_EMPTY_FILTER = "project-empty-filter", PROJECT_ARCHIVED_EMPTY_FILTER = "project-archived-empty-filter", - PROJECT_DRAFT_EMPTY_FILTER = "project-draft-empty-filter", PROJECT_NO_ISSUES = "project-no-issues", PROJECT_ARCHIVED_NO_ISSUES = "project-archived-no-issues", - PROJECT_DRAFT_NO_ISSUES = "project-draft-no-issues", VIEWS_EMPTY_SEARCH = "views-empty-search", PROJECTS_EMPTY_SEARCH = "projects-empty-search", MEMBERS_EMPTY_SEARCH = "members-empty-search", @@ -351,16 +349,6 @@ const emptyStateDetails: Record = { accessType: "project", access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER], }, - [EmptyStateType.PROJECT_DRAFT_EMPTY_FILTER]: { - key: EmptyStateType.PROJECT_DRAFT_EMPTY_FILTER, - title: "No issues found matching the filters applied", - path: "/empty-state/empty-filters/", - secondaryButton: { - text: "Clear all filters", - }, - accessType: "project", - access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER], - }, // project issues [EmptyStateType.PROJECT_NO_ISSUES]: { key: EmptyStateType.PROJECT_NO_ISSUES, @@ -391,13 +379,6 @@ const emptyStateDetails: Record = { accessType: "project", access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER], }, - [EmptyStateType.PROJECT_DRAFT_NO_ISSUES]: { - key: EmptyStateType.PROJECT_DRAFT_NO_ISSUES, - title: "No draft issues yet", - description: - "Quickly stepping away but want to keep your place? No worries – save a draft now. Your issues will be right here waiting for you.", - path: "/empty-state/draft/draft-issues-empty", - }, [EmptyStateType.VIEWS_EMPTY_SEARCH]: { key: EmptyStateType.VIEWS_EMPTY_SEARCH, title: "No matching views", From 007c5cf4cf73ee06cd4f92627de6121c538ea407 Mon Sep 17 00:00:00 2001 From: Prateek Shourya Date: Fri, 17 Jan 2025 18:22:28 +0530 Subject: [PATCH 18/26] chore: project cycle, views and archived issues empty state --- .../i18n/src/locales/en/translations.json | 56 ++++----- .../i18n/src/locales/es/translations.json | 61 +++++----- .../i18n/src/locales/fr/translations.json | 61 +++++----- .../i18n/src/locales/ja/translations.json | 61 +++++----- .../cycles/archived-cycles/root.tsx | 17 ++- .../empty-states/archived-issues.tsx | 69 +++++++---- .../issue-layouts/empty-states/cycle.tsx | 110 +++++++++++------- .../issue-layouts/empty-states/module.tsx | 4 +- .../empty-states/project-issues.tsx | 72 ++++++++---- .../components/project/multi-select-modal.tsx | 15 ++- .../project/project-feature-update.tsx | 2 +- web/core/components/views/views-list.tsx | 23 ++-- web/core/constants/empty-state.tsx | 105 ----------------- 13 files changed, 311 insertions(+), 345 deletions(-) diff --git a/packages/i18n/src/locales/en/translations.json b/packages/i18n/src/locales/en/translations.json index 756f7857805..59faeeb7293 100644 --- a/packages/i18n/src/locales/en/translations.json +++ b/packages/i18n/src/locales/en/translations.json @@ -220,6 +220,7 @@ "join_the_project_to_rearrange": "Join the project to rearrange", "drag_to_rearrange": "Drag to rearrange", "congrats": "Congrats!", + "project": "Project", "open_project": "Open project", "issues": "Issues", "cycles": "Cycles", @@ -377,6 +378,10 @@ "description": "A project could be a product's roadmap, a marketing campaign, or launching a new car." } } + }, + "filter": { + "title": "No matching projects", + "description": "No projects detected with the matching criteria. \n Create a new project instead." } } }, @@ -503,44 +508,22 @@ "text": "Add existing issue" } }, + "completed_no_issues": { + "title": "No issues in the cycle", + "description": "No issues in the cycle. Issues are either transferred or hidden. To see hidden issues if any, update your display properties accordingly." + }, "active": { "title": "No active cycle", "description": "An active cycle includes any period that encompasses today's date within its range. Find the progress and details of the active cycle here." }, - "completed": { - "title": "No issues in the cycle", - "description": "No issues in the cycle. Issues are either transferred or hidden. To see hidden issues if any, update your display properties accordingly." + "archived": { + "title": "No archived cycles yet", + "description": "To tidy up your project, archive completed cycles. Find them here once archived." } } }, - "project_archived_no_cycles_empty_state_title": "No archived cycles yet", - "project_archived_no_cycles_empty_state_description": "To tidy up your project, archive completed cycles. Find them here once archived.", - - "project_archived_empty_filter_empty_state_title": "No issues found matching the filters applied", - "project_archived_empty_filter_empty_state_secondary_button_text": "Clear all filters", - - "project_draft_empty_filter_empty_state_title": "No issues found matching the filters applied", - "project_draft_empty_filter_empty_state_secondary_button_text": "Clear all filters", - - "project_archived_no_issues_empty_state_title": "No archived issues yet", - "project_archived_no_issues_empty_state_description": "Manually or through automation, you can archive issues that are completed or cancelled. Find them here once archived.", - "project_archived_no_issues_empty_state_primary_button_text": "Set automation", - - "project_draft_no_issues_empty_state_title": "No draft issues yet", - "project_draft_no_issues_empty_state_description": "Quickly stepping away but want to keep your place? No worries – save a draft now. Your issues will be right here waiting for you.", - - "views_empty_search_empty_state_title": "No matching views", - "views_empty_search_empty_state_description": "No views match the search criteria. Create a new view instead.", - - "projects_empty_search_empty_state_title": "No matching projects", - "projects_empty_search_empty_state_description": "No projects detected with the matching criteria. Create a new project instead.", - - "members_empty_search_empty_state_title": "No matching members", - "members_empty_search_empty_state_description": "Add them to the project if they are already a part of the workspace", - - "project": { - "label": "Project", + "project_issues": { "empty_state": { "no_issues": { "title": "Create an issue and assign it to someone, even yourself", @@ -553,6 +536,13 @@ } } }, + "no_archived_issues": { + "title": "No archived issues yet", + "description": "Manually or through automation, you can archive issues that are completed or cancelled. Find them here once archived.", + "primary_button": { + "text": "Set automation" + } + }, "issues_empty_filter": { "title": "No issues found matching the filters applied", "secondary_button": { @@ -592,7 +582,7 @@ } }, - "project_view": { + "project_views": { "empty_state": { "general": { "title": "Save filtered views for your project. Create as many as you need", @@ -604,6 +594,10 @@ "description": "You can create a view from here with as many properties as filters as you see fit." } } + }, + "filter": { + "title": "No matching views", + "description": "No views match the search criteria. \n Create a new view instead." } } }, diff --git a/packages/i18n/src/locales/es/translations.json b/packages/i18n/src/locales/es/translations.json index 12702c8ece2..bf65232859d 100644 --- a/packages/i18n/src/locales/es/translations.json +++ b/packages/i18n/src/locales/es/translations.json @@ -219,6 +219,7 @@ "join_the_project_to_rearrange": "Únete al proyecto para reordenar", "drag_to_rearrange": "Arrastra para reordenar", "congrats": "¡Felicitaciones!", + "project": "Proyecto", "open_project": "Abrir proyecto", "issues": "Problemas", "cycles": "Ciclos", @@ -376,6 +377,10 @@ "description": "Un proyecto podría ser la hoja de ruta de un producto, una campaña de marketing o el lanzamiento de un nuevo coche." } } + }, + "filter": { + "title": "No hay proyectos coincidentes", + "description": "No se detectaron proyectos con los criterios coincidentes. \n Crea un nuevo proyecto en su lugar." } } }, @@ -502,47 +507,22 @@ "text": "Añadir problema existente" } }, + "completed_no_issues": { + "title": "No hay problemas en el ciclo", + "description": "No hay problemas en el ciclo. Los problemas se han transferido o están ocultos. Para ver problemas ocultos, si los hay, actualiza las propiedades de visualización en consecuencia." + }, "active": { - "title": "Sin ciclo activo", + "title": "No hay ciclo activo", "description": "Un ciclo activo incluye cualquier período que abarque la fecha de hoy dentro de su rango. Encuentra el progreso y los detalles del ciclo activo aquí." }, - "completed": { - "title": "No hay problemas en el ciclo", - "description": "No hay problemas en el ciclo. Los problemas se transfirieron o están ocultos. Para ver los problemas ocultos, si los hay, actualiza tus propiedades de visualización según sea necesario." + "archived": { + "title": "No hay ciclos archivados todavía", + "description": "Para organizar tu proyecto, archiva ciclos completados. Encuéntralos aquí una vez archivados." } } }, - "project_archived_no_cycles_empty_state_title": "No hay ciclos archivados aún", - "project_archived_no_cycles_empty_state_description": "Para ordenar tu proyecto, archiva los ciclos completados. Encuéntralos aquí una vez archivados.", - - "project_cycle_all_empty_state_title": "No hay ciclos", - "project_cycle_all_empty_state_description": "Un ciclo activo incluye cualquier período que abarque la fecha de hoy dentro de su rango. Encuentra el progreso y los detalles del ciclo activo aquí.", - - "project_archived_empty_filter_empty_state_title": "No se encontraron problemas que coincidan con los filtros aplicados", - "project_archived_empty_filter_empty_state_secondary_button_text": "Limpiar todos los filtros", - - "project_draft_empty_filter_empty_state_title": "No se encontraron problemas que coincidan con los filtros aplicados", - "project_draft_empty_filter_empty_state_secondary_button_text": "Limpiar todos los filtros", - - "project_archived_no_issues_empty_state_title": "No hay problemas archivados aún", - "project_archived_no_issues_empty_state_description": "Manual o mediante automatización, puedes archivar problemas que están completados o cancelados. Encuéntralos aquí una vez archivados.", - "project_archived_no_issues_empty_state_primary_button_text": "Establecer automatización", - - "project_draft_no_issues_empty_state_title": "No hay problemas en borrador aún", - "project_draft_no_issues_empty_state_description": "¿Te alejas rápidamente pero quieres mantener tu lugar? No te preocupes – guarda un borrador ahora. Tus problemas estarán aquí esperándote.", - - "views_empty_search_empty_state_title": "No hay vistas coincidentes", - "views_empty_search_empty_state_description": "No hay vistas que coincidan con los criterios de búsqueda. Crea una nueva vista en su lugar.", - - "projects_empty_search_empty_state_title": "No hay proyectos coincidentes", - "projects_empty_search_empty_state_description": "No se detectaron proyectos con los criterios coincidentes. Crea un nuevo proyecto en su lugar.", - - "members_empty_search_empty_state_title": "No hay miembros coincidentes", - "members_empty_search_empty_state_description": "Añádelos al proyecto si ya son parte del espacio de trabajo", - - "project": { - "label": "Proyecto", + "project_issues": { "empty_state": { "no_issues": { "title": "Crea un problema y asígnalo a alguien, incluso a ti mismo", @@ -555,6 +535,13 @@ } } }, + "no_archived_issues": { + "title": "Aún no hay problemas archivados", + "description": "De forma manual o mediante automatización, puedes archivar problemas que estén completados o cancelados. Encuéntralos aquí una vez archivados.", + "primary_button": { + "text": "Configurar automatización" + } + }, "issues_empty_filter": { "title": "No se encontraron problemas que coincidan con los filtros aplicados", "secondary_button": { @@ -594,7 +581,7 @@ } }, - "project_view": { + "project_views": { "empty_state": { "general": { "title": "Guarda vistas filtradas para tu proyecto. Crea tantas como necesites", @@ -606,6 +593,10 @@ "description": "Puedes crear una vista desde aquí con tantas propiedades como filtros que consideres necesarios." } } + }, + "filter": { + "title": "No hay vistas coincidentes", + "description": "Ninguna vista coincide con los criterios de búsqueda. \n Crea una nueva vista en su lugar." } } }, diff --git a/packages/i18n/src/locales/fr/translations.json b/packages/i18n/src/locales/fr/translations.json index 0025d74a629..22c105e51c7 100644 --- a/packages/i18n/src/locales/fr/translations.json +++ b/packages/i18n/src/locales/fr/translations.json @@ -220,6 +220,7 @@ "join_the_project_to_rearrange": "Rejoindre le projet pour réorganiser", "drag_to_rearrange": "Glisser pour réorganiser", "congrats": "Félicitations !", + "project": "Projet", "open_project": "Ouvrir le projet", "issues": "Problèmes", "cycles": "Cycles", @@ -377,6 +378,10 @@ "description": "Un projet peut être une feuille de route produit, une campagne marketing ou le lancement d'une nouvelle voiture." } } + }, + "filter": { + "title": "Aucun projet correspondant", + "description": "Aucun projet détecté avec les critères correspondants. \n Créez un nouveau projet à la place." } } }, @@ -503,47 +508,22 @@ "text": "Ajouter une tâche existante" } }, + "completed_no_issues": { + "title": "Aucun problème dans le cycle", + "description": "Aucun problème dans le cycle. Les problèmes ont été transférés ou sont cachés. Pour voir les problèmes cachés, le cas échéant, mettez à jour les propriétés d'affichage en conséquence." + }, "active": { "title": "Aucun cycle actif", - "description": "Un cycle actif inclut toute période qui englobe la date d'aujourd'hui dans sa plage. Trouvez les progrès et les détails du cycle actif ici." + "description": "Un cycle actif inclut toute période englobant la date d'aujourd'hui dans sa plage. Retrouvez ici les progrès et les détails du cycle actif." }, - "completed": { - "title": "Aucune tâche dans le cycle", - "description": "Aucune tâche dans le cycle. Les tâches sont soit transférées, soit masquées. Pour voir les tâches masquées, si elles existent, mettez à jour vos propriétés d'affichage en conséquence." + "archived": { + "title": "Aucun cycle archivé pour le moment", + "description": "Pour organiser votre projet, archivez les cycles terminés. Retrouvez-les ici une fois archivés." } } }, - "project_archived_no_cycles_empty_state_title": "Aucun cycle archivé pour le moment", - "project_archived_no_cycles_empty_state_description": "Pour ranger votre projet, archivez les cycles terminés. Retrouvez-les ici une fois archivés.", - - "project_cycle_all_empty_state_title": "Aucun cycle", - "project_cycle_all_empty_state_description": "Un cycle actif inclut toute période qui englobe la date d'aujourd'hui dans sa plage. Trouvez ici les progrès et les détails du cycle actif.", - - "project_archived_empty_filter_empty_state_title": "Aucun problème trouvé correspondant aux filtres appliqués", - "project_archived_empty_filter_empty_state_secondary_button_text": "Effacer tous les filtres", - - "project_draft_empty_filter_empty_state_title": "Aucun problème trouvé correspondant aux filtres appliqués", - "project_draft_empty_filter_empty_state_secondary_button_text": "Effacer tous les filtres", - - "project_archived_no_issues_empty_state_title": "Aucun problème archivé pour le moment", - "project_archived_no_issues_empty_state_description": "Manuellement ou par automatisation, vous pouvez archiver les problèmes terminés ou annulés. Retrouvez-les ici une fois archivés.", - "project_archived_no_issues_empty_state_primary_button_text": "Configurer l'automatisation", - - "project_draft_no_issues_empty_state_title": "Aucun problème en brouillon pour le moment", - "project_draft_no_issues_empty_state_description": "Vous partez rapidement mais voulez garder votre place ? Pas de souci – enregistrez un brouillon maintenant. Vos problèmes seront là à vous attendre.", - - "views_empty_search_empty_state_title": "Aucune vue correspondante", - "views_empty_search_empty_state_description": "Aucune vue ne correspond aux critères de recherche. Créez plutôt une nouvelle vue.", - - "projects_empty_search_empty_state_title": "Aucun projet correspondant", - "projects_empty_search_empty_state_description": "Aucun projet détecté avec les critères correspondants. Créez plutôt un nouveau projet.", - - "members_empty_search_empty_state_title": "Aucun membre correspondant", - "members_empty_search_empty_state_description": "Ajoutez-les au projet s'ils font déjà partie de l'espace de travail", - - "project": { - "label": "Projet", + "project_issues": { "empty_state": { "no_issues": { "title": "Créez un problème et assignez-le à quelqu’un, même à vous-même", @@ -556,6 +536,13 @@ } } }, + "no_archived_issues": { + "title": "Aucun problème archivé pour l'instant", + "description": "Manuellement ou via une automatisation, vous pouvez archiver les problèmes terminés ou annulés. Retrouvez-les ici une fois archivés.", + "primary_button": { + "text": "Configurer l'automatisation" + } + }, "issues_empty_filter": { "title": "Aucun problème trouvé correspondant aux filtres appliqués", "secondary_button": { @@ -595,7 +582,7 @@ } }, - "project_view": { + "project_views": { "empty_state": { "general": { "title": "Enregistrez des vues filtrées pour votre projet. Créez-en autant que nécessaire", @@ -607,6 +594,10 @@ "description": "Vous pouvez créer une vue à partir d'ici avec autant de propriétés ou de filtres que vous le souhaitez." } } + }, + "filter": { + "title": "Aucune vue correspondante", + "description": "Aucune vue ne correspond aux critères de recherche. \n Créez une nouvelle vue à la place." } } }, diff --git a/packages/i18n/src/locales/ja/translations.json b/packages/i18n/src/locales/ja/translations.json index 78955e67b8a..3c6df6d3731 100644 --- a/packages/i18n/src/locales/ja/translations.json +++ b/packages/i18n/src/locales/ja/translations.json @@ -220,6 +220,7 @@ "join_the_project_to_rearrange": "プロジェクトに参加して並べ替え", "drag_to_rearrange": "ドラッグして並べ替え", "congrats": "おめでとうございます!", + "project": "プロジェクト", "open_project": "プロジェクトを開く", "issues": "問題", "cycles": "サイクル", @@ -377,6 +378,10 @@ "description": "プロジェクトは製品ロードマップ、マーケティングキャンペーン、新車の発売など、さまざまなものになります。" } } + }, + "filter": { + "title": "一致するプロジェクトがありません", + "description": "一致する条件のプロジェクトが見つかりませんでした。\n 代わりに新しいプロジェクトを作成してください。" } } }, @@ -503,47 +508,22 @@ "text": "既存のタスクを追加" } }, + "completed_no_issues": { + "title": "サイクルに課題がありません", + "description": "サイクルに課題がありません。課題は転送されるか非表示になっています。非表示の課題がある場合は、表示プロパティを更新して確認してください。" + }, "active": { "title": "アクティブなサイクルがありません", - "description": "アクティブなサイクルは、今日の日付を範囲内に含む期間を指します。アクティブなサイクルの進捗と詳細をここで確認してください。" + "description": "アクティブなサイクルは、今日の日付を含む範囲がある期間を指します。ここでアクティブなサイクルの進捗と詳細を確認してください。" }, - "completed": { - "title": "サイクルにタスクがありません", - "description": "サイクルにタスクがありません。タスクは移行されるか、非表示になっています。存在する場合は、表示プロパティを更新して非表示のタスクを確認してください。" + "archived": { + "title": "まだアーカイブされたサイクルはありません", + "description": "プロジェクトを整理するには、完了したサイクルをアーカイブしてください。アーカイブされたサイクルはここで見つけることができます。" } } }, - "project_archived_no_cycles_empty_state_title": "まだアーカイブされたサイクルはありません", - "project_archived_no_cycles_empty_state_description": "プロジェクトを整理するために、完了したサイクルをアーカイブします。一度アーカイブされると、ここに表示されます。", - - "project_cycle_all_empty_state_title": "サイクルがありません", - "project_cycle_all_empty_state_description": "アクティブなサイクルには、現在の日付が含まれる期間が含まれます。ここでアクティブなサイクルの進捗や詳細を確認できます。", - - "project_archived_empty_filter_empty_state_title": "適用されたフィルターに一致する課題は見つかりません", - "project_archived_empty_filter_empty_state_secondary_button_text": "すべてのフィルターをクリア", - - "project_draft_empty_filter_empty_state_title": "適用されたフィルターに一致する課題は見つかりません", - "project_draft_empty_filter_empty_state_secondary_button_text": "すべてのフィルターをクリア", - - "project_archived_no_issues_empty_state_title": "まだアーカイブされた課題はありません", - "project_archived_no_issues_empty_state_description": "手動または自動化により、完了またはキャンセルされた課題をアーカイブできます。一度アーカイブされると、ここに表示されます。", - "project_archived_no_issues_empty_state_primary_button_text": "自動化を設定する", - - "project_draft_no_issues_empty_state_title": "まだドラフトの課題はありません", - "project_draft_no_issues_empty_state_description": "すぐに離れる必要がある場合でも心配いりません – 今すぐドラフトを保存してください。課題はここで待っています。", - - "views_empty_search_empty_state_title": "一致するビューはありません", - "views_empty_search_empty_state_description": "検索条件に一致するビューはありません。代わりに新しいビューを作成してください。", - - "projects_empty_search_empty_state_title": "一致するプロジェクトはありません", - "projects_empty_search_empty_state_description": "一致する条件のプロジェクトは見つかりませんでした。代わりに新しいプロジェクトを作成してください。", - - "members_empty_search_empty_state_title": "一致するメンバーはありません", - "members_empty_search_empty_state_description": "すでにワークスペースの一員である場合、プロジェクトに追加してください。", - - "project": { - "label": "プロジェクト", + "project_issues": { "empty_state": { "no_issues": { "title": "課題を作成し、誰かに、または自分に割り当てましょう", @@ -556,6 +536,13 @@ } } }, + "no_archived_issues": { + "title": "まだアーカイブされた課題はありません", + "description": "手動または自動化を使用して、完了またはキャンセルされた課題をアーカイブできます。アーカイブされた課題はここで見つけることができます。", + "primary_button": { + "text": "自動化を設定" + } + }, "issues_empty_filter": { "title": "適用されたフィルターに一致する課題は見つかりませんでした", "secondary_button": { @@ -595,7 +582,7 @@ } }, - "project_view": { + "project_views": { "empty_state": { "general": { "title": "プロジェクト用にフィルタされたビューを保存します。必要なだけ作成してください", @@ -607,6 +594,10 @@ "description": "ここから必要に応じてプロパティをフィルターとして使用してビューを作成できます。" } } + }, + "filter": { + "title": "一致するビューがありません", + "description": "検索条件に一致するビューはありません。 \n 代わりに新しいビューを作成してください。" } } }, diff --git a/web/core/components/cycles/archived-cycles/root.tsx b/web/core/components/cycles/archived-cycles/root.tsx index 06f61b66f51..165b5e4aa34 100644 --- a/web/core/components/cycles/archived-cycles/root.tsx +++ b/web/core/components/cycles/archived-cycles/root.tsx @@ -2,28 +2,31 @@ import React from "react"; import { observer } from "mobx-react"; import { useParams } from "next/navigation"; import useSWR from "swr"; -// types +// plane imports +import { useTranslation } from "@plane/i18n"; import { TCycleFilters } from "@plane/types"; // components import { ArchivedCyclesView, CycleAppliedFiltersList } from "@/components/cycles"; -import { EmptyState } from "@/components/empty-state"; +import { DetailedEmptyState } from "@/components/empty-state"; import { CycleModuleListLayout } from "@/components/ui"; -// constants -import { EmptyStateType } from "@/constants/empty-state"; // helpers import { calculateTotalFilters } from "@/helpers/filter.helper"; // hooks import { useCycle, useCycleFilter } from "@/hooks/store"; +import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; export const ArchivedCycleLayoutRoot: React.FC = observer(() => { // router const { workspaceSlug, projectId } = useParams(); + // plane hooks + const { t } = useTranslation(); // hooks const { fetchArchivedCycles, currentProjectArchivedCycleIds, loader } = useCycle(); // cycle filters hook const { clearAllFilters, currentProjectArchivedFilters, updateFilters } = useCycleFilter(); // derived values const totalArchivedCycles = currentProjectArchivedCycleIds?.length ?? 0; + const resolvedPath = useResolvedAssetPath({ basePath: "/empty-state/archived/empty-cycles" }); useSWR( workspaceSlug && projectId ? `ARCHIVED_CYCLES_${workspaceSlug.toString()}_${projectId.toString()}` : null, @@ -64,7 +67,11 @@ export const ArchivedCycleLayoutRoot: React.FC = observer(() => { )} {totalArchivedCycles === 0 ? (
- +
) : (
diff --git a/web/core/components/issues/issue-layouts/empty-states/archived-issues.tsx b/web/core/components/issues/issue-layouts/empty-states/archived-issues.tsx index 833a2d6054e..b4c3f7ae55c 100644 --- a/web/core/components/issues/issue-layouts/empty-states/archived-issues.tsx +++ b/web/core/components/issues/issue-layouts/empty-states/archived-issues.tsx @@ -1,31 +1,46 @@ import size from "lodash/size"; import { observer } from "mobx-react"; import { useParams } from "next/navigation"; -import { EIssueFilterType, EIssuesStoreType } from "@plane/constants"; +// plane imports +import { EIssueFilterType, EIssuesStoreType, EUserPermissionsLevel, EUserProjectRoles } from "@plane/constants"; +import { useTranslation } from "@plane/i18n"; import { IIssueFilterOptions } from "@plane/types"; -// hooks // components -import { EmptyState } from "@/components/empty-state"; -// constants -import { EmptyStateType } from "@/constants/empty-state"; -import { useIssues } from "@/hooks/store"; -// types +import { DetailedEmptyState } from "@/components/empty-state"; +// hooks +import { useIssues, useUserPermissions } from "@/hooks/store"; +import { useAppRouter } from "@/hooks/use-app-router"; +import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; export const ProjectArchivedEmptyState: React.FC = observer(() => { // router + const router = useAppRouter(); const { workspaceSlug, projectId } = useParams(); - // theme + // plane hooks + const { t } = useTranslation(); // store hooks const { issuesFilter } = useIssues(EIssuesStoreType.ARCHIVED); - + const { allowPermissions } = useUserPermissions(); + // derived values const userFilters = issuesFilter?.issueFilters?.filters; const activeLayout = issuesFilter?.issueFilters?.displayFilters?.layout; - const issueFilterCount = size( Object.fromEntries( Object.entries(userFilters ?? {}).filter(([, value]) => value && Array.isArray(value) && value.length > 0) ) ); + const additionalPath = issueFilterCount > 0 ? (activeLayout ?? "list") : undefined; + const canPerformEmptyStateActions = allowPermissions( + [EUserProjectRoles.ADMIN, EUserProjectRoles.MEMBER], + EUserPermissionsLevel.PROJECT + ); + const emptyFilterResolvedPath = useResolvedAssetPath({ + basePath: "/empty-state/empty-filters/", + additionalPath: additionalPath, + }); + const archivedIssuesResolvedPath = useResolvedAssetPath({ + basePath: "/empty-state/archived/empty-issues", + }); const handleClearAllFilters = () => { if (!workspaceSlug || !projectId) return; @@ -38,20 +53,30 @@ export const ProjectArchivedEmptyState: React.FC = observer(() => { }); }; - const emptyStateType = - issueFilterCount > 0 ? EmptyStateType.PROJECT_ARCHIVED_EMPTY_FILTER : EmptyStateType.PROJECT_ARCHIVED_NO_ISSUES; - const additionalPath = issueFilterCount > 0 ? activeLayout ?? "list" : undefined; - return (
- 0 ? undefined : `/${workspaceSlug}/projects/${projectId}/settings/automations` - } - secondaryButtonOnClick={issueFilterCount > 0 ? handleClearAllFilters : undefined} - /> + {issueFilterCount > 0 ? ( + + ) : ( + router.push(`/${workspaceSlug}/projects/${projectId}/settings/automations`), + disabled: !canPerformEmptyStateActions, + }} + /> + )}
); }); diff --git a/web/core/components/issues/issue-layouts/empty-states/cycle.tsx b/web/core/components/issues/issue-layouts/empty-states/cycle.tsx index 274aa85883b..3a2ac22ef40 100644 --- a/web/core/components/issues/issue-layouts/empty-states/cycle.tsx +++ b/web/core/components/issues/issue-layouts/empty-states/cycle.tsx @@ -5,32 +5,58 @@ import isEmpty from "lodash/isEmpty"; import size from "lodash/size"; import { observer } from "mobx-react"; import { useParams } from "next/navigation"; -// types -import { EIssueFilterType, EIssuesStoreType } from "@plane/constants"; +// plane imports +import { EIssueFilterType, EIssuesStoreType, EUserPermissionsLevel, EUserProjectRoles } from "@plane/constants"; +import { useTranslation } from "@plane/i18n"; import { IIssueFilterOptions, ISearchIssueResponse } from "@plane/types"; -// ui import { TOAST_TYPE, setToast } from "@plane/ui"; // components import { ExistingIssuesListModal } from "@/components/core"; -import { EmptyState } from "@/components/empty-state"; -// constants -import { EmptyStateType } from "@/constants/empty-state"; -import { useCommandPalette, useCycle, useEventTracker, useIssues } from "@/hooks/store"; +import { DetailedEmptyState } from "@/components/empty-state"; +import { useCommandPalette, useCycle, useEventTracker, useIssues, useUserPermissions } from "@/hooks/store"; +import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; export const CycleEmptyState: React.FC = observer(() => { // router const { workspaceSlug, projectId, cycleId } = useParams(); // states const [cycleIssuesListModal, setCycleIssuesListModal] = useState(false); + // plane hooks + const { t } = useTranslation(); // store hooks const { getCycleById } = useCycle(); const { issues, issuesFilter } = useIssues(EIssuesStoreType.CYCLE); const { toggleCreateIssueModal } = useCommandPalette(); const { setTrackElement } = useEventTracker(); - + const { allowPermissions } = useUserPermissions(); + // derived values const cycleDetails = cycleId ? getCycleById(cycleId.toString()) : undefined; const userFilters = issuesFilter?.issueFilters?.filters; const activeLayout = issuesFilter?.issueFilters?.displayFilters?.layout; + const issueFilterCount = size( + Object.fromEntries( + Object.entries(userFilters ?? {}).filter(([, value]) => value && Array.isArray(value) && value.length > 0) + ) + ); + const isCompletedCycleSnapshotAvailable = !isEmpty(cycleDetails?.progress_snapshot ?? {}); + const isEmptyFilters = issueFilterCount > 0; + const isCompletedAndEmpty = isCompletedCycleSnapshotAvailable || cycleDetails?.status?.toLowerCase() === "completed"; + const additionalPath = activeLayout ?? "list"; + const canPerformEmptyStateActions = allowPermissions( + [EUserProjectRoles.ADMIN, EUserProjectRoles.MEMBER], + EUserPermissionsLevel.PROJECT + ); + const emptyFilterResolvedPath = useResolvedAssetPath({ + basePath: "/empty-state/empty-filters/", + additionalPath: additionalPath, + }); + const noIssueResolvedPath = useResolvedAssetPath({ + basePath: "/empty-state/cycle-issues/", + additionalPath: additionalPath, + }); + const completedNoIssuesResolvedPath = useResolvedAssetPath({ + basePath: "/empty-state/cycle/completed-no-issues", + }); const handleAddIssuesToCycle = async (data: ISearchIssueResponse[]) => { if (!workspaceSlug || !projectId || !cycleId) return; @@ -54,13 +80,6 @@ export const CycleEmptyState: React.FC = observer(() => { }) ); }; - const issueFilterCount = size( - Object.fromEntries( - Object.entries(userFilters ?? {}).filter(([, value]) => value && Array.isArray(value) && value.length > 0) - ) - ); - - const isCompletedCycleSnapshotAvailable = !isEmpty(cycleDetails?.progress_snapshot ?? {}); const handleClearAllFilters = () => { if (!workspaceSlug || !projectId || !cycleId) return; @@ -79,16 +98,6 @@ export const CycleEmptyState: React.FC = observer(() => { ); }; - const isEmptyFilters = issueFilterCount > 0; - const isCompletedAndEmpty = isCompletedCycleSnapshotAvailable || cycleDetails?.status?.toLowerCase() === "completed"; - - const emptyStateType = isCompletedAndEmpty - ? EmptyStateType.PROJECT_CYCLE_COMPLETED_NO_ISSUES - : isEmptyFilters - ? EmptyStateType.PROJECT_EMPTY_FILTER - : EmptyStateType.PROJECT_CYCLE_NO_ISSUES; - const additionalPath = isCompletedAndEmpty ? undefined : activeLayout ?? "list"; - return (
{ handleOnSubmit={handleAddIssuesToCycle} />
- { - setTrackElement("Cycle issue empty state"); - toggleCreateIssueModal(true, EIssuesStoreType.CYCLE); - } - : undefined - } - secondaryButtonOnClick={ - !isCompletedAndEmpty && isEmptyFilters ? handleClearAllFilters : () => setCycleIssuesListModal(true) - } - /> + {isCompletedAndEmpty ? ( + + ) : isEmptyFilters ? ( + + ) : ( + { + setTrackElement("Cycle issue empty state"); + toggleCreateIssueModal(true, EIssuesStoreType.CYCLE); + }, + disabled: !canPerformEmptyStateActions, + }} + secondaryButton={{ + text: t("project_cycles.empty_state.no_issues.secondary_button.text"), + onClick: () => setCycleIssuesListModal(true), + disabled: !canPerformEmptyStateActions, + }} + /> + )}
); diff --git a/web/core/components/issues/issue-layouts/empty-states/module.tsx b/web/core/components/issues/issue-layouts/empty-states/module.tsx index 3597636100b..517542b44ec 100644 --- a/web/core/components/issues/issue-layouts/empty-states/module.tsx +++ b/web/core/components/issues/issue-layouts/empty-states/module.tsx @@ -103,10 +103,10 @@ export const ModuleEmptyState: React.FC = observer(() => {
{isEmptyFilters ? ( { // router const { workspaceSlug, projectId } = useParams(); + // plane imports + const { t } = useTranslation(); // store hooks const { toggleCreateIssueModal } = useCommandPalette(); const { setTrackElement } = useEventTracker(); - const { issuesFilter } = useIssues(EIssuesStoreType.PROJECT); - + const { allowPermissions } = useUserPermissions(); + // derived values const userFilters = issuesFilter?.issueFilters?.filters; const activeLayout = issuesFilter?.issueFilters?.displayFilters?.layout; - const issueFilterCount = size( Object.fromEntries( Object.entries(userFilters ?? {}).filter(([, value]) => value && Array.isArray(value) && value.length > 0) ) ); + const additionalPath = issueFilterCount > 0 ? (activeLayout ?? "list") : undefined; + const canPerformEmptyStateActions = allowPermissions( + [EUserProjectRoles.ADMIN, EUserProjectRoles.MEMBER], + EUserPermissionsLevel.PROJECT + ); + const emptyFilterResolvedPath = useResolvedAssetPath({ + basePath: "/empty-state/empty-filters/", + additionalPath: additionalPath, + }); + const projectIssuesResolvedPath = useResolvedAssetPath({ + basePath: "/empty-state/onboarding/issues", + }); const handleClearAllFilters = () => { if (!workspaceSlug || !projectId) return; @@ -40,24 +53,37 @@ export const ProjectEmptyState: React.FC = observer(() => { }); }; - const emptyStateType = issueFilterCount > 0 ? EmptyStateType.PROJECT_EMPTY_FILTER : EmptyStateType.PROJECT_NO_ISSUES; - const additionalPath = issueFilterCount > 0 ? activeLayout ?? "list" : undefined; - return (
- 0 - ? undefined - : () => { + {issueFilterCount > 0 ? ( + + ) : ( + { setTrackElement("Project issue empty state"); toggleCreateIssueModal(true, EIssuesStoreType.PROJECT); - } - } - secondaryButtonOnClick={issueFilterCount > 0 ? handleClearAllFilters : undefined} - /> + }} + disabled={!canPerformEmptyStateActions} + /> + } + /> + )}
); }); diff --git a/web/core/components/project/multi-select-modal.tsx b/web/core/components/project/multi-select-modal.tsx index e866f2595e6..30dd3be58be 100644 --- a/web/core/components/project/multi-select-modal.tsx +++ b/web/core/components/project/multi-select-modal.tsx @@ -4,16 +4,18 @@ import { observer } from "mobx-react"; import { Search, X } from "lucide-react"; import { Combobox } from "@headlessui/react"; // plane ui +import { useTranslation } from "@plane/i18n"; import { Button, Checkbox, EModalPosition, EModalWidth, ModalCore } from "@plane/ui"; // components import { Logo } from "@/components/common"; -import { EmptyState } from "@/components/empty-state"; +import { EmptyState, SimpleEmptyState } from "@/components/empty-state"; // constants import { EmptyStateType } from "@/constants/empty-state"; // helpers import { cn } from "@/helpers/common.helper"; // hooks import { useProject } from "@/hooks/store"; +import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; type Props = { isOpen: boolean; @@ -31,6 +33,8 @@ export const ProjectMultiSelectModal: React.FC = observer((props) => { const [isSubmitting, setIsSubmitting] = useState(false); // refs const moveButtonRef = useRef(null); + // plane hooks + const { t } = useTranslation(); // store hooks const { getProjectById } = useProject(); // derived values @@ -44,6 +48,9 @@ export const ProjectMultiSelectModal: React.FC = observer((props) => { const projectQuery = `${project?.identifier} ${project?.name}`.toLowerCase(); return projectQuery.includes(searchTerm.toLowerCase()); }); + const filteredProjectResolvedPath = useResolvedAssetPath({ + basePath: "/empty-state/search/project", + }); useEffect(() => { if (isOpen) setSelectedProjectIds(selectedProjectIdsProp); @@ -114,7 +121,11 @@ export const ProjectMultiSelectModal: React.FC = observer((props) => { > {filteredProjectIds.length === 0 ? (
- +
) : (
    = observer((props) => {
    - {t("congrats")}! {t("project.label")} {" "} + {t("congrats")}! {t("project")} {" "}

    {currentProjectDetails.name}

    {t("created").toLowerCase()}.
    diff --git a/web/core/components/views/views-list.tsx b/web/core/components/views/views-list.tsx index 3d7fed6a1f8..29a0c4cb08f 100644 --- a/web/core/components/views/views-list.tsx +++ b/web/core/components/views/views-list.tsx @@ -5,11 +5,9 @@ import { EUserPermissionsLevel, EUserProjectRoles } from "@plane/constants"; import { useTranslation } from "@plane/i18n"; // components import { ListLayout } from "@/components/core/list"; -import { ComicBoxButton, DetailedEmptyState, EmptyState } from "@/components/empty-state"; +import { ComicBoxButton, DetailedEmptyState, SimpleEmptyState } from "@/components/empty-state"; import { ViewListLoader } from "@/components/ui"; import { ProjectViewListItem } from "@/components/views"; -// constants -import { EmptyStateType } from "@/constants/empty-state"; // hooks import { useCommandPalette, useProjectView, useUserPermissions } from "@/hooks/store"; import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; @@ -32,13 +30,20 @@ export const ProjectViewsList = observer(() => { const generalViewResolvedPath = useResolvedAssetPath({ basePath: "/empty-state/onboarding/views", }); + const filteredViewResolvedPath = useResolvedAssetPath({ + basePath: "/empty-state/search/views", + }); if (loader || !projectViews || !filteredProjectViews) return ; if (filteredProjectViews.length === 0 && projectViews.length > 0) { return (
    - +
    ); } @@ -57,14 +62,14 @@ export const ProjectViewsList = observer(() => {
    ) : ( toggleCreateViewModal(true)} disabled={!canPerformEmptyStateActions} /> diff --git a/web/core/constants/empty-state.tsx b/web/core/constants/empty-state.tsx index e98efd2dc80..5e52ef9e9fd 100644 --- a/web/core/constants/empty-state.tsx +++ b/web/core/constants/empty-state.tsx @@ -49,18 +49,8 @@ export enum EmptyStateType { PROJECT_SETTINGS_INTEGRATIONS = "project-settings-integrations", PROJECT_SETTINGS_ESTIMATE = "project-settings-estimate", PROJECT_CYCLES = "project-cycles", - PROJECT_CYCLE_NO_ISSUES = "project-cycle-no-issues", PROJECT_CYCLE_ACTIVE = "project-cycle-active", PROJECT_CYCLE_ALL = "project-cycle-all", - PROJECT_CYCLE_COMPLETED_NO_ISSUES = "project-cycle-completed-no-issues", - PROJECT_ARCHIVED_NO_CYCLES = "project-archived-no-cycles", - PROJECT_EMPTY_FILTER = "project-empty-filter", - PROJECT_ARCHIVED_EMPTY_FILTER = "project-archived-empty-filter", - PROJECT_NO_ISSUES = "project-no-issues", - PROJECT_ARCHIVED_NO_ISSUES = "project-archived-no-issues", - VIEWS_EMPTY_SEARCH = "views-empty-search", - PROJECTS_EMPTY_SEARCH = "projects-empty-search", - MEMBERS_EMPTY_SEARCH = "members-empty-search", // stickies STICKIES = "stickies", STICKIES_SEARCH = "stickies-search", @@ -287,20 +277,6 @@ const emptyStateDetails: Record = { accessType: "project", access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER], }, - [EmptyStateType.PROJECT_CYCLE_NO_ISSUES]: { - key: EmptyStateType.PROJECT_CYCLE_NO_ISSUES, - title: "No issues added to the cycle", - description: "Add or create issues you wish to timebox and deliver within this cycle", - path: "/empty-state/cycle-issues/", - primaryButton: { - text: "Create new issue ", - }, - secondaryButton: { - text: "Add an existing issue", - }, - accessType: "project", - access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER], - }, [EmptyStateType.PROJECT_CYCLE_ACTIVE]: { key: EmptyStateType.PROJECT_CYCLE_ACTIVE, title: "No active cycle", @@ -308,19 +284,6 @@ const emptyStateDetails: Record = { "An active cycle includes any period that encompasses today's date within its range. Find the progress and details of the active cycle here.", path: "/empty-state/cycle/active", }, - [EmptyStateType.PROJECT_CYCLE_COMPLETED_NO_ISSUES]: { - key: EmptyStateType.PROJECT_CYCLE_COMPLETED_NO_ISSUES, - title: "No issues in the cycle", - description: - "No issues in the cycle. Issues are either transferred or hidden. To see hidden issues if any, update your display properties accordingly.", - path: "/empty-state/cycle/completed-no-issues", - }, - [EmptyStateType.PROJECT_ARCHIVED_NO_CYCLES]: { - key: EmptyStateType.PROJECT_ARCHIVED_NO_CYCLES, - title: "No archived cycles yet", - description: "To tidy up your project, archive completed cycles. Find them here once archived.", - path: "/empty-state/archived/empty-cycles", - }, [EmptyStateType.PROJECT_CYCLE_ALL]: { key: EmptyStateType.PROJECT_CYCLE_ALL, title: "No cycles", @@ -329,74 +292,6 @@ const emptyStateDetails: Record = { path: "/empty-state/cycle/active", }, // empty filters - [EmptyStateType.PROJECT_EMPTY_FILTER]: { - key: EmptyStateType.PROJECT_EMPTY_FILTER, - title: "No issues found matching the filters applied", - path: "/empty-state/empty-filters/", - secondaryButton: { - text: "Clear all filters", - }, - accessType: "project", - access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER], - }, - [EmptyStateType.PROJECT_ARCHIVED_EMPTY_FILTER]: { - key: EmptyStateType.PROJECT_ARCHIVED_EMPTY_FILTER, - title: "No issues found matching the filters applied", - path: "/empty-state/empty-filters/", - secondaryButton: { - text: "Clear all filters", - }, - accessType: "project", - access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER], - }, - // project issues - [EmptyStateType.PROJECT_NO_ISSUES]: { - key: EmptyStateType.PROJECT_NO_ISSUES, - title: "Create an issue and assign it to someone, even yourself", - description: - "Think of issues as jobs, tasks, work, or JTBD. Which we like. An issue and its sub-issues are usually time-based actionables assigned to members of your team. Your team creates, assigns, and completes issues to move your project towards its goal.", - path: "/empty-state/onboarding/issues", - primaryButton: { - text: "Create your first issue", - comicBox: { - title: "Issues are building blocks in Plane.", - description: - "Redesign the Plane UI, Rebrand the company, or Launch the new fuel injection system are examples of issues that likely have sub-issues.", - }, - }, - accessType: "project", - access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER], - }, - [EmptyStateType.PROJECT_ARCHIVED_NO_ISSUES]: { - key: EmptyStateType.PROJECT_ARCHIVED_NO_ISSUES, - title: "No archived issues yet", - description: - "Manually or through automation, you can archive issues that are completed or cancelled. Find them here once archived.", - path: "/empty-state/archived/empty-issues", - primaryButton: { - text: "Set automation", - }, - accessType: "project", - access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER], - }, - [EmptyStateType.VIEWS_EMPTY_SEARCH]: { - key: EmptyStateType.VIEWS_EMPTY_SEARCH, - title: "No matching views", - description: "No views match the search criteria. \n Create a new view instead.", - path: "/empty-state/search/views", - }, - [EmptyStateType.PROJECTS_EMPTY_SEARCH]: { - key: EmptyStateType.PROJECTS_EMPTY_SEARCH, - title: "No matching projects", - description: "No projects detected with the matching criteria. Create a new project instead.", - path: "/empty-state/search/project", - }, - [EmptyStateType.MEMBERS_EMPTY_SEARCH]: { - key: EmptyStateType.MEMBERS_EMPTY_SEARCH, - title: "No matching members", - description: "Add them to the project if they are already a part of the workspace", - path: "/empty-state/search/member", - }, [EmptyStateType.STICKIES]: { key: EmptyStateType.STICKIES, title: "Stickies are quick notes and to-dos you take down on the fly.", From 07ab153511dfa0d263a6638b2c3e679c05c111d4 Mon Sep 17 00:00:00 2001 From: Prateek Shourya Date: Fri, 17 Jan 2025 18:56:59 +0530 Subject: [PATCH 19/26] chore: project cycles related empty state --- .../i18n/src/locales/en/translations.json | 4 --- .../i18n/src/locales/es/translations.json | 4 --- .../i18n/src/locales/fr/translations.json | 4 --- .../i18n/src/locales/ja/translations.json | 4 --- .../[projectId]/cycles/(list)/page.tsx | 34 ++++++++++++------ .../components/cycles/active-cycle/root.tsx | 19 +++++++--- web/core/constants/empty-state.tsx | 35 ------------------- 7 files changed, 37 insertions(+), 67 deletions(-) diff --git a/packages/i18n/src/locales/en/translations.json b/packages/i18n/src/locales/en/translations.json index 59faeeb7293..fd3a75c3829 100644 --- a/packages/i18n/src/locales/en/translations.json +++ b/packages/i18n/src/locales/en/translations.json @@ -494,10 +494,6 @@ } } }, - "all": { - "title": "No cycles", - "description": "An active cycle includes any period that encompasses today's date within its range. Find the progress and details of the active cycle here." - }, "no_issues": { "title": "No issues added to the cycle", "description": "Add or create issues you wish to timebox and deliver within this cycle", diff --git a/packages/i18n/src/locales/es/translations.json b/packages/i18n/src/locales/es/translations.json index bf65232859d..818075fed37 100644 --- a/packages/i18n/src/locales/es/translations.json +++ b/packages/i18n/src/locales/es/translations.json @@ -493,10 +493,6 @@ } } }, - "all": { - "title": "Sin ciclos", - "description": "Un ciclo activo incluye cualquier período que abarque la fecha de hoy dentro de su rango. Encuentra el progreso y los detalles del ciclo activo aquí." - }, "no_issues": { "title": "No hay problemas añadidos al ciclo", "description": "Añade o crea problemas que desees organizar y entregar dentro de este ciclo", diff --git a/packages/i18n/src/locales/fr/translations.json b/packages/i18n/src/locales/fr/translations.json index 22c105e51c7..198e30211a5 100644 --- a/packages/i18n/src/locales/fr/translations.json +++ b/packages/i18n/src/locales/fr/translations.json @@ -494,10 +494,6 @@ } } }, - "all": { - "title": "Aucun cycle", - "description": "Un cycle actif inclut toute période qui englobe la date d'aujourd'hui dans sa plage. Trouvez les progrès et les détails du cycle actif ici." - }, "no_issues": { "title": "Aucune tâche ajoutée au cycle", "description": "Ajoutez ou créez des tâches que vous souhaitez cadencer et livrer dans ce cycle", diff --git a/packages/i18n/src/locales/ja/translations.json b/packages/i18n/src/locales/ja/translations.json index 3c6df6d3731..7f383c77642 100644 --- a/packages/i18n/src/locales/ja/translations.json +++ b/packages/i18n/src/locales/ja/translations.json @@ -494,10 +494,6 @@ } } }, - "all": { - "title": "サイクルがありません", - "description": "アクティブなサイクルは、今日の日付を範囲内に含む期間を指します。アクティブなサイクルの進捗と詳細をここで確認してください。" - }, "no_issues": { "title": "サイクルに追加されたタスクがありません", "description": "このサイクル内でタイムフレーム化し、配信したいタスクを追加または作成してください。", diff --git a/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/cycles/(list)/page.tsx b/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/cycles/(list)/page.tsx index fd20d94275e..b72b46dbeaf 100644 --- a/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/cycles/(list)/page.tsx +++ b/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/cycles/(list)/page.tsx @@ -11,10 +11,8 @@ import { TCycleFilters } from "@plane/types"; import { Header, EHeaderVariant } from "@plane/ui"; import { PageHead } from "@/components/core"; import { CyclesView, CycleCreateUpdateModal, CycleAppliedFiltersList } from "@/components/cycles"; -import { DetailedEmptyState, EmptyState } from "@/components/empty-state"; +import { ComicBoxButton, DetailedEmptyState } from "@/components/empty-state"; import { CycleModuleListLayout } from "@/components/ui"; -// constants -import { EmptyStateType } from "@/constants/empty-state"; // helpers import { calculateTotalFilters } from "@/helpers/filter.helper"; // hooks @@ -41,7 +39,11 @@ const ProjectCyclesPage = observer(() => { const totalCycles = currentProjectCycleIds?.length ?? 0; const project = projectId ? getProjectById(projectId?.toString()) : undefined; const pageTitle = project?.name ? `${project?.name} - Cycles` : undefined; - const canPerformEmptyStateActions = allowPermissions([EUserProjectRoles.ADMIN], EUserPermissionsLevel.PROJECT); + const hasAdminLevelPermission = allowPermissions([EUserProjectRoles.ADMIN], EUserPermissionsLevel.PROJECT); + const hasMemberLevelPermission = allowPermissions( + [EUserProjectRoles.ADMIN, EUserProjectRoles.MEMBER], + EUserPermissionsLevel.PROJECT + ); const resolvedPath = useResolvedAssetPath({ basePath: "/empty-state/disabled-feature/cycles" }); const handleRemoveFilter = (key: keyof TCycleFilters, value: string | null) => { @@ -69,7 +71,7 @@ const ProjectCyclesPage = observer(() => { onClick: () => { router.push(`/${workspaceSlug}/projects/${projectId}/settings/features`); }, - disabled: !canPerformEmptyStateActions, + disabled: !hasAdminLevelPermission, }} />
    @@ -89,12 +91,22 @@ const ProjectCyclesPage = observer(() => { /> {totalCycles === 0 ? (
    - { - setTrackElement("Cycle empty state"); - setCreateModal(true); - }} + { + setTrackElement("Cycle empty state"); + setCreateModal(true); + }} + disabled={!hasMemberLevelPermission} + /> + } />
    ) : ( diff --git a/web/ce/components/cycles/active-cycle/root.tsx b/web/ce/components/cycles/active-cycle/root.tsx index 5ebddc63f23..a13b7f64cfa 100644 --- a/web/ce/components/cycles/active-cycle/root.tsx +++ b/web/ce/components/cycles/active-cycle/root.tsx @@ -3,7 +3,8 @@ import { useMemo } from "react"; import { observer } from "mobx-react"; import { Disclosure } from "@headlessui/react"; -// ui +// plane imports +import { useTranslation } from "@plane/i18n"; import { Row } from "@plane/ui"; // components import { @@ -14,10 +15,10 @@ import { CyclesListItem, } from "@/components/cycles"; import useCyclesDetails from "@/components/cycles/active-cycle/use-cycles-details"; -import { EmptyState } from "@/components/empty-state"; -// constants -import { EmptyStateType } from "@/constants/empty-state"; +import { DetailedEmptyState } from "@/components/empty-state"; +// hooks import { useCycle } from "@/hooks/store"; +import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; import { ActiveCycleIssueDetails } from "@/store/issue/cycle"; interface IActiveCycleDetails { @@ -29,9 +30,13 @@ interface IActiveCycleDetails { export const ActiveCycleRoot: React.FC = observer((props) => { const { workspaceSlug, projectId, cycleId: propsCycleId, showHeader = true } = props; + // plane hooks + const { t } = useTranslation(); + // store hooks const { currentProjectActiveCycleId } = useCycle(); // derived values const cycleId = propsCycleId ?? currentProjectActiveCycleId; + const activeCycleResolvedPath = useResolvedAssetPath({ basePath: "/empty-state/cycle/active" }); // fetch cycle details const { handleFiltersUpdate, @@ -43,7 +48,11 @@ export const ActiveCycleRoot: React.FC = observer((props) = () => ( <> {!cycleId || !activeCycle ? ( - + ) : (
    {cycleId && ( diff --git a/web/core/constants/empty-state.tsx b/web/core/constants/empty-state.tsx index 5e52ef9e9fd..0c81bc711d2 100644 --- a/web/core/constants/empty-state.tsx +++ b/web/core/constants/empty-state.tsx @@ -48,9 +48,6 @@ export enum EmptyStateType { PROJECT_SETTINGS_LABELS = "project-settings-labels", PROJECT_SETTINGS_INTEGRATIONS = "project-settings-integrations", PROJECT_SETTINGS_ESTIMATE = "project-settings-estimate", - PROJECT_CYCLES = "project-cycles", - PROJECT_CYCLE_ACTIVE = "project-cycle-active", - PROJECT_CYCLE_ALL = "project-cycle-all", // stickies STICKIES = "stickies", STICKIES_SEARCH = "stickies-search", @@ -259,38 +256,6 @@ const emptyStateDetails: Record = { description: "Create a set of estimates to communicate the amount of work per issue.", path: "/empty-state/project-settings/estimates", }, - // project cycles - [EmptyStateType.PROJECT_CYCLES]: { - key: EmptyStateType.PROJECT_CYCLES, - title: "Group and timebox your work in Cycles.", - description: - "Break work down by timeboxed chunks, work backwards from your project deadline to set dates, and make tangible progress as a team.", - path: "/empty-state/onboarding/cycles", - primaryButton: { - text: "Set your first cycle", - comicBox: { - title: "Cycles are repetitive time-boxes.", - description: - "A sprint, an iteration, and or any other term you use for weekly or fortnightly tracking of work is a cycle.", - }, - }, - accessType: "project", - access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER], - }, - [EmptyStateType.PROJECT_CYCLE_ACTIVE]: { - key: EmptyStateType.PROJECT_CYCLE_ACTIVE, - title: "No active cycle", - description: - "An active cycle includes any period that encompasses today's date within its range. Find the progress and details of the active cycle here.", - path: "/empty-state/cycle/active", - }, - [EmptyStateType.PROJECT_CYCLE_ALL]: { - key: EmptyStateType.PROJECT_CYCLE_ALL, - title: "No cycles", - description: - "An active cycle includes any period that encompasses today's date within its range. Find the progress and details of the active cycle here.", - path: "/empty-state/cycle/active", - }, // empty filters [EmptyStateType.STICKIES]: { key: EmptyStateType.STICKIES, From 1314b90fd0a6204cc4b4aa070fc836ed79c2b9b5 Mon Sep 17 00:00:00 2001 From: Prateek Shourya Date: Fri, 17 Jan 2025 19:45:05 +0530 Subject: [PATCH 20/26] chore: project settings empty state --- .../i18n/src/locales/en/translations.json | 8 ----- .../i18n/src/locales/es/translations.json | 8 ----- .../i18n/src/locales/fr/translations.json | 8 ----- .../i18n/src/locales/ja/translations.json | 8 ----- .../labels/project-setting-label-list.tsx | 31 +++++++++++-------- web/core/constants/empty-state.tsx | 22 ------------- 6 files changed, 18 insertions(+), 67 deletions(-) diff --git a/packages/i18n/src/locales/en/translations.json b/packages/i18n/src/locales/en/translations.json index fd3a75c3829..4e613f7c612 100644 --- a/packages/i18n/src/locales/en/translations.json +++ b/packages/i18n/src/locales/en/translations.json @@ -469,14 +469,6 @@ "labels": { "title": "No labels yet", "description": "Create labels to help organize and filter issues in you project." - }, - "integerations": { - "title": "No integrations configured", - "description": "Configure GitHub and other integrations to sync your project issues." - }, - "estimates": { - "title": "No estimates added", - "description": "Create a set of estimates to communicate the amount of work per issue." } } }, diff --git a/packages/i18n/src/locales/es/translations.json b/packages/i18n/src/locales/es/translations.json index 818075fed37..63bb13b5f19 100644 --- a/packages/i18n/src/locales/es/translations.json +++ b/packages/i18n/src/locales/es/translations.json @@ -468,14 +468,6 @@ "labels": { "title": "Aún no hay etiquetas", "description": "Crea etiquetas para ayudar a organizar y filtrar problemas en tu proyecto." - }, - "integerations": { - "title": "No se han configurado integraciones", - "description": "Configura GitHub y otras integraciones para sincronizar los problemas de tu proyecto." - }, - "estimates": { - "title": "Aún no hay estimaciones", - "description": "Crea un conjunto de estimaciones para comunicar la cantidad de trabajo por problema." } } }, diff --git a/packages/i18n/src/locales/fr/translations.json b/packages/i18n/src/locales/fr/translations.json index 198e30211a5..30eb6fbbf36 100644 --- a/packages/i18n/src/locales/fr/translations.json +++ b/packages/i18n/src/locales/fr/translations.json @@ -469,14 +469,6 @@ "labels": { "title": "Aucune étiquette pour le moment", "description": "Créez des étiquettes pour organiser et filtrer les tâches de votre projet." - }, - "integerations": { - "title": "Aucune intégration configurée", - "description": "Configurez GitHub et d'autres intégrations pour synchroniser les tâches de votre projet." - }, - "estimates": { - "title": "Aucune estimation ajoutée", - "description": "Créez un ensemble d'estimations pour communiquer la quantité de travail par tâche." } } }, diff --git a/packages/i18n/src/locales/ja/translations.json b/packages/i18n/src/locales/ja/translations.json index 7f383c77642..906e1a27ba5 100644 --- a/packages/i18n/src/locales/ja/translations.json +++ b/packages/i18n/src/locales/ja/translations.json @@ -469,14 +469,6 @@ "labels": { "title": "ラベルがありません", "description": "ラベルを作成して、プロジェクトのタスクを整理し、フィルタリングします。" - }, - "integerations": { - "title": "設定済みの統合がありません", - "description": "GitHubやその他の統合を設定して、プロジェクトのタスクを同期します。" - }, - "estimates": { - "title": "見積もりが追加されていません", - "description": "タスクごとの作業量を伝えるために、見積もりセットを作成します。" } } }, diff --git a/web/core/components/labels/project-setting-label-list.tsx b/web/core/components/labels/project-setting-label-list.tsx index 2fc9c838277..e0943da3769 100644 --- a/web/core/components/labels/project-setting-label-list.tsx +++ b/web/core/components/labels/project-setting-label-list.tsx @@ -3,39 +3,40 @@ import React, { useState, useRef } from "react"; import { observer } from "mobx-react"; import { useParams } from "next/navigation"; +// plane imports +import { useTranslation } from "@plane/i18n"; import { IIssueLabel } from "@plane/types"; -// hooks import { Button, Loader } from "@plane/ui"; -import { EmptyState } from "@/components/empty-state"; +import { DetailedEmptyState } from "@/components/empty-state"; import { CreateUpdateLabelInline, DeleteLabelModal, ProjectSettingLabelGroup, ProjectSettingLabelItem, } from "@/components/labels"; -import { EmptyStateType } from "@/constants/empty-state"; +// hooks import { useLabel, useUserPermissions } from "@/hooks/store"; +import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; +// plane web imports import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions"; -// components -// ui -// types -// constants export const ProjectSettingsLabelList: React.FC = observer(() => { + // router + const { workspaceSlug, projectId } = useParams(); + // refs + const scrollToRef = useRef(null); // states const [showLabelForm, setLabelForm] = useState(false); const [isUpdating, setIsUpdating] = useState(false); const [selectDeleteLabel, setSelectDeleteLabel] = useState(null); - // refs - const scrollToRef = useRef(null); - // router - const { workspaceSlug, projectId } = useParams(); + // plane hooks + const { t } = useTranslation(); // store hooks const { projectLabels, updateLabelPosition, projectLabelsTree } = useLabel(); const { allowPermissions } = useUserPermissions(); - // derived values const isEditable = allowPermissions([EUserPermissions.ADMIN], EUserPermissionsLevel.PROJECT); + const resolvedPath = useResolvedAssetPath({ basePath: "/empty-state/project-settings/labels" }); const newLabel = () => { setIsUpdating(false); @@ -94,7 +95,11 @@ export const ProjectSettingsLabelList: React.FC = observer(() => { {projectLabels ? ( projectLabels.length === 0 && !showLabelForm ? (
    - +
    ) : ( projectLabelsTree && ( diff --git a/web/core/constants/empty-state.tsx b/web/core/constants/empty-state.tsx index 0c81bc711d2..36558b2417f 100644 --- a/web/core/constants/empty-state.tsx +++ b/web/core/constants/empty-state.tsx @@ -45,9 +45,6 @@ export enum EmptyStateType { PROFILE_ASSIGNED = "profile-assigned", PROFILE_CREATED = "profile-created", PROFILE_SUBSCRIBED = "profile-subscribed", - PROJECT_SETTINGS_LABELS = "project-settings-labels", - PROJECT_SETTINGS_INTEGRATIONS = "project-settings-integrations", - PROJECT_SETTINGS_ESTIMATE = "project-settings-estimate", // stickies STICKIES = "stickies", STICKIES_SEARCH = "stickies-search", @@ -237,25 +234,6 @@ const emptyStateDetails: Record = { description: "Subscribe to issues you are interested in, track all of them here.", path: "/empty-state/profile/subscribed", }, - // project settings - [EmptyStateType.PROJECT_SETTINGS_LABELS]: { - key: EmptyStateType.PROJECT_SETTINGS_LABELS, - title: "No labels yet", - description: "Create labels to help organize and filter issues in you project.", - path: "/empty-state/project-settings/labels", - }, - [EmptyStateType.PROJECT_SETTINGS_INTEGRATIONS]: { - key: EmptyStateType.PROJECT_SETTINGS_INTEGRATIONS, - title: "No integrations configured", - description: "Configure GitHub and other integrations to sync your project issues.", - path: "/empty-state/project-settings/integrations", - }, - [EmptyStateType.PROJECT_SETTINGS_ESTIMATE]: { - key: EmptyStateType.PROJECT_SETTINGS_ESTIMATE, - title: "No estimates added", - description: "Create a set of estimates to communicate the amount of work per issue.", - path: "/empty-state/project-settings/estimates", - }, // empty filters [EmptyStateType.STICKIES]: { key: EmptyStateType.STICKIES, From 8497947c72dcac2fa00cb4362f919d5a5fa742d8 Mon Sep 17 00:00:00 2001 From: Prateek Shourya Date: Fri, 17 Jan 2025 20:03:34 +0530 Subject: [PATCH 21/26] chore: profile issue and acitivity empty state --- web/app/profile/activity/page.tsx | 19 ++++++++---- .../empty-states/profile-view.tsx | 22 +++++++++----- web/core/constants/empty-state.tsx | 30 ------------------- 3 files changed, 29 insertions(+), 42 deletions(-) diff --git a/web/app/profile/activity/page.tsx b/web/app/profile/activity/page.tsx index a2a8cad851f..ca6c9511d06 100644 --- a/web/app/profile/activity/page.tsx +++ b/web/app/profile/activity/page.tsx @@ -7,24 +7,27 @@ import { useTranslation } from "@plane/i18n"; import { Button } from "@plane/ui"; // components import { PageHead } from "@/components/core"; -import { EmptyState } from "@/components/empty-state"; +import { DetailedEmptyState } from "@/components/empty-state"; import { ProfileActivityListPage, ProfileSettingContentHeader, ProfileSettingContentWrapper, } from "@/components/profile"; -// constants -import { EmptyStateType } from "@/constants/empty-state"; +// hooks +import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; const PER_PAGE = 100; const ProfileActivityPage = observer(() => { - const { t } = useTranslation(); // states const [pageCount, setPageCount] = useState(1); const [totalPages, setTotalPages] = useState(0); const [resultsCount, setResultsCount] = useState(0); const [isEmpty, setIsEmpty] = useState(false); + // plane hooks + const { t } = useTranslation(); + // derived values + const resolvedPath = useResolvedAssetPath({ basePath: "/empty-state/profile/activity" }); const updateTotalPages = (count: number) => setTotalPages(count); @@ -50,7 +53,13 @@ const ProfileActivityPage = observer(() => { const isLoadMoreVisible = pageCount < totalPages && resultsCount !== 0; if (isEmpty) { - return ; + return ( + + ); } return ( diff --git a/web/core/components/issues/issue-layouts/empty-states/profile-view.tsx b/web/core/components/issues/issue-layouts/empty-states/profile-view.tsx index 12a31df838f..ef13c3d3438 100644 --- a/web/core/components/issues/issue-layouts/empty-states/profile-view.tsx +++ b/web/core/components/issues/issue-layouts/empty-states/profile-view.tsx @@ -1,19 +1,27 @@ import { observer } from "mobx-react"; import { useParams } from "next/navigation"; // components -import { EmptyState } from "@/components/empty-state"; +import { useTranslation } from "@plane/i18n"; +import { DetailedEmptyState } from "@/components/empty-state"; // constants -import { EMPTY_STATE_DETAILS } from "@/constants/empty-state"; - -// assets +import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; +// TODO: If projectViewId changes, everything breaks. Figure out a better way to handle this. export const ProfileViewEmptyState: React.FC = observer(() => { + // plane hooks + const { t } = useTranslation(); // store hooks const { profileViewId } = useParams(); + // derived values + const resolvedPath = useResolvedAssetPath({ basePath: `/empty-state/profile/${profileViewId?.toString()}` }); if (!profileViewId) return null; - const emptyStateType = `profile-${profileViewId.toString()}`; - - return ; + return ( + + ); }); diff --git a/web/core/constants/empty-state.tsx b/web/core/constants/empty-state.tsx index 36558b2417f..39ae4191b8e 100644 --- a/web/core/constants/empty-state.tsx +++ b/web/core/constants/empty-state.tsx @@ -41,10 +41,6 @@ export enum EmptyStateType { WORKSPACE_SETTINGS_WEBHOOKS = "workspace-settings-webhooks", WORKSPACE_SETTINGS_EXPORT = "workspace-settings-export", WORKSPACE_SETTINGS_IMPORT = "workspace-settings-import", - PROFILE_ACTIVITY = "profile-activity", - PROFILE_ASSIGNED = "profile-assigned", - PROFILE_CREATED = "profile-created", - PROFILE_SUBSCRIBED = "profile-subscribed", // stickies STICKIES = "stickies", STICKIES_SEARCH = "stickies-search", @@ -208,32 +204,6 @@ const emptyStateDetails: Record = { description: "Find all your previous imports here and download them.", path: "/empty-state/workspace-settings/imports", }, - // profile - [EmptyStateType.PROFILE_ACTIVITY]: { - key: EmptyStateType.PROFILE_ASSIGNED, - title: "No activities yet", - description: - "Get started by creating a new issue! Add details and properties to it. Explore more in Plane to see your activity.", - path: "/empty-state/profile/activity", - }, - [EmptyStateType.PROFILE_ASSIGNED]: { - key: EmptyStateType.PROFILE_ASSIGNED, - title: "No issues are assigned to you", - description: "Issues assigned to you can be tracked from here.", - path: "/empty-state/profile/assigned", - }, - [EmptyStateType.PROFILE_CREATED]: { - key: EmptyStateType.PROFILE_CREATED, - title: "No issues yet", - description: "All issues created by you come here, track them here directly.", - path: "/empty-state/profile/created", - }, - [EmptyStateType.PROFILE_SUBSCRIBED]: { - key: EmptyStateType.PROFILE_SUBSCRIBED, - title: "No issues yet", - description: "Subscribe to issues you are interested in, track all of them here.", - path: "/empty-state/profile/subscribed", - }, // empty filters [EmptyStateType.STICKIES]: { key: EmptyStateType.STICKIES, From 214c820728b94b5f95c9ccf552972824053d90ac Mon Sep 17 00:00:00 2001 From: Prateek Shourya Date: Fri, 17 Jan 2025 20:25:15 +0530 Subject: [PATCH 22/26] chore: workspace settings realted constants --- .../(projects)/settings/api-tokens/page.tsx | 17 +++++++---- .../(projects)/settings/webhooks/page.tsx | 20 ++++++++----- web/core/components/exporter/guide.tsx | 18 +++++++---- web/core/components/integration/guide.tsx | 3 +- web/core/constants/empty-state.tsx | 30 ------------------- 5 files changed, 40 insertions(+), 48 deletions(-) diff --git a/web/app/[workspaceSlug]/(projects)/settings/api-tokens/page.tsx b/web/app/[workspaceSlug]/(projects)/settings/api-tokens/page.tsx index fd2ed9669b2..03bb1fa6cbe 100644 --- a/web/app/[workspaceSlug]/(projects)/settings/api-tokens/page.tsx +++ b/web/app/[workspaceSlug]/(projects)/settings/api-tokens/page.tsx @@ -4,19 +4,19 @@ import React, { useState } from "react"; import { observer } from "mobx-react"; import { useParams } from "next/navigation"; import useSWR from "swr"; -// ui +// plane imports +import { useTranslation } from "@plane/i18n"; import { Button } from "@plane/ui"; // component import { ApiTokenListItem, CreateApiTokenModal } from "@/components/api-token"; import { NotAuthorizedView } from "@/components/auth-screens"; import { PageHead } from "@/components/core"; -import { EmptyState } from "@/components/empty-state"; +import { DetailedEmptyState } from "@/components/empty-state"; import { APITokenSettingsLoader } from "@/components/ui"; -// constants -import { EmptyStateType } from "@/constants/empty-state"; import { API_TOKENS_LIST } from "@/constants/fetch-keys"; // store hooks import { useUserPermissions, useWorkspace } from "@/hooks/store"; +import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions"; // services import { APITokenService } from "@/services/api_token.service"; @@ -28,11 +28,14 @@ const ApiTokensPage = observer(() => { const [isCreateTokenModalOpen, setIsCreateTokenModalOpen] = useState(false); // router const { workspaceSlug } = useParams(); + // plane hooks + const { t } = useTranslation(); // store hooks const { currentWorkspace } = useWorkspace(); const { workspaceUserInfo, allowPermissions } = useUserPermissions(); // derived values const canPerformWorkspaceAdminActions = allowPermissions([EUserPermissions.ADMIN], EUserPermissionsLevel.WORKSPACE); + const resolvedPath = useResolvedAssetPath({ basePath: "/empty-state/workspace-settings/api-tokens" }); const { data: tokens } = useSWR( workspaceSlug && canPerformWorkspaceAdminActions ? API_TOKENS_LIST(workspaceSlug.toString()) : null, @@ -78,7 +81,11 @@ const ApiTokensPage = observer(() => {
    - +
)} diff --git a/web/app/[workspaceSlug]/(projects)/settings/webhooks/page.tsx b/web/app/[workspaceSlug]/(projects)/settings/webhooks/page.tsx index 86c922f07fb..412c29f5dd2 100644 --- a/web/app/[workspaceSlug]/(projects)/settings/webhooks/page.tsx +++ b/web/app/[workspaceSlug]/(projects)/settings/webhooks/page.tsx @@ -4,18 +4,18 @@ import React, { useEffect, useState } from "react"; import { observer } from "mobx-react"; import { useParams } from "next/navigation"; import useSWR from "swr"; -// ui +// plane imports +import { useTranslation } from "@plane/i18n"; import { Button } from "@plane/ui"; // components import { NotAuthorizedView } from "@/components/auth-screens"; import { PageHead } from "@/components/core"; -import { EmptyState } from "@/components/empty-state"; +import { DetailedEmptyState } from "@/components/empty-state"; import { WebhookSettingsLoader } from "@/components/ui"; import { WebhooksList, CreateWebhookModal } from "@/components/web-hooks"; -// constants -import { EmptyStateType } from "@/constants/empty-state"; // hooks import { useUserPermissions, useWebhook, useWorkspace } from "@/hooks/store"; +import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions"; const WebhooksListPage = observer(() => { @@ -23,13 +23,15 @@ const WebhooksListPage = observer(() => { const [showCreateWebhookModal, setShowCreateWebhookModal] = useState(false); // router const { workspaceSlug } = useParams(); + // plane hooks + const { t } = useTranslation(); // mobx store const { workspaceUserInfo, allowPermissions } = useUserPermissions(); - const { fetchWebhooks, webhooks, clearSecretKey, webhookSecretKey, createWebhook } = useWebhook(); const { currentWorkspace } = useWorkspace(); - + // derived values const canPerformWorkspaceAdminActions = allowPermissions([EUserPermissions.ADMIN], EUserPermissionsLevel.WORKSPACE); + const resolvedPath = useResolvedAssetPath({ basePath: "/empty-state/workspace-settings/webhooks" }); useSWR( workspaceSlug && canPerformWorkspaceAdminActions ? `WEBHOOKS_LIST_${workspaceSlug}` : null, @@ -81,7 +83,11 @@ const WebhooksListPage = observer(() => {
- +
)} diff --git a/web/core/components/exporter/guide.tsx b/web/core/components/exporter/guide.tsx index 7ee2899956a..65e77a6f200 100644 --- a/web/core/components/exporter/guide.tsx +++ b/web/core/components/exporter/guide.tsx @@ -8,19 +8,20 @@ import { useParams, useSearchParams } from "next/navigation"; import useSWR, { mutate } from "swr"; // icons import { MoveLeft, MoveRight, RefreshCw } from "lucide-react"; -// ui +// plane imports +import { useTranslation } from "@plane/i18n"; import { Button } from "@plane/ui"; // components -import { EmptyState } from "@/components/empty-state"; +import { DetailedEmptyState } from "@/components/empty-state"; import { Exporter, SingleExport } from "@/components/exporter"; import { ImportExportSettingsLoader } from "@/components/ui"; // constants -import { EmptyStateType } from "@/constants/empty-state"; import { EXPORT_SERVICES_LIST } from "@/constants/fetch-keys"; import { EXPORTERS_LIST } from "@/constants/workspace"; // hooks import { useProject, useUser, useUserPermissions } from "@/hooks/store"; import { useAppRouter } from "@/hooks/use-app-router"; +import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions"; // services import { IntegrationService } from "@/services/integrations"; @@ -37,11 +38,14 @@ const IntegrationGuide = observer(() => { const { workspaceSlug } = useParams(); const searchParams = useSearchParams(); const provider = searchParams.get("provider"); + // plane hooks + const { t } = useTranslation(); // store hooks const { data: currentUser, canPerformAnyCreateAction } = useUser(); const { allowPermissions } = useUserPermissions(); - const { workspaceProjectIds } = useProject(); + // derived values + const resolvedPath = useResolvedAssetPath({ basePath: "/empty-state/workspace-settings/exports" }); const { data: exporterServices } = useSWR( workspaceSlug && cursor ? EXPORT_SERVICES_LIST(workspaceSlug as string, cursor, `${per_page}`) : null, @@ -164,7 +168,11 @@ const IntegrationGuide = observer(() => {
) : (
- +
) ) : ( diff --git a/web/core/components/integration/guide.tsx b/web/core/components/integration/guide.tsx index da751cde8cf..9023233c4c7 100644 --- a/web/core/components/integration/guide.tsx +++ b/web/core/components/integration/guide.tsx @@ -28,6 +28,7 @@ import { IntegrationService } from "@/services/integrations"; // services const integrationService = new IntegrationService(); +// FIXME: [Deprecated] Remove this component const IntegrationGuide = observer(() => { // states const [refreshing, setRefreshing] = useState(false); @@ -137,7 +138,7 @@ const IntegrationGuide = observer(() => {
) : (
- + {/* */}
) ) : ( diff --git a/web/core/constants/empty-state.tsx b/web/core/constants/empty-state.tsx index 39ae4191b8e..90bd3481a4e 100644 --- a/web/core/constants/empty-state.tsx +++ b/web/core/constants/empty-state.tsx @@ -37,10 +37,6 @@ export enum EmptyStateType { WORKSPACE_CUSTOM_VIEW = "workspace-custom-view", WORKSPACE_NO_PROJECTS = "workspace-no-projects", WORKSPACE_PROJECT_NOT_FOUND = "workspace-project-not-found", - WORKSPACE_SETTINGS_API_TOKENS = "workspace-settings-api-tokens", - WORKSPACE_SETTINGS_WEBHOOKS = "workspace-settings-webhooks", - WORKSPACE_SETTINGS_EXPORT = "workspace-settings-export", - WORKSPACE_SETTINGS_IMPORT = "workspace-settings-import", // stickies STICKIES = "stickies", STICKIES_SEARCH = "stickies-search", @@ -178,32 +174,6 @@ const emptyStateDetails: Record = { accessType: "workspace", access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER], }, - // workspace settings - [EmptyStateType.WORKSPACE_SETTINGS_API_TOKENS]: { - key: EmptyStateType.WORKSPACE_SETTINGS_API_TOKENS, - title: "No API tokens created", - description: - "Plane APIs can be used to integrate your data in Plane with any external system. Create a token to get started.", - path: "/empty-state/workspace-settings/api-tokens", - }, - [EmptyStateType.WORKSPACE_SETTINGS_WEBHOOKS]: { - key: EmptyStateType.WORKSPACE_SETTINGS_WEBHOOKS, - title: "No webhooks added", - description: "Create webhooks to receive real-time updates and automate actions.", - path: "/empty-state/workspace-settings/webhooks", - }, - [EmptyStateType.WORKSPACE_SETTINGS_EXPORT]: { - key: EmptyStateType.WORKSPACE_SETTINGS_EXPORT, - title: "No previous exports yet", - description: "Anytime you export, you will also have a copy here for reference.", - path: "/empty-state/workspace-settings/exports", - }, - [EmptyStateType.WORKSPACE_SETTINGS_IMPORT]: { - key: EmptyStateType.WORKSPACE_SETTINGS_IMPORT, - title: "No previous imports yet", - description: "Find all your previous imports here and download them.", - path: "/empty-state/workspace-settings/imports", - }, // empty filters [EmptyStateType.STICKIES]: { key: EmptyStateType.STICKIES, From 0e3cdee87837847c8b91c69d89db9f689b13257c Mon Sep 17 00:00:00 2001 From: Prateek Shourya Date: Fri, 17 Jan 2025 21:10:43 +0530 Subject: [PATCH 23/26] chore: stickies and home widgets empty state --- .../i18n/src/locales/en/translations.json | 31 ++++++++++ .../i18n/src/locales/es/translations.json | 31 ++++++++++ .../i18n/src/locales/fr/translations.json | 31 ++++++++++ .../i18n/src/locales/ja/translations.json | 31 ++++++++++ .../empty-state/simple-empty-state-root.tsx | 8 +-- .../home/home-dashboard-widgets.tsx | 24 ++++---- .../stickies/layout/stickies-list.tsx | 59 ++++++++++++++----- web/core/constants/empty-state.tsx | 44 -------------- 8 files changed, 182 insertions(+), 77 deletions(-) diff --git a/packages/i18n/src/locales/en/translations.json b/packages/i18n/src/locales/en/translations.json index 4e613f7c612..5a2baed1d62 100644 --- a/packages/i18n/src/locales/en/translations.json +++ b/packages/i18n/src/locales/en/translations.json @@ -753,5 +753,36 @@ "text": "Create your first draft" } } + }, + + "stickies": { + "empty_state": { + "general": { + "title": "Stickies are quick notes and to-dos you take down on the fly.", + "description": "Capture your thoughts and ideas effortlessly by creating stickies that you can access anytime and from anywhere.", + "primary_button": { + "text": "Add sticky" + } + }, + "search": { + "title": "That doesn't match any of your stickies.", + "description": "Try a different term or let us know\nif you are sure your search is right. ", + "primary_button": { + "text": "Add sticky" + } + } + } + }, + + "home_widgets": { + "empty_state": { + "general": { + "title": "It's Quiet Without Widgets, Turn Them On", + "description": "It looks like all your widgets are turned off. Enable them\nnow to enhance your experience!", + "primary_button": { + "text": "Manage widgets" + } + } + } } } diff --git a/packages/i18n/src/locales/es/translations.json b/packages/i18n/src/locales/es/translations.json index 63bb13b5f19..adf76710b81 100644 --- a/packages/i18n/src/locales/es/translations.json +++ b/packages/i18n/src/locales/es/translations.json @@ -752,5 +752,36 @@ "text": "Crea tu primer borrador" } } + }, + + "stickies": { + "empty_state": { + "general": { + "title": "Los stickies son notas rápidas y tareas que tomas al vuelo.", + "description": "Captura tus pensamientos e ideas sin esfuerzo creando stickies a los que puedes acceder en cualquier momento y lugar.", + "primary_button": { + "text": "Agregar sticky" + } + }, + "search": { + "title": "Eso no coincide con ninguno de tus stickies.", + "description": "Prueba con un término diferente o avísanos si estás seguro de que tu búsqueda es correcta.", + "primary_button": { + "text": "Agregar sticky" + } + } + } + }, + + "home_widgets": { + "empty_state": { + "general": { + "title": "Está tranquilo sin widgets, actívalos", + "description": "Parece que todos tus widgets están desactivados. ¡Enciéndelos ahora para mejorar tu experiencia!", + "primary_button": { + "text": "Gestionar widgets" + } + } + } } } diff --git a/packages/i18n/src/locales/fr/translations.json b/packages/i18n/src/locales/fr/translations.json index 30eb6fbbf36..3588ca6ab9f 100644 --- a/packages/i18n/src/locales/fr/translations.json +++ b/packages/i18n/src/locales/fr/translations.json @@ -753,5 +753,36 @@ "text": "Créez votre premier brouillon" } } + }, + + "stickies": { + "empty_state": { + "general": { + "title": "Les stickies sont des notes rapides et des tâches que vous notez à la volée.", + "description": "Capturez vos pensées et vos idées facilement en créant des stickies accessibles à tout moment et de n'importe où.", + "primary_button": { + "text": "Ajouter un sticky" + } + }, + "search": { + "title": "Aucun sticky ne correspond à votre recherche.", + "description": "Essayez un autre terme ou faites-le nous savoir si vous êtes sûr que votre recherche est correcte.", + "primary_button": { + "text": "Ajouter un sticky" + } + } + } + }, + + "home_widgets": { + "empty_state": { + "general": { + "title": "C'est calme sans widgets, activez-les", + "description": "Il semble que tous vos widgets soient désactivés. Activez-les maintenant pour améliorer votre expérience !", + "primary_button": { + "text": "Gérer les widgets" + } + } + } } } diff --git a/packages/i18n/src/locales/ja/translations.json b/packages/i18n/src/locales/ja/translations.json index 906e1a27ba5..6692dcfe8ae 100644 --- a/packages/i18n/src/locales/ja/translations.json +++ b/packages/i18n/src/locales/ja/translations.json @@ -753,5 +753,36 @@ "text": "最初の下書きを作成" } } + }, + + "stickies": { + "empty_state": { + "general": { + "title": "スティッキーは、その場で素早く取るメモやタスクです。", + "description": "いつでもどこでもアクセスできるスティッキーを作成して、思いついたアイデアを簡単にキャプチャしましょう。", + "primary_button": { + "text": "スティッキーを追加" + } + }, + "search": { + "title": "一致するスティッキーはありません。", + "description": "別の用語を試すか、検索が正しい場合はお知らせください。", + "primary_button": { + "text": "スティッキーを追加" + } + } + } + }, + + "home_widgets": { + "empty_state": { + "general": { + "title": "ウィジェットがないと静かですね、オンにしましょう", + "description": "すべてのウィジェットがオフになっているようです。 今すぐ有効にして、体験を向上させましょう!", + "primary_button": { + "text": "ウィジェットを管理" + } + } + } } } diff --git a/web/core/components/empty-state/simple-empty-state-root.tsx b/web/core/components/empty-state/simple-empty-state-root.tsx index d0ab95076a7..ce00a143f9d 100644 --- a/web/core/components/empty-state/simple-empty-state-root.tsx +++ b/web/core/components/empty-state/simple-empty-state-root.tsx @@ -6,7 +6,7 @@ import Image from "next/image"; // utils import { cn } from "@plane/utils"; -type EmptyStateSize = "sm" | "md" | "lg"; +type EmptyStateSize = "sm" | "lg"; type Props = { title: string; @@ -17,12 +17,8 @@ type Props = { const sizeConfig = { sm: { - container: "size-20", - dimensions: 78, - }, - md: { container: "size-24", - dimensions: 80, + dimensions: 78, }, lg: { container: "size-28", diff --git a/web/core/components/home/home-dashboard-widgets.tsx b/web/core/components/home/home-dashboard-widgets.tsx index 009cb9ffe74..c671bf65260 100644 --- a/web/core/components/home/home-dashboard-widgets.tsx +++ b/web/core/components/home/home-dashboard-widgets.tsx @@ -1,14 +1,14 @@ import { observer } from "mobx-react"; import { useParams } from "next/navigation"; -// plane types +// plane imports +import { useTranslation } from "@plane/i18n"; import { THomeWidgetKeys, THomeWidgetProps } from "@plane/types"; // components -import { EmptyState } from "@/components/empty-state"; -// constants -import { EmptyStateType } from "@/constants/empty-state"; +import { SimpleEmptyState } from "@/components/empty-state"; // hooks import { useHome } from "@/hooks/store/use-home"; // plane web components +import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; import { HomePageHeader } from "@/plane-web/components/home/header"; import { StickiesWidget } from "../stickies"; import { RecentActivityWidget } from "./widgets"; @@ -52,8 +52,12 @@ export const HOME_WIDGETS_LIST: { export const DashboardWidgets = observer(() => { // router const { workspaceSlug } = useParams(); + // plane hooks + const { t } = useTranslation(); // store hooks const { toggleWidgetSettings, widgetsMap, showWidgetSettings, orderedWidgets, isAnyWidgetEnabled } = useHome(); + // derived values + const noWidgetsResolvedPath = useResolvedAssetPath({ basePath: "/empty-state/dashboard/widgets" }); if (!workspaceSlug) return null; @@ -80,14 +84,10 @@ export const DashboardWidgets = observer(() => { ) : (
- toggleWidgetSettings(true)} - primaryButtonConfig={{ - size: "sm", - variant: "neutral-primary", - }} +
)} diff --git a/web/core/components/stickies/layout/stickies-list.tsx b/web/core/components/stickies/layout/stickies-list.tsx index 4da6efe7b03..1022f27fe6b 100644 --- a/web/core/components/stickies/layout/stickies-list.tsx +++ b/web/core/components/stickies/layout/stickies-list.tsx @@ -7,18 +7,23 @@ import type { ElementDragPayload } from "@atlaskit/pragmatic-drag-and-drop/eleme import { observer } from "mobx-react"; import { usePathname } from "next/navigation"; import Masonry from "react-masonry-component"; -// plane ui +import { Plus } from "lucide-react"; +// plane imports +import { EUserPermissionsLevel, EUserWorkspaceRoles } from "@plane/constants"; +import { useTranslation } from "@plane/i18n"; import { Loader } from "@plane/ui"; // components -import { EmptyState } from "@/components/empty-state"; +import { DetailedEmptyState, SimpleEmptyState } from "@/components/empty-state"; // constants -import { EmptyStateType } from "@/constants/empty-state"; +import { StickiesEmptyState } from "@/components/home/widgets/empty-states/stickies"; // hooks +import { useUserPermissions } from "@/hooks/store"; +import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; import { useSticky } from "@/hooks/use-stickies"; +// local imports import { useStickyOperations } from "../sticky/use-operations"; import { StickyDNDWrapper } from "./sticky-dnd-wrapper"; import { getInstructionFromPayload } from "./sticky.helpers"; -import { StickiesEmptyState } from "@/components/home/widgets/empty-states/stickies"; type TStickiesLayout = { workspaceSlug: string; @@ -33,8 +38,11 @@ export const StickiesList = observer((props: TProps) => { const { workspaceSlug, intersectionElement, columnCount } = props; // navigation const pathname = usePathname(); + // plane hooks + const { t } = useTranslation(); // store hooks const { getWorkspaceStickyIds, toggleShowNewSticky, searchQuery, loader } = useSticky(); + const { allowPermissions } = useUserPermissions(); // sticky operations const { stickyOperations } = useStickyOperations({ workspaceSlug: workspaceSlug?.toString() }); // derived values @@ -42,6 +50,14 @@ export const StickiesList = observer((props: TProps) => { const itemWidth = `${100 / columnCount}%`; const totalRows = Math.ceil(workspaceStickyIds.length / columnCount); const isStickiesPage = pathname?.includes("stickies"); + const hasGuestLevelPermissions = allowPermissions( + [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER, EUserWorkspaceRoles.GUEST], + EUserPermissionsLevel.WORKSPACE + ); + const stickiesResolvedPath = useResolvedAssetPath({ basePath: "/empty-state/stickies/stickies" }); + const stickiesSearchResolvedPath = useResolvedAssetPath({ + basePath: "/empty-state/stickies/stickies-search", + }); // Function to determine if an item is in first or last row const getRowPositions = (index: number) => { @@ -85,17 +101,30 @@ export const StickiesList = observer((props: TProps) => { return (
{isStickiesPage ? ( - { - toggleShowNewSticky(true); - stickyOperations.create(); - }} - primaryButtonConfig={{ - size: "sm", - }} - /> + <> + {searchQuery ? ( + + ) : ( + , + text: t("stickies.empty_state.general.primary_button.text"), + onClick: () => { + toggleShowNewSticky(true); + stickyOperations.create(); + }, + disabled: !hasGuestLevelPermissions, + }} + /> + )} + ) : ( )} diff --git a/web/core/constants/empty-state.tsx b/web/core/constants/empty-state.tsx index 90bd3481a4e..fd67a303879 100644 --- a/web/core/constants/empty-state.tsx +++ b/web/core/constants/empty-state.tsx @@ -1,5 +1,4 @@ import { EUserPermissions } from "ee/constants/user-permissions"; -import { Plus, Shapes } from "lucide-react"; export interface EmptyStateDetails { key: EmptyStateType; @@ -37,11 +36,6 @@ export enum EmptyStateType { WORKSPACE_CUSTOM_VIEW = "workspace-custom-view", WORKSPACE_NO_PROJECTS = "workspace-no-projects", WORKSPACE_PROJECT_NOT_FOUND = "workspace-project-not-found", - // stickies - STICKIES = "stickies", - STICKIES_SEARCH = "stickies-search", - // home widgets - HOME_WIDGETS = "home-widgets", } const emptyStateDetails: Record = { @@ -174,44 +168,6 @@ const emptyStateDetails: Record = { accessType: "workspace", access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER], }, - // empty filters - [EmptyStateType.STICKIES]: { - key: EmptyStateType.STICKIES, - title: "Stickies are quick notes and to-dos you take down on the fly.", - description: - "Capture your thoughts and ideas effortlessly by creating stickies that you can access anytime and from anywhere.", - path: "/empty-state/stickies/stickies", - primaryButton: { - icon: , - text: "Add sticky", - }, - access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER, EUserPermissions.GUEST], - accessType: "workspace", - }, - [EmptyStateType.STICKIES_SEARCH]: { - key: EmptyStateType.STICKIES_SEARCH, - title: "That doesn't match any of your stickies.", - description: "Try a different term or let us know\nif you are sure your search is right. ", - path: "/empty-state/stickies/stickies-search", - primaryButton: { - icon: , - text: "Add sticky", - }, - access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER, EUserPermissions.GUEST], - accessType: "workspace", - }, - [EmptyStateType.HOME_WIDGETS]: { - key: EmptyStateType.HOME_WIDGETS, - title: "It's Quiet Without Widgets, Turn Them On", - description: "It looks like all your widgets are turned off. Enable them\nnow to enhance your experience!", - path: "/empty-state/dashboard/widgets", - primaryButton: { - icon: , - text: "Manage widgets", - }, - access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER, EUserPermissions.GUEST], - accessType: "workspace", - }, } as const; export const EMPTY_STATE_DETAILS: Record = emptyStateDetails; From e95a40c31f180ec41d84b1e0b7d5aab357e8c6f5 Mon Sep 17 00:00:00 2001 From: Prateek Shourya Date: Fri, 17 Jan 2025 22:08:15 +0530 Subject: [PATCH 24/26] chore: remove all reference to deprecated empty state component and constnats --- .../i18n/src/locales/en/translations.json | 47 ++--- .../i18n/src/locales/es/translations.json | 47 ++--- .../i18n/src/locales/fr/translations.json | 47 ++--- .../i18n/src/locales/ja/translations.json | 47 ++--- .../(projects)/analytics/page.tsx | 14 +- .../components/empty-state/empty-state.tsx | 194 ------------------ web/core/components/empty-state/index.ts | 1 - web/core/components/integration/guide.tsx | 2 - .../empty-states/global-view.tsx | 74 +++++-- .../empty-states/profile-view.tsx | 5 +- .../empty-states/project-epic.tsx | 13 +- .../issues/workspace-draft/root.tsx | 38 +++- .../page-views/workspace-dashboard.tsx | 16 +- web/core/components/project/card-list.tsx | 16 +- .../components/project/multi-select-modal.tsx | 4 +- web/core/constants/empty-state.tsx | 173 ---------------- web/core/constants/profile.ts | 2 +- 17 files changed, 199 insertions(+), 541 deletions(-) delete mode 100644 web/core/components/empty-state/empty-state.tsx delete mode 100644 web/core/constants/empty-state.tsx diff --git a/packages/i18n/src/locales/en/translations.json b/packages/i18n/src/locales/en/translations.json index 5a2baed1d62..d52d125529b 100644 --- a/packages/i18n/src/locales/en/translations.json +++ b/packages/i18n/src/locales/en/translations.json @@ -318,13 +318,15 @@ "workspace_dashboard": { "empty_state": { - "title": "Overview of your projects, activity, and metrics", - "description": "Welcome to Plane, we are excited to have you here. Create your first project and track your issues, and this page will transform into a space that helps you progress. Admins will also see items which help their team progress.", - "primary_button": { - "text": "Build your first project", - "comic": { - "title": "Everything starts with a project in Plane", - "description": "A project could be a product's roadmap, a marketing campaign, or launching a new car." + "general": { + "title": "Overview of your projects, activity, and metrics", + "description": "Welcome to Plane, we are excited to have you here. Create your first project and track your issues, and this page will transform into a space that helps you progress. Admins will also see items which help their team progress.", + "primary_button": { + "text": "Build your first project", + "comic": { + "title": "Everything starts with a project in Plane", + "description": "A project could be a product's roadmap, a marketing campaign, or launching a new car." + } } } } @@ -332,13 +334,15 @@ "workspace_analytics": { "empty_state": { - "title": "Track progress, workloads, and allocations. Spot trends, remove blockers, and move work faster", - "description": "See scope versus demand, estimates, and scope creep. Get performance by team members and teams, and make sure your project runs on time.", - "primary_button": { - "text": "Start your first project", - "comic": { - "title": "Analytics works best with Cycles + Modules", - "description": "First, timebox your issues into Cycles and, if you can, group issues that span more than a cycle into Modules. Check out both on the left nav." + "general": { + "title": "Track progress, workloads, and allocations. Spot trends, remove blockers, and move work faster", + "description": "See scope versus demand, estimates, and scope creep. Get performance by team members and teams, and make sure your project runs on time.", + "primary_button": { + "text": "Start your first project", + "comic": { + "title": "Analytics works best with Cycles + Modules", + "description": "First, timebox your issues into Cycles and, if you can, group issues that span more than a cycle into Modules. Check out both on the left nav." + } } } } @@ -357,17 +361,6 @@ } } }, - "not_found": { - "title": "No such project exists", - "description": "To create issues or manage your work, you need to create a project or be a part of one.", - "primary_button": { - "text": "Create Project", - "comic": { - "title": "Everything starts with a project in Plane", - "description": "A project could be a product's roadmap, a marketing campaign, or launching a new car." - } - } - }, "no_projects": { "title": "No project", "description": "To create issues or manage your work, you need to create a project or be a part of one.", @@ -388,7 +381,7 @@ "workspace_issues": { "empty_state": { - "all_issues": { + "all-issues": { "title": "No issues in the project", "description": "First project done! Now, slice your work into trackable pieces with issues. Let's go!", "primary_button": { @@ -413,7 +406,7 @@ "title": "No issues yet", "description": "Subscribe to issues you are interested in, track all of them here." }, - "custom_view": { + "custom-view": { "title": "No issues yet", "description": "Issues that applies to the filters, track all of them here." } diff --git a/packages/i18n/src/locales/es/translations.json b/packages/i18n/src/locales/es/translations.json index adf76710b81..f516cf152d6 100644 --- a/packages/i18n/src/locales/es/translations.json +++ b/packages/i18n/src/locales/es/translations.json @@ -317,13 +317,15 @@ "workspace_dashboard": { "empty_state": { - "title": "Resumen de tus proyectos, actividad y métricas", - "description": "Bienvenido a Plane, estamos emocionados de tenerte aquí. Crea tu primer proyecto y rastrea tus problemas, y esta página se transformará en un espacio que te ayudará a avanzar. Los administradores también verán elementos que ayudan a su equipo a progresar.", - "primary_button": { - "text": "Construye tu primer proyecto", - "comic": { - "title": "Todo comienza con un proyecto en Plane", - "description": "Un proyecto podría ser la hoja de ruta de un producto, una campaña de marketing o el lanzamiento de un nuevo coche." + "general": { + "title": "Resumen de tus proyectos, actividad y métricas", + "description": "Bienvenido a Plane, estamos emocionados de tenerte aquí. Crea tu primer proyecto y rastrea tus problemas, y esta página se transformará en un espacio que te ayudará a avanzar. Los administradores también verán elementos que ayudan a su equipo a progresar.", + "primary_button": { + "text": "Construye tu primer proyecto", + "comic": { + "title": "Todo comienza con un proyecto en Plane", + "description": "Un proyecto podría ser la hoja de ruta de un producto, una campaña de marketing o el lanzamiento de un nuevo coche." + } } } } @@ -331,13 +333,15 @@ "workspace_analytics": { "empty_state": { - "title": "Rastrea el progreso, cargas de trabajo y asignaciones. Detecta tendencias, elimina bloqueos y acelera el trabajo", - "description": "Consulta el alcance frente a la demanda, estimaciones y desbordamiento del alcance. Obtén el rendimiento por miembros del equipo y equipos, y asegúrate de que tu proyecto termine a tiempo.", - "primary_button": { - "text": "Comienza tu primer proyecto", - "comic": { - "title": "La analítica funciona mejor con Ciclos + Módulos", - "description": "Primero, organiza tus problemas en ciclos y, si puedes, agrupa problemas que abarquen más de un ciclo en módulos. Consulta ambos en el menú de navegación a la izquierda." + "general": { + "title": "Rastrea el progreso, cargas de trabajo y asignaciones. Detecta tendencias, elimina bloqueos y acelera el trabajo", + "description": "Consulta el alcance frente a la demanda, estimaciones y desbordamiento del alcance. Obtén el rendimiento por miembros del equipo y equipos, y asegúrate de que tu proyecto termine a tiempo.", + "primary_button": { + "text": "Comienza tu primer proyecto", + "comic": { + "title": "La analítica funciona mejor con Ciclos + Módulos", + "description": "Primero, organiza tus problemas en ciclos y, si puedes, agrupa problemas que abarquen más de un ciclo en módulos. Consulta ambos en el menú de navegación a la izquierda." + } } } } @@ -356,17 +360,6 @@ } } }, - "not_found": { - "title": "No existe tal proyecto", - "description": "Para crear problemas o gestionar tu trabajo, necesitas crear un proyecto o ser parte de uno.", - "primary_button": { - "text": "Crear proyecto", - "comic": { - "title": "Todo comienza con un proyecto en Plane", - "description": "Un proyecto podría ser la hoja de ruta de un producto, una campaña de marketing o el lanzamiento de un nuevo coche." - } - } - }, "no_projects": { "title": "Sin proyectos", "description": "Para crear problemas o gestionar tu trabajo, necesitas crear un proyecto o ser parte de uno.", @@ -387,7 +380,7 @@ "workspace_issues": { "empty_state": { - "all_issues": { + "all-issues": { "title": "No hay problemas en el proyecto", "description": "¡Primer proyecto terminado! Ahora, divide tu trabajo en piezas rastreables con problemas. ¡Vamos!", "primary_button": { @@ -412,7 +405,7 @@ "title": "Aún no hay problemas", "description": "Suscríbete a los problemas que te interesan y rastrea todos ellos aquí." }, - "custom_view": { + "custom-view": { "title": "Aún no hay problemas", "description": "Los problemas que se aplican a los filtros se rastrean aquí." } diff --git a/packages/i18n/src/locales/fr/translations.json b/packages/i18n/src/locales/fr/translations.json index 3588ca6ab9f..4d5d7512efd 100644 --- a/packages/i18n/src/locales/fr/translations.json +++ b/packages/i18n/src/locales/fr/translations.json @@ -318,13 +318,15 @@ "workspace_dashboard": { "empty_state": { - "title": "Vue d'ensemble de vos projets, activités et métriques", - "description": "Bienvenue sur Plane, nous sommes ravis de vous accueillir. Créez votre premier projet et suivez vos tâches, et cette page se transformera en un espace qui vous aidera à progresser. Les administrateurs verront également des éléments pour aider leur équipe à progresser.", - "primary_button": { - "text": "Créez votre premier projet", - "comic": { - "title": "Tout commence par un projet sur Plane", - "description": "Un projet peut être une feuille de route produit, une campagne marketing ou le lancement d'une nouvelle voiture." + "general": { + "title": "Vue d'ensemble de vos projets, activités et métriques", + "description": "Bienvenue sur Plane, nous sommes ravis de vous accueillir. Créez votre premier projet et suivez vos tâches, et cette page se transformera en un espace qui vous aidera à progresser. Les administrateurs verront également des éléments pour aider leur équipe à progresser.", + "primary_button": { + "text": "Créez votre premier projet", + "comic": { + "title": "Tout commence par un projet sur Plane", + "description": "Un projet peut être une feuille de route produit, une campagne marketing ou le lancement d'une nouvelle voiture." + } } } } @@ -332,13 +334,15 @@ "workspace_analytics": { "empty_state": { - "title": "Suivez les progrès, les charges de travail et les allocations. Repérez les tendances, éliminez les obstacles et accélérez le travail", - "description": "Visualisez l'étendue par rapport à la demande, les estimations et l'expansion des objectifs. Obtenez des performances par membre et par équipe, et assurez-vous que votre projet respecte les délais.", - "primary_button": { - "text": "Commencez votre premier projet", - "comic": { - "title": "Les analyses fonctionnent mieux avec Cycles + Modules", - "description": "D'abord, cadrez vos tâches dans des Cycles et, si possible, regroupez les tâches qui s'étendent sur plus d'un cycle dans des Modules. Consultez-les dans la navigation à gauche." + "general": { + "title": "Suivez les progrès, les charges de travail et les allocations. Repérez les tendances, éliminez les obstacles et accélérez le travail", + "description": "Visualisez l'étendue par rapport à la demande, les estimations et l'expansion des objectifs. Obtenez des performances par membre et par équipe, et assurez-vous que votre projet respecte les délais.", + "primary_button": { + "text": "Commencez votre premier projet", + "comic": { + "title": "Les analyses fonctionnent mieux avec Cycles + Modules", + "description": "D'abord, cadrez vos tâches dans des Cycles et, si possible, regroupez les tâches qui s'étendent sur plus d'un cycle dans des Modules. Consultez-les dans la navigation à gauche." + } } } } @@ -357,17 +361,6 @@ } } }, - "not_found": { - "title": "Aucun projet correspondant", - "description": "Pour créer des tâches ou gérer votre travail, vous devez créer un projet ou en faire partie.", - "primary_button": { - "text": "Créer un projet", - "comic": { - "title": "Tout commence par un projet sur Plane", - "description": "Un projet peut être une feuille de route produit, une campagne marketing ou le lancement d'une nouvelle voiture." - } - } - }, "no_projects": { "title": "Aucun projet", "description": "Pour créer des tâches ou gérer votre travail, vous devez créer un projet ou en faire partie.", @@ -388,7 +381,7 @@ "workspace_issues": { "empty_state": { - "all_issues": { + "all-issues": { "title": "Aucune tâche dans le projet", "description": "Premier projet terminé ! Maintenant, divisez votre travail en morceaux traçables avec des tâches. Allons-y !", "primary_button": { @@ -413,7 +406,7 @@ "title": "Aucune tâche suivie", "description": "Abonnez-vous aux tâches qui vous intéressent, suivez-les toutes ici." }, - "custom_view": { + "custom-view": { "title": "Aucune tâche trouvée", "description": "Les tâches correspondant aux filtres sont affichées ici. Suivez-les toutes ici." } diff --git a/packages/i18n/src/locales/ja/translations.json b/packages/i18n/src/locales/ja/translations.json index 6692dcfe8ae..d7c8e76322d 100644 --- a/packages/i18n/src/locales/ja/translations.json +++ b/packages/i18n/src/locales/ja/translations.json @@ -318,13 +318,15 @@ "workspace_dashboard": { "empty_state": { - "title": "プロジェクト、アクティビティ、指標の概要", - "description": "Planeへようこそ!私たちはあなたを迎えることができて嬉しいです。最初のプロジェクトを作成してタスクを追跡し、このページが進捗を助けるスペースに変わります。管理者は、チームを前進させるための要素も見ることができます。", - "primary_button": { - "text": "最初のプロジェクトを作成", - "comic": { - "title": "すべてはPlaneでのプロジェクトから始まります", - "description": "プロジェクトは製品ロードマップ、マーケティングキャンペーン、新車の発売など、さまざまなものになります。" + "general": { + "title": "プロジェクト、アクティビティ、指標の概要", + "description": "Planeへようこそ!私たちはあなたを迎えることができて嬉しいです。最初のプロジェクトを作成してタスクを追跡し、このページが進捗を助けるスペースに変わります。管理者は、チームを前進させるための要素も見ることができます。", + "primary_button": { + "text": "最初のプロジェクトを作成", + "comic": { + "title": "すべてはPlaneでのプロジェクトから始まります", + "description": "プロジェクトは製品ロードマップ、マーケティングキャンペーン、新車の発売など、さまざまなものになります。" + } } } } @@ -332,13 +334,15 @@ "workspace_analytics": { "empty_state": { - "title": "進捗、作業負荷、割り当てを追跡します。傾向を見つけ、障害を取り除き、作業を加速させます", - "description": "需要に対するスコープ、見積もり、目標の進展を視覚化します。メンバーやチームごとのパフォーマンスを確認し、プロジェクトが期限内に進むことを確認します。", - "primary_button": { - "text": "最初のプロジェクトを開始", - "comic": { - "title": "分析はサイクル+モジュールでより効果的に機能します", - "description": "まず、タスクをサイクルにフレーム化し、可能であれば複数のサイクルにまたがるタスクをモジュールにグループ化します。左側のナビゲーションで確認してください。" + "general": { + "title": "進捗、作業負荷、割り当てを追跡します。傾向を見つけ、障害を取り除き、作業を加速させます", + "description": "需要に対するスコープ、見積もり、目標の進展を視覚化します。メンバーやチームごとのパフォーマンスを確認し、プロジェクトが期限内に進むことを確認します。", + "primary_button": { + "text": "最初のプロジェクトを開始", + "comic": { + "title": "分析はサイクル+モジュールでより効果的に機能します", + "description": "まず、タスクをサイクルにフレーム化し、可能であれば複数のサイクルにまたがるタスクをモジュールにグループ化します。左側のナビゲーションで確認してください。" + } } } } @@ -357,17 +361,6 @@ } } }, - "not_found": { - "title": "一致するプロジェクトがありません", - "description": "タスクを作成したり作業を管理するには、プロジェクトを作成するか、その一部である必要があります。", - "primary_button": { - "text": "プロジェクトを作成", - "comic": { - "title": "すべてはPlaneでのプロジェクトから始まります", - "description": "プロジェクトは製品ロードマップ、マーケティングキャンペーン、新車の発売など、さまざまなものになります。" - } - } - }, "no_projects": { "title": "プロジェクトがありません", "description": "タスクを作成したり作業を管理するには、プロジェクトを作成するか、その一部である必要があります。", @@ -388,7 +381,7 @@ "workspace_issues": { "empty_state": { - "all_issues": { + "all-issues": { "title": "プロジェクトにタスクがありません", "description": "最初のプロジェクトが完了しました!次に、追跡可能なチャンクに分割してタスクを作成します。始めましょう!", "primary_button": { @@ -413,7 +406,7 @@ "title": "フォローしているタスクがありません", "description": "興味のあるタスクをフォローして、すべてここで追跡してください。" }, - "custom_view": { + "custom-view": { "title": "タスクが見つかりません", "description": "フィルタに一致するタスクがここに表示されます。すべてここで追跡してください。" } diff --git a/web/app/[workspaceSlug]/(projects)/analytics/page.tsx b/web/app/[workspaceSlug]/(projects)/analytics/page.tsx index 36b21e9fcc0..f6094276328 100644 --- a/web/app/[workspaceSlug]/(projects)/analytics/page.tsx +++ b/web/app/[workspaceSlug]/(projects)/analytics/page.tsx @@ -6,6 +6,7 @@ import { useSearchParams } from "next/navigation"; import { Tab } from "@headlessui/react"; // plane package imports import { ANALYTICS_TABS, EUserPermissionsLevel } from "@plane/constants"; +import { useTranslation } from "@plane/i18n"; import { Header, EHeaderVariant } from "@plane/ui"; // components import { CustomAnalytics, ScopeAndDemand } from "@/components/analytics"; @@ -20,13 +21,14 @@ import { EUserPermissions } from "@/plane-web/constants"; const AnalyticsPage = observer(() => { const searchParams = useSearchParams(); const analytics_tab = searchParams.get("analytics_tab"); + // plane imports + const { t } = useTranslation(); // store hooks const { toggleCreateProjectModal } = useCommandPalette(); const { setTrackElement } = useEventTracker(); const { workspaceProjectIds, loader } = useProject(); const { currentWorkspace } = useWorkspace(); const { allowPermissions } = useUserPermissions(); - // helper hooks const resolvedPath = useResolvedAssetPath({ basePath: "/empty-state/onboarding/analytics" }); // derived values @@ -79,14 +81,14 @@ const AnalyticsPage = observer(() => {
) : ( { setTrackElement("Analytics empty state"); toggleCreateProjectModal(true); diff --git a/web/core/components/empty-state/empty-state.tsx b/web/core/components/empty-state/empty-state.tsx deleted file mode 100644 index faab4ebc290..00000000000 --- a/web/core/components/empty-state/empty-state.tsx +++ /dev/null @@ -1,194 +0,0 @@ -"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 -// components -import { Button, TButtonSizes, TButtonVariant } from "@plane/ui"; -// constant -import { EMPTY_STATE_DETAILS, EmptyStateType } from "@/constants/empty-state"; -// helpers -import { cn } from "@/helpers/common.helper"; -import { useUserPermissions } from "@/hooks/store"; -import { EUserPermissionsLevel } from "@/plane-web/constants/user-permissions"; -import { ComicBoxButton } from "./comic-box-button"; - -export type EmptyStateProps = { - size?: TButtonSizes; - type: EmptyStateType; - layout?: "screen-detailed" | "screen-simple"; - additionalPath?: string; - primaryButtonConfig?: { - size?: TButtonSizes; - variant?: TButtonVariant; - }; - primaryButtonOnClick?: () => void; - primaryButtonLink?: string; - secondaryButtonOnClick?: () => void; -}; - -export const EmptyState: React.FC = observer((props) => { - const { - size = "lg", - type, - layout = "screen-detailed", - additionalPath = "", - primaryButtonConfig = { - size: "lg", - variant: "primary", - }, - primaryButtonOnClick, - primaryButtonLink, - secondaryButtonOnClick, - } = props; - // store - const { allowPermissions } = useUserPermissions(); - // theme - const { resolvedTheme } = useTheme(); - - // if empty state type is not found - if (!EMPTY_STATE_DETAILS[type]) return null; - - // current empty state details - const { key, title, description, path, primaryButton, secondaryButton, accessType, access } = - EMPTY_STATE_DETAILS[type]; - // resolved empty state path - const resolvedEmptyStatePath = `${additionalPath && additionalPath !== "" ? `${path}${additionalPath}` : path}-${ - resolvedTheme === "light" ? "light" : "dark" - }.webp`; - // permission - const isEditingAllowed = - access && - accessType && - allowPermissions( - access, - accessType === "workspace" ? EUserPermissionsLevel.WORKSPACE : EUserPermissionsLevel.PROJECT - ); - const anyButton = primaryButton || secondaryButton; - - // primary button - const renderPrimaryButton = () => { - if (!primaryButton) return null; - - const commonProps = { - size: primaryButtonConfig.size, - variant: primaryButtonConfig.variant, - prependIcon: primaryButton.icon, - onClick: primaryButtonOnClick ? primaryButtonOnClick : undefined, - disabled: !isEditingAllowed, - }; - - if (primaryButton.comicBox) { - return ( - - ); - } else if (primaryButtonLink) { - return ( - - - - ); - } else { - return ; - } - }; - // secondary button - const renderSecondaryButton = () => { - if (!secondaryButton) return null; - - return ( - - ); - }; - - return ( - <> - {layout === "screen-detailed" && ( -
-
-
- {description ? ( - <> -

{title}

-

{description}

- - ) : ( -

{title}

- )} -
- - {path && ( - {key - )} - - {anyButton && ( -
- {renderPrimaryButton()} - {renderSecondaryButton()} -
- )} -
-
- )} - {layout === "screen-simple" && ( -
-
- {key -
- {description ? ( - <> -

{title}

-

{description}

- - ) : ( -

{title}

- )} - {anyButton && ( -
- {renderPrimaryButton()} - {renderSecondaryButton()} -
- )} -
- )} - - ); -}); diff --git a/web/core/components/empty-state/index.ts b/web/core/components/empty-state/index.ts index afa892f2712..3ba1c3ad302 100644 --- a/web/core/components/empty-state/index.ts +++ b/web/core/components/empty-state/index.ts @@ -1,4 +1,3 @@ -export * from "./empty-state"; export * from "./helper"; export * from "./comic-box-button"; export * from "./detailed-empty-state-root"; diff --git a/web/core/components/integration/guide.tsx b/web/core/components/integration/guide.tsx index 9023233c4c7..e40085fce14 100644 --- a/web/core/components/integration/guide.tsx +++ b/web/core/components/integration/guide.tsx @@ -13,11 +13,9 @@ import { IImporterService } from "@plane/types"; // ui import { Button } from "@plane/ui"; // components -import { EmptyState } from "@/components/empty-state"; import { DeleteImportModal, GithubImporterRoot, JiraImporterRoot, SingleImport } from "@/components/integration"; import { ImportExportSettingsLoader } from "@/components/ui"; // constants -import { EmptyStateType } from "@/constants/empty-state"; import { IMPORTER_SERVICES_LIST } from "@/constants/fetch-keys"; import { IMPORTERS_LIST } from "@/constants/workspace"; // hooks diff --git a/web/core/components/issues/issue-layouts/empty-states/global-view.tsx b/web/core/components/issues/issue-layouts/empty-states/global-view.tsx index 8850fe22677..6eb8543d9e7 100644 --- a/web/core/components/issues/issue-layouts/empty-states/global-view.tsx +++ b/web/core/components/issues/issue-layouts/empty-states/global-view.tsx @@ -1,43 +1,77 @@ import { observer } from "mobx-react"; import { useParams } from "next/navigation"; +// plane imports +import { EIssuesStoreType, EUserPermissionsLevel, EUserWorkspaceRoles } from "@plane/constants"; +import { useTranslation } from "@plane/i18n"; // components -import { EIssuesStoreType } from "@plane/constants"; -import { EmptyState } from "@/components/empty-state"; -// constants -import { EMPTY_STATE_DETAILS, EmptyStateType } from "@/constants/empty-state"; +import { ComicBoxButton, DetailedEmptyState } from "@/components/empty-state"; // hooks -import { useCommandPalette, useEventTracker, useProject } from "@/hooks/store"; -// assets +import { useCommandPalette, useEventTracker, useProject, useUserPermissions } from "@/hooks/store"; +import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; export const GlobalViewEmptyState: React.FC = observer(() => { const { globalViewId } = useParams(); + // plane imports + const { t } = useTranslation(); // store hooks const { workspaceProjectIds } = useProject(); const { toggleCreateIssueModal, toggleCreateProjectModal } = useCommandPalette(); const { setTrackElement } = useEventTracker(); - + const { allowPermissions } = useUserPermissions(); + // derived values + const hasMemberLevelPermission = allowPermissions( + [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER], + EUserPermissionsLevel.WORKSPACE + ); const isDefaultView = ["all-issues", "assigned", "created", "subscribed"].includes(globalViewId?.toString() ?? ""); const currentView = isDefaultView && globalViewId ? globalViewId : "custom-view"; + const resolvedCurrentView = currentView?.toString(); + const noProjectResolvedPath = useResolvedAssetPath({ basePath: "/empty-state/onboarding/projects" }); + const globalViewsResolvedPath = useResolvedAssetPath({ + basePath: "/empty-state/all-issues/", + additionalPath: resolvedCurrentView, + }); - const emptyStateType = - (workspaceProjectIds ?? []).length > 0 ? `workspace-${currentView}` : EmptyStateType.WORKSPACE_NO_PROJECTS; + if (workspaceProjectIds?.length === 0) { + return ( + { + setTrackElement("All issues empty state"); + toggleCreateProjectModal(true); + }} + disabled={!hasMemberLevelPermission} + /> + } + /> + ); + } return ( - 0 - ? currentView !== "custom-view" && currentView !== "subscribed" - ? () => { + title={t(`workspace_issues.empty_state.${resolvedCurrentView}.title`)} + description={t(`workspace_issues.empty_state.${resolvedCurrentView}.description`)} + assetPath={globalViewsResolvedPath} + primaryButton={ + ["subscribed", "custom-view"].includes(resolvedCurrentView) === false + ? { + text: t(`workspace_issues.empty_state.${resolvedCurrentView}.primary_button.text`), + onClick: () => { setTrackElement("All issues empty state"); toggleCreateIssueModal(true, EIssuesStoreType.PROJECT); - } - : undefined - : () => { - setTrackElement("All issues empty state"); - toggleCreateProjectModal(true); + }, + disabled: !hasMemberLevelPermission, } + : undefined } /> ); diff --git a/web/core/components/issues/issue-layouts/empty-states/profile-view.tsx b/web/core/components/issues/issue-layouts/empty-states/profile-view.tsx index ef13c3d3438..d67aad491f9 100644 --- a/web/core/components/issues/issue-layouts/empty-states/profile-view.tsx +++ b/web/core/components/issues/issue-layouts/empty-states/profile-view.tsx @@ -13,7 +13,10 @@ export const ProfileViewEmptyState: React.FC = observer(() => { // store hooks const { profileViewId } = useParams(); // derived values - const resolvedPath = useResolvedAssetPath({ basePath: `/empty-state/profile/${profileViewId?.toString()}` }); + const resolvedPath = useResolvedAssetPath({ + basePath: "/empty-state/profile/", + additionalPath: profileViewId?.toString(), + }); if (!profileViewId) return null; diff --git a/web/core/components/issues/issue-layouts/empty-states/project-epic.tsx b/web/core/components/issues/issue-layouts/empty-states/project-epic.tsx index 213e5ac405c..e8bf3a9d565 100644 --- a/web/core/components/issues/issue-layouts/empty-states/project-epic.tsx +++ b/web/core/components/issues/issue-layouts/empty-states/project-epic.tsx @@ -1,12 +1 @@ -// types -// components -import { EmptyState } from "@/components/empty-state"; -// constants -import { EmptyStateType } from "@/constants/empty-state"; -// hooks - -export const ProjectEpicsEmptyState: React.FC = () => ( -
- {}} /> -
-); +export const ProjectEpicsEmptyState: React.FC = () => <>; diff --git a/web/core/components/issues/workspace-draft/root.tsx b/web/core/components/issues/workspace-draft/root.tsx index 633fdead729..30f99bde671 100644 --- a/web/core/components/issues/workspace-draft/root.tsx +++ b/web/core/components/issues/workspace-draft/root.tsx @@ -3,15 +3,18 @@ import { FC, Fragment } from "react"; import { observer } from "mobx-react"; import useSWR from "swr"; +// plane imports +import { EUserPermissionsLevel, EUserWorkspaceRoles } from "@plane/constants/src/user"; +import { useTranslation } from "@plane/i18n"; // components -import { EmptyState } from "@/components/empty-state"; +import { ComicBoxButton, DetailedEmptyState } from "@/components/empty-state"; // constants -import { EmptyStateType } from "@/constants/empty-state"; import { EDraftIssuePaginationType } from "@/constants/workspace-drafts"; // helpers import { cn } from "@/helpers/common.helper"; // hooks -import { useCommandPalette, useProject, useWorkspaceDraftIssues } from "@/hooks/store"; +import { useCommandPalette, useProject, useUserPermissions, useWorkspaceDraftIssues } from "@/hooks/store"; +import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; import { useWorkspaceIssueProperties } from "@/hooks/use-workspace-issue-properties"; // components import { DraftIssueBlock } from "./draft-issue-block"; @@ -24,10 +27,19 @@ type TWorkspaceDraftIssuesRoot = { export const WorkspaceDraftIssuesRoot: FC = observer((props) => { const { workspaceSlug } = props; + // plane hooks + const { t } = useTranslation(); // hooks const { loader, paginationInfo, fetchIssues, issueIds } = useWorkspaceDraftIssues(); const { workspaceProjectIds } = useProject(); const { toggleCreateProjectModal } = useCommandPalette(); + const { allowPermissions } = useUserPermissions(); + // derived values + const hasMemberLevelPermission = allowPermissions( + [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER], + EUserPermissionsLevel.WORKSPACE + ); + const noProjectResolvedPath = useResolvedAssetPath({ basePath: "/empty-state/onboarding/projects" }); //swr hook for fetching issue properties useWorkspaceIssueProperties(workspaceSlug); @@ -51,12 +63,22 @@ export const WorkspaceDraftIssuesRoot: FC = observer( if (workspaceProjectIds?.length === 0) return ( - { - toggleCreateProjectModal(true); - }} + title={t("workspace_projects.empty_state.no_projects.title")} + description={t("workspace_projects.empty_state.no_projects.description")} + assetPath={noProjectResolvedPath} + customPrimaryButton={ + { + toggleCreateProjectModal(true); + }} + disabled={!hasMemberLevelPermission} + /> + } /> ); diff --git a/web/core/components/page-views/workspace-dashboard.tsx b/web/core/components/page-views/workspace-dashboard.tsx index a3f6d3a28d7..b20ed914b5a 100644 --- a/web/core/components/page-views/workspace-dashboard.tsx +++ b/web/core/components/page-views/workspace-dashboard.tsx @@ -1,9 +1,11 @@ import { useEffect } from "react"; import { observer } from "mobx-react"; import { useParams } from "next/navigation"; +// plane imports import { EUserPermissionsLevel } from "@plane/constants"; -// components +import { useTranslation } from "@plane/i18n"; import { ContentWrapper } from "@plane/ui"; +// components import { DashboardWidgets } from "@/components/dashboard"; import { ComicBoxButton, DetailedEmptyState } from "@/components/empty-state"; import { IssuePeekOverview } from "@/components/issues"; @@ -28,6 +30,8 @@ import useSize from "@/hooks/use-window-size"; import { EUserPermissions } from "@/plane-web/constants"; export const WorkspaceDashboardView = observer(() => { + // plane hooks + const { t } = useTranslation(); // store hooks const { // captureEvent, @@ -96,14 +100,14 @@ export const WorkspaceDashboardView = observer(() => { ) : ( { setTrackElement("Dashboard empty state"); toggleCreateProjectModal(true); diff --git a/web/core/components/project/card-list.tsx b/web/core/components/project/card-list.tsx index 60155c82865..3d0fa1fae74 100644 --- a/web/core/components/project/card-list.tsx +++ b/web/core/components/project/card-list.tsx @@ -1,8 +1,10 @@ import { observer } from "mobx-react"; import Image from "next/image"; +// plane imports import { EUserPermissionsLevel } from "@plane/constants"; -// components +import { useTranslation } from "@plane/i18n"; import { ContentWrapper } from "@plane/ui"; +// components import { ComicBoxButton, DetailedEmptyState } from "@/components/empty-state"; import { ProjectCard } from "@/components/project"; import { ProjectsLoader } from "@/components/ui"; @@ -22,6 +24,8 @@ type TProjectCardListProps = { export const ProjectCardList = observer((props: TProjectCardListProps) => { const { totalProjectIds: totalProjectIdsProps, filteredProjectIds: filteredProjectIdsProps } = props; + // plane hooks + const { t } = useTranslation(); // store hooks const { toggleCreateProjectModal } = useCommandPalette(); const { setTrackElement } = useEventTracker(); @@ -52,14 +56,14 @@ export const ProjectCardList = observer((props: TProjectCardListProps) => { if (workspaceProjectIds?.length === 0 && !currentWorkspaceDisplayFilters?.archived_projects) return ( { setTrackElement("Project empty state"); toggleCreateProjectModal(true); diff --git a/web/core/components/project/multi-select-modal.tsx b/web/core/components/project/multi-select-modal.tsx index 30dd3be58be..013cd1248bf 100644 --- a/web/core/components/project/multi-select-modal.tsx +++ b/web/core/components/project/multi-select-modal.tsx @@ -8,9 +8,7 @@ import { useTranslation } from "@plane/i18n"; import { Button, Checkbox, EModalPosition, EModalWidth, ModalCore } from "@plane/ui"; // components import { Logo } from "@/components/common"; -import { EmptyState, SimpleEmptyState } from "@/components/empty-state"; -// constants -import { EmptyStateType } from "@/constants/empty-state"; +import { SimpleEmptyState } from "@/components/empty-state"; // helpers import { cn } from "@/helpers/common.helper"; // hooks diff --git a/web/core/constants/empty-state.tsx b/web/core/constants/empty-state.tsx deleted file mode 100644 index fd67a303879..00000000000 --- a/web/core/constants/empty-state.tsx +++ /dev/null @@ -1,173 +0,0 @@ -import { EUserPermissions } from "ee/constants/user-permissions"; - -export interface EmptyStateDetails { - key: EmptyStateType; - title?: string; - description?: string; - path?: string; - primaryButton?: { - icon?: React.ReactNode; - text: string; - comicBox?: { - title?: string; - description?: string; - }; - }; - secondaryButton?: { - icon?: React.ReactNode; - text: string; - comicBox?: { - title?: string; - description?: string; - }; - }; - accessType?: "workspace" | "project"; - access?: any; -} - -export enum EmptyStateType { - WORKSPACE_DASHBOARD = "workspace-dashboard", - WORKSPACE_ANALYTICS = "workspace-analytics", - WORKSPACE_PROJECTS = "workspace-projects", - WORKSPACE_ALL_ISSUES = "workspace-all-issues", - WORKSPACE_ASSIGNED = "workspace-assigned", - WORKSPACE_CREATED = "workspace-created", - WORKSPACE_SUBSCRIBED = "workspace-subscribed", - WORKSPACE_CUSTOM_VIEW = "workspace-custom-view", - WORKSPACE_NO_PROJECTS = "workspace-no-projects", - WORKSPACE_PROJECT_NOT_FOUND = "workspace-project-not-found", -} - -const emptyStateDetails: Record = { - // workspace - [EmptyStateType.WORKSPACE_DASHBOARD]: { - key: EmptyStateType.WORKSPACE_DASHBOARD, - title: "Overview of your projects, activity, and metrics", - description: - " Welcome to Plane, we are excited to have you here. Create your first project and track your issues, and this page will transform into a space that helps you progress. Admins will also see items which help their team progress.", - path: "/empty-state/onboarding/dashboard", - // path: "/empty-state/onboarding/", - primaryButton: { - text: "Build your first project", - comicBox: { - title: "Everything starts with a project in Plane", - description: "A project could be a product’s roadmap, a marketing campaign, or launching a new car.", - }, - }, - - accessType: "workspace", - access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER], - }, - [EmptyStateType.WORKSPACE_ANALYTICS]: { - key: EmptyStateType.WORKSPACE_ANALYTICS, - title: "Track progress, workloads, and allocations. Spot trends, remove blockers, and move work faster", - description: - "See scope versus demand, estimates, and scope creep. Get performance by team members and teams, and make sure your project runs on time.", - path: "/empty-state/onboarding/analytics", - primaryButton: { - text: "Start your first project", - comicBox: { - title: "Analytics works best with Cycles + Modules", - description: - "First, timebox your issues into Cycles and, if you can, group issues that span more than a cycle into Modules. Check out both on the left nav.", - }, - }, - accessType: "workspace", - access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER], - }, - [EmptyStateType.WORKSPACE_PROJECTS]: { - key: EmptyStateType.WORKSPACE_PROJECTS, - title: "No active projects", - description: - "Think of each project as the parent for goal-oriented work. Projects are where Jobs, Cycles, and Modules live and, along with your colleagues, help you achieve that goal. Create a new project or filter for archived projects.", - path: "/empty-state/onboarding/projects", - primaryButton: { - text: "Start your first project", - comicBox: { - title: "Everything starts with a project in Plane", - description: "A project could be a product’s roadmap, a marketing campaign, or launching a new car.", - }, - }, - accessType: "workspace", - access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER], - }, - // all-issues - [EmptyStateType.WORKSPACE_ALL_ISSUES]: { - key: EmptyStateType.WORKSPACE_ALL_ISSUES, - title: "No issues in the project", - description: "First project done! Now, slice your work into trackable pieces with issues. Let's go!", - path: "/empty-state/all-issues/all-issues", - primaryButton: { - text: "Create new issue", - }, - accessType: "workspace", - access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER], - }, - [EmptyStateType.WORKSPACE_ASSIGNED]: { - key: EmptyStateType.WORKSPACE_ASSIGNED, - title: "No issues yet", - description: "Issues assigned to you can be tracked from here.", - path: "/empty-state/all-issues/assigned", - primaryButton: { - text: "Create new issue", - }, - accessType: "workspace", - access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER], - }, - [EmptyStateType.WORKSPACE_CREATED]: { - key: EmptyStateType.WORKSPACE_CREATED, - title: "No issues yet", - description: "All issues created by you come here, track them here directly.", - path: "/empty-state/all-issues/created", - primaryButton: { - text: "Create new issue", - }, - accessType: "workspace", - access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER], - }, - [EmptyStateType.WORKSPACE_SUBSCRIBED]: { - key: EmptyStateType.WORKSPACE_SUBSCRIBED, - title: "No issues yet", - description: "Subscribe to issues you are interested in, track all of them here.", - path: "/empty-state/all-issues/subscribed", - }, - [EmptyStateType.WORKSPACE_CUSTOM_VIEW]: { - key: EmptyStateType.WORKSPACE_CUSTOM_VIEW, - title: "No issues yet", - description: "Issues that applies to the filters, track all of them here.", - path: "/empty-state/all-issues/custom-view", - }, - [EmptyStateType.WORKSPACE_PROJECT_NOT_FOUND]: { - key: EmptyStateType.WORKSPACE_PROJECT_NOT_FOUND, - title: "No such project exists", - description: "To create issues or manage your work, you need to create a project or be a part of one.", - path: "/empty-state/onboarding/projects", - primaryButton: { - text: "Create Project", - comicBox: { - title: "Everything starts with a project in Plane", - description: "A project could be a product’s roadmap, a marketing campaign, or launching a new car.", - }, - }, - - accessType: "workspace", - access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER], - }, - [EmptyStateType.WORKSPACE_NO_PROJECTS]: { - key: EmptyStateType.WORKSPACE_NO_PROJECTS, - title: "No project", - description: "To create issues or manage your work, you need to create a project or be a part of one.", - path: "/empty-state/onboarding/projects", - primaryButton: { - text: "Start your first project", - comicBox: { - title: "Everything starts with a project in Plane", - description: "A project could be a product’s roadmap, a marketing campaign, or launching a new car.", - }, - }, - accessType: "workspace", - access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER], - }, -} as const; - -export const EMPTY_STATE_DETAILS: Record = emptyStateDetails; diff --git a/web/core/constants/profile.ts b/web/core/constants/profile.ts index d6ccf658324..14fc08638de 100644 --- a/web/core/constants/profile.ts +++ b/web/core/constants/profile.ts @@ -10,7 +10,7 @@ export const PROFILE_ACTION_LINKS: { Icon: React.FC; }[] = [ { - key: "profile", + key: "profile.label", label: "Profile", href: `/profile`, highlight: (pathname: string) => pathname === "/profile/", From 8efc19dda01043aa568b86b3f3c756e02051f949 Mon Sep 17 00:00:00 2001 From: Prateek Shourya Date: Tue, 21 Jan 2025 12:56:00 +0530 Subject: [PATCH 25/26] chore: add support to ignore theme in resolved asset path hook --- web/core/hooks/use-resolved-asset-path.tsx | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/web/core/hooks/use-resolved-asset-path.tsx b/web/core/hooks/use-resolved-asset-path.tsx index f5543d2006e..4233dc6469c 100644 --- a/web/core/hooks/use-resolved-asset-path.tsx +++ b/web/core/hooks/use-resolved-asset-path.tsx @@ -4,14 +4,23 @@ type AssetPathConfig = { basePath: string; additionalPath?: string; extension?: string; + includeThemeInPath?: boolean; }; -export const useResolvedAssetPath = ({ basePath, additionalPath = "", extension = "webp" }: AssetPathConfig) => { +export const useResolvedAssetPath = ({ + basePath, + additionalPath = "", + extension = "webp", + includeThemeInPath = true, +}: AssetPathConfig) => { // hooks const { resolvedTheme } = useTheme(); - // resolved theme const theme = resolvedTheme === "light" ? "light" : "dark"; + if (!includeThemeInPath) { + return `${additionalPath && additionalPath !== "" ? `${basePath}${additionalPath}` : basePath}.${extension}`; + } + return `${additionalPath && additionalPath !== "" ? `${basePath}${additionalPath}` : basePath}-${theme}.${extension}`; }; From 67b639696d3d5068e380168c6c235fb8c8ab46c6 Mon Sep 17 00:00:00 2001 From: Prateek Shourya Date: Tue, 21 Jan 2025 19:45:48 +0530 Subject: [PATCH 26/26] chore: minor updates --- .../components/command-palette/command-modal.tsx | 2 +- web/core/layouts/auth-layout/project-wrapper.tsx | 15 +++++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/web/core/components/command-palette/command-modal.tsx b/web/core/components/command-palette/command-modal.tsx index c6e8cb90951..8422288cf51 100644 --- a/web/core/components/command-palette/command-modal.tsx +++ b/web/core/components/command-palette/command-modal.tsx @@ -265,7 +265,7 @@ export const CommandModal: React.FC = observer(() => { {!isLoading && resultsCount === 0 && searchTerm !== "" && debouncedSearchTerm !== "" && (
- +
)} diff --git a/web/core/layouts/auth-layout/project-wrapper.tsx b/web/core/layouts/auth-layout/project-wrapper.tsx index fe8a367e3c9..61d8f89d4b3 100644 --- a/web/core/layouts/auth-layout/project-wrapper.tsx +++ b/web/core/layouts/auth-layout/project-wrapper.tsx @@ -4,7 +4,8 @@ import { FC, ReactNode, useEffect } from "react"; import { observer } from "mobx-react"; import { useParams } from "next/navigation"; import useSWR from "swr"; - +// plane imports +import { useTranslation } from "@plane/i18n"; // components import { JoinProject } from "@/components/auth-screens"; import { LogoSpinner } from "@/components/common"; @@ -40,6 +41,8 @@ export const ProjectAuthWrapper: FC = observer((props) => { const { children, isLoading: isParentLoading = false } = props; // router const { workspaceSlug, projectId } = useParams(); + // plane hooks + const { t } = useTranslation(); // store hooks const { toggleCreateProjectModal } = useCommandPalette(); const { setTrackElement } = useEventTracker(); @@ -178,14 +181,14 @@ export const ProjectAuthWrapper: FC = observer((props) => { return (
{ setTrackElement("Project empty state"); toggleCreateProjectModal(true);