diff --git a/packages/constants/src/issue.ts b/packages/constants/src/issue.ts deleted file mode 100644 index 19cfe60f3a6..00000000000 --- a/packages/constants/src/issue.ts +++ /dev/null @@ -1,185 +0,0 @@ -import { List, Kanban } from "lucide-react"; - -export const ALL_ISSUES = "All Issues"; - -export type TIssuePriorities = "urgent" | "high" | "medium" | "low" | "none"; - -export type TIssueFilterKeys = "priority" | "state" | "labels"; - -export type TIssueLayout = - | "list" - | "kanban" - | "calendar" - | "spreadsheet" - | "gantt"; - -export type TIssueFilterPriorityObject = { - key: TIssuePriorities; - title: string; - className: string; - icon: string; -}; - -export enum EIssueGroupByToServerOptions { - "state" = "state_id", - "priority" = "priority", - "labels" = "labels__id", - "state_detail.group" = "state__group", - "assignees" = "assignees__id", - "cycle" = "cycle_id", - "module" = "issue_module__module_id", - "target_date" = "target_date", - "project" = "project_id", - "created_by" = "created_by", - "team_project" = "project_id", -} - -export enum EIssueGroupBYServerToProperty { - "state_id" = "state_id", - "priority" = "priority", - "labels__id" = "label_ids", - "state__group" = "state__group", - "assignees__id" = "assignee_ids", - "cycle_id" = "cycle_id", - "issue_module__module_id" = "module_ids", - "target_date" = "target_date", - "project_id" = "project_id", - "created_by" = "created_by", -} - -export enum EServerGroupByToFilterOptions { - "state_id" = "state", - "priority" = "priority", - "labels__id" = "labels", - "state__group" = "state_group", - "assignees__id" = "assignees", - "cycle_id" = "cycle", - "issue_module__module_id" = "module", - "target_date" = "target_date", - "project_id" = "project", - "created_by" = "created_by", -} - -export enum EIssueServiceType { - ISSUES = "issues", - EPICS = "epics", -} - -export enum EIssueLayoutTypes { - LIST = "list", - KANBAN = "kanban", - CALENDAR = "calendar", - GANTT = "gantt_chart", - SPREADSHEET = "spreadsheet", -} - -export enum EIssuesStoreType { - GLOBAL = "GLOBAL", - PROFILE = "PROFILE", - TEAM = "TEAM", - PROJECT = "PROJECT", - CYCLE = "CYCLE", - MODULE = "MODULE", - TEAM_VIEW = "TEAM_VIEW", - PROJECT_VIEW = "PROJECT_VIEW", - ARCHIVED = "ARCHIVED", - DRAFT = "DRAFT", - DEFAULT = "DEFAULT", - WORKSPACE_DRAFT = "WORKSPACE_DRAFT", - EPIC = "EPIC", -} - -export enum EIssueFilterType { - FILTERS = "filters", - DISPLAY_FILTERS = "display_filters", - DISPLAY_PROPERTIES = "display_properties", - KANBAN_FILTERS = "kanban_filters", -} - -export enum EIssueCommentAccessSpecifier { - EXTERNAL = "EXTERNAL", - INTERNAL = "INTERNAL", -} - -export enum EIssueListRow { - HEADER = "HEADER", - ISSUE = "ISSUE", - NO_ISSUES = "NO_ISSUES", - QUICK_ADD = "QUICK_ADD", -} - -export const ISSUE_DISPLAY_FILTERS_BY_LAYOUT: { - [key in TIssueLayout]: Record<"filters", TIssueFilterKeys[]>; -} = { - list: { - filters: ["priority", "state", "labels"], - }, - kanban: { - filters: ["priority", "state", "labels"], - }, - calendar: { - filters: ["priority", "state", "labels"], - }, - spreadsheet: { - filters: ["priority", "state", "labels"], - }, - gantt: { - filters: ["priority", "state", "labels"], - }, -}; - -export const ISSUE_PRIORITIES: { - key: TIssuePriorities; - title: string; -}[] = [ - { key: "urgent", title: "Urgent" }, - { key: "high", title: "High" }, - { key: "medium", title: "Medium" }, - { key: "low", title: "Low" }, - { key: "none", title: "None" }, -]; - -export const ISSUE_PRIORITY_FILTERS: TIssueFilterPriorityObject[] = [ - { - key: "urgent", - title: "Urgent", - className: "bg-red-500 border-red-500 text-white", - icon: "error", - }, - { - key: "high", - title: "High", - className: "text-orange-500 border-custom-border-300", - icon: "signal_cellular_alt", - }, - { - key: "medium", - title: "Medium", - className: "text-yellow-500 border-custom-border-300", - icon: "signal_cellular_alt_2_bar", - }, - { - key: "low", - title: "Low", - className: "text-green-500 border-custom-border-300", - icon: "signal_cellular_alt_1_bar", - }, - { - key: "none", - title: "None", - className: "text-gray-500 border-custom-border-300", - icon: "block", - }, -]; - -export const SITES_ISSUE_LAYOUTS: { - key: TIssueLayout; - title: string; - icon: any; -}[] = [ - { key: "list", title: "List", icon: List }, - { key: "kanban", title: "Kanban", icon: Kanban }, - // { key: "calendar", title: "Calendar", icon: Calendar }, - // { key: "spreadsheet", title: "Spreadsheet", icon: Sheet }, - // { key: "gantt", title: "Gantt chart", icon: GanttChartSquare }, -]; diff --git a/packages/constants/src/issue/common.ts b/packages/constants/src/issue/common.ts new file mode 100644 index 00000000000..a63dd110d39 --- /dev/null +++ b/packages/constants/src/issue/common.ts @@ -0,0 +1,217 @@ +import { + TIssueGroupByOptions, + TIssueOrderByOptions, + IIssueDisplayProperties, +} from "@plane/types"; + +export const ALL_ISSUES = "All Issues"; + +export type TIssuePriorities = "urgent" | "high" | "medium" | "low" | "none"; + +export type TIssueFilterPriorityObject = { + key: TIssuePriorities; + titleTranslationKey: string; + className: string; + icon: string; +}; + +export enum EIssueGroupByToServerOptions { + "state" = "state_id", + "priority" = "priority", + "labels" = "labels__id", + "state_detail.group" = "state__group", + "assignees" = "assignees__id", + "cycle" = "cycle_id", + "module" = "issue_module__module_id", + "target_date" = "target_date", + "project" = "project_id", + "created_by" = "created_by", + "team_project" = "project_id", +} + +export enum EIssueGroupBYServerToProperty { + "state_id" = "state_id", + "priority" = "priority", + "labels__id" = "label_ids", + "state__group" = "state__group", + "assignees__id" = "assignee_ids", + "cycle_id" = "cycle_id", + "issue_module__module_id" = "module_ids", + "target_date" = "target_date", + "project_id" = "project_id", + "created_by" = "created_by", +} + +export enum EIssueServiceType { + ISSUES = "issues", + EPICS = "epics", +} + +export enum EIssuesStoreType { + GLOBAL = "GLOBAL", + PROFILE = "PROFILE", + TEAM = "TEAM", + PROJECT = "PROJECT", + CYCLE = "CYCLE", + MODULE = "MODULE", + TEAM_VIEW = "TEAM_VIEW", + PROJECT_VIEW = "PROJECT_VIEW", + ARCHIVED = "ARCHIVED", + DRAFT = "DRAFT", + DEFAULT = "DEFAULT", + WORKSPACE_DRAFT = "WORKSPACE_DRAFT", + EPIC = "EPIC", +} + +export enum EIssueCommentAccessSpecifier { + EXTERNAL = "EXTERNAL", + INTERNAL = "INTERNAL", +} + +export enum EIssueListRow { + HEADER = "HEADER", + ISSUE = "ISSUE", + NO_ISSUES = "NO_ISSUES", + QUICK_ADD = "QUICK_ADD", +} + +export const ISSUE_PRIORITIES: { + key: TIssuePriorities; + title: string; +}[] = [ + { + key: "urgent", + title: "Urgent", + }, + { + key: "high", + title: "High", + }, + { + key: "medium", + title: "Medium", + }, + { + key: "low", + title: "Low", + }, + { + key: "none", + title: "None", + }, +]; + +export const DRAG_ALLOWED_GROUPS: TIssueGroupByOptions[] = [ + "state", + "priority", + "assignees", + "labels", + "module", + "cycle", +]; + +export type TCreateModalStoreTypes = + | EIssuesStoreType.TEAM + | EIssuesStoreType.PROJECT + | EIssuesStoreType.TEAM_VIEW + | EIssuesStoreType.PROJECT_VIEW + | EIssuesStoreType.PROFILE + | EIssuesStoreType.CYCLE + | EIssuesStoreType.MODULE + | EIssuesStoreType.EPIC; + +export const ISSUE_GROUP_BY_OPTIONS: { + key: TIssueGroupByOptions; + titleTranslationKey: string; +}[] = [ + { key: "state", titleTranslationKey: "common.states" }, + { key: "state_detail.group", titleTranslationKey: "common.state_groups" }, + { key: "priority", titleTranslationKey: "common.priority" }, + { key: "team_project", titleTranslationKey: "common.team_project" }, // required this on team issues + { key: "project", titleTranslationKey: "common.project" }, // required this on my issues + { key: "cycle", titleTranslationKey: "common.cycle" }, // required this on my issues + { key: "module", titleTranslationKey: "common.module" }, // required this on my issues + { key: "labels", titleTranslationKey: "common.labels" }, + { key: "assignees", titleTranslationKey: "common.assignees" }, + { key: "created_by", titleTranslationKey: "common.created_by" }, + { key: null, titleTranslationKey: "common.none" }, +]; + +export const ISSUE_ORDER_BY_OPTIONS: { + key: TIssueOrderByOptions; + titleTranslationKey: string; +}[] = [ + { key: "sort_order", titleTranslationKey: "common.order_by.manual" }, + { key: "-created_at", titleTranslationKey: "common.order_by.last_created" }, + { key: "-updated_at", titleTranslationKey: "common.order_by.last_updated" }, + { key: "start_date", titleTranslationKey: "common.order_by.start_date" }, + { key: "target_date", titleTranslationKey: "common.order_by.due_date" }, + { key: "-priority", titleTranslationKey: "common.priority" }, +]; + +export const ISSUE_DISPLAY_PROPERTIES_KEYS: (keyof IIssueDisplayProperties)[] = + [ + "assignee", + "start_date", + "due_date", + "labels", + "key", + "priority", + "state", + "sub_issue_count", + "link", + "attachment_count", + "estimate", + "created_on", + "updated_on", + "modules", + "cycle", + "issue_type", + ]; + +export const ISSUE_DISPLAY_PROPERTIES: { + key: keyof IIssueDisplayProperties; + titleTranslationKey: string; +}[] = [ + { + key: "key", + titleTranslationKey: "issue.display.properties.id", + }, + { + key: "issue_type", + titleTranslationKey: "issue.display.properties.issue_type", + }, + { + key: "assignee", + titleTranslationKey: "common.assignee", + }, + { + key: "start_date", + titleTranslationKey: "common.order_by.start_date", + }, + { + key: "due_date", + titleTranslationKey: "common.order_by.due_date", + }, + { key: "labels", titleTranslationKey: "common.labels" }, + { + key: "priority", + titleTranslationKey: "common.priority", + }, + { key: "state", titleTranslationKey: "common.state" }, + { + key: "sub_issue_count", + titleTranslationKey: "issue.display.properties.sub_issue_count", + }, + { + key: "attachment_count", + titleTranslationKey: "issue.display.properties.attachment_count", + }, + { key: "link", titleTranslationKey: "common.link" }, + { + key: "estimate", + titleTranslationKey: "common.estimate", + }, + { key: "modules", titleTranslationKey: "common.module" }, + { key: "cycle", titleTranslationKey: "common.cycle" }, +]; diff --git a/packages/constants/src/issue/filter.ts b/packages/constants/src/issue/filter.ts new file mode 100644 index 00000000000..5d1d694b722 --- /dev/null +++ b/packages/constants/src/issue/filter.ts @@ -0,0 +1,530 @@ +import { + ILayoutDisplayFiltersOptions, + TIssueActivityComment, +} from "@plane/types"; +import { + TIssueFilterPriorityObject, + ISSUE_DISPLAY_PROPERTIES_KEYS, + EIssuesStoreType, +} from "./common"; + +import { TIssueLayout } from "./layout"; + +export type TIssueFilterKeys = "priority" | "state" | "labels"; + +export enum EServerGroupByToFilterOptions { + "state_id" = "state", + "priority" = "priority", + "labels__id" = "labels", + "state__group" = "state_group", + "assignees__id" = "assignees", + "cycle_id" = "cycle", + "issue_module__module_id" = "module", + "target_date" = "target_date", + "project_id" = "project", + "created_by" = "created_by", +} + +export enum EIssueFilterType { + FILTERS = "filters", + DISPLAY_FILTERS = "display_filters", + DISPLAY_PROPERTIES = "display_properties", + KANBAN_FILTERS = "kanban_filters", +} + +export const ISSUE_DISPLAY_FILTERS_BY_LAYOUT: { + [key in TIssueLayout]: Record<"filters", TIssueFilterKeys[]>; +} = { + list: { + filters: ["priority", "state", "labels"], + }, + kanban: { + filters: ["priority", "state", "labels"], + }, + calendar: { + filters: ["priority", "state", "labels"], + }, + spreadsheet: { + filters: ["priority", "state", "labels"], + }, + gantt: { + filters: ["priority", "state", "labels"], + }, +}; + +export const ISSUE_PRIORITY_FILTERS: TIssueFilterPriorityObject[] = [ + { + key: "urgent", + titleTranslationKey: "issue.priority.urgent", + className: "bg-red-500 border-red-500 text-white", + icon: "error", + }, + { + key: "high", + titleTranslationKey: "issue.priority.high", + className: "text-orange-500 border-custom-border-300", + icon: "signal_cellular_alt", + }, + { + key: "medium", + titleTranslationKey: "issue.priority.medium", + className: "text-yellow-500 border-custom-border-300", + icon: "signal_cellular_alt_2_bar", + }, + { + key: "low", + titleTranslationKey: "issue.priority.low", + className: "text-green-500 border-custom-border-300", + icon: "signal_cellular_alt_1_bar", + }, + { + key: "none", + titleTranslationKey: "common.none", + className: "text-gray-500 border-custom-border-300", + icon: "block", + }, +]; + +export type TFiltersByLayout = { + [layoutType: string]: ILayoutDisplayFiltersOptions; +}; + +export type TIssueFiltersToDisplayByPageType = { + [pageType: string]: TFiltersByLayout; +}; + +export const ISSUE_DISPLAY_FILTERS_BY_PAGE: TIssueFiltersToDisplayByPageType = { + profile_issues: { + list: { + filters: [ + "priority", + "state_group", + "labels", + "start_date", + "target_date", + ], + display_properties: ISSUE_DISPLAY_PROPERTIES_KEYS, + display_filters: { + group_by: ["state_detail.group", "priority", "project", "labels", null], + order_by: [ + "sort_order", + "-created_at", + "-updated_at", + "start_date", + "-priority", + ], + type: [null, "active", "backlog"], + }, + extra_options: { + access: true, + values: ["show_empty_groups", "sub_issue"], + }, + }, + kanban: { + filters: [ + "priority", + "state_group", + "labels", + "start_date", + "target_date", + ], + display_properties: ISSUE_DISPLAY_PROPERTIES_KEYS, + display_filters: { + group_by: ["state_detail.group", "priority", "project", "labels"], + order_by: [ + "sort_order", + "-created_at", + "-updated_at", + "start_date", + "-priority", + ], + type: [null, "active", "backlog"], + }, + extra_options: { + access: true, + values: ["show_empty_groups"], + }, + }, + }, + archived_issues: { + list: { + filters: [ + "priority", + "state", + "cycle", + "module", + "assignees", + "created_by", + "labels", + "start_date", + "target_date", + "issue_type", + ], + display_properties: ISSUE_DISPLAY_PROPERTIES_KEYS, + display_filters: { + group_by: [ + "state", + "cycle", + "module", + "state_detail.group", + "priority", + "labels", + "assignees", + "created_by", + null, + ], + order_by: [ + "sort_order", + "-created_at", + "-updated_at", + "start_date", + "-priority", + ], + type: [null, "active", "backlog"], + }, + extra_options: { + access: true, + values: ["show_empty_groups"], + }, + }, + }, + draft_issues: { + list: { + filters: [ + "priority", + "state_group", + "cycle", + "module", + "labels", + "start_date", + "target_date", + "issue_type", + ], + display_properties: ISSUE_DISPLAY_PROPERTIES_KEYS, + display_filters: { + group_by: [ + "state_detail.group", + "cycle", + "module", + "priority", + "project", + "labels", + null, + ], + order_by: [ + "sort_order", + "-created_at", + "-updated_at", + "start_date", + "-priority", + ], + type: [null, "active", "backlog"], + }, + extra_options: { + access: true, + values: ["show_empty_groups"], + }, + }, + kanban: { + filters: [ + "priority", + "state_group", + "cycle", + "module", + "labels", + "start_date", + "target_date", + "issue_type", + ], + display_properties: ISSUE_DISPLAY_PROPERTIES_KEYS, + display_filters: { + group_by: [ + "state_detail.group", + "cycle", + "module", + "priority", + "project", + "labels", + ], + order_by: [ + "sort_order", + "-created_at", + "-updated_at", + "start_date", + "-priority", + ], + type: [null, "active", "backlog"], + }, + extra_options: { + access: true, + values: ["show_empty_groups"], + }, + }, + }, + my_issues: { + spreadsheet: { + filters: [ + "priority", + "state_group", + "labels", + "assignees", + "created_by", + "subscriber", + "project", + "start_date", + "target_date", + ], + display_properties: ISSUE_DISPLAY_PROPERTIES_KEYS, + display_filters: { + order_by: [], + type: [null, "active", "backlog"], + }, + extra_options: { + access: true, + values: ["sub_issue"], + }, + }, + list: { + filters: [ + "priority", + "state_group", + "labels", + "assignees", + "created_by", + "subscriber", + "project", + "start_date", + "target_date", + ], + display_properties: ISSUE_DISPLAY_PROPERTIES_KEYS, + display_filters: { + type: [null, "active", "backlog"], + }, + extra_options: { + access: false, + values: [], + }, + }, + }, + issues: { + list: { + filters: [ + "priority", + "state", + "cycle", + "module", + "assignees", + "mentions", + "created_by", + "labels", + "start_date", + "target_date", + "issue_type", + ], + display_properties: ISSUE_DISPLAY_PROPERTIES_KEYS, + display_filters: { + group_by: [ + "state", + "priority", + "cycle", + "module", + "labels", + "assignees", + "created_by", + null, + ], + order_by: [ + "sort_order", + "-created_at", + "-updated_at", + "start_date", + "-priority", + ], + type: [null, "active", "backlog"], + }, + extra_options: { + access: true, + values: ["show_empty_groups", "sub_issue"], + }, + }, + kanban: { + filters: [ + "priority", + "state", + "cycle", + "module", + "assignees", + "mentions", + "created_by", + "labels", + "start_date", + "target_date", + "issue_type", + ], + display_properties: ISSUE_DISPLAY_PROPERTIES_KEYS, + display_filters: { + group_by: [ + "state", + "priority", + "cycle", + "module", + "labels", + "assignees", + "created_by", + ], + sub_group_by: [ + "state", + "priority", + "cycle", + "module", + "labels", + "assignees", + "created_by", + null, + ], + order_by: [ + "sort_order", + "-created_at", + "-updated_at", + "start_date", + "-priority", + "target_date", + ], + type: [null, "active", "backlog"], + }, + extra_options: { + access: true, + values: ["show_empty_groups", "sub_issue"], + }, + }, + calendar: { + filters: [ + "priority", + "state", + "cycle", + "module", + "assignees", + "mentions", + "created_by", + "labels", + "start_date", + "issue_type", + ], + display_properties: ["key", "issue_type"], + display_filters: { + type: [null, "active", "backlog"], + }, + extra_options: { + access: true, + values: ["sub_issue"], + }, + }, + spreadsheet: { + filters: [ + "priority", + "state", + "cycle", + "module", + "assignees", + "mentions", + "created_by", + "labels", + "start_date", + "target_date", + "issue_type", + ], + display_properties: ISSUE_DISPLAY_PROPERTIES_KEYS, + display_filters: { + order_by: [ + "sort_order", + "-created_at", + "-updated_at", + "start_date", + "-priority", + ], + type: [null, "active", "backlog"], + }, + extra_options: { + access: true, + values: ["sub_issue"], + }, + }, + gantt_chart: { + filters: [ + "priority", + "state", + "cycle", + "module", + "assignees", + "mentions", + "created_by", + "labels", + "start_date", + "target_date", + "issue_type", + ], + display_properties: ["key", "issue_type"], + display_filters: { + order_by: [ + "sort_order", + "-created_at", + "-updated_at", + "start_date", + "-priority", + ], + type: [null, "active", "backlog"], + }, + extra_options: { + access: true, + values: ["sub_issue"], + }, + }, + }, +}; + +export const ISSUE_STORE_TO_FILTERS_MAP: Partial< + Record +> = { + [EIssuesStoreType.PROJECT]: ISSUE_DISPLAY_FILTERS_BY_PAGE.issues, +}; + +export enum EActivityFilterType { + ACTIVITY = "ACTIVITY", + COMMENT = "COMMENT", +} + +export type TActivityFilters = EActivityFilterType; + +export const ACTIVITY_FILTER_TYPE_OPTIONS: Record< + TActivityFilters, + { labelTranslationKey: string } +> = { + [EActivityFilterType.ACTIVITY]: { + labelTranslationKey: "common.updates", + }, + [EActivityFilterType.COMMENT]: { + labelTranslationKey: "common.comments", + }, +}; + +export type TActivityFilterOption = { + key: TActivityFilters; + labelTranslationKey: string; + isSelected: boolean; + onClick: () => void; +}; + +export const defaultActivityFilters: TActivityFilters[] = [ + EActivityFilterType.ACTIVITY, + EActivityFilterType.COMMENT, +]; + +export const filterActivityOnSelectedFilters = ( + activity: TIssueActivityComment[], + filters: TActivityFilters[] +): TIssueActivityComment[] => + activity.filter((activity) => + filters.includes(activity.activity_type as TActivityFilters) + ); + +export const ENABLE_ISSUE_DEPENDENCIES = false; diff --git a/packages/constants/src/issue/index.ts b/packages/constants/src/issue/index.ts new file mode 100644 index 00000000000..63320322340 --- /dev/null +++ b/packages/constants/src/issue/index.ts @@ -0,0 +1,3 @@ +export * from "./common"; +export * from "./filter"; +export * from "./layout"; diff --git a/packages/constants/src/issue/layout.ts b/packages/constants/src/issue/layout.ts new file mode 100644 index 00000000000..6dd62fd177d --- /dev/null +++ b/packages/constants/src/issue/layout.ts @@ -0,0 +1,76 @@ +export type TIssueLayout = + | "list" + | "kanban" + | "calendar" + | "spreadsheet" + | "gantt"; + +export enum EIssueLayoutTypes { + LIST = "list", + KANBAN = "kanban", + CALENDAR = "calendar", + GANTT = "gantt_chart", + SPREADSHEET = "spreadsheet", +} + +export type TIssueLayoutMap = Record< + EIssueLayoutTypes, + { + key: EIssueLayoutTypes; + i18n_title: string; + i18n_label: string; + } +>; + +export const SITES_ISSUE_LAYOUTS: { + key: TIssueLayout; + titleTranslationKey: string; + icon: any; +}[] = [ + { + key: "list", + icon: "List", + titleTranslationKey: "issue.layouts.list", + }, + { + key: "kanban", + icon: "Kanban", + titleTranslationKey: "issue.layouts.kanban", + }, + // { key: "calendar", title: "Calendar", icon: Calendar }, + // { key: "spreadsheet", title: "Spreadsheet", icon: Sheet }, + // { key: "gantt", title: "Gantt chart", icon: GanttChartSquare }, +]; + +export const ISSUE_LAYOUT_MAP: TIssueLayoutMap = { + [EIssueLayoutTypes.LIST]: { + key: EIssueLayoutTypes.LIST, + i18n_title: "issue.layouts.title.list", + i18n_label: "issue.layouts.list", + }, + [EIssueLayoutTypes.KANBAN]: { + key: EIssueLayoutTypes.KANBAN, + i18n_title: "issue.layouts.title.kanban", + i18n_label: "issue.layouts.kanban", + }, + [EIssueLayoutTypes.CALENDAR]: { + key: EIssueLayoutTypes.CALENDAR, + i18n_title: "issue.layouts.title.calendar", + i18n_label: "issue.layouts.calendar", + }, + [EIssueLayoutTypes.SPREADSHEET]: { + key: EIssueLayoutTypes.SPREADSHEET, + i18n_title: "issue.layouts.title.spreadsheet", + i18n_label: "issue.layouts.spreadsheet", + }, + [EIssueLayoutTypes.GANTT]: { + key: EIssueLayoutTypes.GANTT, + i18n_title: "issue.layouts.title.gantt", + i18n_label: "issue.layouts.gantt", + }, +}; + +export const ISSUE_LAYOUTS: { + key: EIssueLayoutTypes; + i18n_title: string; +}[] = Object.values(ISSUE_LAYOUT_MAP); diff --git a/packages/i18n/src/locales/en/translations.json b/packages/i18n/src/locales/en/translations.json index 276384a0b4b..e115a99ec67 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", @@ -314,9 +313,153 @@ "remove_parent_issue": "Remove parent issue", "add_parent": "Add parent", "loading_members": "Loading members...", - "no_data_yet": "No Data yet", + "no_data_yet": "No Data yet", "connections": "Connections", + "common": { + "all": "All", + "states": "States", + "state": "State", + "state_groups": "State groups", + "priority": "Priority", + "team_project": "Team project", + "project": "Project", + "cycle": "Cycle", + "cycles": "Cycles", + "module": "Module", + "modules": "Modules", + "labels": "Labels", + "assignees": "Assignees", + "assignee": "Assignee", + "created_by": "Created by", + "none": "None", + "link": "Link", + "estimate": "Estimate", + "layout": "Layout", + "filters": "Filters", + "display": "Display", + "load_more": "Load more", + "no_matches_found": "No matches found", + "activity": "Activity", + "analytics": "Analytics", + "success": "Success", + "error": "Error", + "group_by": "Group by", + "search": "Search", + "epic": "Epic", + "issue": "Issue", + "warning": "Warning", + "updating": "Updating", + "update": "Update", + "creating": "Creating", + "cancel": "Cancel", + "description": "Description", + "title": "Title", + "order_by": { + "label": "Order by", + "manual": "Manual", + "last_created": "Last created", + "last_updated": "Last updated", + "start_date": "Start date", + "due_date": "Due date" + }, + "comments": "Comments", + "updates": "Updates" + }, + + "form": { + "title": { + "required": "Title is required", + "max_length": "Title should be less than {length} characters" + } + }, + + "entity": { + "grouping_title": "{entity} Grouping", + "priority": "{entity} ", + "all": "All {entity}", + "drop_here_to_move": "Drop here to move the {entity}" + }, + + "epic": { + "all": "All Epics", + "label": "{count, plural, one {Epic} other {Epics}}" + }, + + "issue": { + "label": "{count, plural, one {Issue} other {Issues}}", + "all": "All Issues", + "add": "Add Issue", + "priority": { + "urgent": "Urgent", + "high": "High", + "medium": "Medium", + "low": "Low" + }, + "display": { + "properties": { + "label": "Display Properties", + "id": "ID", + "issue_type": "Issue Type", + "sub_issue_count": "Sub issue count", + "attachment_count": "Attachment count" + }, + "extra": { + "show_sub_issues": "Show sub-issues", + "show_empty_groups": "Show empty groups" + } + }, + "layouts": { + "ordered_by_label": "This layout is ordered by", + "list": "List", + "kanban": "Board", + "calendar": "Calendar", + "spreadsheet": "Table", + "gantt": "Timeline", + "title": { + "list": "List Layout", + "kanban": "Board Layout", + "calendar": "Calendar Layout", + "spreadsheet": "Table Layout", + "gantt": "Timeline Layout" + } + }, + "states": { + "active": "Active", + "backlog": "Backlog" + }, + "comments": { + "create": { + "success": "Comment created successfully", + "error": "Comment creation failed. Please try again later." + }, + "update": { + "success": "Comment updated successfully", + "error": "Comment update failed. Please try again later." + }, + "remove": { + "success": "Comment removed successfully", + "error": "Comment remove failed. Please try again later." + }, + "upload": { + "error": "Asset upload failed. Please try again later." + } + } + }, + + "project": { + "label": "{count, plural, one {Project} other {Projects}}" + }, + + "view": { + "create": { + "label": "Create View" + }, + "update": { + "label": "Update View" + } + }, + "workspace_dashboard": { "empty_state": { "general": { @@ -441,9 +584,9 @@ "page_label": "Your work", "work": "Work", "details": { - "joined_on": "Joined on", - "time_zone": "Timezone" - }, + "joined_on": "Joined on", + "time_zone": "Timezone" + }, "stats": { "workload": "Workload", "overview": "Overview", diff --git a/packages/i18n/src/locales/es/translations.json b/packages/i18n/src/locales/es/translations.json index 5fe8916cb5c..557abd6bb51 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", @@ -313,10 +312,153 @@ "remove_parent_issue": "Eliminar problema padre", "add_parent": "Agregar padre", "loading_members": "Cargando miembros...", - "inbox": "bandeja de entrada", "no_data_yet": "Sin datos aún", "connections": "Conexiones", + "common": { + "all": "Todos", + "states": "Estados", + "state": "Estado", + "state_groups": "Grupos de estado", + "priority": "Prioridad", + "team_project": "Proyecto de equipo", + "project": "Proyecto", + "cycle": "Ciclo", + "cycles": "Ciclos", + "module": "Módulo", + "modules": "Módulos", + "labels": "Etiquetas", + "assignees": "Asignados", + "assignee": "Asignado", + "created_by": "Creado por", + "none": "Ninguno", + "link": "Enlace", + "estimate": "Estimación", + "layout": "Diseño", + "filters": "Filtros", + "display": "Mostrar", + "load_more": "Cargar más", + "no_matches_found": "No se encontraron coincidencias", + "activity": "Actividad", + "analytics": "Analítica", + "success": "Éxito", + "error": "Error", + "group_by": "Agrupar por", + "search": "Buscar", + "epic": "Épica", + "issue": "Problema", + "warning": "Advertencia", + "updating": "Actualizando", + "update": "Actualizar", + "creating": "Creando", + "cancel": "Cancelar", + "description": "Descripción", + "title": "Título", + "order_by": { + "label": "Ordenar por", + "manual": "Manual", + "last_created": "Último creado", + "last_updated": "Última actualización", + "start_date": "Fecha de inicio", + "due_date": "Fecha de vencimiento" + }, + "comments": "Comentarios", + "updates": "Actualizaciones" + }, + + "form": { + "title": { + "required": "El título es obligatorio", + "max_length": "El título debe tener menos de {length} caracteres" + } + }, + + "entity": { + "grouping_title": "Agrupación de {entity}", + "priority": "{entity}", + "all": "Todos los {entity}", + "drop_here_to_move": "Suelte aquí para mover el {entity}" + }, + + "epic": { + "all": "Todas las épicas", + "label": "{count, plural, one {Épica} other {Épicas}}" + }, + + "issue": { + "label": "{count, plural, one {Problema} other {Problemas}}", + "all": "Todos los problemas", + "add": "Agregar problema", + "priority": { + "urgent": "Urgente", + "high": "Alta", + "medium": "Media", + "low": "Baja" + }, + "display": { + "properties": { + "label": "Propiedades de visualización", + "id": "ID", + "issue_type": "Tipo de problema", + "sub_issue_count": "Cantidad de subproblemas", + "attachment_count": "Cantidad de archivos adjuntos" + }, + "extra": { + "show_sub_issues": "Mostrar subproblemas", + "show_empty_groups": "Mostrar grupos vacíos" + } + }, + "layouts": { + "ordered_by_label": "Este diseño está ordenado por", + "list": "Lista", + "kanban": "Tablero", + "calendar": "Calendario", + "spreadsheet": "Hoja de cálculo", + "gantt": "Línea de tiempo", + "title": { + "list": "Diseño de lista", + "kanban": "Diseño de tablero", + "calendar": "Diseño de calendario", + "spreadsheet": "Diseño de hoja de cálculo", + "gantt": "Diseño de línea de tiempo" + } + }, + "states": { + "active": "Activo", + "backlog": "Pendientes" + }, + "comments": { + "create": { + "success": "Comentario creado con éxito", + "error": "Error al crear el comentario. Por favor, inténtalo de nuevo más tarde." + }, + "update": { + "success": "Comentario actualizado con éxito", + "error": "Error al actualizar el comentario. Por favor, inténtalo más tarde." + }, + "remove": { + "success": "Comentario eliminado con éxito", + "error": "Error al eliminar el comentario. Por favor, inténtalo de nuevo más tarde." + }, + "upload": { + "error": "Error al subir el archivo. Por favor, inténtalo de nuevo más tarde." + } + } + }, + + "project": { + "label": "{count, plural, one {Proyecto} other {Proyectos}}" + }, + + "view": { + "create": { + "label": "Crear vista" + }, + "update": { + "label": "Actualizar vista" + } + }, + "workspace_dashboard": { "empty_state": { "general": { diff --git a/packages/i18n/src/locales/fr/translations.json b/packages/i18n/src/locales/fr/translations.json index e4490819d4a..4a5594a81d9 100644 --- a/packages/i18n/src/locales/fr/translations.json +++ b/packages/i18n/src/locales/fr/translations.json @@ -314,10 +314,149 @@ "remove_parent_issue": "Supprimer le problème parent", "add_parent": "Ajouter un parent", "loading_members": "Chargement des membres...", - "inbox": "Boîte de réception", "no_data_yet": "Pas encore de données", "connections": "Connexions", + "common": { + "all": "Tout", + "states": "États", + "state": "État", + "state_groups": "Groupes d'états", + "priority": "Priorité", + "team_project": "Projet d'équipe", + "project": "Projet", + "cycle": "Cycle", + "cycles": "Cycles", + "module": "Module", + "modules": "Modules", + "labels": "Étiquettes", + "assignees": "Assignés", + "assignee": "Assigné", + "created_by": "Créé par", + "none": "Aucun", + "link": "Lien", + "estimate": "Estimation", + "layout": "Disposition", + "filters": "Filtres", + "display": "Affichage", + "load_more": "Charger plus", + "no_matches_found": "Aucun résultat trouvé", + "activity": "Activité", + "analytics": "Analyses", + "success": "Succès", + "error": "Erreur", + "group_by": "Grouper par", + "search": "Rechercher", + "epic": "Épopée", + "issue": "Problème", + "warning": "Avertissement", + "updating": "Mise à jour", + "update": "Mettre à jour", + "creating": "Création", + "cancel": "Annuler", + "description": "Description", + "title": "Titre", + "order_by": { + "label": "Trier par", + "manual": "Manuel", + "last_created": "Dernière création", + "last_updated": "Dernière mise à jour", + "start_date": "Date de début", + "due_date": "Date d'échéance" + }, + "comments": "Commentaires", + "updates": "Mises à jour" + }, + + "form": { + "title": { + "required": "Le titre est requis", + "max_length": "Le titre ne doit pas dépasser {length} caractères" + } + }, + + "entity": { + "grouping_title": "Groupement de {entity}", + "priority": "{entity}", + "all": "Tous les {entity}", + "drop_here_to_move": "Déposer ici pour déplacer {entity}" + }, + + "epic": { + "all": "Toutes les épopées", + "label": "{count, plural, one {Épopée} other {Épopées}}" + }, + + "issue": { + "label": "{count, plural, one {Problème} other {Problèmes}}", + "all": "Tous les problèmes", + "add": "Ajouter un problème", + "priority": { + "urgent": "Urgent", + "high": "Haute", + "medium": "Moyenne", + "low": "Basse" + }, + "display": { + "properties": { + "label": "Propriétés d'affichage", + "id": "ID", + "issue_type": "Type de problème", + "sub_issue_count": "Nombre de sous-problèmes", + "attachment_count": "Nombre de pièces jointes" + }, + "extra": { + "show_sub_issues": "Afficher les sous-problèmes", + "show_empty_groups": "Afficher les groupes vides" + } + }, + "layouts": { + "ordered_by_label": "Cette disposition est triée par", + "list": "Liste", + "kanban": "Tableau", + "calendar": "Calendrier", + "spreadsheet": "Feuille de calcul", + "gantt": "Chronologie", + "title": { + "list": "Disposition en liste", + "kanban": "Disposition en tableau", + "calendar": "Disposition en calendrier", + "spreadsheet": "Disposition en feuille de calcul", + "gantt": "Disposition en chronologie" + } + }, + "states": { + "active": "Actif", + "backlog": "Backlog" + }, + "comments": { + "create": { + "success": "Commentaire créé avec succès", + "error": "Échec de la création du commentaire. Veuillez réessayer plus tard." + }, + "update": { + "success": "Commentaire mis à jour avec succès", + "error": "Échec de la mise à jour du commentaire. Veuillez réessayer plus tard." + }, + "remove": { + "success": "Commentaire supprimé avec succès", + "error": "Échec de la suppression du commentaire. Veuillez réessayer plus tard." + }, + "upload": { + "error": "Échec du téléchargement du fichier. Veuillez réessayer plus tard." + } + } + }, + + "view": { + "create": { + "label": "Créer une vue" + }, + "update": { + "label": "Mettre à jour la vue" + } + }, + "workspace_dashboard": { "empty_state": { "general": { diff --git a/packages/i18n/src/locales/ja/translations.json b/packages/i18n/src/locales/ja/translations.json index 361cda4753a..4f53184200a 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": "サイクル", @@ -317,12 +316,156 @@ "no_data_yet": "まだデータがありません", "connections": "接続", + "common": { + "all": "すべて", + "states": "ステータス", + "state": "ステータス", + "state_groups": "ステータスグループ", + "priority": "優先度", + "team_project": "チームプロジェクト", + "project": "プロジェクト", + "cycle": "サイクル", + "cycles": "サイクル", + "module": "モジュール", + "modules": "モジュール", + "labels": "ラベル", + "assignees": "アサイン者", + "assignee": "アサイン者", + "created_by": "作成者", + "none": "なし", + "link": "リンク", + "estimate": "見積もり", + "layout": "レイアウト", + "filters": "フィルター", + "display": "表示", + "load_more": "もっと見る", + "no_matches_found": "一致する結果はありません", + "activity": "アクティビティ", + "analytics": "分析", + "success": "成功", + "error": "エラー", + "group_by": "グループ化", + "search": "検索", + "epic": "エピック", + "issue": "問題", + "warning": "警告", + "updating": "更新中", + "update": "更新", + "creating": "作成中", + "cancel": "キャンセル", + "description": "説明", + "title": "タイトル", + "order_by": { + "label": "オーダー", + "manual": "手動", + "last_created": "最後に作成", + "last_updated": "最後に更新", + "start_date": "開始日", + "due_date": "期限日" + }, + "comments": "コメント", + "updates": "更新" + }, + + "form": { + "title": { + "required": "タイトルは必須です", + "max_length": "タイトルは{length}文字未満である必要があります" + } + }, + + "entity": { + "grouping_title": "{entity}グループ化", + "priority": "", + "all": "すべての{entity}", + "drop_here_to_move": "ここにドロップして{entity}を移動" + }, + + "epic": { + "all": "すべてのエピック", + "label": "{count, plural, one {エピック} other {エピック}}" + }, + + "issue": { + "label": "{count, plural, one {問題} other {問題}}", + "all": "すべての問題", + "add": "問題を追加", + "priority": { + "urgent": "緊急", + "high": "高", + "medium": "中", + "low": "低" + }, + "display": { + "properties": { + "label": "表示プロパティ", + "id": "ID", + "issue_type": "課題タイプ", + "sub_issue_count": "サブ課題数", + "attachment_count": "添付ファイル数" + }, + "extra": { + "show_sub_issues": "サブ課題を表示", + "show_empty_groups": "空のグループを表示" + } + }, + "layouts": { + "ordered_by_label": "このレイアウトは", + "list": "リスト", + "kanban": "ボード", + "calendar": "カレンダー", + "spreadsheet": "表", + "gantt": "ガントチャート", + "title": { + "list": "リストレイアウト", + "kanban": "ボードレイアウト", + "calendar": "カレンダーレイアウト", + "spreadsheet": "テーブルレイアウト", + "gantt": "タイムラインレイアウト" + } + }, + "states": { + "active": "アクティブ", + "backlog": "バックログ" + }, + "comments": { + "create": { + "success": "コメントが正常に作成されました。", + "error": "コメントの作成に失敗しました。後で再試行してください。" + }, + "update": { + "success": "コメントが正常に更新されました。", + "error": "コメントの更新に失敗しました。後で再試行してください。" + }, + "remove": { + "success": "コメントが正常に削除されました。", + "error": "コメントの削除に失敗しました。後で再試行してください。" + }, + "upload": { + "error": "コメントのアセットのアップロードに失敗しました。後で再試行してください。" + } + } + }, + + "project": { + "label": "{count, plural, one {プロジェクト} other {プロジェクト}}" + }, + + "view": { + "create": { + "label": "ビューを作成" + }, + "update": { + "label": "ビューを更新" + } + }, + "workspace_dashboard": { - "empty_state": { - "general": { - "title": "プロジェクト、アクティビティ、指標の概要", - "description": "Planeへようこそ!私たちはあなたを迎えることができて嬉しいです。最初のプロジェクトを作成してタスクを追跡し、このページが進捗を助けるスペースに変わります。管理者は、チームを前進させるための要素も見ることができます。", - "primary_button": { + "empty_state": { + "general": { + "title": "プロジェクト、アクティビティ、指標の概要", + "description": "Planeへようこそ!私たちはあなたを迎えることができて嬉しいです。最初のプロジェクトを作成してタスクを追跡し、このページが進捗を助けるスペースに変わります。管理者は、チームを前進させるための要素も見ることができます。", + "primary_button": { "text": "最初のプロジェクトを作成", "comic": { "title": "すべてはPlaneでのプロジェクトから始まります", diff --git a/packages/i18n/src/locales/zh-CN/translations.json b/packages/i18n/src/locales/zh-CN/translations.json index 0da2835d89f..12c85b57f7b 100644 --- a/packages/i18n/src/locales/zh-CN/translations.json +++ b/packages/i18n/src/locales/zh-CN/translations.json @@ -222,7 +222,6 @@ "join_the_project_to_rearrange": "加入项目以重新排序", "drag_to_rearrange": "拖动以重新排序", "congrats": "恭喜!", - "project": "项目", "open_project": "打开项目", "issues": "问题", "cycles": "周期", @@ -316,7 +315,146 @@ "add_parent": "添加父问题", "loading_members": "正在加载成员...", "inbox": "收件箱", - "no_data_yet": "暂无数据", + "common": { + "all": "全部", + "states": "状态", + "state": "状态", + "state_groups": "状态组", + "priority": "优先级", + "team_project": "团队项目", + "project": "项目", + "cycle": "周期", + "cycles": "周期", + "module": "模块", + "modules": "模块", + "labels": "标签", + "assignees": "分配人", + "assignee": "分配人", + "created_by": "创建者", + "none": "无", + "link": "链接", + "estimate": "估算", + "layout": "布局", + "filters": "筛选", + "display": "显示", + "load_more": "加载更多", + "no_matches_found": "未找到匹配项", + "activity": "活动", + "analytics": "分析", + "success": "成功", + "error": "错误", + "group_by": "分组方式", + "search": "搜索", + "epic": "史诗", + "issue": "问题", + "warning": "警告", + "updating": "更新中", + "update": "更新", + "creating": "创建中", + "cancel": "取消", + "description": "描述", + "title": "标题", + "order_by": { + "label": "排序方式", + "manual": "手动", + "last_created": "最近创建", + "last_updated": "最近更新", + "start_date": "开始日期", + "due_date": "截止日期" + }, + "comments": "评论", + "updates": "更新" + }, + "form": { + "title": { + "required": "标题为必填项", + "max_length": "标题不能超过{length}个字符" + } + }, + "entity": { + "grouping_title": "{entity}分组", + "priority": "{entity}", + "all": "所有{entity}", + "drop_here_to_move": "拖放至此以移动{entity}" + }, + "epic": { + "all": "所有史诗", + "label": "{count, plural, one {史诗} other {史诗}}" + }, + "issue": { + "label": "{count, plural, one {问题} other {问题}}", + "all": "所有问题", + "add": "添加问题", + "priority": { + "urgent": "紧急", + "high": "高", + "medium": "中", + "low": "低" + }, + "display": { + "properties": { + "label": "显示属性", + "id": "ID", + "issue_type": "问题类型", + "sub_issue_count": "子问题数量", + "attachment_count": "附件数量" + }, + "extra": { + "show_sub_issues": "显示子问题", + "show_empty_groups": "显示空分组" + } + }, + "layouts": { + "ordered_by_label": "当前排序方式", + "list": "列表", + "kanban": "看板", + "calendar": "日历", + "spreadsheet": "表格", + "gantt": "时间线", + "title": { + "list": "列表视图", + "kanban": "看板视图", + "calendar": "日历视图", + "spreadsheet": "表格视图", + "gantt": "时间线视图" + } + }, + "states": { + "active": "进行中", + "backlog": "待办" + }, + "comments": { + "create": { + "success": "评论创建成功", + "error": "评论创建失败,请稍后重试" + }, + "update": { + "success": "评论更新成功", + "error": "评论更新失败,请稍后重试" + }, + "remove": { + "success": "评论删除成功", + "error": "评论删除失败,请稍后重试" + }, + "upload": { + "error": "资源上传失败,请稍后重试" + } + } + }, + + "project": { + "label": "{count, plural, one {项目} other {项目}}" + }, + + "view": { + "create": { + "label": "创建视图" + }, + "update": { + "label": "更新视图" + } + }, + "user_profile": { "title": "你的工作", "work": "工作", diff --git a/packages/types/src/issues.d.ts b/packages/types/src/issues.d.ts index f77408fd6c0..a630d0ba20a 100644 --- a/packages/types/src/issues.d.ts +++ b/packages/types/src/issues.d.ts @@ -15,7 +15,7 @@ import type { TIssueGroupByOptions, TIssueOrderByOptions, TIssueGroupingFilters, - TIssueExtraOptions + TIssueExtraOptions, } from "@plane/types"; export interface IIssueCycle { diff --git a/space/core/components/issues/filters/priority.tsx b/space/core/components/issues/filters/priority.tsx index 4f16f89ba83..916c17abb86 100644 --- a/space/core/components/issues/filters/priority.tsx +++ b/space/core/components/issues/filters/priority.tsx @@ -2,8 +2,9 @@ import React, { useState } from "react"; import { observer } from "mobx-react"; -// ui import { ISSUE_PRIORITY_FILTERS } from "@plane/constants"; +import { useTranslation } from "@plane/i18n"; +// ui import { PriorityIcon } from "@plane/ui"; // components import { FilterHeader, FilterOption } from "./helpers"; @@ -18,6 +19,9 @@ type Props = { export const FilterPriority: React.FC = observer((props) => { const { appliedFilters, handleUpdate, searchQuery } = props; + // hooks + const { t } = useTranslation(); + const [previewEnabled, setPreviewEnabled] = useState(true); const appliedFiltersCount = appliedFilters?.length ?? 0; @@ -40,11 +44,11 @@ export const FilterPriority: React.FC = observer((props) => { isChecked={appliedFilters?.includes(priority.key) ? true : false} onClick={() => handleUpdate(priority.key)} icon={} - title={priority.title} + title={t(priority.titleTranslationKey)} /> )) ) : ( -

No matches found

+

{t("common.no_matches_found")}

)} )} diff --git a/space/core/components/issues/issue-layouts/kanban/swimlanes.tsx b/space/core/components/issues/issue-layouts/kanban/swimlanes.tsx index bc61c54af6e..48dd4047c34 100644 --- a/space/core/components/issues/issue-layouts/kanban/swimlanes.tsx +++ b/space/core/components/issues/issue-layouts/kanban/swimlanes.tsx @@ -131,10 +131,14 @@ const SubGroupSwimlaneHeader: React.FC = observer( const subGroupByVisibilityToggle = visibilitySubGroupByGroupCount(groupCount, showEmptyGroup); if (subGroupByVisibilityToggle === false) return <>; - return (
- +
); })} diff --git a/space/core/components/issues/issue-layouts/list/list-group.tsx b/space/core/components/issues/issue-layouts/list/list-group.tsx index 75d280d0d07..0a8c5ebb0d2 100644 --- a/space/core/components/issues/issue-layouts/list/list-group.tsx +++ b/space/core/components/issues/issue-layouts/list/list-group.tsx @@ -2,6 +2,7 @@ import { Fragment, MutableRefObject, forwardRef, useRef, useState } from "react"; import { observer } from "mobx-react"; +import { useTranslation } from "@plane/i18n"; // plane types import { IGroupByColumn, TIssueGroupByOptions, IIssueDisplayProperties, TPaginationData, TLoader } from "@plane/types"; // plane utils @@ -62,6 +63,8 @@ export const ListGroup = observer((props: Props) => { } = props; const [isExpanded, setIsExpanded] = useState(true); const groupRef = useRef(null); + // hooks + const { t } = useTranslation(); const [intersectionElement, setIntersectionElement] = useState(null); @@ -85,7 +88,7 @@ export const ListGroup = observer((props: Props) => { } onClick={() => loadMoreIssues(group.id)} > - Load More ↓ + {t("common.load_more")} ↓ ); diff --git a/space/core/components/issues/issue-layouts/properties/priority.tsx b/space/core/components/issues/issue-layouts/properties/priority.tsx index 7b4bbda7714..e3bb6e178e6 100644 --- a/space/core/components/issues/issue-layouts/properties/priority.tsx +++ b/space/core/components/issues/issue-layouts/properties/priority.tsx @@ -1,5 +1,6 @@ "use client"; +import { useTranslation } from "@plane/i18n"; // types import { TIssuePriorities } from "@plane/types"; import { Tooltip } from "@plane/ui"; @@ -13,17 +14,19 @@ export const IssueBlockPriority = ({ priority: TIssuePriorities | null; shouldShowName?: boolean; }) => { + // hooks + const { t } = useTranslation(); const priority_detail = priority != null ? getIssuePriorityFilters(priority) : null; if (priority_detail === null) return <>; return ( - +
{priority_detail?.icon}
- {shouldShowName && {priority_detail?.title}} + {shouldShowName && {t(priority_detail?.titleTranslationKey || "")}}
); diff --git a/space/core/components/issues/navbar/layout-selection.tsx b/space/core/components/issues/navbar/layout-selection.tsx index 1b8344d0242..36c8f8e243d 100644 --- a/space/core/components/issues/navbar/layout-selection.tsx +++ b/space/core/components/issues/navbar/layout-selection.tsx @@ -5,6 +5,8 @@ import { observer } from "mobx-react"; import { useRouter, useSearchParams } from "next/navigation"; // ui import { SITES_ISSUE_LAYOUTS } from "@plane/constants"; +// plane i18n +import { useTranslation } from "@plane/i18n"; import { Tooltip } from "@plane/ui"; // helpers import { queryParamGenerator } from "@/helpers/query-param-generator"; @@ -19,6 +21,8 @@ type Props = { export const IssuesLayoutSelection: FC = observer((props) => { const { anchor } = props; + // hooks + const { t } = useTranslation(); // router const router = useRouter(); const searchParams = useSearchParams(); @@ -45,7 +49,7 @@ export const IssuesLayoutSelection: FC = observer((props) => { if (!layoutOptions[layout.key]) return; return ( - + {!isCompletedCycle && ( )} diff --git a/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/cycles/(detail)/mobile-header.tsx b/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/cycles/(detail)/mobile-header.tsx index 1f85665fa86..31eb5b249fd 100644 --- a/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/cycles/(detail)/mobile-header.tsx +++ b/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/cycles/(detail)/mobile-header.tsx @@ -5,32 +5,42 @@ import { useParams } from "next/navigation"; // icons import { Calendar, ChevronDown, Kanban, List } from "lucide-react"; // plane constants -import { EIssueLayoutTypes, EIssueFilterType, EIssuesStoreType } from "@plane/constants"; +import { + EIssueLayoutTypes, + EIssueFilterType, + EIssuesStoreType, + ISSUE_LAYOUTS, + ISSUE_DISPLAY_FILTERS_BY_PAGE, +} from "@plane/constants"; +// i18n +import { useTranslation } from "@plane/i18n"; // types import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions } from "@plane/types"; // ui import { CustomMenu } from "@plane/ui"; // components import { ProjectAnalyticsModal } from "@/components/analytics"; -import { DisplayFiltersSelection, FilterSelection, FiltersDropdown } from "@/components/issues"; -// constants -import { ISSUE_DISPLAY_FILTERS_BY_LAYOUT, ISSUE_LAYOUTS } from "@/constants/issue"; +import { DisplayFiltersSelection, FilterSelection, FiltersDropdown, IssueLayoutIcon } from "@/components/issues"; // helpers import { isIssueFilterActive } from "@/helpers/filter.helper"; // hooks import { useIssues, useCycle, useProjectState, useLabel, useMember, useProject } from "@/hooks/store"; export const CycleIssuesMobileHeader = () => { + // i18n + const { t } = useTranslation(); + const [analyticsModal, setAnalyticsModal] = useState(false); const { getCycleById } = useCycle(); const layouts = [ - { key: "list", title: "List", icon: List }, - { key: "kanban", title: "Board", icon: Kanban }, - { key: "calendar", title: "Calendar", icon: Calendar }, + { key: "list", titleTranslationKey: "issue.layouts.list", icon: List }, + { key: "kanban", titleTranslationKey: "issue.layouts.kanban", icon: Kanban }, + { key: "calendar", titleTranslationKey: "issue.layouts.calendar", icon: Calendar }, ]; const { workspaceSlug, projectId, cycleId } = useParams(); const cycleDetails = cycleId ? getCycleById(cycleId.toString()) : undefined; + // store hooks const { currentProjectDetails } = useProject(); const { @@ -123,7 +133,9 @@ export const CycleIssuesMobileHeader = () => { maxHeight={"md"} className="flex flex-grow justify-center text-custom-text-200 text-sm" placement="bottom-start" - customButton={Layout} + customButton={ + {t("common.layout")} + } customButtonClassName="flex flex-grow justify-center text-custom-text-200 text-sm" closeOnSelect > @@ -135,18 +147,18 @@ export const CycleIssuesMobileHeader = () => { }} className="flex items-center gap-2" > - -
{layout.title}
+ +
{t(layout.titleTranslationKey)}
))}
- Filters + {t("common.filters")} } @@ -156,7 +168,7 @@ export const CycleIssuesMobileHeader = () => { filters={issueFilters?.filters ?? {}} handleFiltersUpdate={handleFiltersUpdate} layoutDisplayFiltersOptions={ - activeLayout ? ISSUE_DISPLAY_FILTERS_BY_LAYOUT.issues[activeLayout] : undefined + activeLayout ? ISSUE_DISPLAY_FILTERS_BY_PAGE.issues[activeLayout] : undefined } displayFilters={issueFilters?.displayFilters ?? {}} handleDisplayFiltersUpdate={handleDisplayFilters} @@ -170,18 +182,18 @@ export const CycleIssuesMobileHeader = () => {
- Display + {t("common.display")} } > { onClick={() => setAnalyticsModal(true)} className="flex flex-grow justify-center text-custom-text-200 text-sm border-l border-custom-border-200" > - Analytics + {t("common.analytics")}
diff --git a/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/draft-issues/header.tsx b/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/draft-issues/header.tsx index 3c996a8d14a..7ad851e86f7 100644 --- a/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/draft-issues/header.tsx +++ b/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/draft-issues/header.tsx @@ -4,7 +4,9 @@ import { FC, useCallback } from "react"; import { observer } from "mobx-react"; import { useParams } from "next/navigation"; // plane constants -import { EIssueLayoutTypes, EIssueFilterType, EIssuesStoreType } from "@plane/constants"; +import { EIssueLayoutTypes, EIssueFilterType, EIssuesStoreType, ISSUE_DISPLAY_FILTERS_BY_PAGE } from "@plane/constants"; +// i18n +import { useTranslation } from "@plane/i18n"; // types import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions } from "@plane/types"; // ui @@ -12,8 +14,6 @@ import { Breadcrumbs, LayersIcon, Tooltip } from "@plane/ui"; // components import { BreadcrumbLink } from "@/components/common"; import { DisplayFiltersSelection, FiltersDropdown, FilterSelection, LayoutSelection } from "@/components/issues"; -// constants -import { ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "@/constants/issue"; // helpers import { isIssueFilterActive } from "@/helpers/filter.helper"; // hooks @@ -23,6 +23,8 @@ import { usePlatformOS } from "@/hooks/use-platform-os"; import { ProjectBreadcrumb } from "@/plane-web/components/breadcrumbs"; export const ProjectDraftIssueHeader: FC = observer(() => { + // i18n + const { t } = useTranslation(); // router const { workspaceSlug, projectId } = useParams() as { workspaceSlug: string; projectId: string }; // store hooks @@ -122,14 +124,18 @@ export const ProjectDraftIssueHeader: FC = observer(() => { onChange={(layout) => handleLayoutChange(layout)} selectedLayout={activeLayout} /> - + { moduleViewDisabled={!currentProjectDetails?.module_view} /> - + { + // i18n + const { t } = useTranslation(); const layouts = [ - { key: "list", title: "List", icon: List }, - { key: "kanban", title: "Board", icon: Kanban }, - { key: "calendar", title: "Calendar", icon: Calendar }, + { key: "list", titleTranslationKey: "issue.layouts.list", icon: List }, + { key: "kanban", titleTranslationKey: "issue.layouts.kanban", icon: Kanban }, + { key: "calendar", titleTranslationKey: "issue.layouts.calendar", icon: Calendar }, ]; const [analyticsModal, setAnalyticsModal] = useState(false); const { workspaceSlug, projectId } = useParams() as { @@ -104,7 +117,7 @@ export const ProjectIssuesMobileHeader = observer(() => { placement="bottom-start" customButton={
- Layout + {t("common.layout")}
} @@ -119,18 +132,18 @@ export const ProjectIssuesMobileHeader = observer(() => { }} className="flex items-center gap-2" > - -
{layout.title}
+ +
{t(layout.titleTranslationKey)}
))}
- Filters + {t("common.filters")} } @@ -142,7 +155,7 @@ export const ProjectIssuesMobileHeader = observer(() => { displayFilters={issueFilters?.displayFilters ?? {}} handleDisplayFiltersUpdate={handleDisplayFilters} layoutDisplayFiltersOptions={ - activeLayout ? ISSUE_DISPLAY_FILTERS_BY_LAYOUT.issues[activeLayout] : undefined + activeLayout ? ISSUE_DISPLAY_FILTERS_BY_PAGE.issues[activeLayout] : undefined } labels={projectLabels} memberIds={projectMemberIds ?? undefined} @@ -154,18 +167,18 @@ export const ProjectIssuesMobileHeader = observer(() => {
- Display + {t("common.display")} } > { onClick={() => setAnalyticsModal(true)} className="flex flex-grow justify-center border-l border-custom-border-200 text-sm text-custom-text-200" > - Analytics + {t("common.analytics")}
diff --git a/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/modules/(detail)/header.tsx b/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/modules/(detail)/header.tsx index e167509f221..8e9f49f173b 100644 --- a/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/modules/(detail)/header.tsx +++ b/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/modules/(detail)/header.tsx @@ -7,7 +7,7 @@ import { useParams } from "next/navigation"; // icons import { ArrowRight, PanelRight } from "lucide-react"; // plane constants -import { EIssueLayoutTypes, EIssuesStoreType, EIssueFilterType } from "@plane/constants"; +import { EIssueLayoutTypes, EIssuesStoreType, EIssueFilterType, ISSUE_DISPLAY_FILTERS_BY_PAGE } from "@plane/constants"; // types import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions } from "@plane/types"; // ui @@ -16,8 +16,6 @@ import { Breadcrumbs, Button, CustomMenu, DiceIcon, Tooltip, Header } from "@pla import { ProjectAnalyticsModal } from "@/components/analytics"; import { BreadcrumbLink } from "@/components/common"; import { DisplayFiltersSelection, FiltersDropdown, FilterSelection, LayoutSelection } from "@/components/issues"; -// constants -import { ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "@/constants/issue"; // helpers import { cn } from "@/helpers/common.helper"; import { isIssueFilterActive } from "@/helpers/filter.helper"; @@ -247,7 +245,7 @@ export const ModuleIssuesHeader: React.FC = observer(() => { displayFilters={issueFilters?.displayFilters ?? {}} handleDisplayFiltersUpdate={handleDisplayFilters} layoutDisplayFiltersOptions={ - activeLayout ? ISSUE_DISPLAY_FILTERS_BY_LAYOUT.issues[activeLayout] : undefined + activeLayout ? ISSUE_DISPLAY_FILTERS_BY_PAGE.issues[activeLayout] : undefined } labels={projectLabels} memberIds={projectMemberIds ?? undefined} @@ -259,7 +257,7 @@ export const ModuleIssuesHeader: React.FC = observer(() => { { const [analyticsModal, setAnalyticsModal] = useState(false); const { currentProjectDetails } = useProject(); const { getModuleById } = useModule(); + const { t } = useTranslation(); const layouts = [ - { key: "list", title: "List", icon: List }, - { key: "kanban", title: "Board", icon: Kanban }, - { key: "calendar", title: "Calendar", icon: Calendar }, + { key: "list", i18n_title: "issue.layouts.list", icon: List }, + { key: "kanban", i18n_title: "issue.layouts.kanban", icon: Kanban }, + { key: "calendar", i18n_title: "issue.layouts.calendar", icon: Calendar }, ]; const { workspaceSlug, projectId, moduleId } = useParams() as { workspaceSlug: string; @@ -116,8 +128,8 @@ export const ModuleIssuesMobileHeader = observer(() => { }} className="flex items-center gap-2" > - -
{layout.title}
+ +
{t(layout.i18n_title)}
))} @@ -139,7 +151,7 @@ export const ModuleIssuesMobileHeader = observer(() => { displayFilters={issueFilters?.displayFilters ?? {}} handleDisplayFiltersUpdate={handleDisplayFilters} layoutDisplayFiltersOptions={ - activeLayout ? ISSUE_DISPLAY_FILTERS_BY_LAYOUT.issues[activeLayout] : undefined + activeLayout ? ISSUE_DISPLAY_FILTERS_BY_PAGE.issues[activeLayout] : undefined } labels={projectLabels} memberIds={projectMemberIds ?? undefined} @@ -162,7 +174,7 @@ export const ModuleIssuesMobileHeader = observer(() => { > { displayFilters={issueFilters?.displayFilters ?? {}} handleDisplayFiltersUpdate={handleDisplayFilters} layoutDisplayFiltersOptions={ - activeLayout ? ISSUE_DISPLAY_FILTERS_BY_LAYOUT.issues[activeLayout] : undefined + activeLayout ? ISSUE_DISPLAY_FILTERS_BY_PAGE.issues[activeLayout] : undefined } projectId={projectId.toString()} labels={projectLabels} @@ -255,7 +254,7 @@ export const ProjectViewIssuesHeader: React.FC = observer(() => { { isFiltersApplied={isIssueFilterActive(issueFilters)} > { = (props) => { const filterKey = key as TActivityFilters; return { key: filterKey, - label: value.label, + labelTranslationKey: value.labelTranslationKey, isSelected: selectedFilters.includes(filterKey), onClick: () => toggleFilter(filterKey), }; diff --git a/web/ce/constants/index.ts b/web/ce/constants/index.ts index 123db122c8a..329f796ceb9 100644 --- a/web/ce/constants/index.ts +++ b/web/ce/constants/index.ts @@ -1,7 +1,6 @@ export * from "./ai"; export * from "./estimates"; export * from "./gantt-chart"; -export * from "./issues"; export * from "./project"; export * from "./user-permissions"; export * from "./workspace"; diff --git a/web/ce/constants/issues.ts b/web/ce/constants/issues.ts deleted file mode 100644 index 70a34577f73..00000000000 --- a/web/ce/constants/issues.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { ILayoutDisplayFiltersOptions, TIssueActivityComment } from "@plane/types"; - -export enum EActivityFilterType { - ACTIVITY = "ACTIVITY", - COMMENT = "COMMENT", -} - -export type TActivityFilters = EActivityFilterType; - -export const ACTIVITY_FILTER_TYPE_OPTIONS: Record = { - [EActivityFilterType.ACTIVITY]: { - label: "Updates", - }, - [EActivityFilterType.COMMENT]: { - label: "Comments", - }, -}; - -export const defaultActivityFilters: TActivityFilters[] = [EActivityFilterType.ACTIVITY, EActivityFilterType.COMMENT]; - -export type TActivityFilterOption = { - key: TActivityFilters; - label: string; - isSelected: boolean; - onClick: () => void; -}; - -export const filterActivityOnSelectedFilters = ( - activity: TIssueActivityComment[], - filter: TActivityFilters[] -): TIssueActivityComment[] => - activity.filter((activity) => filter.includes(activity.activity_type as TActivityFilters)); - -export const ENABLE_ISSUE_DEPENDENCIES = false; - -export const ADDITIONAL_ISSUE_DISPLAY_FILTERS_BY_LAYOUT: { - [pageType: string]: { [layoutType: string]: ILayoutDisplayFiltersOptions }; -} = {}; diff --git a/web/ce/store/issue/issue-details/activity.store.ts b/web/ce/store/issue/issue-details/activity.store.ts index 72c725010b8..93b925aba9d 100644 --- a/web/ce/store/issue/issue-details/activity.store.ts +++ b/web/ce/store/issue/issue-details/activity.store.ts @@ -8,7 +8,7 @@ import update from "lodash/update"; import { action, makeObservable, observable, runInAction } from "mobx"; import { computedFn } from "mobx-utils"; // plane package imports -import { EIssueServiceType, E_SORT_ORDER } from "@plane/constants"; +import { EIssueServiceType, E_SORT_ORDER, EActivityFilterType } from "@plane/constants"; import { TIssueActivityComment, TIssueActivity, @@ -17,7 +17,6 @@ import { TIssueServiceType, } from "@plane/types"; // plane web constants -import { EActivityFilterType } from "@/plane-web/constants/issues"; // services import { IssueActivityService } from "@/services/issue"; // store diff --git a/web/core/components/command-palette/actions/issue-actions/change-priority.tsx b/web/core/components/command-palette/actions/issue-actions/change-priority.tsx index 2f004e8eae0..d5fd09a55a5 100644 --- a/web/core/components/command-palette/actions/issue-actions/change-priority.tsx +++ b/web/core/components/command-palette/actions/issue-actions/change-priority.tsx @@ -5,12 +5,11 @@ import { observer } from "mobx-react"; import { useParams } from "next/navigation"; import { Check } from "lucide-react"; // plane constants -import { EIssuesStoreType } from "@plane/constants"; +import { EIssuesStoreType, ISSUE_PRIORITIES } from "@plane/constants"; // plane types import { TIssue, TIssuePriorities } from "@plane/types"; // mobx store import { PriorityIcon } from "@plane/ui"; -import { ISSUE_PRIORITIES } from "@/constants/issue"; import { useIssues } from "@/hooks/store"; // ui // types diff --git a/web/core/components/dropdowns/layout.tsx b/web/core/components/dropdowns/layout.tsx index 9907ab1406f..5864f4a2933 100644 --- a/web/core/components/dropdowns/layout.tsx +++ b/web/core/components/dropdowns/layout.tsx @@ -2,13 +2,15 @@ import { useCallback, useMemo } from "react"; import { observer } from "mobx-react"; import { Check } from "lucide-react"; // plane constants -import { EIssueLayoutTypes } from "@plane/constants"; +import { EIssueLayoutTypes, ISSUE_LAYOUT_MAP } from "@plane/constants"; +// plane i18n +import { useTranslation } from "@plane/i18n"; // plane ui import { Dropdown } from "@plane/ui"; // plane utils import { cn } from "@plane/utils"; -// constants -import { ISSUE_LAYOUT_MAP } from "@/constants/issue"; +// components +import { IssueLayoutIcon } from "@/components/issues"; type TLayoutDropDown = { onChange: (value: EIssueLayoutTypes) => void; @@ -18,6 +20,8 @@ type TLayoutDropDown = { export const LayoutDropDown = observer((props: TLayoutDropDown) => { const { onChange, value = EIssueLayoutTypes.LIST, disabledLayouts = [] } = props; + // plane i18n + const { t } = useTranslation(); // derived values const availableLayouts = useMemo( () => Object.values(ISSUE_LAYOUT_MAP).filter((layout) => !disabledLayouts.includes(layout.key)), @@ -35,11 +39,10 @@ export const LayoutDropDown = observer((props: TLayoutDropDown) => { const buttonContent = useCallback((isOpen: boolean, buttonValue: string | string[] | undefined) => { const dropdownValue = ISSUE_LAYOUT_MAP[buttonValue as EIssueLayoutTypes]; - return (
- - {dropdownValue.label} + + {t(dropdownValue.i18n_label)}
); }, []); @@ -50,8 +53,8 @@ export const LayoutDropDown = observer((props: TLayoutDropDown) => { return (
- - {dropdownValue.label} + + {t(dropdownValue.i18n_label)}
{props.selected && }
diff --git a/web/core/components/dropdowns/priority.tsx b/web/core/components/dropdowns/priority.tsx index acf6dc26b12..4009405571d 100644 --- a/web/core/components/dropdowns/priority.tsx +++ b/web/core/components/dropdowns/priority.tsx @@ -5,13 +5,12 @@ import { useTheme } from "next-themes"; import { usePopper } from "react-popper"; import { Check, ChevronDown, Search, SignalHigh } from "lucide-react"; import { Combobox } from "@headlessui/react"; +import { ISSUE_PRIORITIES } from "@plane/constants"; import { useTranslation } from "@plane/i18n"; // types import { TIssuePriorities } from "@plane/types"; // ui import { ComboDropDown, PriorityIcon, Tooltip } from "@plane/ui"; -// constants -import { ISSUE_PRIORITIES } from "@/constants/issue"; // helpers import { cn } from "@/helpers/common.helper"; // hooks @@ -77,7 +76,7 @@ const BorderButton = (props: ButtonProps) => { return ( { ) : ( ))} - {!hideText && {t(priorityDetails?.key ?? "priority") ?? placeholder}} + {!hideText && {priorityDetails?.title ?? placeholder}} {dropdownArrow && (