Initial commit: Plane
Some checks failed
Branch Build CE / Build Setup (push) Has been cancelled
Branch Build CE / Build-Push Admin Docker Image (push) Has been cancelled
Branch Build CE / Build-Push Web Docker Image (push) Has been cancelled
Branch Build CE / Build-Push Space Docker Image (push) Has been cancelled
Branch Build CE / Build-Push Live Collaboration Docker Image (push) Has been cancelled
Branch Build CE / Build-Push API Server Docker Image (push) Has been cancelled
Branch Build CE / Build-Push Proxy Docker Image (push) Has been cancelled
Branch Build CE / Build-Push AIO Docker Image (push) Has been cancelled
Branch Build CE / Upload Build Assets (push) Has been cancelled
Branch Build CE / Build Release (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Codespell / Check for spelling errors (push) Has been cancelled
Sync Repositories / sync_changes (push) Has been cancelled
Some checks failed
Branch Build CE / Build Setup (push) Has been cancelled
Branch Build CE / Build-Push Admin Docker Image (push) Has been cancelled
Branch Build CE / Build-Push Web Docker Image (push) Has been cancelled
Branch Build CE / Build-Push Space Docker Image (push) Has been cancelled
Branch Build CE / Build-Push Live Collaboration Docker Image (push) Has been cancelled
Branch Build CE / Build-Push API Server Docker Image (push) Has been cancelled
Branch Build CE / Build-Push Proxy Docker Image (push) Has been cancelled
Branch Build CE / Build-Push AIO Docker Image (push) Has been cancelled
Branch Build CE / Upload Build Assets (push) Has been cancelled
Branch Build CE / Build Release (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Codespell / Check for spelling errors (push) Has been cancelled
Sync Repositories / sync_changes (push) Has been cancelled
Synced from upstream: 8853637e981ed7d8a6cff32bd98e7afe20f54362
This commit is contained in:
4
packages/constants/.eslintignore
Normal file
4
packages/constants/.eslintignore
Normal file
@@ -0,0 +1,4 @@
|
||||
node_modules
|
||||
build/*
|
||||
dist/*
|
||||
out/*
|
||||
4
packages/constants/.eslintrc.js
Normal file
4
packages/constants/.eslintrc.js
Normal file
@@ -0,0 +1,4 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
extends: ["@plane/eslint-config/library.js"],
|
||||
};
|
||||
5
packages/constants/.prettierignore
Normal file
5
packages/constants/.prettierignore
Normal file
@@ -0,0 +1,5 @@
|
||||
.next
|
||||
.turbo
|
||||
out/
|
||||
dist/
|
||||
build/
|
||||
5
packages/constants/.prettierrc
Normal file
5
packages/constants/.prettierrc
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"printWidth": 120,
|
||||
"tabWidth": 2,
|
||||
"trailingComma": "es5"
|
||||
}
|
||||
37
packages/constants/package.json
Normal file
37
packages/constants/package.json
Normal file
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"name": "@plane/constants",
|
||||
"version": "1.1.0",
|
||||
"private": true,
|
||||
"license": "AGPL-3.0",
|
||||
"scripts": {
|
||||
"dev": "tsdown --watch",
|
||||
"build": "tsdown",
|
||||
"check:lint": "eslint . --max-warnings 0",
|
||||
"check:types": "tsc --noEmit",
|
||||
"check:format": "prettier --check \"**/*.{ts,tsx,md,json,css,scss}\"",
|
||||
"fix:lint": "eslint . --fix",
|
||||
"fix:format": "prettier --write \"**/*.{ts,tsx,md,json,css,scss}\"",
|
||||
"clean": "rm -rf .turbo && rm -rf .next && rm -rf node_modules && rm -rf dist"
|
||||
},
|
||||
"dependencies": {
|
||||
"@plane/types": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@plane/eslint-config": "workspace:*",
|
||||
"@plane/typescript-config": "workspace:*",
|
||||
"@types/node": "catalog:",
|
||||
"@types/react": "catalog:",
|
||||
"tsdown": "catalog:",
|
||||
"typescript": "catalog:"
|
||||
},
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.mjs",
|
||||
"types": "./dist/index.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./dist/index.mjs",
|
||||
"require": "./dist/index.js"
|
||||
},
|
||||
"./package.json": "./package.json"
|
||||
}
|
||||
}
|
||||
3
packages/constants/src/ai.ts
Normal file
3
packages/constants/src/ai.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export enum AI_EDITOR_TASKS {
|
||||
ASK_ANYTHING = "ASK_ANYTHING",
|
||||
}
|
||||
183
packages/constants/src/analytics/common.ts
Normal file
183
packages/constants/src/analytics/common.ts
Normal file
@@ -0,0 +1,183 @@
|
||||
import { ChartXAxisProperty, ChartYAxisMetric, TAnalyticsTabsBase } from "@plane/types";
|
||||
|
||||
export interface IInsightField {
|
||||
key: string;
|
||||
i18nKey: string;
|
||||
i18nProps?: {
|
||||
entity?: string;
|
||||
entityPlural?: string;
|
||||
prefix?: string;
|
||||
suffix?: string;
|
||||
[key: string]: unknown;
|
||||
};
|
||||
}
|
||||
|
||||
export const ANALYTICS_INSIGHTS_FIELDS: Record<TAnalyticsTabsBase, IInsightField[]> = {
|
||||
overview: [
|
||||
{
|
||||
key: "total_users",
|
||||
i18nKey: "workspace_analytics.total",
|
||||
i18nProps: {
|
||||
entity: "common.users",
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "total_admins",
|
||||
i18nKey: "workspace_analytics.total",
|
||||
i18nProps: {
|
||||
entity: "common.admins",
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "total_members",
|
||||
i18nKey: "workspace_analytics.total",
|
||||
i18nProps: {
|
||||
entity: "common.members",
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "total_guests",
|
||||
i18nKey: "workspace_analytics.total",
|
||||
i18nProps: {
|
||||
entity: "common.guests",
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "total_projects",
|
||||
i18nKey: "workspace_analytics.total",
|
||||
i18nProps: {
|
||||
entity: "common.projects",
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "total_work_items",
|
||||
i18nKey: "workspace_analytics.total",
|
||||
i18nProps: {
|
||||
entity: "common.work_items",
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "total_cycles",
|
||||
i18nKey: "workspace_analytics.total",
|
||||
i18nProps: {
|
||||
entity: "common.cycles",
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "total_intake",
|
||||
i18nKey: "workspace_analytics.total",
|
||||
i18nProps: {
|
||||
entity: "sidebar.intake",
|
||||
},
|
||||
},
|
||||
],
|
||||
"work-items": [
|
||||
{
|
||||
key: "total_work_items",
|
||||
i18nKey: "workspace_analytics.total",
|
||||
},
|
||||
{
|
||||
key: "started_work_items",
|
||||
i18nKey: "workspace_analytics.started_work_items",
|
||||
},
|
||||
{
|
||||
key: "backlog_work_items",
|
||||
i18nKey: "workspace_analytics.backlog_work_items",
|
||||
},
|
||||
{
|
||||
key: "un_started_work_items",
|
||||
i18nKey: "workspace_analytics.un_started_work_items",
|
||||
},
|
||||
{
|
||||
key: "completed_work_items",
|
||||
i18nKey: "workspace_analytics.completed_work_items",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const ANALYTICS_DURATION_FILTER_OPTIONS = [
|
||||
{
|
||||
name: "Yesterday",
|
||||
value: "yesterday",
|
||||
},
|
||||
{
|
||||
name: "Last 7 days",
|
||||
value: "last_7_days",
|
||||
},
|
||||
{
|
||||
name: "Last 30 days",
|
||||
value: "last_30_days",
|
||||
},
|
||||
{
|
||||
name: "Last 3 months",
|
||||
value: "last_3_months",
|
||||
},
|
||||
];
|
||||
|
||||
export const ANALYTICS_X_AXIS_VALUES: { value: ChartXAxisProperty; label: string }[] = [
|
||||
{
|
||||
value: ChartXAxisProperty.STATES,
|
||||
label: "State name",
|
||||
},
|
||||
{
|
||||
value: ChartXAxisProperty.STATE_GROUPS,
|
||||
label: "State group",
|
||||
},
|
||||
{
|
||||
value: ChartXAxisProperty.PRIORITY,
|
||||
label: "Priority",
|
||||
},
|
||||
{
|
||||
value: ChartXAxisProperty.LABELS,
|
||||
label: "Label",
|
||||
},
|
||||
{
|
||||
value: ChartXAxisProperty.ASSIGNEES,
|
||||
label: "Assignee",
|
||||
},
|
||||
{
|
||||
value: ChartXAxisProperty.ESTIMATE_POINTS,
|
||||
label: "Estimate point",
|
||||
},
|
||||
{
|
||||
value: ChartXAxisProperty.CYCLES,
|
||||
label: "Cycle",
|
||||
},
|
||||
{
|
||||
value: ChartXAxisProperty.MODULES,
|
||||
label: "Module",
|
||||
},
|
||||
{
|
||||
value: ChartXAxisProperty.COMPLETED_AT,
|
||||
label: "Completed date",
|
||||
},
|
||||
{
|
||||
value: ChartXAxisProperty.TARGET_DATE,
|
||||
label: "Due date",
|
||||
},
|
||||
{
|
||||
value: ChartXAxisProperty.START_DATE,
|
||||
label: "Start date",
|
||||
},
|
||||
{
|
||||
value: ChartXAxisProperty.CREATED_AT,
|
||||
label: "Created date",
|
||||
},
|
||||
];
|
||||
|
||||
export const ANALYTICS_Y_AXIS_VALUES: { value: ChartYAxisMetric; label: string }[] = [
|
||||
{
|
||||
value: ChartYAxisMetric.WORK_ITEM_COUNT,
|
||||
label: "Work item",
|
||||
},
|
||||
{
|
||||
value: ChartYAxisMetric.ESTIMATE_POINT_COUNT,
|
||||
label: "Estimate",
|
||||
},
|
||||
{
|
||||
value: ChartYAxisMetric.EPIC_WORK_ITEM_COUNT,
|
||||
label: "Epic",
|
||||
},
|
||||
];
|
||||
|
||||
export const ANALYTICS_V2_DATE_KEYS = ["completed_at", "target_date", "start_date", "created_at"];
|
||||
1
packages/constants/src/analytics/index.ts
Normal file
1
packages/constants/src/analytics/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from "./common";
|
||||
158
packages/constants/src/auth.ts
Normal file
158
packages/constants/src/auth.ts
Normal file
@@ -0,0 +1,158 @@
|
||||
export enum E_PASSWORD_STRENGTH {
|
||||
EMPTY = "empty",
|
||||
LENGTH_NOT_VALID = "length_not_valid",
|
||||
STRENGTH_NOT_VALID = "strength_not_valid",
|
||||
STRENGTH_VALID = "strength_valid",
|
||||
}
|
||||
|
||||
export const PASSWORD_MIN_LENGTH = 8;
|
||||
|
||||
export const SPACE_PASSWORD_CRITERIA = [
|
||||
{
|
||||
key: "min_8_char",
|
||||
label: "Min 8 characters",
|
||||
isCriteriaValid: (password: string) => password.length >= PASSWORD_MIN_LENGTH,
|
||||
},
|
||||
// {
|
||||
// key: "min_1_upper_case",
|
||||
// label: "Min 1 upper-case letter",
|
||||
// isCriteriaValid: (password: string) => PASSWORD_NUMBER_REGEX.test(password),
|
||||
// },
|
||||
// {
|
||||
// key: "min_1_number",
|
||||
// label: "Min 1 number",
|
||||
// isCriteriaValid: (password: string) => PASSWORD_CHAR_CAPS_REGEX.test(password),
|
||||
// },
|
||||
// {
|
||||
// key: "min_1_special_char",
|
||||
// label: "Min 1 special character",
|
||||
// isCriteriaValid: (password: string) => PASSWORD_SPECIAL_CHAR_REGEX.test(password),
|
||||
// },
|
||||
];
|
||||
|
||||
export enum EAuthPageTypes {
|
||||
PUBLIC = "PUBLIC",
|
||||
NON_AUTHENTICATED = "NON_AUTHENTICATED",
|
||||
SET_PASSWORD = "SET_PASSWORD",
|
||||
ONBOARDING = "ONBOARDING",
|
||||
AUTHENTICATED = "AUTHENTICATED",
|
||||
}
|
||||
|
||||
export enum EPageTypes {
|
||||
INIT = "INIT",
|
||||
PUBLIC = "PUBLIC",
|
||||
NON_AUTHENTICATED = "NON_AUTHENTICATED",
|
||||
ONBOARDING = "ONBOARDING",
|
||||
AUTHENTICATED = "AUTHENTICATED",
|
||||
}
|
||||
|
||||
export enum EAuthModes {
|
||||
SIGN_IN = "SIGN_IN",
|
||||
SIGN_UP = "SIGN_UP",
|
||||
}
|
||||
|
||||
export enum EAuthSteps {
|
||||
EMAIL = "EMAIL",
|
||||
PASSWORD = "PASSWORD",
|
||||
UNIQUE_CODE = "UNIQUE_CODE",
|
||||
}
|
||||
|
||||
export enum EErrorAlertType {
|
||||
BANNER_ALERT = "BANNER_ALERT",
|
||||
TOAST_ALERT = "TOAST_ALERT",
|
||||
INLINE_FIRST_NAME = "INLINE_FIRST_NAME",
|
||||
INLINE_EMAIL = "INLINE_EMAIL",
|
||||
INLINE_PASSWORD = "INLINE_PASSWORD",
|
||||
INLINE_EMAIL_CODE = "INLINE_EMAIL_CODE",
|
||||
}
|
||||
|
||||
export type TAuthErrorInfo = {
|
||||
type: EErrorAlertType;
|
||||
code: EAuthErrorCodes;
|
||||
title: string;
|
||||
message: string | React.ReactNode;
|
||||
};
|
||||
|
||||
export enum EAdminAuthErrorCodes {
|
||||
// Admin
|
||||
ADMIN_ALREADY_EXIST = "5150",
|
||||
REQUIRED_ADMIN_EMAIL_PASSWORD_FIRST_NAME = "5155",
|
||||
INVALID_ADMIN_EMAIL = "5160",
|
||||
INVALID_ADMIN_PASSWORD = "5165",
|
||||
REQUIRED_ADMIN_EMAIL_PASSWORD = "5170",
|
||||
ADMIN_AUTHENTICATION_FAILED = "5175",
|
||||
ADMIN_USER_ALREADY_EXIST = "5180",
|
||||
ADMIN_USER_DOES_NOT_EXIST = "5185",
|
||||
ADMIN_USER_DEACTIVATED = "5190",
|
||||
}
|
||||
|
||||
export type TAdminAuthErrorInfo = {
|
||||
type: EErrorAlertType;
|
||||
code: EAdminAuthErrorCodes;
|
||||
title: string;
|
||||
message: string | React.ReactNode;
|
||||
};
|
||||
|
||||
export enum EAuthErrorCodes {
|
||||
// Global
|
||||
INSTANCE_NOT_CONFIGURED = "5000",
|
||||
INVALID_EMAIL = "5005",
|
||||
EMAIL_REQUIRED = "5010",
|
||||
SIGNUP_DISABLED = "5015",
|
||||
MAGIC_LINK_LOGIN_DISABLED = "5016",
|
||||
PASSWORD_LOGIN_DISABLED = "5018",
|
||||
USER_ACCOUNT_DEACTIVATED = "5019",
|
||||
// Password strength
|
||||
INVALID_PASSWORD = "5020",
|
||||
SMTP_NOT_CONFIGURED = "5025",
|
||||
// Sign Up
|
||||
USER_ALREADY_EXIST = "5030",
|
||||
AUTHENTICATION_FAILED_SIGN_UP = "5035",
|
||||
REQUIRED_EMAIL_PASSWORD_SIGN_UP = "5040",
|
||||
INVALID_EMAIL_SIGN_UP = "5045",
|
||||
INVALID_EMAIL_MAGIC_SIGN_UP = "5050",
|
||||
MAGIC_SIGN_UP_EMAIL_CODE_REQUIRED = "5055",
|
||||
// Sign In
|
||||
USER_DOES_NOT_EXIST = "5060",
|
||||
AUTHENTICATION_FAILED_SIGN_IN = "5065",
|
||||
REQUIRED_EMAIL_PASSWORD_SIGN_IN = "5070",
|
||||
INVALID_EMAIL_SIGN_IN = "5075",
|
||||
INVALID_EMAIL_MAGIC_SIGN_IN = "5080",
|
||||
MAGIC_SIGN_IN_EMAIL_CODE_REQUIRED = "5085",
|
||||
// Both Sign in and Sign up for magic
|
||||
INVALID_MAGIC_CODE_SIGN_IN = "5090",
|
||||
INVALID_MAGIC_CODE_SIGN_UP = "5092",
|
||||
EXPIRED_MAGIC_CODE_SIGN_IN = "5095",
|
||||
EXPIRED_MAGIC_CODE_SIGN_UP = "5097",
|
||||
EMAIL_CODE_ATTEMPT_EXHAUSTED_SIGN_IN = "5100",
|
||||
EMAIL_CODE_ATTEMPT_EXHAUSTED_SIGN_UP = "5102",
|
||||
// Oauth
|
||||
OAUTH_NOT_CONFIGURED = "5104",
|
||||
GOOGLE_NOT_CONFIGURED = "5105",
|
||||
GITHUB_NOT_CONFIGURED = "5110",
|
||||
GITLAB_NOT_CONFIGURED = "5111",
|
||||
GOOGLE_OAUTH_PROVIDER_ERROR = "5115",
|
||||
GITHUB_OAUTH_PROVIDER_ERROR = "5120",
|
||||
GITLAB_OAUTH_PROVIDER_ERROR = "5121",
|
||||
// Reset Password
|
||||
INVALID_PASSWORD_TOKEN = "5125",
|
||||
EXPIRED_PASSWORD_TOKEN = "5130",
|
||||
// Change password
|
||||
INCORRECT_OLD_PASSWORD = "5135",
|
||||
MISSING_PASSWORD = "5138",
|
||||
INVALID_NEW_PASSWORD = "5140",
|
||||
// set password
|
||||
PASSWORD_ALREADY_SET = "5145",
|
||||
// Admin
|
||||
ADMIN_ALREADY_EXIST = "5150",
|
||||
REQUIRED_ADMIN_EMAIL_PASSWORD_FIRST_NAME = "5155",
|
||||
INVALID_ADMIN_EMAIL = "5160",
|
||||
INVALID_ADMIN_PASSWORD = "5165",
|
||||
REQUIRED_ADMIN_EMAIL_PASSWORD = "5170",
|
||||
ADMIN_AUTHENTICATION_FAILED = "5175",
|
||||
ADMIN_USER_ALREADY_EXIST = "5180",
|
||||
ADMIN_USER_DOES_NOT_EXIST = "5185",
|
||||
ADMIN_USER_DEACTIVATED = "5190",
|
||||
// Rate limit
|
||||
RATE_LIMIT_EXCEEDED = "5900",
|
||||
}
|
||||
124
packages/constants/src/chart.ts
Normal file
124
packages/constants/src/chart.ts
Normal file
@@ -0,0 +1,124 @@
|
||||
import { ChartXAxisProperty, TChartColorScheme } from "@plane/types";
|
||||
|
||||
export const LABEL_CLASSNAME = "uppercase text-custom-text-300/60 text-sm tracking-wide";
|
||||
export const AXIS_LABEL_CLASSNAME = "uppercase text-custom-text-300/60 text-sm tracking-wide";
|
||||
|
||||
export enum ChartXAxisDateGrouping {
|
||||
DAY = "DAY",
|
||||
WEEK = "WEEK",
|
||||
MONTH = "MONTH",
|
||||
YEAR = "YEAR",
|
||||
}
|
||||
|
||||
export const TO_CAPITALIZE_PROPERTIES: ChartXAxisProperty[] = [
|
||||
ChartXAxisProperty.PRIORITY,
|
||||
ChartXAxisProperty.STATE_GROUPS,
|
||||
];
|
||||
|
||||
export const CHART_X_AXIS_DATE_PROPERTIES: ChartXAxisProperty[] = [
|
||||
ChartXAxisProperty.START_DATE,
|
||||
ChartXAxisProperty.TARGET_DATE,
|
||||
ChartXAxisProperty.CREATED_AT,
|
||||
ChartXAxisProperty.COMPLETED_AT,
|
||||
];
|
||||
|
||||
export enum EChartModels {
|
||||
BASIC = "BASIC",
|
||||
STACKED = "STACKED",
|
||||
GROUPED = "GROUPED",
|
||||
MULTI_LINE = "MULTI_LINE",
|
||||
COMPARISON = "COMPARISON",
|
||||
PROGRESS = "PROGRESS",
|
||||
}
|
||||
|
||||
export const CHART_COLOR_PALETTES: {
|
||||
key: TChartColorScheme;
|
||||
i18n_label: string;
|
||||
light: string[];
|
||||
dark: string[];
|
||||
}[] = [
|
||||
{
|
||||
key: "modern",
|
||||
i18n_label: "dashboards.widget.color_palettes.modern",
|
||||
light: [
|
||||
"#6172E8",
|
||||
"#8B6EDB",
|
||||
"#E05F99",
|
||||
"#29A383",
|
||||
"#CB8A37",
|
||||
"#3AA7C1",
|
||||
"#F1B24A",
|
||||
"#E84855",
|
||||
"#50C799",
|
||||
"#B35F9E",
|
||||
],
|
||||
dark: [
|
||||
"#6B7CDE",
|
||||
"#8E9DE6",
|
||||
"#D45D9E",
|
||||
"#2EAF85",
|
||||
"#D4A246",
|
||||
"#29A7C1",
|
||||
"#B89F6A",
|
||||
"#D15D64",
|
||||
"#4ED079",
|
||||
"#A169A4",
|
||||
],
|
||||
},
|
||||
{
|
||||
key: "horizon",
|
||||
i18n_label: "dashboards.widget.color_palettes.horizon",
|
||||
light: [
|
||||
"#E76E50",
|
||||
"#289D90",
|
||||
"#F3A362",
|
||||
"#E9C368",
|
||||
"#264753",
|
||||
"#8A6FA0",
|
||||
"#5B9EE5",
|
||||
"#7CC474",
|
||||
"#BA7DB5",
|
||||
"#CF8640",
|
||||
],
|
||||
dark: [
|
||||
"#E05A3A",
|
||||
"#1D8A7E",
|
||||
"#D98B4D",
|
||||
"#D1AC50",
|
||||
"#3A6B7C",
|
||||
"#7D6297",
|
||||
"#4D8ACD",
|
||||
"#569C64",
|
||||
"#C16A8C",
|
||||
"#B77436",
|
||||
],
|
||||
},
|
||||
{
|
||||
key: "earthen",
|
||||
i18n_label: "dashboards.widget.color_palettes.earthen",
|
||||
light: [
|
||||
"#386641",
|
||||
"#6A994E",
|
||||
"#A7C957",
|
||||
"#E97F4E",
|
||||
"#BC4749",
|
||||
"#9E2A2B",
|
||||
"#80CED1",
|
||||
"#5C3E79",
|
||||
"#526EAB",
|
||||
"#6B5B95",
|
||||
],
|
||||
dark: [
|
||||
"#497752",
|
||||
"#7BAA5F",
|
||||
"#B8DA68",
|
||||
"#FA905F",
|
||||
"#CD585A",
|
||||
"#AF3B3C",
|
||||
"#91DFE2",
|
||||
"#6D4F8A",
|
||||
"#637FBC",
|
||||
"#7C6CA6",
|
||||
],
|
||||
},
|
||||
];
|
||||
42
packages/constants/src/cycle.ts
Normal file
42
packages/constants/src/cycle.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
// types
|
||||
export const CYCLE_STATUS: {
|
||||
i18n_label: string;
|
||||
value: "current" | "upcoming" | "completed" | "draft";
|
||||
i18n_title: string;
|
||||
color: string;
|
||||
textColor: string;
|
||||
bgColor: string;
|
||||
}[] = [
|
||||
{
|
||||
i18n_label: "project_cycles.status.days_left",
|
||||
value: "current",
|
||||
i18n_title: "project_cycles.status.in_progress",
|
||||
color: "#F59E0B",
|
||||
textColor: "text-amber-500",
|
||||
bgColor: "bg-amber-50",
|
||||
},
|
||||
{
|
||||
i18n_label: "project_cycles.status.yet_to_start",
|
||||
value: "upcoming",
|
||||
i18n_title: "project_cycles.status.yet_to_start",
|
||||
color: "#3F76FF",
|
||||
textColor: "text-blue-500",
|
||||
bgColor: "bg-indigo-50",
|
||||
},
|
||||
{
|
||||
i18n_label: "project_cycles.status.completed",
|
||||
value: "completed",
|
||||
i18n_title: "project_cycles.status.completed",
|
||||
color: "#16A34A",
|
||||
textColor: "text-green-600",
|
||||
bgColor: "bg-green-50",
|
||||
},
|
||||
{
|
||||
i18n_label: "project_cycles.status.draft",
|
||||
value: "draft",
|
||||
i18n_title: "project_cycles.status.draft",
|
||||
color: "#525252",
|
||||
textColor: "text-custom-text-300",
|
||||
bgColor: "bg-custom-background-90",
|
||||
},
|
||||
];
|
||||
92
packages/constants/src/dashboard.ts
Normal file
92
packages/constants/src/dashboard.ts
Normal file
@@ -0,0 +1,92 @@
|
||||
// types
|
||||
import { TIssuesListTypes } from "@plane/types";
|
||||
|
||||
export enum EDurationFilters {
|
||||
NONE = "none",
|
||||
TODAY = "today",
|
||||
THIS_WEEK = "this_week",
|
||||
THIS_MONTH = "this_month",
|
||||
THIS_YEAR = "this_year",
|
||||
CUSTOM = "custom",
|
||||
}
|
||||
|
||||
// filter duration options
|
||||
export const DURATION_FILTER_OPTIONS: {
|
||||
key: EDurationFilters;
|
||||
label: string;
|
||||
}[] = [
|
||||
{
|
||||
key: EDurationFilters.NONE,
|
||||
label: "All time",
|
||||
},
|
||||
{
|
||||
key: EDurationFilters.TODAY,
|
||||
label: "Due today",
|
||||
},
|
||||
{
|
||||
key: EDurationFilters.THIS_WEEK,
|
||||
label: "Due this week",
|
||||
},
|
||||
{
|
||||
key: EDurationFilters.THIS_MONTH,
|
||||
label: "Due this month",
|
||||
},
|
||||
{
|
||||
key: EDurationFilters.THIS_YEAR,
|
||||
label: "Due this year",
|
||||
},
|
||||
{
|
||||
key: EDurationFilters.CUSTOM,
|
||||
label: "Custom",
|
||||
},
|
||||
];
|
||||
|
||||
// random background colors for project cards
|
||||
export const PROJECT_BACKGROUND_COLORS = [
|
||||
"bg-gray-500/20",
|
||||
"bg-green-500/20",
|
||||
"bg-red-500/20",
|
||||
"bg-orange-500/20",
|
||||
"bg-blue-500/20",
|
||||
"bg-yellow-500/20",
|
||||
"bg-pink-500/20",
|
||||
"bg-purple-500/20",
|
||||
];
|
||||
|
||||
// assigned and created issues widgets tabs list
|
||||
export const FILTERED_ISSUES_TABS_LIST: {
|
||||
key: TIssuesListTypes;
|
||||
label: string;
|
||||
}[] = [
|
||||
{
|
||||
key: "upcoming",
|
||||
label: "Upcoming",
|
||||
},
|
||||
{
|
||||
key: "overdue",
|
||||
label: "Overdue",
|
||||
},
|
||||
{
|
||||
key: "completed",
|
||||
label: "Marked completed",
|
||||
},
|
||||
];
|
||||
|
||||
// assigned and created issues widgets tabs list
|
||||
export const UNFILTERED_ISSUES_TABS_LIST: {
|
||||
key: TIssuesListTypes;
|
||||
label: string;
|
||||
}[] = [
|
||||
{
|
||||
key: "pending",
|
||||
label: "Pending",
|
||||
},
|
||||
{
|
||||
key: "completed",
|
||||
label: "Marked completed",
|
||||
},
|
||||
];
|
||||
|
||||
export type TLinkOptions = {
|
||||
userId: string | undefined;
|
||||
};
|
||||
25
packages/constants/src/emoji.ts
Normal file
25
packages/constants/src/emoji.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
export const ISSUE_REACTION_EMOJI_CODES = [
|
||||
"128077",
|
||||
"128078",
|
||||
"128516",
|
||||
"128165",
|
||||
"128533",
|
||||
"129505",
|
||||
"9992",
|
||||
"128064",
|
||||
];
|
||||
|
||||
export const RANDOM_EMOJI_CODES = [
|
||||
"8986",
|
||||
"9200",
|
||||
"128204",
|
||||
"127773",
|
||||
"127891",
|
||||
"128076",
|
||||
"128077",
|
||||
"128187",
|
||||
"128188",
|
||||
"128512",
|
||||
"128522",
|
||||
"128578",
|
||||
];
|
||||
27
packages/constants/src/endpoints.ts
Normal file
27
packages/constants/src/endpoints.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
export const API_BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL || "";
|
||||
export const API_BASE_PATH = process.env.NEXT_PUBLIC_API_BASE_PATH || "";
|
||||
export const API_URL = encodeURI(`${API_BASE_URL}${API_BASE_PATH}`);
|
||||
// God Mode Admin App Base Url
|
||||
export const ADMIN_BASE_URL = process.env.NEXT_PUBLIC_ADMIN_BASE_URL || "";
|
||||
export const ADMIN_BASE_PATH = process.env.NEXT_PUBLIC_ADMIN_BASE_PATH || "";
|
||||
export const GOD_MODE_URL = encodeURI(`${ADMIN_BASE_URL}${ADMIN_BASE_PATH}`);
|
||||
// Publish App Base Url
|
||||
export const SPACE_BASE_URL = process.env.NEXT_PUBLIC_SPACE_BASE_URL || "";
|
||||
export const SPACE_BASE_PATH = process.env.NEXT_PUBLIC_SPACE_BASE_PATH || "";
|
||||
export const SITES_URL = encodeURI(`${SPACE_BASE_URL}${SPACE_BASE_PATH}`);
|
||||
// Live App Base Url
|
||||
export const LIVE_BASE_URL = process.env.NEXT_PUBLIC_LIVE_BASE_URL || "";
|
||||
export const LIVE_BASE_PATH = process.env.NEXT_PUBLIC_LIVE_BASE_PATH || "";
|
||||
export const LIVE_URL = encodeURI(`${LIVE_BASE_URL}${LIVE_BASE_PATH}`);
|
||||
// Web App Base Url
|
||||
export const WEB_BASE_URL = process.env.NEXT_PUBLIC_WEB_BASE_URL || "";
|
||||
export const WEB_BASE_PATH = process.env.NEXT_PUBLIC_WEB_BASE_PATH || "";
|
||||
export const WEB_URL = encodeURI(`${WEB_BASE_URL}${WEB_BASE_PATH}`);
|
||||
// plane website url
|
||||
export const WEBSITE_URL = process.env.NEXT_PUBLIC_WEBSITE_URL || "https://plane.so";
|
||||
// support email
|
||||
export const SUPPORT_EMAIL = process.env.NEXT_PUBLIC_SUPPORT_EMAIL || "support@plane.so";
|
||||
// marketing links
|
||||
export const MARKETING_PRICING_PAGE_LINK = "https://plane.so/pricing";
|
||||
export const MARKETING_CONTACT_US_PAGE_LINK = "https://plane.so/contact";
|
||||
export const MARKETING_PLANE_ONE_PAGE_LINK = "https://plane.so/one";
|
||||
136
packages/constants/src/estimates.ts
Normal file
136
packages/constants/src/estimates.ts
Normal file
@@ -0,0 +1,136 @@
|
||||
// plane imports
|
||||
import { TEstimateSystems } from "@plane/types";
|
||||
|
||||
export const MAX_ESTIMATE_POINT_INPUT_LENGTH = 20;
|
||||
|
||||
export enum EEstimateSystem {
|
||||
POINTS = "points",
|
||||
CATEGORIES = "categories",
|
||||
TIME = "time",
|
||||
}
|
||||
|
||||
export enum EEstimateUpdateStages {
|
||||
CREATE = "create",
|
||||
EDIT = "edit",
|
||||
SWITCH = "switch",
|
||||
}
|
||||
|
||||
export const estimateCount = {
|
||||
min: 2,
|
||||
max: 6,
|
||||
};
|
||||
|
||||
export const ESTIMATE_SYSTEMS: TEstimateSystems = {
|
||||
points: {
|
||||
name: "Points",
|
||||
i18n_name: "project_settings.estimates.systems.points.label",
|
||||
templates: {
|
||||
fibonacci: {
|
||||
title: "Fibonacci",
|
||||
i18n_title: "project_settings.estimates.systems.points.fibonacci",
|
||||
values: [
|
||||
{ id: undefined, key: 1, value: "1" },
|
||||
{ id: undefined, key: 2, value: "2" },
|
||||
{ id: undefined, key: 3, value: "3" },
|
||||
{ id: undefined, key: 4, value: "5" },
|
||||
{ id: undefined, key: 5, value: "8" },
|
||||
{ id: undefined, key: 6, value: "13" },
|
||||
],
|
||||
},
|
||||
linear: {
|
||||
title: "Linear",
|
||||
i18n_title: "project_settings.estimates.systems.points.linear",
|
||||
values: [
|
||||
{ id: undefined, key: 1, value: "1" },
|
||||
{ id: undefined, key: 2, value: "2" },
|
||||
{ id: undefined, key: 3, value: "3" },
|
||||
{ id: undefined, key: 4, value: "4" },
|
||||
{ id: undefined, key: 5, value: "5" },
|
||||
{ id: undefined, key: 6, value: "6" },
|
||||
],
|
||||
},
|
||||
squares: {
|
||||
title: "Squares",
|
||||
i18n_title: "project_settings.estimates.systems.points.squares",
|
||||
values: [
|
||||
{ id: undefined, key: 1, value: "1" },
|
||||
{ id: undefined, key: 2, value: "4" },
|
||||
{ id: undefined, key: 3, value: "9" },
|
||||
{ id: undefined, key: 4, value: "16" },
|
||||
{ id: undefined, key: 5, value: "25" },
|
||||
{ id: undefined, key: 6, value: "36" },
|
||||
],
|
||||
},
|
||||
custom: {
|
||||
title: "Custom",
|
||||
i18n_title: "project_settings.estimates.systems.points.custom",
|
||||
values: [
|
||||
{ id: undefined, key: 1, value: "1" },
|
||||
{ id: undefined, key: 2, value: "2" },
|
||||
],
|
||||
hide: true,
|
||||
},
|
||||
},
|
||||
is_available: true,
|
||||
is_ee: false,
|
||||
},
|
||||
categories: {
|
||||
name: "Categories",
|
||||
i18n_name: "project_settings.estimates.systems.categories.label",
|
||||
templates: {
|
||||
t_shirt_sizes: {
|
||||
title: "T-Shirt Sizes",
|
||||
i18n_title: "project_settings.estimates.systems.categories.t_shirt_sizes",
|
||||
values: [
|
||||
{ id: undefined, key: 1, value: "XS" },
|
||||
{ id: undefined, key: 2, value: "S" },
|
||||
{ id: undefined, key: 3, value: "M" },
|
||||
{ id: undefined, key: 4, value: "L" },
|
||||
{ id: undefined, key: 5, value: "XL" },
|
||||
{ id: undefined, key: 6, value: "XXL" },
|
||||
],
|
||||
},
|
||||
easy_to_hard: {
|
||||
title: "Easy to hard",
|
||||
i18n_title: "project_settings.estimates.systems.categories.easy_to_hard",
|
||||
values: [
|
||||
{ id: undefined, key: 1, value: "Easy" },
|
||||
{ id: undefined, key: 2, value: "Medium" },
|
||||
{ id: undefined, key: 3, value: "Hard" },
|
||||
{ id: undefined, key: 4, value: "Very Hard" },
|
||||
],
|
||||
},
|
||||
custom: {
|
||||
title: "Custom",
|
||||
i18n_title: "project_settings.estimates.systems.categories.custom",
|
||||
values: [
|
||||
{ id: undefined, key: 1, value: "Easy" },
|
||||
{ id: undefined, key: 2, value: "Hard" },
|
||||
],
|
||||
hide: true,
|
||||
},
|
||||
},
|
||||
is_available: true,
|
||||
is_ee: false,
|
||||
},
|
||||
time: {
|
||||
name: "Time",
|
||||
i18n_name: "project_settings.estimates.systems.time.label",
|
||||
templates: {
|
||||
hours: {
|
||||
title: "Hours",
|
||||
i18n_title: "project_settings.estimates.systems.time.hours",
|
||||
values: [
|
||||
{ id: undefined, key: 1, value: "1" },
|
||||
{ id: undefined, key: 2, value: "2" },
|
||||
{ id: undefined, key: 3, value: "3" },
|
||||
{ id: undefined, key: 4, value: "4" },
|
||||
{ id: undefined, key: 5, value: "5" },
|
||||
{ id: undefined, key: 6, value: "6" },
|
||||
],
|
||||
},
|
||||
},
|
||||
is_available: true,
|
||||
is_ee: true,
|
||||
},
|
||||
};
|
||||
502
packages/constants/src/event-tracker/core.ts
Normal file
502
packages/constants/src/event-tracker/core.ts
Normal file
@@ -0,0 +1,502 @@
|
||||
import { EProductSubscriptionEnum } from "@plane/types";
|
||||
|
||||
/**
|
||||
* ===========================================================================
|
||||
* Event Groups
|
||||
* ===========================================================================
|
||||
*/
|
||||
export const GROUP_WORKSPACE_TRACKER_EVENT = "workspace_metrics";
|
||||
export const GITHUB_REDIRECTED_TRACKER_EVENT = "github_redirected";
|
||||
export const HEADER_GITHUB_ICON = "header_github_icon";
|
||||
|
||||
/**
|
||||
* ===========================================================================
|
||||
* Command palette tracker
|
||||
* ===========================================================================
|
||||
*/
|
||||
export const COMMAND_PALETTE_TRACKER_ELEMENTS = {
|
||||
COMMAND_PALETTE_SHORTCUT_KEY: "command_palette_shortcut_key",
|
||||
};
|
||||
|
||||
/**
|
||||
* ===========================================================================
|
||||
* Workspace Events and Elements
|
||||
* ===========================================================================
|
||||
*/
|
||||
export const WORKSPACE_TRACKER_EVENTS = {
|
||||
create: "workspace_created",
|
||||
update: "workspace_updated",
|
||||
delete: "workspace_deleted",
|
||||
};
|
||||
|
||||
export const WORKSPACE_TRACKER_ELEMENTS = {
|
||||
DELETE_WORKSPACE_BUTTON: "delete_workspace_button",
|
||||
ONBOARDING_CREATE_WORKSPACE_BUTTON: "onboarding_create_workspace_button",
|
||||
CREATE_WORKSPACE_BUTTON: "create_workspace_button",
|
||||
UPDATE_WORKSPACE_BUTTON: "update_workspace_button",
|
||||
};
|
||||
|
||||
/**
|
||||
* ===========================================================================
|
||||
* Project Events and Elements
|
||||
* ===========================================================================
|
||||
*/
|
||||
export const PROJECT_TRACKER_EVENTS = {
|
||||
create: "project_created",
|
||||
update: "project_updated",
|
||||
delete: "project_deleted",
|
||||
feature_toggled: "feature_toggled",
|
||||
};
|
||||
|
||||
export const PROJECT_TRACKER_ELEMENTS = {
|
||||
EXTENDED_SIDEBAR_ADD_BUTTON: "extended_sidebar_add_project_button",
|
||||
SIDEBAR_CREATE_PROJECT_BUTTON: "sidebar_create_project_button",
|
||||
SIDEBAR_CREATE_PROJECT_TOOLTIP: "sidebar_create_project_tooltip",
|
||||
COMMAND_PALETTE_CREATE_BUTTON: "command_palette_create_project_button",
|
||||
COMMAND_PALETTE_SHORTCUT_CREATE_BUTTON: "command_palette_shortcut_create_project_button",
|
||||
EMPTY_STATE_CREATE_PROJECT_BUTTON: "empty_state_create_project_button",
|
||||
CREATE_HEADER_BUTTON: "create_project_header_button",
|
||||
CREATE_FIRST_PROJECT_BUTTON: "create_first_project_button",
|
||||
DELETE_PROJECT_BUTTON: "delete_project_button",
|
||||
UPDATE_PROJECT_BUTTON: "update_project_button",
|
||||
CREATE_PROJECT_JIRA_IMPORT_DETAIL_PAGE: "create_project_jira_import_detail_page",
|
||||
TOGGLE_FEATURE: "toggle_project_feature",
|
||||
};
|
||||
|
||||
/**
|
||||
* ===========================================================================
|
||||
* Cycle Events and Elements
|
||||
* ===========================================================================
|
||||
*/
|
||||
export const CYCLE_TRACKER_EVENTS = {
|
||||
create: "cycle_created",
|
||||
update: "cycle_updated",
|
||||
delete: "cycle_deleted",
|
||||
favorite: "cycle_favorited",
|
||||
unfavorite: "cycle_unfavorited",
|
||||
archive: "cycle_archived",
|
||||
restore: "cycle_restored",
|
||||
};
|
||||
|
||||
export const CYCLE_TRACKER_ELEMENTS = {
|
||||
RIGHT_HEADER_ADD_BUTTON: "right_header_add_cycle_button",
|
||||
EMPTY_STATE_ADD_BUTTON: "empty_state_add_cycle_button",
|
||||
COMMAND_PALETTE_ADD_ITEM: "command_palette_add_cycle_item",
|
||||
RIGHT_SIDEBAR: "cycle_right_sidebar",
|
||||
QUICK_ACTIONS: "cycle_quick_actions",
|
||||
CONTEXT_MENU: "cycle_context_menu",
|
||||
LIST_ITEM: "cycle_list_item",
|
||||
} as const;
|
||||
|
||||
/**
|
||||
* ===========================================================================
|
||||
* Module Events and Elements
|
||||
* ===========================================================================
|
||||
*/
|
||||
export const MODULE_TRACKER_EVENTS = {
|
||||
create: "module_created",
|
||||
update: "module_updated",
|
||||
delete: "module_deleted",
|
||||
favorite: "module_favorited",
|
||||
unfavorite: "module_unfavorited",
|
||||
archive: "module_archived",
|
||||
restore: "module_restored",
|
||||
link: {
|
||||
create: "module_link_created",
|
||||
update: "module_link_updated",
|
||||
delete: "module_link_deleted",
|
||||
},
|
||||
};
|
||||
|
||||
export const MODULE_TRACKER_ELEMENTS = {
|
||||
RIGHT_HEADER_ADD_BUTTON: "right_header_add_module_button",
|
||||
EMPTY_STATE_ADD_BUTTON: "empty_state_add_module_button",
|
||||
COMMAND_PALETTE_ADD_ITEM: "command_palette_add_module_item",
|
||||
RIGHT_SIDEBAR: "module_right_sidebar",
|
||||
QUICK_ACTIONS: "module_quick_actions",
|
||||
CONTEXT_MENU: "module_context_menu",
|
||||
LIST_ITEM: "module_list_item",
|
||||
CARD_ITEM: "module_card_item",
|
||||
} as const;
|
||||
|
||||
/**
|
||||
* ===========================================================================
|
||||
* Work Item Events and Elements
|
||||
* ===========================================================================
|
||||
*/
|
||||
export const WORK_ITEM_TRACKER_EVENTS = {
|
||||
create: "work_item_created",
|
||||
add_existing: "work_item_add_existing",
|
||||
update: "work_item_updated",
|
||||
delete: "work_item_deleted",
|
||||
archive: "work_item_archived",
|
||||
restore: "work_item_restored",
|
||||
attachment: {
|
||||
add: "work_item_attachment_added",
|
||||
remove: "work_item_attachment_removed",
|
||||
},
|
||||
sub_issue: {
|
||||
update: "sub_issue_updated",
|
||||
remove: "sub_issue_removed",
|
||||
delete: "sub_issue_deleted",
|
||||
create: "sub_issue_created",
|
||||
add_existing: "sub_issue_add_existing",
|
||||
},
|
||||
draft: {
|
||||
create: "draft_work_item_created",
|
||||
},
|
||||
};
|
||||
export const WORK_ITEM_TRACKER_ELEMENTS = {
|
||||
HEADER_ADD_BUTTON: {
|
||||
WORK_ITEMS: "work_items_header_add_work_item_button",
|
||||
PROJECT_VIEW: "project_view_header_add_work_item_button",
|
||||
CYCLE: "cycle_header_add_work_item_button",
|
||||
MODULE: "module_header_add_work_item_button",
|
||||
},
|
||||
COMMAND_PALETTE_ADD_BUTTON: "command_palette_add_work_item_button",
|
||||
EMPTY_STATE_ADD_BUTTON: {
|
||||
WORK_ITEMS: "work_items_empty_state_add_work_item_button",
|
||||
PROJECT_VIEW: "project_view_empty_state_add_work_item_button",
|
||||
CYCLE: "cycle_empty_state_add_work_item_button",
|
||||
MODULE: "module_empty_state_add_work_item_button",
|
||||
GLOBAL_VIEW: "global_view_empty_state_add_work_item_button",
|
||||
},
|
||||
QUICK_ACTIONS: {
|
||||
WORK_ITEMS: "work_items_quick_actions",
|
||||
PROJECT_VIEW: "project_view_work_items_quick_actions",
|
||||
CYCLE: "cycle_work_items_quick_actions",
|
||||
MODULE: "module_work_items_quick_actions",
|
||||
GLOBAL_VIEW: "global_view_work_items_quick_actions",
|
||||
ARCHIVED: "archived_work_items_quick_actions",
|
||||
DRAFT: "draft_work_items_quick_actions",
|
||||
},
|
||||
CONTEXT_MENU: {
|
||||
WORK_ITEMS: "work_items_context_menu",
|
||||
PROJECT_VIEW: "project_view_context_menu",
|
||||
CYCLE: "cycle_context_menu",
|
||||
MODULE: "module_context_menu",
|
||||
GLOBAL_VIEW: "global_view_context_menu",
|
||||
ARCHIVED: "archived_context_menu",
|
||||
DRAFT: "draft_context_menu",
|
||||
},
|
||||
} as const;
|
||||
|
||||
/**
|
||||
* ===========================================================================
|
||||
* State Events and Elements
|
||||
* ===========================================================================
|
||||
*/
|
||||
export const STATE_TRACKER_EVENTS = {
|
||||
create: "state_created",
|
||||
update: "state_updated",
|
||||
delete: "state_deleted",
|
||||
};
|
||||
export const STATE_TRACKER_ELEMENTS = {
|
||||
STATE_GROUP_ADD_BUTTON: "state_group_add_button",
|
||||
STATE_LIST_DELETE_BUTTON: "state_list_delete_button",
|
||||
STATE_LIST_EDIT_BUTTON: "state_list_edit_button",
|
||||
};
|
||||
|
||||
/**
|
||||
* ===========================================================================
|
||||
* Project Page Events and Elements
|
||||
* ===========================================================================
|
||||
*/
|
||||
export const PROJECT_PAGE_TRACKER_EVENTS = {
|
||||
create: "project_page_created",
|
||||
update: "project_page_updated",
|
||||
delete: "project_page_deleted",
|
||||
archive: "project_page_archived",
|
||||
restore: "project_page_restored",
|
||||
lock: "project_page_locked",
|
||||
unlock: "project_page_unlocked",
|
||||
access_update: "project_page_access_updated",
|
||||
duplicate: "project_page_duplicated",
|
||||
favorite: "project_page_favorited",
|
||||
unfavorite: "project_page_unfavorited",
|
||||
move: "project_page_moved",
|
||||
};
|
||||
export const PROJECT_PAGE_TRACKER_ELEMENTS = {
|
||||
COMMAND_PALETTE_SHORTCUT_CREATE_BUTTON: "command_palette_shortcut_create_page_button",
|
||||
EMPTY_STATE_CREATE_BUTTON: "empty_state_create_page_button",
|
||||
COMMAND_PALETTE_CREATE_BUTTON: "command_palette_create_page_button",
|
||||
CONTEXT_MENU: "page_context_menu",
|
||||
QUICK_ACTIONS: "page_quick_actions",
|
||||
LIST_ITEM: "page_list_item",
|
||||
FAVORITE_BUTTON: "page_favorite_button",
|
||||
ARCHIVE_BUTTON: "page_archive_button",
|
||||
LOCK_BUTTON: "page_lock_button",
|
||||
ACCESS_TOGGLE: "page_access_toggle",
|
||||
DUPLICATE_BUTTON: "page_duplicate_button",
|
||||
} as const;
|
||||
|
||||
/**
|
||||
* ===========================================================================
|
||||
* Member Events and Elements
|
||||
* ===========================================================================
|
||||
*/
|
||||
export const MEMBER_TRACKER_EVENTS = {
|
||||
invite: "member_invited",
|
||||
accept: "member_accepted",
|
||||
project: {
|
||||
add: "project_member_added",
|
||||
leave: "project_member_left",
|
||||
},
|
||||
workspace: {
|
||||
leave: "workspace_member_left",
|
||||
},
|
||||
};
|
||||
export const MEMBER_TRACKER_ELEMENTS = {
|
||||
HEADER_ADD_BUTTON: "header_add_member_button",
|
||||
ACCEPT_INVITATION_BUTTON: "accept_invitation_button",
|
||||
ONBOARDING_JOIN_WORKSPACE: "workspace_join_continue_to_workspace_button",
|
||||
ONBOARDING_INVITE_MEMBER: "invite_member_continue_button",
|
||||
SIDEBAR_PROJECT_QUICK_ACTIONS: "sidebar_project_quick_actions",
|
||||
PROJECT_MEMBER_TABLE_CONTEXT_MENU: "project_member_table_context_menu",
|
||||
WORKSPACE_MEMBER_TABLE_CONTEXT_MENU: "workspace_member_table_context_menu",
|
||||
WORKSPACE_INVITATIONS_LIST_CONTEXT_MENU: "workspace_invitations_list_context_menu",
|
||||
} as const;
|
||||
|
||||
/**
|
||||
* ===========================================================================
|
||||
* Auth Events and Elements
|
||||
* ===========================================================================
|
||||
*/
|
||||
export const AUTH_TRACKER_EVENTS = {
|
||||
code_verify: "code_verified",
|
||||
sign_up_with_password: "sign_up_with_password",
|
||||
sign_in_with_password: "sign_in_with_password",
|
||||
forgot_password: "forgot_password_clicked",
|
||||
new_code_requested: "new_code_requested",
|
||||
password_created: "password_created",
|
||||
};
|
||||
|
||||
export const AUTH_TRACKER_ELEMENTS = {
|
||||
NAVIGATE_TO_SIGN_UP: "navigate_to_sign_up",
|
||||
FORGOT_PASSWORD_FROM_SIGNIN: "forgot_password_from_signin",
|
||||
SIGNUP_FROM_FORGOT_PASSWORD: "signup_from_forgot_password",
|
||||
SIGN_IN_FROM_SIGNUP: "sign_in_from_signup",
|
||||
SIGN_IN_WITH_UNIQUE_CODE: "sign_in_with_unique_code",
|
||||
REQUEST_NEW_CODE: "request_new_code",
|
||||
VERIFY_CODE: "verify_code",
|
||||
SET_PASSWORD_FORM: "set_password_form",
|
||||
};
|
||||
|
||||
/**
|
||||
* ===========================================================================
|
||||
* Global View Events and Elements
|
||||
* ===========================================================================
|
||||
*/
|
||||
export const GLOBAL_VIEW_TRACKER_EVENTS = {
|
||||
create: "global_view_created",
|
||||
update: "global_view_updated",
|
||||
delete: "global_view_deleted",
|
||||
open: "global_view_opened",
|
||||
};
|
||||
|
||||
export const GLOBAL_VIEW_TRACKER_ELEMENTS = {
|
||||
RIGHT_HEADER_ADD_BUTTON: "global_view_right_header_add_button",
|
||||
HEADER_SAVE_VIEW_BUTTON: "global_view_header_save_view_button",
|
||||
QUICK_ACTIONS: "global_view_quick_actions",
|
||||
LIST_ITEM: "global_view_list_item",
|
||||
};
|
||||
|
||||
/**
|
||||
* ===========================================================================
|
||||
* Project View Events and Elements
|
||||
* ===========================================================================
|
||||
*/
|
||||
export const PROJECT_VIEW_TRACKER_EVENTS = {
|
||||
create: "project_view_created",
|
||||
update: "project_view_updated",
|
||||
delete: "project_view_deleted",
|
||||
};
|
||||
|
||||
export const PROJECT_VIEW_TRACKER_ELEMENTS = {
|
||||
RIGHT_HEADER_ADD_BUTTON: "project_view_right_header_add_button",
|
||||
COMMAND_PALETTE_ADD_ITEM: "command_palette_add_project_view_item",
|
||||
EMPTY_STATE_CREATE_BUTTON: "project_view_empty_state_create_button",
|
||||
HEADER_SAVE_VIEW_BUTTON: "project_view_header_save_view_button",
|
||||
PROJECT_HEADER_SAVE_AS_VIEW_BUTTON: "project_view_header_save_as_view_button",
|
||||
CYCLE_HEADER_SAVE_AS_VIEW_BUTTON: "cycle_header_save_as_view_button",
|
||||
MODULE_HEADER_SAVE_AS_VIEW_BUTTON: "module_header_save_as_view_button",
|
||||
QUICK_ACTIONS: "project_view_quick_actions",
|
||||
LIST_ITEM_CONTEXT_MENU: "project_view_list_item_context_menu",
|
||||
};
|
||||
|
||||
/**
|
||||
* ===========================================================================
|
||||
* Product Tour Events and Elements
|
||||
* ===========================================================================
|
||||
*/
|
||||
export const PRODUCT_TOUR_TRACKER_EVENTS = {
|
||||
complete: "product_tour_completed",
|
||||
};
|
||||
|
||||
export const PRODUCT_TOUR_TRACKER_ELEMENTS = {
|
||||
START_BUTTON: "product_tour_start_button",
|
||||
SKIP_BUTTON: "product_tour_skip_button",
|
||||
CREATE_PROJECT_BUTTON: "product_tour_create_project_button",
|
||||
};
|
||||
|
||||
/**
|
||||
* ===========================================================================
|
||||
* Notification Events and Elements
|
||||
* ===========================================================================
|
||||
*/
|
||||
export const NOTIFICATION_TRACKER_EVENTS = {
|
||||
archive: "notification_archived",
|
||||
unarchive: "notification_unarchived",
|
||||
mark_read: "notification_marked_read",
|
||||
mark_unread: "notification_marked_unread",
|
||||
all_marked_read: "all_notifications_marked_read",
|
||||
};
|
||||
|
||||
export const NOTIFICATION_TRACKER_ELEMENTS = {
|
||||
MARK_ALL_AS_READ_BUTTON: "mark_all_as_read_button",
|
||||
ARCHIVE_UNARCHIVE_BUTTON: "archive_unarchive_button",
|
||||
MARK_READ_UNREAD_BUTTON: "mark_read_unread_button",
|
||||
};
|
||||
|
||||
/**
|
||||
* ===========================================================================
|
||||
* User Events
|
||||
* ===========================================================================
|
||||
*/
|
||||
export const USER_TRACKER_EVENTS = {
|
||||
add_details: "user_details_added",
|
||||
onboarding_complete: "user_onboarding_completed",
|
||||
};
|
||||
|
||||
export const USER_TRACKER_ELEMENTS = {
|
||||
PRODUCT_CHANGELOG_MODAL: "product_changelog_modal",
|
||||
CHANGELOG_REDIRECTED: "changelog_redirected",
|
||||
};
|
||||
|
||||
/**
|
||||
* ===========================================================================
|
||||
* Onboarding Events and Elements
|
||||
* ===========================================================================
|
||||
*/
|
||||
export const ONBOARDING_TRACKER_ELEMENTS = {
|
||||
PROFILE_SETUP_FORM: "onboarding_profile_setup_form",
|
||||
PASSWORD_CREATION_SELECTED: "onboarding_password_creation_selected",
|
||||
PASSWORD_CREATION_SKIPPED: "onboarding_password_creation_skipped",
|
||||
};
|
||||
|
||||
/**
|
||||
* ===========================================================================
|
||||
* Sidebar Events
|
||||
* ===========================================================================
|
||||
*/
|
||||
export const SIDEBAR_TRACKER_ELEMENTS = {
|
||||
USER_MENU_ITEM: "sidenav_user_menu_item",
|
||||
CREATE_WORK_ITEM_BUTTON: "sidebar_create_work_item_button",
|
||||
};
|
||||
|
||||
/**
|
||||
* ===========================================================================
|
||||
* Project Settings Events and Elements
|
||||
* ===========================================================================
|
||||
*/
|
||||
export const PROJECT_SETTINGS_TRACKER_ELEMENTS = {
|
||||
LABELS_EMPTY_STATE_CREATE_BUTTON: "labels_empty_state_create_button",
|
||||
LABELS_HEADER_CREATE_BUTTON: "labels_header_create_button",
|
||||
LABELS_CONTEXT_MENU: "labels_context_menu",
|
||||
LABELS_DELETE_BUTTON: "labels_delete_button",
|
||||
ESTIMATES_TOGGLE_BUTTON: "estimates_toggle_button",
|
||||
ESTIMATES_EMPTY_STATE_CREATE_BUTTON: "estimates_empty_state_create_button",
|
||||
ESTIMATES_LIST_ITEM: "estimates_list_item",
|
||||
AUTOMATIONS_ARCHIVE_TOGGLE_BUTTON: "automations_archive_toggle_button",
|
||||
AUTOMATIONS_CLOSE_TOGGLE_BUTTON: "automations_close_toggle_button",
|
||||
};
|
||||
|
||||
export const PROJECT_SETTINGS_TRACKER_EVENTS = {
|
||||
// labels
|
||||
label_created: "label_created",
|
||||
label_updated: "label_updated",
|
||||
label_deleted: "label_deleted",
|
||||
// estimates
|
||||
estimate_created: "estimate_created",
|
||||
estimate_updated: "estimate_updated",
|
||||
estimate_deleted: "estimate_deleted",
|
||||
estimates_toggle: "estimates_toggled",
|
||||
// automations
|
||||
auto_close_workitems: "auto_close_workitems",
|
||||
auto_archive_workitems: "auto_archive_workitems",
|
||||
};
|
||||
|
||||
/**
|
||||
* ===========================================================================
|
||||
* Profile Settings Events and Elements
|
||||
* ===========================================================================
|
||||
*/
|
||||
export const PROFILE_SETTINGS_TRACKER_EVENTS = {
|
||||
// Account
|
||||
deactivate_account: "deactivate_account",
|
||||
update_profile: "update_profile",
|
||||
// Preferences
|
||||
first_day_updated: "first_day_updated",
|
||||
language_updated: "language_updated",
|
||||
timezone_updated: "timezone_updated",
|
||||
theme_updated: "theme_updated",
|
||||
// Notifications
|
||||
notifications_updated: "notifications_updated",
|
||||
// PAT
|
||||
pat_created: "pat_created",
|
||||
pat_deleted: "pat_deleted",
|
||||
};
|
||||
|
||||
export const PROFILE_SETTINGS_TRACKER_ELEMENTS = {
|
||||
// Account
|
||||
SAVE_CHANGES_BUTTON: "save_changes_button",
|
||||
DEACTIVATE_ACCOUNT_BUTTON: "deactivate_account_button",
|
||||
// Preferences
|
||||
THEME_DROPDOWN: "preferences_theme_dropdown",
|
||||
FIRST_DAY_OF_WEEK_DROPDOWN: "preferences_first_day_of_week_dropdown",
|
||||
LANGUAGE_DROPDOWN: "preferences_language_dropdown",
|
||||
TIMEZONE_DROPDOWN: "preferences_timezone_dropdown",
|
||||
// Notifications
|
||||
PROPERTY_CHANGES_TOGGLE: "notifications_property_changes_toggle",
|
||||
STATE_CHANGES_TOGGLE: "notifications_state_changes_toggle",
|
||||
COMMENTS_TOGGLE: "notifications_comments_toggle",
|
||||
MENTIONS_TOGGLE: "notifications_mentions_toggle",
|
||||
// PAT
|
||||
HEADER_ADD_PAT_BUTTON: "header_add_pat_button",
|
||||
EMPTY_STATE_ADD_PAT_BUTTON: "empty_state_add_pat_button",
|
||||
LIST_ITEM_DELETE_ICON: "list_item_delete_icon",
|
||||
};
|
||||
|
||||
/**
|
||||
* ===========================================================================
|
||||
* Workspace Settings Events and Elements
|
||||
* ===========================================================================
|
||||
*/
|
||||
export const WORKSPACE_SETTINGS_TRACKER_EVENTS = {
|
||||
// Billing
|
||||
upgrade_plan_redirected: "upgrade_plan_redirected",
|
||||
// Exports
|
||||
csv_exported: "csv_exported",
|
||||
// Webhooks
|
||||
webhook_created: "webhook_created",
|
||||
webhook_deleted: "webhook_deleted",
|
||||
webhook_toggled: "webhook_toggled",
|
||||
webhook_details_page_toggled: "webhook_details_page_toggled",
|
||||
webhook_updated: "webhook_updated",
|
||||
};
|
||||
|
||||
export const WORKSPACE_SETTINGS_TRACKER_ELEMENTS = {
|
||||
// Billing
|
||||
BILLING_UPGRADE_BUTTON: (subscriptionType: EProductSubscriptionEnum) => `billing_upgrade_${subscriptionType}_button`,
|
||||
BILLING_TALK_TO_SALES_BUTTON: "billing_talk_to_sales_button",
|
||||
// Exports
|
||||
EXPORT_BUTTON: "export_button",
|
||||
// Webhooks
|
||||
HEADER_ADD_WEBHOOK_BUTTON: "header_add_webhook_button",
|
||||
EMPTY_STATE_ADD_WEBHOOK_BUTTON: "empty_state_add_webhook_button",
|
||||
LIST_ITEM_DELETE_BUTTON: "list_item_delete_button",
|
||||
WEBHOOK_LIST_ITEM_TOGGLE_SWITCH: "webhook_list_item_toggle_switch",
|
||||
WEBHOOK_DETAILS_PAGE_TOGGLE_SWITCH: "webhook_details_page_toggle_switch",
|
||||
WEBHOOK_DELETE_BUTTON: "webhook_delete_button",
|
||||
WEBHOOK_UPDATE_BUTTON: "webhook_update_button",
|
||||
};
|
||||
1
packages/constants/src/event-tracker/index.ts
Normal file
1
packages/constants/src/event-tracker/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from "./core";
|
||||
14
packages/constants/src/file.ts
Normal file
14
packages/constants/src/file.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
export const MAX_FILE_SIZE = 5 * 1024 * 1024; // 5MB
|
||||
|
||||
export const ACCEPTED_AVATAR_IMAGE_MIME_TYPES_FOR_REACT_DROPZONE = {
|
||||
"image/jpeg": [],
|
||||
"image/jpg": [],
|
||||
"image/png": [],
|
||||
"image/webp": [],
|
||||
};
|
||||
export const ACCEPTED_COVER_IMAGE_MIME_TYPES_FOR_REACT_DROPZONE = {
|
||||
"image/jpeg": [],
|
||||
"image/jpg": [],
|
||||
"image/png": [],
|
||||
"image/webp": [],
|
||||
};
|
||||
57
packages/constants/src/filter.ts
Normal file
57
packages/constants/src/filter.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
export enum E_SORT_ORDER {
|
||||
ASC = "asc",
|
||||
DESC = "desc",
|
||||
}
|
||||
export const DATE_AFTER_FILTER_OPTIONS = [
|
||||
{
|
||||
name: "1 week from now",
|
||||
value: "1_weeks;after;fromnow",
|
||||
},
|
||||
{
|
||||
name: "2 weeks from now",
|
||||
value: "2_weeks;after;fromnow",
|
||||
},
|
||||
{
|
||||
name: "1 month from now",
|
||||
value: "1_months;after;fromnow",
|
||||
},
|
||||
{
|
||||
name: "2 months from now",
|
||||
value: "2_months;after;fromnow",
|
||||
},
|
||||
];
|
||||
|
||||
export const DATE_BEFORE_FILTER_OPTIONS = [
|
||||
{
|
||||
name: "1 week ago",
|
||||
value: "1_weeks;before;fromnow",
|
||||
},
|
||||
{
|
||||
name: "2 weeks ago",
|
||||
value: "2_weeks;before;fromnow",
|
||||
},
|
||||
{
|
||||
name: "1 month ago",
|
||||
i18n_name: "date_filters.1_month_ago",
|
||||
value: "1_months;before;fromnow",
|
||||
},
|
||||
];
|
||||
|
||||
export const PROJECT_CREATED_AT_FILTER_OPTIONS = [
|
||||
{
|
||||
name: "Today",
|
||||
value: "today;custom;custom",
|
||||
},
|
||||
{
|
||||
name: "Yesterday",
|
||||
value: "yesterday;custom;custom",
|
||||
},
|
||||
{
|
||||
name: "Last 7 days",
|
||||
value: "last_7_days;custom;custom",
|
||||
},
|
||||
{
|
||||
name: "Last 30 days",
|
||||
value: "last_30_days;custom;custom",
|
||||
},
|
||||
];
|
||||
34
packages/constants/src/graph.ts
Normal file
34
packages/constants/src/graph.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
export const CHARTS_THEME = {
|
||||
background: "transparent",
|
||||
text: {
|
||||
color: "rgb(var(--color-text-200))",
|
||||
},
|
||||
axis: {
|
||||
domain: {
|
||||
line: {
|
||||
stroke: "rgb(var(--color-background-80))",
|
||||
strokeWidth: 0.5,
|
||||
},
|
||||
},
|
||||
},
|
||||
tooltip: {
|
||||
container: {
|
||||
background: "rgb(var(--color-background-80))",
|
||||
color: "rgb(var(--color-text-200))",
|
||||
fontSize: "0.8rem",
|
||||
border: "1px solid rgb(var(--color-border-300))",
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
line: {
|
||||
stroke: "rgb(var(--color-border-100))",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const CHART_DEFAULT_MARGIN = {
|
||||
top: 50,
|
||||
right: 50,
|
||||
bottom: 50,
|
||||
left: 50,
|
||||
};
|
||||
7
packages/constants/src/icon.ts
Normal file
7
packages/constants/src/icon.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export enum EIconSize {
|
||||
XS = "xs",
|
||||
SM = "sm",
|
||||
MD = "md",
|
||||
LG = "lg",
|
||||
XL = "xl",
|
||||
}
|
||||
40
packages/constants/src/index.ts
Normal file
40
packages/constants/src/index.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
export * from "./ai";
|
||||
export * from "./analytics";
|
||||
export * from "./auth";
|
||||
export * from "./chart";
|
||||
export * from "./cycle";
|
||||
export * from "./dashboard";
|
||||
export * from "./emoji";
|
||||
export * from "./endpoints";
|
||||
export * from "./estimates";
|
||||
export * from "./event-tracker";
|
||||
export * from "./file";
|
||||
export * from "./filter";
|
||||
export * from "./graph";
|
||||
export * from "./icon";
|
||||
export * from "./instance";
|
||||
export * from "./intake";
|
||||
export * from "./issue";
|
||||
export * from "./members";
|
||||
export * from "./label";
|
||||
export * from "./metadata";
|
||||
export * from "./module";
|
||||
export * from "./notification";
|
||||
export * from "./page";
|
||||
export * from "./payment";
|
||||
export * from "./profile";
|
||||
export * from "./project";
|
||||
export * from "./rich-filters";
|
||||
export * from "./settings";
|
||||
export * from "./sidebar";
|
||||
export * from "./spreadsheet";
|
||||
export * from "./state";
|
||||
export * from "./stickies";
|
||||
export * from "./subscription";
|
||||
export * from "./swr";
|
||||
export * from "./tab-indices";
|
||||
export * from "./themes";
|
||||
export * from "./user";
|
||||
export * from "./views";
|
||||
export * from "./workspace-drafts";
|
||||
export * from "./workspace";
|
||||
9
packages/constants/src/instance.ts
Normal file
9
packages/constants/src/instance.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
export enum EInstanceStatus {
|
||||
ERROR = "ERROR",
|
||||
NOT_YET_READY = "NOT_YET_READY",
|
||||
}
|
||||
|
||||
export type TInstanceStatus = {
|
||||
status: EInstanceStatus | undefined;
|
||||
data?: object;
|
||||
};
|
||||
94
packages/constants/src/intake.ts
Normal file
94
packages/constants/src/intake.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
import { EInboxIssueStatus, TInboxIssueStatus } from "@plane/types";
|
||||
|
||||
export const INBOX_STATUS: {
|
||||
key: string;
|
||||
status: TInboxIssueStatus;
|
||||
i18n_title: string;
|
||||
i18n_description: () => string;
|
||||
}[] = [
|
||||
{
|
||||
key: "pending",
|
||||
i18n_title: "inbox_issue.status.pending.title",
|
||||
status: EInboxIssueStatus.PENDING,
|
||||
i18n_description: () => `inbox_issue.status.pending.description`,
|
||||
},
|
||||
{
|
||||
key: "declined",
|
||||
i18n_title: "inbox_issue.status.declined.title",
|
||||
status: EInboxIssueStatus.DECLINED,
|
||||
i18n_description: () => `inbox_issue.status.declined.description`,
|
||||
},
|
||||
{
|
||||
key: "snoozed",
|
||||
i18n_title: "inbox_issue.status.snoozed.title",
|
||||
status: EInboxIssueStatus.SNOOZED,
|
||||
i18n_description: () => `inbox_issue.status.snoozed.description`,
|
||||
},
|
||||
{
|
||||
key: "accepted",
|
||||
i18n_title: "inbox_issue.status.accepted.title",
|
||||
status: EInboxIssueStatus.ACCEPTED,
|
||||
i18n_description: () => `inbox_issue.status.accepted.description`,
|
||||
},
|
||||
{
|
||||
key: "duplicate",
|
||||
i18n_title: "inbox_issue.status.duplicate.title",
|
||||
status: EInboxIssueStatus.DUPLICATE,
|
||||
i18n_description: () => `inbox_issue.status.duplicate.description`,
|
||||
},
|
||||
];
|
||||
|
||||
export const INBOX_ISSUE_ORDER_BY_OPTIONS = [
|
||||
{
|
||||
key: "issue__created_at",
|
||||
i18n_label: "inbox_issue.order_by.created_at",
|
||||
},
|
||||
{
|
||||
key: "issue__updated_at",
|
||||
i18n_label: "inbox_issue.order_by.updated_at",
|
||||
},
|
||||
{
|
||||
key: "issue__sequence_id",
|
||||
i18n_label: "inbox_issue.order_by.id",
|
||||
},
|
||||
];
|
||||
|
||||
export const INBOX_ISSUE_SORT_BY_OPTIONS = [
|
||||
{
|
||||
key: "asc",
|
||||
i18n_label: "common.sort.asc",
|
||||
},
|
||||
{
|
||||
key: "desc",
|
||||
i18n_label: "common.sort.desc",
|
||||
},
|
||||
];
|
||||
|
||||
export enum EPastDurationFilters {
|
||||
TODAY = "today",
|
||||
YESTERDAY = "yesterday",
|
||||
LAST_7_DAYS = "last_7_days",
|
||||
LAST_30_DAYS = "last_30_days",
|
||||
}
|
||||
|
||||
export const PAST_DURATION_FILTER_OPTIONS: {
|
||||
name: string;
|
||||
value: string;
|
||||
}[] = [
|
||||
{
|
||||
name: "Today",
|
||||
value: EPastDurationFilters.TODAY,
|
||||
},
|
||||
{
|
||||
name: "Yesterday",
|
||||
value: EPastDurationFilters.YESTERDAY,
|
||||
},
|
||||
{
|
||||
name: "Last 7 days",
|
||||
value: EPastDurationFilters.LAST_7_DAYS,
|
||||
},
|
||||
{
|
||||
name: "Last 30 days",
|
||||
value: EPastDurationFilters.LAST_30_DAYS,
|
||||
},
|
||||
];
|
||||
364
packages/constants/src/issue/common.ts
Normal file
364
packages/constants/src/issue/common.ts
Normal file
@@ -0,0 +1,364 @@
|
||||
import {
|
||||
TIssueGroupByOptions,
|
||||
TIssueOrderByOptions,
|
||||
IIssueDisplayProperties,
|
||||
IIssueFilterOptions,
|
||||
TIssue,
|
||||
EIssuesStoreType,
|
||||
} 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",
|
||||
// eslint-disable-next-line @typescript-eslint/no-duplicate-enum-values
|
||||
"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 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
|
||||
| EIssuesStoreType.TEAM_PROJECT_WORK_ITEMS;
|
||||
|
||||
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 SUB_ISSUES_DISPLAY_PROPERTIES_KEYS: (keyof IIssueDisplayProperties)[] = [
|
||||
"key",
|
||||
"assignee",
|
||||
"start_date",
|
||||
"due_date",
|
||||
"priority",
|
||||
"state",
|
||||
];
|
||||
|
||||
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" },
|
||||
];
|
||||
|
||||
export const SPREADSHEET_PROPERTY_LIST: (keyof IIssueDisplayProperties)[] = [
|
||||
"state",
|
||||
"priority",
|
||||
"assignee",
|
||||
"labels",
|
||||
"modules",
|
||||
"cycle",
|
||||
"start_date",
|
||||
"due_date",
|
||||
"estimate",
|
||||
"created_on",
|
||||
"updated_on",
|
||||
"link",
|
||||
"attachment_count",
|
||||
"sub_issue_count",
|
||||
];
|
||||
|
||||
export const SPREADSHEET_PROPERTY_DETAILS: {
|
||||
[key in keyof IIssueDisplayProperties]: {
|
||||
i18n_title: string;
|
||||
ascendingOrderKey: TIssueOrderByOptions;
|
||||
ascendingOrderTitle: string;
|
||||
descendingOrderKey: TIssueOrderByOptions;
|
||||
descendingOrderTitle: string;
|
||||
icon: string;
|
||||
};
|
||||
} = {
|
||||
assignee: {
|
||||
i18n_title: "common.assignees",
|
||||
ascendingOrderKey: "assignees__first_name",
|
||||
ascendingOrderTitle: "A",
|
||||
descendingOrderKey: "-assignees__first_name",
|
||||
descendingOrderTitle: "Z",
|
||||
icon: "MembersPropertyIcon",
|
||||
},
|
||||
created_on: {
|
||||
i18n_title: "common.sort.created_on",
|
||||
ascendingOrderKey: "-created_at",
|
||||
ascendingOrderTitle: "New",
|
||||
descendingOrderKey: "created_at",
|
||||
descendingOrderTitle: "Old",
|
||||
icon: "CalendarDays",
|
||||
},
|
||||
due_date: {
|
||||
i18n_title: "common.order_by.due_date",
|
||||
ascendingOrderKey: "-target_date",
|
||||
ascendingOrderTitle: "New",
|
||||
descendingOrderKey: "target_date",
|
||||
descendingOrderTitle: "Old",
|
||||
icon: "DueDatePropertyIcon",
|
||||
},
|
||||
estimate: {
|
||||
i18n_title: "common.estimate",
|
||||
ascendingOrderKey: "estimate_point__key",
|
||||
ascendingOrderTitle: "Low",
|
||||
descendingOrderKey: "-estimate_point__key",
|
||||
descendingOrderTitle: "High",
|
||||
icon: "EstimatePropertyIcon",
|
||||
},
|
||||
labels: {
|
||||
i18n_title: "common.labels",
|
||||
ascendingOrderKey: "labels__name",
|
||||
ascendingOrderTitle: "A",
|
||||
descendingOrderKey: "-labels__name",
|
||||
descendingOrderTitle: "Z",
|
||||
icon: "LabelPropertyIcon",
|
||||
},
|
||||
modules: {
|
||||
i18n_title: "common.modules",
|
||||
ascendingOrderKey: "issue_module__module__name",
|
||||
ascendingOrderTitle: "A",
|
||||
descendingOrderKey: "-issue_module__module__name",
|
||||
descendingOrderTitle: "Z",
|
||||
icon: "DiceIcon",
|
||||
},
|
||||
cycle: {
|
||||
i18n_title: "common.cycle",
|
||||
ascendingOrderKey: "issue_cycle__cycle__name",
|
||||
ascendingOrderTitle: "A",
|
||||
descendingOrderKey: "-issue_cycle__cycle__name",
|
||||
descendingOrderTitle: "Z",
|
||||
icon: "ContrastIcon",
|
||||
},
|
||||
priority: {
|
||||
i18n_title: "common.priority",
|
||||
ascendingOrderKey: "priority",
|
||||
ascendingOrderTitle: "None",
|
||||
descendingOrderKey: "-priority",
|
||||
descendingOrderTitle: "Urgent",
|
||||
icon: "PriorityPropertyIcon",
|
||||
},
|
||||
start_date: {
|
||||
i18n_title: "common.order_by.start_date",
|
||||
ascendingOrderKey: "-start_date",
|
||||
ascendingOrderTitle: "New",
|
||||
descendingOrderKey: "start_date",
|
||||
descendingOrderTitle: "Old",
|
||||
icon: "StartDatePropertyIcon",
|
||||
},
|
||||
state: {
|
||||
i18n_title: "common.state",
|
||||
ascendingOrderKey: "state__name",
|
||||
ascendingOrderTitle: "A",
|
||||
descendingOrderKey: "-state__name",
|
||||
descendingOrderTitle: "Z",
|
||||
icon: "StatePropertyIcon",
|
||||
},
|
||||
updated_on: {
|
||||
i18n_title: "common.sort.updated_on",
|
||||
ascendingOrderKey: "-updated_at",
|
||||
ascendingOrderTitle: "New",
|
||||
descendingOrderKey: "updated_at",
|
||||
descendingOrderTitle: "Old",
|
||||
icon: "CalendarDays",
|
||||
},
|
||||
link: {
|
||||
i18n_title: "common.link",
|
||||
ascendingOrderKey: "-link_count",
|
||||
ascendingOrderTitle: "Most",
|
||||
descendingOrderKey: "link_count",
|
||||
descendingOrderTitle: "Least",
|
||||
icon: "Link2",
|
||||
},
|
||||
attachment_count: {
|
||||
i18n_title: "common.attachment",
|
||||
ascendingOrderKey: "-attachment_count",
|
||||
ascendingOrderTitle: "Most",
|
||||
descendingOrderKey: "attachment_count",
|
||||
descendingOrderTitle: "Least",
|
||||
icon: "Paperclip",
|
||||
},
|
||||
sub_issue_count: {
|
||||
i18n_title: "issue.display.properties.sub_issue",
|
||||
ascendingOrderKey: "-sub_issues_count",
|
||||
ascendingOrderTitle: "Most",
|
||||
descendingOrderKey: "sub_issues_count",
|
||||
descendingOrderTitle: "Least",
|
||||
icon: "LayersIcon",
|
||||
},
|
||||
};
|
||||
|
||||
// Map filter keys to their corresponding issue property keys
|
||||
export const FILTER_TO_ISSUE_MAP: Partial<Record<keyof IIssueFilterOptions, keyof TIssue>> = {
|
||||
assignees: "assignee_ids",
|
||||
created_by: "created_by",
|
||||
labels: "label_ids",
|
||||
priority: "priority",
|
||||
cycle: "cycle_id",
|
||||
module: "module_ids",
|
||||
project: "project_id",
|
||||
state: "state_id",
|
||||
issue_type: "type_id",
|
||||
state_group: "state__group",
|
||||
} as const;
|
||||
358
packages/constants/src/issue/filter.ts
Normal file
358
packages/constants/src/issue/filter.ts
Normal file
@@ -0,0 +1,358 @@
|
||||
import {
|
||||
EIssuesStoreType,
|
||||
IIssueFilterOptions,
|
||||
ILayoutDisplayFiltersOptions,
|
||||
TIssueActivityComment,
|
||||
TWorkItemFilterProperty,
|
||||
} from "@plane/types";
|
||||
import {
|
||||
TIssueFilterPriorityObject,
|
||||
ISSUE_DISPLAY_PROPERTIES_KEYS,
|
||||
SUB_ISSUES_DISPLAY_PROPERTIES_KEYS,
|
||||
} 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 = "rich_filters",
|
||||
DISPLAY_FILTERS = "display_filters",
|
||||
DISPLAY_PROPERTIES = "display_properties",
|
||||
KANBAN_FILTERS = "kanban_filters",
|
||||
}
|
||||
|
||||
export type TSupportedFilterTypeForUpdate =
|
||||
| EIssueFilterType.DISPLAY_FILTERS
|
||||
| EIssueFilterType.DISPLAY_PROPERTIES
|
||||
| EIssueFilterType.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 TFiltersLayoutOptions = {
|
||||
[layoutType: string]: ILayoutDisplayFiltersOptions;
|
||||
};
|
||||
|
||||
export type TFilterPropertiesByPageType = {
|
||||
filters: TWorkItemFilterProperty[];
|
||||
layoutOptions: TFiltersLayoutOptions;
|
||||
};
|
||||
|
||||
export type TIssueFiltersToDisplayByPageType = {
|
||||
[pageType: string]: TFilterPropertiesByPageType;
|
||||
};
|
||||
|
||||
export const ISSUE_DISPLAY_FILTERS_BY_PAGE: TIssueFiltersToDisplayByPageType = {
|
||||
profile_issues: {
|
||||
filters: ["priority", "state_group", "label_id", "start_date", "target_date"],
|
||||
layoutOptions: {
|
||||
list: {
|
||||
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: ["active", "backlog"],
|
||||
},
|
||||
extra_options: {
|
||||
access: true,
|
||||
values: ["show_empty_groups", "sub_issue"],
|
||||
},
|
||||
},
|
||||
kanban: {
|
||||
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: ["active", "backlog"],
|
||||
},
|
||||
extra_options: {
|
||||
access: true,
|
||||
values: ["show_empty_groups"],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
archived_issues: {
|
||||
filters: [
|
||||
"priority",
|
||||
"state_group",
|
||||
"state_id",
|
||||
"cycle_id",
|
||||
"module_id",
|
||||
"assignee_id",
|
||||
"created_by_id",
|
||||
"label_id",
|
||||
"start_date",
|
||||
"target_date",
|
||||
],
|
||||
layoutOptions: {
|
||||
list: {
|
||||
display_properties: ISSUE_DISPLAY_PROPERTIES_KEYS,
|
||||
display_filters: {
|
||||
group_by: ["state", "cycle", "module", "priority", "labels", "assignees", "created_by", null],
|
||||
order_by: ["sort_order", "-created_at", "-updated_at", "start_date", "-priority"],
|
||||
type: ["active", "backlog"],
|
||||
},
|
||||
extra_options: {
|
||||
access: true,
|
||||
values: ["show_empty_groups"],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
my_issues: {
|
||||
filters: [
|
||||
"priority",
|
||||
"state_group",
|
||||
"label_id",
|
||||
"assignee_id",
|
||||
"created_by_id",
|
||||
"subscriber_id",
|
||||
"project_id",
|
||||
"start_date",
|
||||
"target_date",
|
||||
],
|
||||
layoutOptions: {
|
||||
spreadsheet: {
|
||||
display_properties: ISSUE_DISPLAY_PROPERTIES_KEYS,
|
||||
display_filters: {
|
||||
order_by: [],
|
||||
type: ["active", "backlog"],
|
||||
},
|
||||
extra_options: {
|
||||
access: true,
|
||||
values: ["sub_issue"],
|
||||
},
|
||||
},
|
||||
list: {
|
||||
display_properties: ISSUE_DISPLAY_PROPERTIES_KEYS,
|
||||
display_filters: {
|
||||
type: ["active", "backlog"],
|
||||
},
|
||||
extra_options: {
|
||||
access: false,
|
||||
values: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
issues: {
|
||||
filters: [
|
||||
"priority",
|
||||
"state_group",
|
||||
"state_id",
|
||||
"cycle_id",
|
||||
"module_id",
|
||||
"assignee_id",
|
||||
"mention_id",
|
||||
"created_by_id",
|
||||
"label_id",
|
||||
"start_date",
|
||||
"target_date",
|
||||
],
|
||||
layoutOptions: {
|
||||
list: {
|
||||
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", "target_date"],
|
||||
type: ["active", "backlog"],
|
||||
},
|
||||
extra_options: {
|
||||
access: true,
|
||||
values: ["show_empty_groups", "sub_issue"],
|
||||
},
|
||||
},
|
||||
kanban: {
|
||||
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: ["active", "backlog"],
|
||||
},
|
||||
extra_options: {
|
||||
access: true,
|
||||
values: ["show_empty_groups", "sub_issue"],
|
||||
},
|
||||
},
|
||||
calendar: {
|
||||
display_properties: ["key", "issue_type"],
|
||||
display_filters: {
|
||||
type: ["active", "backlog"],
|
||||
},
|
||||
extra_options: {
|
||||
access: true,
|
||||
values: ["sub_issue"],
|
||||
},
|
||||
},
|
||||
spreadsheet: {
|
||||
display_properties: ISSUE_DISPLAY_PROPERTIES_KEYS,
|
||||
display_filters: {
|
||||
order_by: ["sort_order", "-created_at", "-updated_at", "start_date", "-priority"],
|
||||
type: ["active", "backlog"],
|
||||
},
|
||||
extra_options: {
|
||||
access: true,
|
||||
values: ["sub_issue"],
|
||||
},
|
||||
},
|
||||
gantt_chart: {
|
||||
display_properties: ["key", "issue_type"],
|
||||
display_filters: {
|
||||
order_by: ["sort_order", "-created_at", "-updated_at", "start_date", "-priority"],
|
||||
type: ["active", "backlog"],
|
||||
},
|
||||
extra_options: {
|
||||
access: true,
|
||||
values: ["sub_issue"],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
sub_work_items: {
|
||||
filters: ["priority", "state_id", "assignee_id", "start_date", "target_date"],
|
||||
layoutOptions: {
|
||||
list: {
|
||||
display_properties: SUB_ISSUES_DISPLAY_PROPERTIES_KEYS,
|
||||
display_filters: {
|
||||
order_by: ["-created_at", "-updated_at", "start_date", "-priority"],
|
||||
group_by: ["state", "priority", "assignees", null],
|
||||
},
|
||||
extra_options: {
|
||||
access: true,
|
||||
values: ["sub_issue"],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const ISSUE_STORE_TO_FILTERS_MAP: Partial<Record<EIssuesStoreType, TFilterPropertiesByPageType>> = {
|
||||
[EIssuesStoreType.PROJECT]: ISSUE_DISPLAY_FILTERS_BY_PAGE.issues,
|
||||
};
|
||||
|
||||
export const SUB_WORK_ITEM_AVAILABLE_FILTERS_FOR_WORK_ITEM_PAGE: (keyof IIssueFilterOptions)[] = [
|
||||
"priority",
|
||||
"state",
|
||||
"issue_type",
|
||||
"assignees",
|
||||
"start_date",
|
||||
"target_date",
|
||||
];
|
||||
|
||||
export enum EActivityFilterType {
|
||||
ACTIVITY = "ACTIVITY",
|
||||
COMMENT = "COMMENT",
|
||||
STATE = "STATE",
|
||||
ASSIGNEE = "ASSIGNEE",
|
||||
DEFAULT = "DEFAULT",
|
||||
}
|
||||
|
||||
export type TActivityFilters = EActivityFilterType;
|
||||
|
||||
export type TActivityFilterOptionsKey = Exclude<TActivityFilters, EActivityFilterType.DEFAULT>;
|
||||
|
||||
export const ACTIVITY_FILTER_TYPE_OPTIONS: Record<TActivityFilterOptionsKey, { labelTranslationKey: string }> = {
|
||||
[EActivityFilterType.ACTIVITY]: {
|
||||
labelTranslationKey: "common.updates",
|
||||
},
|
||||
[EActivityFilterType.COMMENT]: {
|
||||
labelTranslationKey: "common.comments",
|
||||
},
|
||||
[EActivityFilterType.STATE]: {
|
||||
labelTranslationKey: "common.state",
|
||||
},
|
||||
[EActivityFilterType.ASSIGNEE]: {
|
||||
labelTranslationKey: "common.assignee",
|
||||
},
|
||||
};
|
||||
|
||||
export type TActivityFilterOption = {
|
||||
key: TActivityFilters;
|
||||
labelTranslationKey: string;
|
||||
isSelected: boolean;
|
||||
onClick: () => void;
|
||||
};
|
||||
|
||||
export const defaultActivityFilters: TActivityFilters[] = [
|
||||
EActivityFilterType.ACTIVITY,
|
||||
EActivityFilterType.COMMENT,
|
||||
EActivityFilterType.STATE,
|
||||
EActivityFilterType.ASSIGNEE,
|
||||
];
|
||||
|
||||
export const filterActivityOnSelectedFilters = (
|
||||
activity: TIssueActivityComment[],
|
||||
filters: TActivityFilters[]
|
||||
): TIssueActivityComment[] =>
|
||||
activity.filter((activity) => {
|
||||
if (activity.activity_type === EActivityFilterType.DEFAULT) return true;
|
||||
return filters.includes(activity.activity_type as TActivityFilters);
|
||||
});
|
||||
|
||||
export const ENABLE_ISSUE_DEPENDENCIES = false;
|
||||
4
packages/constants/src/issue/index.ts
Normal file
4
packages/constants/src/issue/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export * from "./common";
|
||||
export * from "./filter";
|
||||
export * from "./layout";
|
||||
export * from "./modal";
|
||||
63
packages/constants/src/issue/layout.ts
Normal file
63
packages/constants/src/issue/layout.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import { EIssueLayoutTypes } from "@plane/types";
|
||||
|
||||
export type TIssueLayout = "list" | "kanban" | "calendar" | "spreadsheet" | "gantt";
|
||||
|
||||
export type TIssueLayoutMap = Record<
|
||||
EIssueLayoutTypes,
|
||||
{
|
||||
key: EIssueLayoutTypes;
|
||||
i18n_title: string;
|
||||
i18n_label: string;
|
||||
}
|
||||
>;
|
||||
|
||||
export const SITES_ISSUE_LAYOUTS: {
|
||||
key: TIssueLayout;
|
||||
titleTranslationKey: string;
|
||||
icon: string;
|
||||
}[] = [
|
||||
{
|
||||
key: "list",
|
||||
icon: "List",
|
||||
titleTranslationKey: "issue.layouts.list",
|
||||
},
|
||||
{
|
||||
key: "kanban",
|
||||
icon: "Kanban",
|
||||
titleTranslationKey: "issue.layouts.kanban",
|
||||
},
|
||||
];
|
||||
|
||||
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;
|
||||
i18n_label: string;
|
||||
}[] = Object.values(ISSUE_LAYOUT_MAP);
|
||||
19
packages/constants/src/issue/modal.ts
Normal file
19
packages/constants/src/issue/modal.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
// plane imports
|
||||
import { TIssue } from "@plane/types";
|
||||
|
||||
export const DEFAULT_WORK_ITEM_FORM_VALUES: Partial<TIssue> = {
|
||||
project_id: "",
|
||||
type_id: null,
|
||||
name: "",
|
||||
description_html: "",
|
||||
estimate_point: null,
|
||||
state_id: "",
|
||||
parent_id: null,
|
||||
priority: "none",
|
||||
assignee_ids: [],
|
||||
label_ids: [],
|
||||
cycle_id: null,
|
||||
module_ids: null,
|
||||
start_date: null,
|
||||
target_date: null,
|
||||
};
|
||||
17
packages/constants/src/label.ts
Normal file
17
packages/constants/src/label.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
export const LABEL_COLOR_OPTIONS = [
|
||||
"#FF6900",
|
||||
"#FCB900",
|
||||
"#7BDCB5",
|
||||
"#00D084",
|
||||
"#8ED1FC",
|
||||
"#0693E3",
|
||||
"#ABB8C3",
|
||||
"#EB144C",
|
||||
"#F78DA7",
|
||||
"#9900EF",
|
||||
];
|
||||
|
||||
export const getRandomLabelColor = () => {
|
||||
const randomIndex = Math.floor(Math.random() * LABEL_COLOR_OPTIONS.length);
|
||||
return LABEL_COLOR_OPTIONS[randomIndex];
|
||||
};
|
||||
79
packages/constants/src/members.ts
Normal file
79
packages/constants/src/members.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
// Member property constants - Single source of truth for member spreadsheet properties
|
||||
|
||||
export type TMemberOrderByOptions =
|
||||
| "display_name"
|
||||
| "-display_name"
|
||||
| "full_name"
|
||||
| "-full_name"
|
||||
| "email"
|
||||
| "-email"
|
||||
| "joining_date"
|
||||
| "-joining_date"
|
||||
| "role"
|
||||
| "-role";
|
||||
|
||||
export interface IProjectMemberDisplayProperties {
|
||||
full_name: boolean;
|
||||
display_name: boolean;
|
||||
email: boolean;
|
||||
joining_date: boolean;
|
||||
role: boolean;
|
||||
}
|
||||
|
||||
export const MEMBER_PROPERTY_DETAILS: {
|
||||
[key in keyof IProjectMemberDisplayProperties]: {
|
||||
i18n_title: string;
|
||||
ascendingOrderKey: TMemberOrderByOptions;
|
||||
ascendingOrderTitle: string;
|
||||
descendingOrderKey: TMemberOrderByOptions;
|
||||
descendingOrderTitle: string;
|
||||
iconName: string;
|
||||
isSortingAllowed: boolean;
|
||||
};
|
||||
} = {
|
||||
full_name: {
|
||||
i18n_title: "project_members.full_name",
|
||||
ascendingOrderKey: "full_name",
|
||||
ascendingOrderTitle: "A",
|
||||
descendingOrderKey: "-full_name",
|
||||
descendingOrderTitle: "Z",
|
||||
iconName: "User",
|
||||
isSortingAllowed: true,
|
||||
},
|
||||
display_name: {
|
||||
i18n_title: "project_members.display_name",
|
||||
ascendingOrderKey: "display_name",
|
||||
ascendingOrderTitle: "A",
|
||||
descendingOrderKey: "-display_name",
|
||||
descendingOrderTitle: "Z",
|
||||
iconName: "User",
|
||||
isSortingAllowed: true,
|
||||
},
|
||||
email: {
|
||||
i18n_title: "project_members.email",
|
||||
ascendingOrderKey: "email",
|
||||
ascendingOrderTitle: "A",
|
||||
descendingOrderKey: "-email",
|
||||
descendingOrderTitle: "Z",
|
||||
iconName: "Mail",
|
||||
isSortingAllowed: true,
|
||||
},
|
||||
joining_date: {
|
||||
i18n_title: "project_members.joining_date",
|
||||
ascendingOrderKey: "joining_date",
|
||||
ascendingOrderTitle: "Old",
|
||||
descendingOrderKey: "-joining_date",
|
||||
descendingOrderTitle: "New",
|
||||
iconName: "Calendar",
|
||||
isSortingAllowed: true,
|
||||
},
|
||||
role: {
|
||||
i18n_title: "project_members.role",
|
||||
ascendingOrderKey: "role",
|
||||
ascendingOrderTitle: "Guest",
|
||||
descendingOrderKey: "-role",
|
||||
descendingOrderTitle: "Admin",
|
||||
iconName: "Shield",
|
||||
isSortingAllowed: true,
|
||||
},
|
||||
};
|
||||
17
packages/constants/src/metadata.ts
Normal file
17
packages/constants/src/metadata.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
export const SITE_NAME = "Plane | Simple, extensible, open-source project management tool.";
|
||||
export const SITE_TITLE = "Plane | Simple, extensible, open-source project management tool.";
|
||||
export const SITE_DESCRIPTION =
|
||||
"Open-source project management tool to manage work items, cycles, and product roadmaps easily";
|
||||
export const SITE_KEYWORDS =
|
||||
"software development, plan, ship, software, accelerate, code management, release management, project management, work items tracking, agile, scrum, kanban, collaboration";
|
||||
export const SITE_URL = "https://app.plane.so/";
|
||||
export const TWITTER_USER_NAME = "Plane | Simple, extensible, open-source project management tool.";
|
||||
|
||||
// Plane Sites Metadata
|
||||
export const SPACE_SITE_NAME = "Plane Publish | Make your Plane boards and roadmaps pubic with just one-click. ";
|
||||
export const SPACE_SITE_TITLE = "Plane Publish | Make your Plane boards public with one-click";
|
||||
export const SPACE_SITE_DESCRIPTION = "Plane Publish is a customer feedback management tool built on top of plane.so";
|
||||
export const SPACE_SITE_KEYWORDS =
|
||||
"software development, customer feedback, software, accelerate, code management, release management, project management, work items tracking, agile, scrum, kanban, collaboration";
|
||||
export const SPACE_SITE_URL = "https://app.plane.so/";
|
||||
export const SPACE_TWITTER_USER_NAME = "planepowers";
|
||||
112
packages/constants/src/module.ts
Normal file
112
packages/constants/src/module.ts
Normal file
@@ -0,0 +1,112 @@
|
||||
// types
|
||||
import { TModuleLayoutOptions, TModuleOrderByOptions, TModuleStatus } from "@plane/types";
|
||||
|
||||
export const MODULE_STATUS_COLORS: {
|
||||
[key in TModuleStatus]: string;
|
||||
} = {
|
||||
backlog: "#a3a3a2",
|
||||
planned: "#3f76ff",
|
||||
paused: "#525252",
|
||||
completed: "#16a34a",
|
||||
cancelled: "#ef4444",
|
||||
"in-progress": "#f39e1f",
|
||||
};
|
||||
|
||||
export const MODULE_STATUS: {
|
||||
i18n_label: string;
|
||||
value: TModuleStatus;
|
||||
color: string;
|
||||
textColor: string;
|
||||
bgColor: string;
|
||||
}[] = [
|
||||
{
|
||||
i18n_label: "project_modules.status.backlog",
|
||||
value: "backlog",
|
||||
color: MODULE_STATUS_COLORS.backlog,
|
||||
textColor: "text-custom-text-400",
|
||||
bgColor: "bg-custom-background-80",
|
||||
},
|
||||
{
|
||||
i18n_label: "project_modules.status.planned",
|
||||
value: "planned",
|
||||
color: MODULE_STATUS_COLORS.planned,
|
||||
textColor: "text-blue-500",
|
||||
bgColor: "bg-indigo-50",
|
||||
},
|
||||
{
|
||||
i18n_label: "project_modules.status.in_progress",
|
||||
value: "in-progress",
|
||||
color: MODULE_STATUS_COLORS["in-progress"],
|
||||
textColor: "text-amber-500",
|
||||
bgColor: "bg-amber-50",
|
||||
},
|
||||
{
|
||||
i18n_label: "project_modules.status.paused",
|
||||
value: "paused",
|
||||
color: MODULE_STATUS_COLORS.paused,
|
||||
textColor: "text-custom-text-300",
|
||||
bgColor: "bg-custom-background-90",
|
||||
},
|
||||
{
|
||||
i18n_label: "project_modules.status.completed",
|
||||
value: "completed",
|
||||
color: MODULE_STATUS_COLORS.completed,
|
||||
textColor: "text-green-600",
|
||||
bgColor: "bg-green-100",
|
||||
},
|
||||
{
|
||||
i18n_label: "project_modules.status.cancelled",
|
||||
value: "cancelled",
|
||||
color: MODULE_STATUS_COLORS.cancelled,
|
||||
textColor: "text-red-500",
|
||||
bgColor: "bg-red-50",
|
||||
},
|
||||
];
|
||||
|
||||
export const MODULE_VIEW_LAYOUTS: {
|
||||
key: TModuleLayoutOptions;
|
||||
i18n_title: string;
|
||||
}[] = [
|
||||
{
|
||||
key: "list",
|
||||
i18n_title: "project_modules.layout.list",
|
||||
},
|
||||
{
|
||||
key: "board",
|
||||
i18n_title: "project_modules.layout.board",
|
||||
},
|
||||
{
|
||||
key: "gantt",
|
||||
i18n_title: "project_modules.layout.timeline",
|
||||
},
|
||||
];
|
||||
|
||||
export const MODULE_ORDER_BY_OPTIONS: {
|
||||
key: TModuleOrderByOptions;
|
||||
i18n_label: string;
|
||||
}[] = [
|
||||
{
|
||||
key: "name",
|
||||
i18n_label: "project_modules.order_by.name",
|
||||
},
|
||||
{
|
||||
key: "progress",
|
||||
i18n_label: "project_modules.order_by.progress",
|
||||
},
|
||||
{
|
||||
key: "issues_length",
|
||||
i18n_label: "project_modules.order_by.issues",
|
||||
},
|
||||
{
|
||||
key: "target_date",
|
||||
i18n_label: "project_modules.order_by.due_date",
|
||||
},
|
||||
{
|
||||
key: "created_at",
|
||||
i18n_label: "project_modules.order_by.created_at",
|
||||
},
|
||||
{
|
||||
key: "sort_order",
|
||||
i18n_label: "project_modules.order_by.manual",
|
||||
},
|
||||
];
|
||||
136
packages/constants/src/notification.ts
Normal file
136
packages/constants/src/notification.ts
Normal file
@@ -0,0 +1,136 @@
|
||||
import { TUnreadNotificationsCount } from "@plane/types";
|
||||
|
||||
export enum ENotificationTab {
|
||||
ALL = "all",
|
||||
MENTIONS = "mentions",
|
||||
}
|
||||
|
||||
export enum ENotificationFilterType {
|
||||
CREATED = "created",
|
||||
ASSIGNED = "assigned",
|
||||
SUBSCRIBED = "subscribed",
|
||||
}
|
||||
|
||||
export enum ENotificationLoader {
|
||||
INIT_LOADER = "init-loader",
|
||||
MUTATION_LOADER = "mutation-loader",
|
||||
PAGINATION_LOADER = "pagination-loader",
|
||||
REFRESH = "refresh",
|
||||
MARK_ALL_AS_READY = "mark-all-as-read",
|
||||
}
|
||||
|
||||
export enum ENotificationQueryParamType {
|
||||
INIT = "init",
|
||||
CURRENT = "current",
|
||||
NEXT = "next",
|
||||
}
|
||||
|
||||
export type TNotificationTab = ENotificationTab.ALL | ENotificationTab.MENTIONS;
|
||||
|
||||
export const NOTIFICATION_TABS = [
|
||||
{
|
||||
i18n_label: "notification.tabs.all",
|
||||
value: ENotificationTab.ALL,
|
||||
count: (unReadNotification: TUnreadNotificationsCount) => unReadNotification?.total_unread_notifications_count || 0,
|
||||
},
|
||||
{
|
||||
i18n_label: "notification.tabs.mentions",
|
||||
value: ENotificationTab.MENTIONS,
|
||||
count: (unReadNotification: TUnreadNotificationsCount) =>
|
||||
unReadNotification?.mention_unread_notifications_count || 0,
|
||||
},
|
||||
];
|
||||
|
||||
export const FILTER_TYPE_OPTIONS = [
|
||||
{
|
||||
i18n_label: "notification.filter.assigned",
|
||||
value: ENotificationFilterType.ASSIGNED,
|
||||
},
|
||||
{
|
||||
i18n_label: "notification.filter.created",
|
||||
value: ENotificationFilterType.CREATED,
|
||||
},
|
||||
{
|
||||
i18n_label: "notification.filter.subscribed",
|
||||
value: ENotificationFilterType.SUBSCRIBED,
|
||||
},
|
||||
];
|
||||
|
||||
export const NOTIFICATION_SNOOZE_OPTIONS = [
|
||||
{
|
||||
key: "1_day",
|
||||
i18n_label: "notification.snooze.1_day",
|
||||
value: () => {
|
||||
const date = new Date();
|
||||
return new Date(date.getTime() + 24 * 60 * 60 * 1000);
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "3_days",
|
||||
i18n_label: "notification.snooze.3_days",
|
||||
value: () => {
|
||||
const date = new Date();
|
||||
return new Date(date.getTime() + 3 * 24 * 60 * 60 * 1000);
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "5_days",
|
||||
i18n_label: "notification.snooze.5_days",
|
||||
value: () => {
|
||||
const date = new Date();
|
||||
return new Date(date.getTime() + 5 * 24 * 60 * 60 * 1000);
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "1_week",
|
||||
i18n_label: "notification.snooze.1_week",
|
||||
value: () => {
|
||||
const date = new Date();
|
||||
return new Date(date.getTime() + 7 * 24 * 60 * 60 * 1000);
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "2_weeks",
|
||||
i18n_label: "notification.snooze.2_weeks",
|
||||
value: () => {
|
||||
const date = new Date();
|
||||
return new Date(date.getTime() + 14 * 24 * 60 * 60 * 1000);
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "custom",
|
||||
i18n_label: "notification.snooze.custom",
|
||||
value: undefined,
|
||||
},
|
||||
];
|
||||
|
||||
// Constant for all time values in 30 minutes interval in 12 hours format
|
||||
export const allTimeIn30MinutesInterval12HoursFormat: Array<{
|
||||
label: string;
|
||||
value: string;
|
||||
}> = [
|
||||
{ label: "12:00", value: "12:00" },
|
||||
{ label: "12:30", value: "12:30" },
|
||||
{ label: "01:00", value: "01:00" },
|
||||
{ label: "01:30", value: "01:30" },
|
||||
{ label: "02:00", value: "02:00" },
|
||||
{ label: "02:30", value: "02:30" },
|
||||
{ label: "03:00", value: "03:00" },
|
||||
{ label: "03:30", value: "03:30" },
|
||||
{ label: "04:00", value: "04:00" },
|
||||
{ label: "04:30", value: "04:30" },
|
||||
{ label: "05:00", value: "05:00" },
|
||||
{ label: "05:30", value: "05:30" },
|
||||
{ label: "06:00", value: "06:00" },
|
||||
{ label: "06:30", value: "06:30" },
|
||||
{ label: "07:00", value: "07:00" },
|
||||
{ label: "07:30", value: "07:30" },
|
||||
{ label: "08:00", value: "08:00" },
|
||||
{ label: "08:30", value: "08:30" },
|
||||
{ label: "09:00", value: "09:00" },
|
||||
{ label: "09:30", value: "09:30" },
|
||||
{ label: "10:00", value: "10:00" },
|
||||
{ label: "10:30", value: "10:30" },
|
||||
{ label: "11:00", value: "11:00" },
|
||||
{ label: "11:30", value: "11:30" },
|
||||
];
|
||||
14
packages/constants/src/page.ts
Normal file
14
packages/constants/src/page.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
export enum EPageAccess {
|
||||
PUBLIC = 0,
|
||||
PRIVATE = 1,
|
||||
}
|
||||
|
||||
export type TCreatePageModal = {
|
||||
isOpen: boolean;
|
||||
pageAccess?: EPageAccess;
|
||||
};
|
||||
|
||||
export const DEFAULT_CREATE_PAGE_MODAL_DATA: TCreatePageModal = {
|
||||
isOpen: false,
|
||||
pageAccess: EPageAccess.PUBLIC,
|
||||
};
|
||||
152
packages/constants/src/payment.ts
Normal file
152
packages/constants/src/payment.ts
Normal file
@@ -0,0 +1,152 @@
|
||||
import { EProductSubscriptionEnum, IPaymentProduct, TBillingFrequency, TProductBillingFrequency } from "@plane/types";
|
||||
|
||||
/**
|
||||
* Default billing frequency for each product subscription type
|
||||
*/
|
||||
export const DEFAULT_PRODUCT_BILLING_FREQUENCY: TProductBillingFrequency = {
|
||||
[EProductSubscriptionEnum.FREE]: undefined,
|
||||
[EProductSubscriptionEnum.ONE]: undefined,
|
||||
[EProductSubscriptionEnum.PRO]: "month",
|
||||
[EProductSubscriptionEnum.BUSINESS]: "month",
|
||||
[EProductSubscriptionEnum.ENTERPRISE]: "month",
|
||||
};
|
||||
|
||||
/**
|
||||
* Subscription types that support billing frequency toggle (monthly/yearly)
|
||||
*/
|
||||
export const SUBSCRIPTION_WITH_BILLING_FREQUENCY = [
|
||||
EProductSubscriptionEnum.PRO,
|
||||
EProductSubscriptionEnum.BUSINESS,
|
||||
EProductSubscriptionEnum.ENTERPRISE,
|
||||
];
|
||||
|
||||
/**
|
||||
* Mapping of product subscription types to their respective payment product details
|
||||
* Used to provide information about each product's pricing and features
|
||||
*/
|
||||
export const PLANE_COMMUNITY_PRODUCTS: Record<string, IPaymentProduct> = {
|
||||
[EProductSubscriptionEnum.PRO]: {
|
||||
id: EProductSubscriptionEnum.PRO,
|
||||
name: "Plane Pro",
|
||||
description:
|
||||
"More views, more cycles powers, more pages features, new reports, and better dashboards are waiting to be unlocked.",
|
||||
type: "PRO",
|
||||
prices: [
|
||||
{
|
||||
id: `price_monthly_${EProductSubscriptionEnum.PRO}`,
|
||||
unit_amount: 800,
|
||||
recurring: "month",
|
||||
currency: "usd",
|
||||
workspace_amount: 800,
|
||||
product: EProductSubscriptionEnum.PRO,
|
||||
},
|
||||
{
|
||||
id: `price_yearly_${EProductSubscriptionEnum.PRO}`,
|
||||
unit_amount: 7200,
|
||||
recurring: "year",
|
||||
currency: "usd",
|
||||
workspace_amount: 7200,
|
||||
product: EProductSubscriptionEnum.PRO,
|
||||
},
|
||||
],
|
||||
payment_quantity: 1,
|
||||
is_active: true,
|
||||
},
|
||||
[EProductSubscriptionEnum.BUSINESS]: {
|
||||
id: EProductSubscriptionEnum.BUSINESS,
|
||||
name: "Plane Business",
|
||||
description:
|
||||
"The earliest packaging of Business at $10 a seat a month billed annually, $12 a seat a month billed monthly for Plane Cloud",
|
||||
type: "BUSINESS",
|
||||
prices: [
|
||||
{
|
||||
id: `price_yearly_${EProductSubscriptionEnum.BUSINESS}`,
|
||||
unit_amount: 15600,
|
||||
recurring: "year",
|
||||
currency: "usd",
|
||||
workspace_amount: 15600,
|
||||
product: EProductSubscriptionEnum.BUSINESS,
|
||||
},
|
||||
{
|
||||
id: `price_monthly_${EProductSubscriptionEnum.BUSINESS}`,
|
||||
unit_amount: 1500,
|
||||
recurring: "month",
|
||||
currency: "usd",
|
||||
workspace_amount: 1500,
|
||||
product: EProductSubscriptionEnum.BUSINESS,
|
||||
},
|
||||
],
|
||||
payment_quantity: 1,
|
||||
is_active: true,
|
||||
},
|
||||
[EProductSubscriptionEnum.ENTERPRISE]: {
|
||||
id: EProductSubscriptionEnum.ENTERPRISE,
|
||||
name: "Plane Enterprise",
|
||||
description: "",
|
||||
type: "ENTERPRISE",
|
||||
prices: [
|
||||
{
|
||||
id: `price_yearly_${EProductSubscriptionEnum.ENTERPRISE}`,
|
||||
unit_amount: 0,
|
||||
recurring: "year",
|
||||
currency: "usd",
|
||||
workspace_amount: 0,
|
||||
product: EProductSubscriptionEnum.ENTERPRISE,
|
||||
},
|
||||
{
|
||||
id: `price_monthly_${EProductSubscriptionEnum.ENTERPRISE}`,
|
||||
unit_amount: 0,
|
||||
recurring: "month",
|
||||
currency: "usd",
|
||||
workspace_amount: 0,
|
||||
product: EProductSubscriptionEnum.ENTERPRISE,
|
||||
},
|
||||
],
|
||||
payment_quantity: 1,
|
||||
is_active: false,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* URL for the "Talk to Sales" page where users can contact sales team
|
||||
*/
|
||||
export const TALK_TO_SALES_URL = "https://plane.so/talk-to-sales";
|
||||
|
||||
/**
|
||||
* Mapping of subscription types to their respective upgrade/redirection URLs based on billing frequency
|
||||
* Used for self-hosted installations to redirect users to appropriate upgrade pages
|
||||
*/
|
||||
export const SUBSCRIPTION_REDIRECTION_URLS: Record<EProductSubscriptionEnum, Record<TBillingFrequency, string>> = {
|
||||
[EProductSubscriptionEnum.FREE]: {
|
||||
month: TALK_TO_SALES_URL,
|
||||
year: TALK_TO_SALES_URL,
|
||||
},
|
||||
[EProductSubscriptionEnum.ONE]: {
|
||||
month: TALK_TO_SALES_URL,
|
||||
year: TALK_TO_SALES_URL,
|
||||
},
|
||||
[EProductSubscriptionEnum.PRO]: {
|
||||
month: "https://app.plane.so/upgrade/pro/self-hosted?plan=month",
|
||||
year: "https://app.plane.so/upgrade/pro/self-hosted?plan=year",
|
||||
},
|
||||
[EProductSubscriptionEnum.BUSINESS]: {
|
||||
month: "https://app.plane.so/upgrade/business/self-hosted?plan=month",
|
||||
year: "https://app.plane.so/upgrade/business/self-hosted?plan=year",
|
||||
},
|
||||
[EProductSubscriptionEnum.ENTERPRISE]: {
|
||||
month: TALK_TO_SALES_URL,
|
||||
year: TALK_TO_SALES_URL,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Mapping of subscription types to their respective marketing webpage URLs
|
||||
* Used to direct users to learn more about each plan's features and pricing
|
||||
*/
|
||||
export const SUBSCRIPTION_WEBPAGE_URLS: Record<EProductSubscriptionEnum, string> = {
|
||||
[EProductSubscriptionEnum.FREE]: TALK_TO_SALES_URL,
|
||||
[EProductSubscriptionEnum.ONE]: TALK_TO_SALES_URL,
|
||||
[EProductSubscriptionEnum.PRO]: "https://plane.so/pro",
|
||||
[EProductSubscriptionEnum.BUSINESS]: "https://plane.so/business",
|
||||
[EProductSubscriptionEnum.ENTERPRISE]: "https://plane.so/business",
|
||||
};
|
||||
142
packages/constants/src/profile.ts
Normal file
142
packages/constants/src/profile.ts
Normal file
@@ -0,0 +1,142 @@
|
||||
import { EStartOfTheWeek } from "@plane/types";
|
||||
|
||||
export const PROFILE_SETTINGS = {
|
||||
profile: {
|
||||
key: "profile",
|
||||
i18n_label: "profile.actions.profile",
|
||||
href: `/settings/account`,
|
||||
highlight: (pathname: string) => pathname === "/settings/account/",
|
||||
},
|
||||
security: {
|
||||
key: "security",
|
||||
i18n_label: "profile.actions.security",
|
||||
href: `/settings/account/security`,
|
||||
highlight: (pathname: string) => pathname === "/settings/account/security/",
|
||||
},
|
||||
activity: {
|
||||
key: "activity",
|
||||
i18n_label: "profile.actions.activity",
|
||||
href: `/settings/account/activity`,
|
||||
highlight: (pathname: string) => pathname === "/settings/account/activity/",
|
||||
},
|
||||
preferences: {
|
||||
key: "preferences",
|
||||
i18n_label: "profile.actions.preferences",
|
||||
href: `/settings/account/preferences`,
|
||||
highlight: (pathname: string) => pathname === "/settings/account/preferences",
|
||||
},
|
||||
notifications: {
|
||||
key: "notifications",
|
||||
i18n_label: "profile.actions.notifications",
|
||||
href: `/settings/account/notifications`,
|
||||
highlight: (pathname: string) => pathname === "/settings/account/notifications/",
|
||||
},
|
||||
"api-tokens": {
|
||||
key: "api-tokens",
|
||||
i18n_label: "profile.actions.api-tokens",
|
||||
href: `/settings/account/api-tokens`,
|
||||
highlight: (pathname: string) => pathname === "/settings/account/api-tokens/",
|
||||
},
|
||||
};
|
||||
export const PROFILE_ACTION_LINKS: {
|
||||
key: string;
|
||||
i18n_label: string;
|
||||
href: string;
|
||||
highlight: (pathname: string) => boolean;
|
||||
}[] = [
|
||||
PROFILE_SETTINGS["profile"],
|
||||
PROFILE_SETTINGS["security"],
|
||||
PROFILE_SETTINGS["activity"],
|
||||
PROFILE_SETTINGS["preferences"],
|
||||
PROFILE_SETTINGS["notifications"],
|
||||
PROFILE_SETTINGS["api-tokens"],
|
||||
];
|
||||
|
||||
export const PROFILE_VIEWER_TAB = [
|
||||
{
|
||||
key: "summary",
|
||||
route: "",
|
||||
i18n_label: "profile.tabs.summary",
|
||||
selected: "/",
|
||||
},
|
||||
];
|
||||
|
||||
export const PROFILE_ADMINS_TAB = [
|
||||
{
|
||||
key: "assigned",
|
||||
route: "assigned",
|
||||
i18n_label: "profile.tabs.assigned",
|
||||
selected: "/assigned/",
|
||||
},
|
||||
{
|
||||
key: "created",
|
||||
route: "created",
|
||||
i18n_label: "profile.tabs.created",
|
||||
selected: "/created/",
|
||||
},
|
||||
{
|
||||
key: "subscribed",
|
||||
route: "subscribed",
|
||||
i18n_label: "profile.tabs.subscribed",
|
||||
selected: "/subscribed/",
|
||||
},
|
||||
{
|
||||
key: "activity",
|
||||
route: "activity",
|
||||
i18n_label: "profile.tabs.activity",
|
||||
selected: "/activity/",
|
||||
},
|
||||
];
|
||||
|
||||
export const PREFERENCE_OPTIONS: {
|
||||
id: string;
|
||||
title: string;
|
||||
description: string;
|
||||
}[] = [
|
||||
{
|
||||
id: "theme",
|
||||
title: "theme",
|
||||
description: "select_or_customize_your_interface_color_scheme",
|
||||
},
|
||||
{
|
||||
id: "start_of_week",
|
||||
title: "First day of the week",
|
||||
description: "This will change how all calendars in your app look.",
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* @description The options for the start of the week
|
||||
* @type {Array<{value: EStartOfTheWeek, label: string}>}
|
||||
* @constant
|
||||
*/
|
||||
export const START_OF_THE_WEEK_OPTIONS = [
|
||||
{
|
||||
value: EStartOfTheWeek.SUNDAY,
|
||||
label: "Sunday",
|
||||
},
|
||||
{
|
||||
value: EStartOfTheWeek.MONDAY,
|
||||
label: "Monday",
|
||||
},
|
||||
{
|
||||
value: EStartOfTheWeek.TUESDAY,
|
||||
label: "Tuesday",
|
||||
},
|
||||
{
|
||||
value: EStartOfTheWeek.WEDNESDAY,
|
||||
label: "Wednesday",
|
||||
},
|
||||
{
|
||||
value: EStartOfTheWeek.THURSDAY,
|
||||
label: "Thursday",
|
||||
},
|
||||
{
|
||||
value: EStartOfTheWeek.FRIDAY,
|
||||
label: "Friday",
|
||||
},
|
||||
{
|
||||
value: EStartOfTheWeek.SATURDAY,
|
||||
label: "Saturday",
|
||||
},
|
||||
];
|
||||
160
packages/constants/src/project.ts
Normal file
160
packages/constants/src/project.ts
Normal file
@@ -0,0 +1,160 @@
|
||||
// plane imports
|
||||
import { IProject, TProjectAppliedDisplayFilterKeys, TProjectOrderByOptions } from "@plane/types";
|
||||
// local imports
|
||||
import { RANDOM_EMOJI_CODES } from "./emoji";
|
||||
|
||||
export type TNetworkChoiceIconKey = "Lock" | "Globe2";
|
||||
|
||||
export type TNetworkChoice = {
|
||||
key: 0 | 2;
|
||||
labelKey: string;
|
||||
i18n_label: string;
|
||||
description: string;
|
||||
iconKey: TNetworkChoiceIconKey;
|
||||
};
|
||||
|
||||
export const NETWORK_CHOICES: TNetworkChoice[] = [
|
||||
{
|
||||
key: 0,
|
||||
labelKey: "Private",
|
||||
i18n_label: "workspace_projects.network.private.title",
|
||||
description: "workspace_projects.network.private.description", //"Accessible only by invite",
|
||||
iconKey: "Lock",
|
||||
},
|
||||
{
|
||||
key: 2,
|
||||
labelKey: "Public",
|
||||
i18n_label: "workspace_projects.network.public.title",
|
||||
description: "workspace_projects.network.public.description", //"Anyone in the workspace except Guests can join",
|
||||
iconKey: "Globe2",
|
||||
},
|
||||
];
|
||||
|
||||
export const GROUP_CHOICES = {
|
||||
backlog: {
|
||||
key: "backlog",
|
||||
i18n_label: "workspace_projects.state.backlog",
|
||||
},
|
||||
unstarted: {
|
||||
key: "unstarted",
|
||||
i18n_label: "workspace_projects.state.unstarted",
|
||||
},
|
||||
started: {
|
||||
key: "started",
|
||||
i18n_label: "workspace_projects.state.started",
|
||||
},
|
||||
completed: {
|
||||
key: "completed",
|
||||
i18n_label: "workspace_projects.state.completed",
|
||||
},
|
||||
cancelled: {
|
||||
key: "cancelled",
|
||||
i18n_label: "workspace_projects.state.cancelled",
|
||||
},
|
||||
};
|
||||
|
||||
export const PROJECT_AUTOMATION_MONTHS = [
|
||||
{ i18n_label: "workspace_projects.common.months_count", value: 1 },
|
||||
{ i18n_label: "workspace_projects.common.months_count", value: 3 },
|
||||
{ i18n_label: "workspace_projects.common.months_count", value: 6 },
|
||||
{ i18n_label: "workspace_projects.common.months_count", value: 9 },
|
||||
{ i18n_label: "workspace_projects.common.months_count", value: 12 },
|
||||
];
|
||||
|
||||
export const PROJECT_UNSPLASH_COVERS = [
|
||||
"https://images.unsplash.com/photo-1531045535792-b515d59c3d1f?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=870&q=80",
|
||||
"https://images.unsplash.com/photo-1693027407934-e3aa8a54c7ae?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=870&q=80",
|
||||
"https://images.unsplash.com/photo-1518837695005-2083093ee35b?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=870&q=80",
|
||||
"https://images.unsplash.com/photo-1464925257126-6450e871c667?auto=format&fit=crop&q=80&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&w=870&q=80",
|
||||
"https://images.unsplash.com/photo-1606768666853-403c90a981ad?auto=format&fit=crop&q=80&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&w=870&q=80",
|
||||
"https://images.unsplash.com/photo-1627556592933-ffe99c1cd9eb?auto=format&fit=crop&q=80&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&w=870&q=80",
|
||||
"https://images.unsplash.com/photo-1643330683233-ff2ac89b002c?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=870&q=80",
|
||||
"https://images.unsplash.com/photo-1542202229-7d93c33f5d07?auto=format&fit=crop&q=80&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&w=870&q=80",
|
||||
"https://images.unsplash.com/photo-1511497584788-876760111969?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=870&q=80",
|
||||
"https://images.unsplash.com/photo-1475738972911-5b44ce984c42?auto=format&fit=crop&q=80&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&w=870&q=80",
|
||||
"https://images.unsplash.com/photo-1418065460487-3e41a6c84dc5?auto=format&fit=crop&q=80&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&w=870&q=80",
|
||||
"https://images.unsplash.com/photo-1673393058808-50e9baaf4d2c?auto=format&fit=crop&q=80&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&w=870&q=80",
|
||||
"https://images.unsplash.com/photo-1696643830146-44a8755f1905?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=870&q=80",
|
||||
"https://images.unsplash.com/photo-1693868769698-6c7440636a09?auto=format&fit=crop&q=80&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&w=870&q=80",
|
||||
"https://images.unsplash.com/photo-1691230995681-480d86cbc135?auto=format&fit=crop&q=80&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&w=870&q=80",
|
||||
"https://images.unsplash.com/photo-1675351066828-6fc770b90dd2?auto=format&fit=crop&q=80&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&w=870&q=80",
|
||||
];
|
||||
|
||||
export const PROJECT_ORDER_BY_OPTIONS: {
|
||||
key: TProjectOrderByOptions;
|
||||
i18n_label: string;
|
||||
}[] = [
|
||||
{
|
||||
key: "sort_order",
|
||||
i18n_label: "workspace_projects.sort.manual",
|
||||
},
|
||||
{
|
||||
key: "name",
|
||||
i18n_label: "workspace_projects.sort.name",
|
||||
},
|
||||
{
|
||||
key: "created_at",
|
||||
i18n_label: "workspace_projects.sort.created_at",
|
||||
},
|
||||
{
|
||||
key: "members_length",
|
||||
i18n_label: "workspace_projects.sort.members_length",
|
||||
},
|
||||
];
|
||||
|
||||
export const PROJECT_DISPLAY_FILTER_OPTIONS: {
|
||||
key: TProjectAppliedDisplayFilterKeys;
|
||||
i18n_label: string;
|
||||
}[] = [
|
||||
{
|
||||
key: "my_projects",
|
||||
i18n_label: "workspace_projects.scope.my_projects",
|
||||
},
|
||||
{
|
||||
key: "archived_projects",
|
||||
i18n_label: "workspace_projects.scope.archived_projects",
|
||||
},
|
||||
];
|
||||
|
||||
export const PROJECT_ERROR_MESSAGES = {
|
||||
permissionError: {
|
||||
i18n_title: "workspace_projects.error.permission",
|
||||
i18n_message: undefined,
|
||||
},
|
||||
cycleDeleteError: {
|
||||
i18n_title: "error",
|
||||
i18n_message: "workspace_projects.error.cycle_delete",
|
||||
},
|
||||
moduleDeleteError: {
|
||||
i18n_title: "error",
|
||||
i18n_message: "workspace_projects.error.module_delete",
|
||||
},
|
||||
issueDeleteError: {
|
||||
i18n_title: "error",
|
||||
i18n_message: "workspace_projects.error.issue_delete",
|
||||
},
|
||||
};
|
||||
|
||||
export const DEFAULT_PROJECT_FORM_VALUES: Partial<IProject> = {
|
||||
cover_image_url: PROJECT_UNSPLASH_COVERS[Math.floor(Math.random() * PROJECT_UNSPLASH_COVERS.length)],
|
||||
description: "",
|
||||
logo_props: {
|
||||
in_use: "emoji",
|
||||
emoji: {
|
||||
value: RANDOM_EMOJI_CODES[Math.floor(Math.random() * RANDOM_EMOJI_CODES.length)],
|
||||
},
|
||||
},
|
||||
identifier: "",
|
||||
name: "",
|
||||
network: 2,
|
||||
project_lead: null,
|
||||
};
|
||||
|
||||
export enum EProjectFeatureKey {
|
||||
WORK_ITEMS = "work_items",
|
||||
CYCLES = "cycles",
|
||||
MODULES = "modules",
|
||||
VIEWS = "views",
|
||||
PAGES = "pages",
|
||||
INTAKE = "intake",
|
||||
}
|
||||
2
packages/constants/src/rich-filters/index.ts
Normal file
2
packages/constants/src/rich-filters/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from "./operator-labels";
|
||||
export * from "./option";
|
||||
24
packages/constants/src/rich-filters/operator-labels/core.ts
Normal file
24
packages/constants/src/rich-filters/operator-labels/core.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import {
|
||||
CORE_EQUALITY_OPERATOR,
|
||||
CORE_COLLECTION_OPERATOR,
|
||||
CORE_COMPARISON_OPERATOR,
|
||||
TCoreSupportedOperators,
|
||||
TCoreSupportedDateFilterOperators,
|
||||
} from "@plane/types";
|
||||
|
||||
/**
|
||||
* Core operator labels
|
||||
*/
|
||||
export const CORE_OPERATOR_LABELS_MAP: Record<TCoreSupportedOperators, string> = {
|
||||
[CORE_EQUALITY_OPERATOR.EXACT]: "is",
|
||||
[CORE_COLLECTION_OPERATOR.IN]: "is any of",
|
||||
[CORE_COMPARISON_OPERATOR.RANGE]: "between",
|
||||
} as const;
|
||||
|
||||
/**
|
||||
* Core date-specific operator labels
|
||||
*/
|
||||
export const CORE_DATE_OPERATOR_LABELS_MAP: Record<TCoreSupportedDateFilterOperators, string> = {
|
||||
[CORE_EQUALITY_OPERATOR.EXACT]: "is",
|
||||
[CORE_COMPARISON_OPERATOR.RANGE]: "between",
|
||||
} as const;
|
||||
@@ -0,0 +1,21 @@
|
||||
import { TExtendedSupportedOperators } from "@plane/types";
|
||||
|
||||
/**
|
||||
* Extended operator labels
|
||||
*/
|
||||
export const EXTENDED_OPERATOR_LABELS_MAP: Record<TExtendedSupportedOperators, string> = {} as const;
|
||||
|
||||
/**
|
||||
* Extended date-specific operator labels
|
||||
*/
|
||||
export const EXTENDED_DATE_OPERATOR_LABELS_MAP: Record<TExtendedSupportedOperators, string> = {} as const;
|
||||
|
||||
/**
|
||||
* Negated operator labels for all operators
|
||||
*/
|
||||
export const NEGATED_OPERATOR_LABELS_MAP: Record<never, string> = {} as const;
|
||||
|
||||
/**
|
||||
* Negated date operator labels for all date operators
|
||||
*/
|
||||
export const NEGATED_DATE_OPERATOR_LABELS_MAP: Record<never, string> = {} as const;
|
||||
36
packages/constants/src/rich-filters/operator-labels/index.ts
Normal file
36
packages/constants/src/rich-filters/operator-labels/index.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { TAllAvailableOperatorsForDisplay, TAllAvailableDateFilterOperatorsForDisplay } from "@plane/types";
|
||||
import { CORE_OPERATOR_LABELS_MAP, CORE_DATE_OPERATOR_LABELS_MAP } from "./core";
|
||||
import {
|
||||
EXTENDED_OPERATOR_LABELS_MAP,
|
||||
EXTENDED_DATE_OPERATOR_LABELS_MAP,
|
||||
NEGATED_OPERATOR_LABELS_MAP,
|
||||
NEGATED_DATE_OPERATOR_LABELS_MAP,
|
||||
} from "./extended";
|
||||
|
||||
/**
|
||||
* Empty operator label for unselected state
|
||||
*/
|
||||
export const EMPTY_OPERATOR_LABEL = "--";
|
||||
|
||||
/**
|
||||
* Complete operator labels mapping - combines core, extended, and negated labels
|
||||
*/
|
||||
export const OPERATOR_LABELS_MAP: Record<TAllAvailableOperatorsForDisplay, string> = {
|
||||
...CORE_OPERATOR_LABELS_MAP,
|
||||
...EXTENDED_OPERATOR_LABELS_MAP,
|
||||
...NEGATED_OPERATOR_LABELS_MAP,
|
||||
} as const;
|
||||
|
||||
/**
|
||||
* Complete date operator labels mapping - combines core, extended, and negated labels
|
||||
*/
|
||||
export const DATE_OPERATOR_LABELS_MAP: Record<TAllAvailableDateFilterOperatorsForDisplay, string> = {
|
||||
...CORE_DATE_OPERATOR_LABELS_MAP,
|
||||
...EXTENDED_DATE_OPERATOR_LABELS_MAP,
|
||||
...NEGATED_DATE_OPERATOR_LABELS_MAP,
|
||||
} as const;
|
||||
|
||||
// -------- RE-EXPORTS --------
|
||||
|
||||
export * from "./core";
|
||||
export * from "./extended";
|
||||
83
packages/constants/src/rich-filters/option.ts
Normal file
83
packages/constants/src/rich-filters/option.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
import { TExternalFilter } from "@plane/types";
|
||||
|
||||
/**
|
||||
* Filter config options.
|
||||
*/
|
||||
export type TConfigOptions = Record<string, unknown>;
|
||||
|
||||
/**
|
||||
* Default filter config options.
|
||||
*/
|
||||
export const DEFAULT_FILTER_CONFIG_OPTIONS: TConfigOptions = {};
|
||||
|
||||
/**
|
||||
* Clear filter config.
|
||||
*/
|
||||
export type TClearFilterOptions = {
|
||||
label?: string;
|
||||
onFilterClear: () => void | Promise<void>;
|
||||
isDisabled?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* Save view config.
|
||||
*/
|
||||
export type TSaveViewOptions<E extends TExternalFilter> = {
|
||||
label?: string;
|
||||
onViewSave: (expression: E) => void | Promise<void>;
|
||||
isDisabled?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* Update view config.
|
||||
*/
|
||||
export type TUpdateViewOptions<E extends TExternalFilter> = {
|
||||
label?: string;
|
||||
hasAdditionalChanges?: boolean;
|
||||
onViewUpdate: (expression: E) => void | Promise<void>;
|
||||
isDisabled?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* Filter expression options.
|
||||
*/
|
||||
export type TExpressionOptions<E extends TExternalFilter> = {
|
||||
clearFilterOptions?: TClearFilterOptions;
|
||||
saveViewOptions?: TSaveViewOptions<E>;
|
||||
updateViewOptions?: TUpdateViewOptions<E>;
|
||||
};
|
||||
|
||||
/**
|
||||
* Default filter expression options.
|
||||
*/
|
||||
export const DEFAULT_FILTER_EXPRESSION_OPTIONS: TExpressionOptions<TExternalFilter> = {};
|
||||
|
||||
/**
|
||||
* Auto visibility options.
|
||||
*/
|
||||
export type TAutoVisibilityOptions =
|
||||
| {
|
||||
autoSetVisibility: true;
|
||||
}
|
||||
| {
|
||||
autoSetVisibility: false;
|
||||
isVisibleOnMount: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* Default filter visibility options.
|
||||
*/
|
||||
export const DEFAULT_FILTER_VISIBILITY_OPTIONS: TAutoVisibilityOptions = {
|
||||
autoSetVisibility: true,
|
||||
};
|
||||
|
||||
/**
|
||||
* Filter options.
|
||||
* - expression: Filter expression options.
|
||||
* - config: Filter config options.
|
||||
*/
|
||||
export type TFilterOptions<E extends TExternalFilter> = {
|
||||
expression: Partial<TExpressionOptions<E>>;
|
||||
config: Partial<TConfigOptions>;
|
||||
visibility: TAutoVisibilityOptions;
|
||||
};
|
||||
52
packages/constants/src/settings.ts
Normal file
52
packages/constants/src/settings.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { PROFILE_SETTINGS } from "./profile";
|
||||
import { WORKSPACE_SETTINGS } from "./workspace";
|
||||
|
||||
export enum WORKSPACE_SETTINGS_CATEGORY {
|
||||
ADMINISTRATION = "administration",
|
||||
FEATURES = "features",
|
||||
DEVELOPER = "developer",
|
||||
}
|
||||
|
||||
export enum PROFILE_SETTINGS_CATEGORY {
|
||||
YOUR_PROFILE = "your profile",
|
||||
DEVELOPER = "developer",
|
||||
}
|
||||
|
||||
export enum PROJECT_SETTINGS_CATEGORY {
|
||||
PROJECTS = "projects",
|
||||
}
|
||||
|
||||
export const WORKSPACE_SETTINGS_CATEGORIES = [
|
||||
WORKSPACE_SETTINGS_CATEGORY.ADMINISTRATION,
|
||||
WORKSPACE_SETTINGS_CATEGORY.FEATURES,
|
||||
WORKSPACE_SETTINGS_CATEGORY.DEVELOPER,
|
||||
];
|
||||
|
||||
export const PROFILE_SETTINGS_CATEGORIES = [
|
||||
PROFILE_SETTINGS_CATEGORY.YOUR_PROFILE,
|
||||
PROFILE_SETTINGS_CATEGORY.DEVELOPER,
|
||||
];
|
||||
|
||||
export const PROJECT_SETTINGS_CATEGORIES = [PROJECT_SETTINGS_CATEGORY.PROJECTS];
|
||||
|
||||
export const GROUPED_WORKSPACE_SETTINGS = {
|
||||
[WORKSPACE_SETTINGS_CATEGORY.ADMINISTRATION]: [
|
||||
WORKSPACE_SETTINGS["general"],
|
||||
WORKSPACE_SETTINGS["members"],
|
||||
WORKSPACE_SETTINGS["billing-and-plans"],
|
||||
WORKSPACE_SETTINGS["export"],
|
||||
],
|
||||
[WORKSPACE_SETTINGS_CATEGORY.FEATURES]: [],
|
||||
[WORKSPACE_SETTINGS_CATEGORY.DEVELOPER]: [WORKSPACE_SETTINGS["webhooks"]],
|
||||
};
|
||||
|
||||
export const GROUPED_PROFILE_SETTINGS = {
|
||||
[PROFILE_SETTINGS_CATEGORY.YOUR_PROFILE]: [
|
||||
PROFILE_SETTINGS["profile"],
|
||||
PROFILE_SETTINGS["preferences"],
|
||||
PROFILE_SETTINGS["notifications"],
|
||||
PROFILE_SETTINGS["security"],
|
||||
PROFILE_SETTINGS["activity"],
|
||||
],
|
||||
[PROFILE_SETTINGS_CATEGORY.DEVELOPER]: [PROFILE_SETTINGS["api-tokens"]],
|
||||
};
|
||||
2
packages/constants/src/sidebar.ts
Normal file
2
packages/constants/src/sidebar.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export const SIDEBAR_WIDTH = 250;
|
||||
export const EXTENDED_SIDEBAR_WIDTH = 300;
|
||||
1
packages/constants/src/spreadsheet.ts
Normal file
1
packages/constants/src/spreadsheet.ts
Normal file
@@ -0,0 +1 @@
|
||||
export const SPREADSHEET_SELECT_GROUP = "spreadsheet-issues";
|
||||
108
packages/constants/src/state.ts
Normal file
108
packages/constants/src/state.ts
Normal file
@@ -0,0 +1,108 @@
|
||||
import { TStateGroups } from "@plane/types";
|
||||
|
||||
export type TDraggableData = {
|
||||
groupKey: TStateGroups;
|
||||
id: string;
|
||||
};
|
||||
|
||||
export const STATE_GROUPS: {
|
||||
[key in TStateGroups]: {
|
||||
key: TStateGroups;
|
||||
label: string;
|
||||
defaultStateName: string;
|
||||
color: string;
|
||||
};
|
||||
} = {
|
||||
backlog: {
|
||||
key: "backlog",
|
||||
label: "Backlog",
|
||||
defaultStateName: "Backlog",
|
||||
color: "#d9d9d9",
|
||||
},
|
||||
unstarted: {
|
||||
key: "unstarted",
|
||||
label: "Unstarted",
|
||||
defaultStateName: "Todo",
|
||||
color: "#3f76ff",
|
||||
},
|
||||
started: {
|
||||
key: "started",
|
||||
label: "Started",
|
||||
defaultStateName: "In Progress",
|
||||
color: "#f59e0b",
|
||||
},
|
||||
completed: {
|
||||
key: "completed",
|
||||
label: "Completed",
|
||||
defaultStateName: "Done",
|
||||
color: "#16a34a",
|
||||
},
|
||||
cancelled: {
|
||||
key: "cancelled",
|
||||
label: "Canceled",
|
||||
defaultStateName: "Cancelled",
|
||||
color: "#dc2626",
|
||||
},
|
||||
};
|
||||
|
||||
export const ARCHIVABLE_STATE_GROUPS = [STATE_GROUPS.completed.key, STATE_GROUPS.cancelled.key];
|
||||
export const COMPLETED_STATE_GROUPS = [STATE_GROUPS.completed.key];
|
||||
export const PENDING_STATE_GROUPS = [
|
||||
STATE_GROUPS.backlog.key,
|
||||
STATE_GROUPS.unstarted.key,
|
||||
STATE_GROUPS.started.key,
|
||||
STATE_GROUPS.cancelled.key,
|
||||
];
|
||||
|
||||
export const STATE_DISTRIBUTION = {
|
||||
[STATE_GROUPS.backlog.key]: {
|
||||
key: STATE_GROUPS.backlog.key,
|
||||
issues: "backlog_issues",
|
||||
points: "backlog_estimate_points",
|
||||
},
|
||||
[STATE_GROUPS.unstarted.key]: {
|
||||
key: STATE_GROUPS.unstarted.key,
|
||||
issues: "unstarted_issues",
|
||||
points: "unstarted_estimate_points",
|
||||
},
|
||||
[STATE_GROUPS.started.key]: {
|
||||
key: STATE_GROUPS.started.key,
|
||||
issues: "started_issues",
|
||||
points: "started_estimate_points",
|
||||
},
|
||||
[STATE_GROUPS.completed.key]: {
|
||||
key: STATE_GROUPS.completed.key,
|
||||
issues: "completed_issues",
|
||||
points: "completed_estimate_points",
|
||||
},
|
||||
[STATE_GROUPS.cancelled.key]: {
|
||||
key: STATE_GROUPS.cancelled.key,
|
||||
issues: "cancelled_issues",
|
||||
points: "cancelled_estimate_points",
|
||||
},
|
||||
};
|
||||
|
||||
export const PROGRESS_STATE_GROUPS_DETAILS = [
|
||||
{
|
||||
key: "completed_issues",
|
||||
title: "Completed",
|
||||
color: "#16A34A",
|
||||
},
|
||||
{
|
||||
key: "started_issues",
|
||||
title: "Started",
|
||||
color: "#F59E0B",
|
||||
},
|
||||
{
|
||||
key: "unstarted_issues",
|
||||
title: "Unstarted",
|
||||
color: "#3A3A3A",
|
||||
},
|
||||
{
|
||||
key: "backlog_issues",
|
||||
title: "Backlog",
|
||||
color: "#A3A3A3",
|
||||
},
|
||||
];
|
||||
|
||||
export const DISPLAY_WORKFLOW_PRO_CTA = false;
|
||||
1
packages/constants/src/stickies.ts
Normal file
1
packages/constants/src/stickies.ts
Normal file
@@ -0,0 +1 @@
|
||||
export const STICKIES_PER_PAGE = 30;
|
||||
42
packages/constants/src/subscription.ts
Normal file
42
packages/constants/src/subscription.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
export const ENTERPRISE_PLAN_FEATURES = [
|
||||
"Private + managed deployments",
|
||||
"GAC",
|
||||
"LDAP support",
|
||||
"Databases + Formulas",
|
||||
"Unlimited and full Automation Flows",
|
||||
"Full-suite professional services",
|
||||
];
|
||||
|
||||
export const BUSINESS_PLAN_FEATURES = [
|
||||
"Project Templates",
|
||||
"Workflows + Approvals",
|
||||
"Decision + Loops Automation",
|
||||
"Custom Reports",
|
||||
"Nested Pages",
|
||||
"Intake Forms",
|
||||
];
|
||||
|
||||
export const PRO_PLAN_FEATURES = [
|
||||
"Dashboards + Reports",
|
||||
"Full Time Tracking + Bulk Ops",
|
||||
"Teamspaces",
|
||||
"Trigger And Action",
|
||||
"Wikis",
|
||||
"Popular integrations",
|
||||
];
|
||||
|
||||
export const ONE_PLAN_FEATURES = [
|
||||
"OIDC + SAML for SSO",
|
||||
"Active Cycles",
|
||||
"Real-time collab + public views and page",
|
||||
"Link pages in issues and vice-versa",
|
||||
"Time-tracking + limited bulk ops",
|
||||
"Docker, Kubernetes and more",
|
||||
];
|
||||
|
||||
export const FREE_PLAN_UPGRADE_FEATURES = [
|
||||
"OIDC + SAML for SSO",
|
||||
"Time Tracking and Bulk Ops",
|
||||
"Integrations",
|
||||
"Public Views and Pages",
|
||||
];
|
||||
16
packages/constants/src/swr.ts
Normal file
16
packages/constants/src/swr.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
export const DEFAULT_SWR_CONFIG = {
|
||||
refreshWhenHidden: false,
|
||||
revalidateIfStale: false,
|
||||
revalidateOnFocus: false,
|
||||
revalidateOnMount: true,
|
||||
refreshInterval: 600000,
|
||||
errorRetryCount: 3,
|
||||
};
|
||||
|
||||
export const WEB_SWR_CONFIG = {
|
||||
refreshWhenHidden: false,
|
||||
revalidateIfStale: true,
|
||||
revalidateOnFocus: true,
|
||||
revalidateOnMount: true,
|
||||
errorRetryCount: 3,
|
||||
};
|
||||
93
packages/constants/src/tab-indices.ts
Normal file
93
packages/constants/src/tab-indices.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
export const ISSUE_FORM_TAB_INDICES = [
|
||||
"name",
|
||||
"description_html",
|
||||
"feeling_lucky",
|
||||
"state_id",
|
||||
"priority",
|
||||
"assignee_ids",
|
||||
"label_ids",
|
||||
"start_date",
|
||||
"target_date",
|
||||
"cycle_id",
|
||||
"module_ids",
|
||||
"estimate_point",
|
||||
"parent_id",
|
||||
"create_more",
|
||||
"discard_button",
|
||||
"draft_button",
|
||||
"submit_button",
|
||||
"project_id",
|
||||
"remove_parent",
|
||||
];
|
||||
|
||||
export const INTAKE_ISSUE_CREATE_FORM_TAB_INDICES = [
|
||||
"name",
|
||||
"description_html",
|
||||
"state_id",
|
||||
"priority",
|
||||
"assignee_ids",
|
||||
"label_ids",
|
||||
"start_date",
|
||||
"target_date",
|
||||
"cycle_id",
|
||||
"module_ids",
|
||||
"estimate_point",
|
||||
"parent_id",
|
||||
"create_more",
|
||||
"discard_button",
|
||||
"submit_button",
|
||||
];
|
||||
|
||||
export const CREATE_LABEL_TAB_INDICES = ["name", "color", "cancel", "submit"];
|
||||
|
||||
export const PROJECT_CREATE_TAB_INDICES = [
|
||||
"name",
|
||||
"identifier",
|
||||
"description",
|
||||
"network",
|
||||
"lead",
|
||||
"cancel",
|
||||
"submit",
|
||||
"close",
|
||||
"cover_image",
|
||||
"logo_props",
|
||||
];
|
||||
|
||||
export const PROJECT_CYCLE_TAB_INDICES = ["name", "description", "date_range", "cancel", "submit", "project_id"];
|
||||
|
||||
export const PROJECT_MODULE_TAB_INDICES = [
|
||||
"name",
|
||||
"description",
|
||||
"date_range",
|
||||
"status",
|
||||
"lead",
|
||||
"member_ids",
|
||||
"cancel",
|
||||
"submit",
|
||||
];
|
||||
|
||||
export const PROJECT_VIEW_TAB_INDICES = ["name", "description", "filters", "cancel", "submit"];
|
||||
|
||||
export const PROJECT_PAGE_TAB_INDICES = ["name", "public", "private", "cancel", "submit"];
|
||||
|
||||
export enum ETabIndices {
|
||||
ISSUE_FORM = "issue-form",
|
||||
INTAKE_ISSUE_FORM = "intake-issue-form",
|
||||
CREATE_LABEL = "create-label",
|
||||
PROJECT_CREATE = "project-create",
|
||||
PROJECT_CYCLE = "project-cycle",
|
||||
PROJECT_MODULE = "project-module",
|
||||
PROJECT_VIEW = "project-view",
|
||||
PROJECT_PAGE = "project-page",
|
||||
}
|
||||
|
||||
export const TAB_INDEX_MAP: Record<ETabIndices, string[]> = {
|
||||
[ETabIndices.ISSUE_FORM]: ISSUE_FORM_TAB_INDICES,
|
||||
[ETabIndices.INTAKE_ISSUE_FORM]: INTAKE_ISSUE_CREATE_FORM_TAB_INDICES,
|
||||
[ETabIndices.CREATE_LABEL]: CREATE_LABEL_TAB_INDICES,
|
||||
[ETabIndices.PROJECT_CREATE]: PROJECT_CREATE_TAB_INDICES,
|
||||
[ETabIndices.PROJECT_CYCLE]: PROJECT_CYCLE_TAB_INDICES,
|
||||
[ETabIndices.PROJECT_MODULE]: PROJECT_MODULE_TAB_INDICES,
|
||||
[ETabIndices.PROJECT_VIEW]: PROJECT_VIEW_TAB_INDICES,
|
||||
[ETabIndices.PROJECT_PAGE]: PROJECT_PAGE_TAB_INDICES,
|
||||
};
|
||||
82
packages/constants/src/themes.ts
Normal file
82
packages/constants/src/themes.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
export const THEMES = ["light", "dark", "light-contrast", "dark-contrast", "custom"];
|
||||
|
||||
export interface I_THEME_OPTION {
|
||||
key: string;
|
||||
value: string;
|
||||
i18n_label: string;
|
||||
type: string;
|
||||
icon: {
|
||||
border: string;
|
||||
color1: string;
|
||||
color2: string;
|
||||
};
|
||||
}
|
||||
|
||||
export const THEME_OPTIONS: I_THEME_OPTION[] = [
|
||||
{
|
||||
key: "system_preference",
|
||||
value: "system",
|
||||
i18n_label: "System preference",
|
||||
type: "light",
|
||||
icon: {
|
||||
border: "#DEE2E6",
|
||||
color1: "#FAFAFA",
|
||||
color2: "#3F76FF",
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "light",
|
||||
value: "light",
|
||||
i18n_label: "Light",
|
||||
type: "light",
|
||||
icon: {
|
||||
border: "#DEE2E6",
|
||||
color1: "#FAFAFA",
|
||||
color2: "#3F76FF",
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "dark",
|
||||
value: "dark",
|
||||
i18n_label: "Dark",
|
||||
type: "dark",
|
||||
icon: {
|
||||
border: "#2E3234",
|
||||
color1: "#191B1B",
|
||||
color2: "#3C85D9",
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "light_contrast",
|
||||
value: "light-contrast",
|
||||
i18n_label: "Light high contrast",
|
||||
type: "light",
|
||||
icon: {
|
||||
border: "#000000",
|
||||
color1: "#FFFFFF",
|
||||
color2: "#3F76FF",
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "dark_contrast",
|
||||
value: "dark-contrast",
|
||||
i18n_label: "Dark high contrast",
|
||||
type: "dark",
|
||||
icon: {
|
||||
border: "#FFFFFF",
|
||||
color1: "#030303",
|
||||
color2: "#3A8BE9",
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "custom",
|
||||
value: "custom",
|
||||
i18n_label: "Custom theme",
|
||||
type: "light",
|
||||
icon: {
|
||||
border: "#FFC9C9",
|
||||
color1: "#FFF7F7",
|
||||
color2: "#FF5151",
|
||||
},
|
||||
},
|
||||
];
|
||||
59
packages/constants/src/user.ts
Normal file
59
packages/constants/src/user.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
export enum EAuthenticationPageType {
|
||||
STATIC = "STATIC",
|
||||
NOT_AUTHENTICATED = "NOT_AUTHENTICATED",
|
||||
AUTHENTICATED = "AUTHENTICATED",
|
||||
}
|
||||
|
||||
export enum EInstancePageType {
|
||||
PRE_SETUP = "PRE_SETUP",
|
||||
POST_SETUP = "POST_SETUP",
|
||||
}
|
||||
|
||||
export enum EUserStatus {
|
||||
ERROR = "ERROR",
|
||||
AUTHENTICATION_NOT_DONE = "AUTHENTICATION_NOT_DONE",
|
||||
NOT_YET_READY = "NOT_YET_READY",
|
||||
}
|
||||
|
||||
export type TUserStatus = {
|
||||
status: EUserStatus | undefined;
|
||||
message?: string;
|
||||
};
|
||||
|
||||
export enum EUserPermissionsLevel {
|
||||
WORKSPACE = "WORKSPACE",
|
||||
PROJECT = "PROJECT",
|
||||
}
|
||||
|
||||
export type TUserPermissionsLevel = EUserPermissionsLevel;
|
||||
|
||||
export enum EUserPermissions {
|
||||
ADMIN = 20,
|
||||
MEMBER = 15,
|
||||
GUEST = 5,
|
||||
}
|
||||
export type TUserPermissions = EUserPermissions;
|
||||
|
||||
export type TUserAllowedPermissionsObject = {
|
||||
create: TUserPermissions[];
|
||||
update: TUserPermissions[];
|
||||
delete: TUserPermissions[];
|
||||
read: TUserPermissions[];
|
||||
};
|
||||
export type TUserAllowedPermissions = {
|
||||
workspace: {
|
||||
[key: string]: Partial<TUserAllowedPermissionsObject>;
|
||||
};
|
||||
project: {
|
||||
[key: string]: Partial<TUserAllowedPermissionsObject>;
|
||||
};
|
||||
};
|
||||
|
||||
export const USER_ALLOWED_PERMISSIONS: TUserAllowedPermissions = {
|
||||
workspace: {
|
||||
dashboard: {
|
||||
read: [EUserPermissions.ADMIN, EUserPermissions.MEMBER, EUserPermissions.GUEST],
|
||||
},
|
||||
},
|
||||
project: {},
|
||||
};
|
||||
20
packages/constants/src/views.ts
Normal file
20
packages/constants/src/views.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { EViewAccess } from "@plane/types";
|
||||
|
||||
export const VIEW_ACCESS_SPECIFIERS: {
|
||||
key: EViewAccess;
|
||||
i18n_label: string;
|
||||
}[] = [
|
||||
{ key: EViewAccess.PUBLIC, i18n_label: "common.access.public" },
|
||||
{ key: EViewAccess.PRIVATE, i18n_label: "common.access.private" },
|
||||
];
|
||||
|
||||
export const VIEW_SORTING_KEY_OPTIONS = [
|
||||
{ key: "name", i18n_label: "project_view.sort_by.name" },
|
||||
{ key: "created_at", i18n_label: "project_view.sort_by.created_at" },
|
||||
{ key: "updated_at", i18n_label: "project_view.sort_by.updated_at" },
|
||||
];
|
||||
|
||||
export const VIEW_SORT_BY_OPTIONS = [
|
||||
{ key: "asc", i18n_label: "common.order_by.asc" },
|
||||
{ key: "desc", i18n_label: "common.order_by.desc" },
|
||||
];
|
||||
6
packages/constants/src/workspace-drafts.ts
Normal file
6
packages/constants/src/workspace-drafts.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export enum EDraftIssuePaginationType {
|
||||
INIT = "INIT",
|
||||
NEXT = "NEXT",
|
||||
PREV = "PREV",
|
||||
CURRENT = "CURRENT",
|
||||
}
|
||||
348
packages/constants/src/workspace.ts
Normal file
348
packages/constants/src/workspace.ts
Normal file
@@ -0,0 +1,348 @@
|
||||
import { TStaticViewTypes, IWorkspaceSearchResults, EUserWorkspaceRoles } from "@plane/types";
|
||||
|
||||
export const ORGANIZATION_SIZE = ["Just myself", "2-10", "11-50", "51-200", "201-500", "500+"];
|
||||
|
||||
export const RESTRICTED_URLS = [
|
||||
"404",
|
||||
"accounts",
|
||||
"api",
|
||||
"create-workspace",
|
||||
"god-mode",
|
||||
"installations",
|
||||
"invitations",
|
||||
"onboarding",
|
||||
"profile",
|
||||
"spaces",
|
||||
"workspace-invitations",
|
||||
"password",
|
||||
"flags",
|
||||
"monitor",
|
||||
"monitoring",
|
||||
"ingest",
|
||||
"plane-pro",
|
||||
"plane-ultimate",
|
||||
"enterprise",
|
||||
"plane-enterprise",
|
||||
"disco",
|
||||
"silo",
|
||||
"chat",
|
||||
"calendar",
|
||||
"drive",
|
||||
"channels",
|
||||
"upgrade",
|
||||
"billing",
|
||||
"sign-in",
|
||||
"sign-up",
|
||||
"signin",
|
||||
"signup",
|
||||
"config",
|
||||
"live",
|
||||
"admin",
|
||||
"m",
|
||||
"import",
|
||||
"importers",
|
||||
"integrations",
|
||||
"integration",
|
||||
"configuration",
|
||||
"initiatives",
|
||||
"initiative",
|
||||
"config",
|
||||
"workflow",
|
||||
"workflows",
|
||||
"epics",
|
||||
"epic",
|
||||
"story",
|
||||
"mobile",
|
||||
"dashboard",
|
||||
"desktop",
|
||||
"onload",
|
||||
"real-time",
|
||||
"one",
|
||||
"pages",
|
||||
"mobile",
|
||||
"business",
|
||||
"pro",
|
||||
"settings",
|
||||
"monitor",
|
||||
"license",
|
||||
"licenses",
|
||||
"instances",
|
||||
"instance",
|
||||
];
|
||||
|
||||
export const WORKSPACE_SETTINGS = {
|
||||
general: {
|
||||
key: "general",
|
||||
i18n_label: "workspace_settings.settings.general.title",
|
||||
href: `/settings`,
|
||||
access: [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER],
|
||||
highlight: (pathname: string, baseUrl: string) => pathname === `${baseUrl}/settings/`,
|
||||
},
|
||||
members: {
|
||||
key: "members",
|
||||
i18n_label: "workspace_settings.settings.members.title",
|
||||
href: `/settings/members`,
|
||||
access: [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER],
|
||||
highlight: (pathname: string, baseUrl: string) => pathname === `${baseUrl}/settings/members/`,
|
||||
},
|
||||
"billing-and-plans": {
|
||||
key: "billing-and-plans",
|
||||
i18n_label: "workspace_settings.settings.billing_and_plans.title",
|
||||
href: `/settings/billing`,
|
||||
access: [EUserWorkspaceRoles.ADMIN],
|
||||
highlight: (pathname: string, baseUrl: string) => pathname === `${baseUrl}/settings/billing/`,
|
||||
},
|
||||
export: {
|
||||
key: "export",
|
||||
i18n_label: "workspace_settings.settings.exports.title",
|
||||
href: `/settings/exports`,
|
||||
access: [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER],
|
||||
highlight: (pathname: string, baseUrl: string) => pathname === `${baseUrl}/settings/exports/`,
|
||||
},
|
||||
webhooks: {
|
||||
key: "webhooks",
|
||||
i18n_label: "workspace_settings.settings.webhooks.title",
|
||||
href: `/settings/webhooks`,
|
||||
access: [EUserWorkspaceRoles.ADMIN],
|
||||
highlight: (pathname: string, baseUrl: string) => pathname === `${baseUrl}/settings/webhooks/`,
|
||||
},
|
||||
};
|
||||
|
||||
export const WORKSPACE_SETTINGS_ACCESS = Object.fromEntries(
|
||||
Object.entries(WORKSPACE_SETTINGS).map(([_, { href, access }]) => [href, access])
|
||||
);
|
||||
|
||||
export const WORKSPACE_SETTINGS_LINKS: {
|
||||
key: string;
|
||||
i18n_label: string;
|
||||
href: string;
|
||||
access: EUserWorkspaceRoles[];
|
||||
highlight: (pathname: string, baseUrl: string) => boolean;
|
||||
}[] = [
|
||||
WORKSPACE_SETTINGS["general"],
|
||||
WORKSPACE_SETTINGS["members"],
|
||||
WORKSPACE_SETTINGS["billing-and-plans"],
|
||||
WORKSPACE_SETTINGS["export"],
|
||||
WORKSPACE_SETTINGS["webhooks"],
|
||||
];
|
||||
|
||||
export const ROLE = {
|
||||
[EUserWorkspaceRoles.GUEST]: "Guest",
|
||||
[EUserWorkspaceRoles.MEMBER]: "Member",
|
||||
[EUserWorkspaceRoles.ADMIN]: "Admin",
|
||||
};
|
||||
|
||||
export const ROLE_DETAILS = {
|
||||
[EUserWorkspaceRoles.GUEST]: {
|
||||
i18n_title: "role_details.guest.title",
|
||||
i18n_description: "role_details.guest.description",
|
||||
},
|
||||
[EUserWorkspaceRoles.MEMBER]: {
|
||||
i18n_title: "role_details.member.title",
|
||||
i18n_description: "role_details.member.description",
|
||||
},
|
||||
[EUserWorkspaceRoles.ADMIN]: {
|
||||
i18n_title: "role_details.admin.title",
|
||||
i18n_description: "role_details.admin.description",
|
||||
},
|
||||
};
|
||||
|
||||
export const USER_ROLES = [
|
||||
{
|
||||
value: "Product / Project Manager",
|
||||
i18n_label: "user_roles.product_or_project_manager",
|
||||
},
|
||||
{
|
||||
value: "Development / Engineering",
|
||||
i18n_label: "user_roles.development_or_engineering",
|
||||
},
|
||||
{
|
||||
value: "Founder / Executive",
|
||||
i18n_label: "user_roles.founder_or_executive",
|
||||
},
|
||||
{
|
||||
value: "Freelancer / Consultant",
|
||||
i18n_label: "user_roles.freelancer_or_consultant",
|
||||
},
|
||||
{ value: "Marketing / Growth", i18n_label: "user_roles.marketing_or_growth" },
|
||||
{
|
||||
value: "Sales / Business Development",
|
||||
i18n_label: "user_roles.sales_or_business_development",
|
||||
},
|
||||
{
|
||||
value: "Support / Operations",
|
||||
i18n_label: "user_roles.support_or_operations",
|
||||
},
|
||||
{
|
||||
value: "Student / Professor",
|
||||
i18n_label: "user_roles.student_or_professor",
|
||||
},
|
||||
{ value: "Human Resources", i18n_label: "user_roles.human_resources" },
|
||||
{ value: "Other", i18n_label: "user_roles.other" },
|
||||
];
|
||||
|
||||
export const IMPORTERS_LIST = [
|
||||
{
|
||||
provider: "github",
|
||||
type: "import",
|
||||
i18n_title: "importer.github.title",
|
||||
i18n_description: "importer.github.description",
|
||||
},
|
||||
{
|
||||
provider: "jira",
|
||||
type: "import",
|
||||
i18n_title: "importer.jira.title",
|
||||
i18n_description: "importer.jira.description",
|
||||
},
|
||||
];
|
||||
|
||||
export const EXPORTERS_LIST = [
|
||||
{
|
||||
provider: "csv",
|
||||
type: "export",
|
||||
i18n_title: "exporter.csv.title",
|
||||
i18n_description: "exporter.csv.description",
|
||||
},
|
||||
{
|
||||
provider: "xlsx",
|
||||
type: "export",
|
||||
i18n_title: "exporter.excel.title",
|
||||
i18n_description: "exporter.csv.description",
|
||||
},
|
||||
{
|
||||
provider: "json",
|
||||
type: "export",
|
||||
i18n_title: "exporter.json.title",
|
||||
i18n_description: "exporter.csv.description",
|
||||
},
|
||||
];
|
||||
|
||||
export const DEFAULT_GLOBAL_VIEWS_LIST: {
|
||||
key: TStaticViewTypes;
|
||||
i18n_label: string;
|
||||
}[] = [
|
||||
{
|
||||
key: "all-issues",
|
||||
i18n_label: "default_global_view.all_issues",
|
||||
},
|
||||
{
|
||||
key: "assigned",
|
||||
i18n_label: "default_global_view.assigned",
|
||||
},
|
||||
{
|
||||
key: "created",
|
||||
i18n_label: "default_global_view.created",
|
||||
},
|
||||
{
|
||||
key: "subscribed",
|
||||
i18n_label: "default_global_view.subscribed",
|
||||
},
|
||||
];
|
||||
|
||||
export interface IWorkspaceSidebarNavigationItem {
|
||||
key: string;
|
||||
labelTranslationKey: string;
|
||||
href: string;
|
||||
access: EUserWorkspaceRoles[];
|
||||
highlight: (pathname: string, url: string) => boolean;
|
||||
}
|
||||
|
||||
export const WORKSPACE_SIDEBAR_DYNAMIC_NAVIGATION_ITEMS: Record<string, IWorkspaceSidebarNavigationItem> = {
|
||||
views: {
|
||||
key: "views",
|
||||
labelTranslationKey: "views",
|
||||
href: `/workspace-views/all-issues/`,
|
||||
access: [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER, EUserWorkspaceRoles.GUEST],
|
||||
highlight: (pathname: string, url: string) => pathname === url,
|
||||
},
|
||||
analytics: {
|
||||
key: "analytics",
|
||||
labelTranslationKey: "analytics",
|
||||
href: `/analytics/`,
|
||||
access: [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER],
|
||||
highlight: (pathname: string, url: string) => pathname.includes(url),
|
||||
},
|
||||
drafts: {
|
||||
key: "drafts",
|
||||
labelTranslationKey: "drafts",
|
||||
href: `/drafts/`,
|
||||
access: [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER],
|
||||
highlight: (pathname: string, url: string) => pathname.includes(url),
|
||||
},
|
||||
archives: {
|
||||
key: "archives",
|
||||
labelTranslationKey: "archives",
|
||||
href: `/projects/archives/`,
|
||||
access: [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER],
|
||||
highlight: (pathname: string, url: string) => pathname.includes(url),
|
||||
},
|
||||
};
|
||||
|
||||
export const WORKSPACE_SIDEBAR_DYNAMIC_NAVIGATION_ITEMS_LINKS: IWorkspaceSidebarNavigationItem[] = [
|
||||
WORKSPACE_SIDEBAR_DYNAMIC_NAVIGATION_ITEMS["views"]!,
|
||||
WORKSPACE_SIDEBAR_DYNAMIC_NAVIGATION_ITEMS["analytics"]!,
|
||||
WORKSPACE_SIDEBAR_DYNAMIC_NAVIGATION_ITEMS["drafts"]!,
|
||||
WORKSPACE_SIDEBAR_DYNAMIC_NAVIGATION_ITEMS["archives"]!,
|
||||
];
|
||||
|
||||
export const WORKSPACE_SIDEBAR_STATIC_NAVIGATION_ITEMS: Record<string, IWorkspaceSidebarNavigationItem> = {
|
||||
home: {
|
||||
key: "home",
|
||||
labelTranslationKey: "home.title",
|
||||
href: `/`,
|
||||
access: [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER, EUserWorkspaceRoles.GUEST],
|
||||
highlight: (pathname: string, url: string) => pathname === url,
|
||||
},
|
||||
inbox: {
|
||||
key: "inbox",
|
||||
labelTranslationKey: "notification.label",
|
||||
href: `/notifications/`,
|
||||
access: [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER, EUserWorkspaceRoles.GUEST],
|
||||
highlight: (pathname: string, url: string) => pathname.includes(url),
|
||||
},
|
||||
"your-work": {
|
||||
key: "your_work",
|
||||
labelTranslationKey: "your_work",
|
||||
href: `/profile/`,
|
||||
access: [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER],
|
||||
highlight: (pathname: string, url: string) => pathname.includes(url),
|
||||
},
|
||||
projects: {
|
||||
key: "projects",
|
||||
labelTranslationKey: "projects",
|
||||
href: `/projects/`,
|
||||
access: [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER, EUserWorkspaceRoles.GUEST],
|
||||
highlight: (pathname: string, url: string) => pathname === url,
|
||||
},
|
||||
};
|
||||
|
||||
export const WORKSPACE_SIDEBAR_STATIC_NAVIGATION_ITEMS_LINKS: IWorkspaceSidebarNavigationItem[] = [
|
||||
WORKSPACE_SIDEBAR_STATIC_NAVIGATION_ITEMS["home"]!,
|
||||
WORKSPACE_SIDEBAR_STATIC_NAVIGATION_ITEMS["inbox"]!,
|
||||
WORKSPACE_SIDEBAR_STATIC_NAVIGATION_ITEMS["your-work"]!,
|
||||
];
|
||||
|
||||
export const WORKSPACE_SIDEBAR_STATIC_PINNED_NAVIGATION_ITEMS_LINKS: IWorkspaceSidebarNavigationItem[] = [
|
||||
WORKSPACE_SIDEBAR_STATIC_NAVIGATION_ITEMS["projects"]!,
|
||||
];
|
||||
|
||||
export const IS_FAVORITE_MENU_OPEN = "is_favorite_menu_open";
|
||||
export const WORKSPACE_DEFAULT_SEARCH_RESULT: IWorkspaceSearchResults = {
|
||||
results: {
|
||||
workspace: [],
|
||||
project: [],
|
||||
issue: [],
|
||||
cycle: [],
|
||||
module: [],
|
||||
issue_view: [],
|
||||
page: [],
|
||||
},
|
||||
};
|
||||
|
||||
export const USE_CASES = [
|
||||
"Plan and track product roadmaps",
|
||||
"Manage engineering sprints",
|
||||
"Coordinate cross-functional projects",
|
||||
"Replace our current tool",
|
||||
"Just exploring",
|
||||
];
|
||||
12
packages/constants/tsconfig.json
Normal file
12
packages/constants/tsconfig.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"extends": "@plane/typescript-config/base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "dist",
|
||||
"rootDir": "src",
|
||||
"sourceMap": true,
|
||||
"strictNullChecks": true,
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"include": ["src/**/*.ts"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
||||
11
packages/constants/tsdown.config.ts
Normal file
11
packages/constants/tsdown.config.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { defineConfig } from "tsdown";
|
||||
|
||||
export default defineConfig({
|
||||
entry: ["src/index.ts"],
|
||||
outDir: "dist",
|
||||
format: ["esm", "cjs"],
|
||||
exports: true,
|
||||
dts: true,
|
||||
clean: true,
|
||||
sourcemap: false,
|
||||
});
|
||||
4
packages/decorators/.eslintignore
Normal file
4
packages/decorators/.eslintignore
Normal file
@@ -0,0 +1,4 @@
|
||||
node_modules
|
||||
build/*
|
||||
dist/*
|
||||
out/*
|
||||
4
packages/decorators/.eslintrc.js
Normal file
4
packages/decorators/.eslintrc.js
Normal file
@@ -0,0 +1,4 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
extends: ["@plane/eslint-config/library.js"],
|
||||
};
|
||||
2
packages/decorators/.prettierignore
Normal file
2
packages/decorators/.prettierignore
Normal file
@@ -0,0 +1,2 @@
|
||||
# Ignore generated build artifacts
|
||||
dist/
|
||||
5
packages/decorators/.prettierrc
Normal file
5
packages/decorators/.prettierrc
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"printWidth": 120,
|
||||
"tabWidth": 2,
|
||||
"trailingComma": "es5"
|
||||
}
|
||||
95
packages/decorators/README.md
Normal file
95
packages/decorators/README.md
Normal file
@@ -0,0 +1,95 @@
|
||||
# @plane/decorators
|
||||
|
||||
A lightweight TypeScript decorator library for building Express.js controllers with a clean, declarative syntax.
|
||||
|
||||
## Features
|
||||
|
||||
- TypeScript-first design
|
||||
- Decorators for HTTP methods (GET, POST, PUT, PATCH, DELETE)
|
||||
- WebSocket support
|
||||
- Middleware support
|
||||
- No build step required - works directly with TypeScript files
|
||||
|
||||
## Installation
|
||||
|
||||
This package is part of the Plane workspace and can be used by adding it to your project's dependencies:
|
||||
|
||||
```json
|
||||
{
|
||||
"dependencies": {
|
||||
"@plane/decorators": "workspace:*"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic REST Controller
|
||||
|
||||
```typescript
|
||||
import { Controller, Get, Post, BaseController } from "@plane/decorators";
|
||||
import { Router, Request, Response } from "express";
|
||||
|
||||
@Controller("/api/users")
|
||||
class UserController extends BaseController {
|
||||
@Get("/")
|
||||
async getUsers(req: Request, res: Response) {
|
||||
return res.json({ users: [] });
|
||||
}
|
||||
|
||||
@Post("/")
|
||||
async createUser(req: Request, res: Response) {
|
||||
return res.json({ success: true });
|
||||
}
|
||||
}
|
||||
|
||||
// Register routes
|
||||
const router = Router();
|
||||
const userController = new UserController();
|
||||
userController.registerRoutes(router);
|
||||
```
|
||||
|
||||
### WebSocket Controller
|
||||
|
||||
```typescript
|
||||
import { Controller, WebSocket, BaseWebSocketController } from "@plane/decorators";
|
||||
import { Request } from "express";
|
||||
import { WebSocket as WS } from "ws";
|
||||
|
||||
@Controller("/ws/chat")
|
||||
class ChatController extends BaseWebSocketController {
|
||||
@WebSocket("/")
|
||||
handleConnection(ws: WS, req: Request) {
|
||||
ws.on("message", (message) => {
|
||||
ws.send(`Received: ${message}`);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Register WebSocket routes
|
||||
const router = require("express-ws")(app).router;
|
||||
const chatController = new ChatController();
|
||||
chatController.registerWebSocketRoutes(router);
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### Decorators
|
||||
|
||||
- `@Controller(baseRoute: string)` - Class decorator for defining a base route
|
||||
- `@Get(route: string)` - Method decorator for HTTP GET endpoints
|
||||
- `@Post(route: string)` - Method decorator for HTTP POST endpoints
|
||||
- `@Put(route: string)` - Method decorator for HTTP PUT endpoints
|
||||
- `@Patch(route: string)` - Method decorator for HTTP PATCH endpoints
|
||||
- `@Delete(route: string)` - Method decorator for HTTP DELETE endpoints
|
||||
- `@WebSocket(route: string)` - Method decorator for WebSocket endpoints
|
||||
- `@Middleware(middleware: RequestHandler)` - Method decorator for applying middleware
|
||||
|
||||
### Classes
|
||||
|
||||
- `BaseController` - Base class for REST controllers
|
||||
- `BaseWebSocketController` - Base class for WebSocket controllers
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the [GNU Affero General Public License v3.0](https://github.com/makeplane/plane/blob/master/LICENSE.txt).
|
||||
37
packages/decorators/package.json
Normal file
37
packages/decorators/package.json
Normal file
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"name": "@plane/decorators",
|
||||
"version": "0.1.0",
|
||||
"description": "Controller and route decorators for Express.js applications",
|
||||
"license": "AGPL-3.0",
|
||||
"private": true,
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./dist/index.mjs",
|
||||
"require": "./dist/index.js"
|
||||
},
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsdown",
|
||||
"dev": "tsdown --watch",
|
||||
"check:lint": "eslint . --max-warnings 2",
|
||||
"check:types": "tsc --noEmit",
|
||||
"check:format": "prettier --check \"**/*.{ts,tsx,md,json,css,scss}\"",
|
||||
"fix:lint": "eslint . --fix",
|
||||
"fix:format": "prettier --write \"**/*.{ts,tsx,md,json,css,scss}\"",
|
||||
"clean": "rm -rf .turbo && rm -rf .next && rm -rf node_modules && rm -rf dist"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@plane/eslint-config": "workspace:*",
|
||||
"@plane/typescript-config": "workspace:*",
|
||||
"@types/express": "4.17.23",
|
||||
"@types/node": "catalog:",
|
||||
"@types/ws": "^8.5.10",
|
||||
"reflect-metadata": "^0.2.2",
|
||||
"tsdown": "catalog:",
|
||||
"typescript": "catalog:"
|
||||
},
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.mjs",
|
||||
"types": "./dist/index.d.ts"
|
||||
}
|
||||
102
packages/decorators/src/controller.ts
Normal file
102
packages/decorators/src/controller.ts
Normal file
@@ -0,0 +1,102 @@
|
||||
import type { RequestHandler, Router, Request } from "express";
|
||||
import type { WebSocket } from "ws";
|
||||
|
||||
import "reflect-metadata";
|
||||
|
||||
export type HttpMethod = "get" | "post" | "put" | "delete" | "patch" | "options" | "head" | "ws";
|
||||
|
||||
type ControllerInstance = {
|
||||
[key: string]: any;
|
||||
};
|
||||
|
||||
export type ControllerConstructor = {
|
||||
new (...args: any[]): ControllerInstance;
|
||||
prototype: ControllerInstance;
|
||||
};
|
||||
|
||||
export function registerController(
|
||||
router: Router,
|
||||
Controller: ControllerConstructor,
|
||||
dependencies: unknown[] = []
|
||||
): void {
|
||||
// Create the controller instance with dependencies
|
||||
const instance = new Controller(...dependencies);
|
||||
|
||||
// Determine if it's a WebSocket controller or REST controller by checking
|
||||
// if it has any methods with the "ws" method metadata
|
||||
const isWebsocket = Object.getOwnPropertyNames(Controller.prototype).some((methodName) => {
|
||||
if (methodName === "constructor") return false;
|
||||
return Reflect.getMetadata("method", instance, methodName) === "ws";
|
||||
});
|
||||
|
||||
if (isWebsocket) {
|
||||
// Register as WebSocket controller
|
||||
// Pass the existing instance with dependencies to avoid creating a new instance without them
|
||||
registerWebSocketController(router, Controller, instance);
|
||||
} else {
|
||||
// Register as REST controller with the existing instance
|
||||
registerRestController(router, Controller, instance);
|
||||
}
|
||||
}
|
||||
|
||||
function registerRestController(
|
||||
router: Router,
|
||||
Controller: ControllerConstructor,
|
||||
existingInstance?: ControllerInstance
|
||||
): void {
|
||||
const instance = existingInstance || new Controller();
|
||||
const baseRoute = Reflect.getMetadata("baseRoute", Controller) as string;
|
||||
|
||||
Object.getOwnPropertyNames(Controller.prototype).forEach((methodName) => {
|
||||
if (methodName === "constructor") return; // Skip the constructor
|
||||
|
||||
const method = Reflect.getMetadata("method", instance, methodName) as HttpMethod;
|
||||
const route = Reflect.getMetadata("route", instance, methodName) as string;
|
||||
const middlewares = (Reflect.getMetadata("middlewares", instance, methodName) as RequestHandler[]) || [];
|
||||
|
||||
if (method && route) {
|
||||
const handler = instance[methodName] as unknown;
|
||||
|
||||
if (typeof handler === "function") {
|
||||
if (method !== "ws") {
|
||||
(router[method] as (path: string, ...handlers: RequestHandler[]) => void)(
|
||||
`${baseRoute}${route}`,
|
||||
...middlewares,
|
||||
handler.bind(instance)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function registerWebSocketController(
|
||||
router: Router,
|
||||
Controller: ControllerConstructor,
|
||||
existingInstance?: ControllerInstance
|
||||
): void {
|
||||
const instance = existingInstance || new Controller();
|
||||
const baseRoute = Reflect.getMetadata("baseRoute", Controller) as string;
|
||||
|
||||
Object.getOwnPropertyNames(Controller.prototype).forEach((methodName) => {
|
||||
if (methodName === "constructor") return; // Skip the constructor
|
||||
|
||||
const method = Reflect.getMetadata("method", instance, methodName) as string;
|
||||
const route = Reflect.getMetadata("route", instance, methodName) as string;
|
||||
|
||||
if (method === "ws" && route) {
|
||||
const handler = instance[methodName] as unknown;
|
||||
|
||||
if (typeof handler === "function" && "ws" in router && typeof router.ws === "function") {
|
||||
router.ws(`${baseRoute}${route}`, (ws: WebSocket, req: Request) => {
|
||||
try {
|
||||
handler.call(instance, ws, req);
|
||||
} catch (error) {
|
||||
console.error(`WebSocket error in ${Controller.name}.${methodName}`, error);
|
||||
ws.close(1011, error instanceof Error ? error.message : "Internal server error");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
3
packages/decorators/src/index.ts
Normal file
3
packages/decorators/src/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export * from "./controller";
|
||||
export * from "./rest";
|
||||
export * from "./websocket";
|
||||
51
packages/decorators/src/rest.ts
Normal file
51
packages/decorators/src/rest.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import "reflect-metadata";
|
||||
import { RequestHandler } from "express";
|
||||
|
||||
// Define valid HTTP methods
|
||||
type RestMethod = "get" | "post" | "put" | "patch" | "delete";
|
||||
|
||||
/**
|
||||
* Controller decorator
|
||||
* @param baseRoute
|
||||
* @returns
|
||||
*/
|
||||
export function Controller(baseRoute: string = ""): ClassDecorator {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
||||
return function (target: Function) {
|
||||
Reflect.defineMetadata("baseRoute", baseRoute, target);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory function to create HTTP method decorators
|
||||
* @param method HTTP method to handle
|
||||
* @returns Method decorator
|
||||
*/
|
||||
function createHttpMethodDecorator(method: RestMethod): (route: string) => MethodDecorator {
|
||||
return function (route: string): MethodDecorator {
|
||||
return function (target: object, propertyKey: string | symbol) {
|
||||
Reflect.defineMetadata("method", method, target, propertyKey);
|
||||
Reflect.defineMetadata("route", route, target, propertyKey);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
// Export HTTP method decorators using the factory
|
||||
export const Get = createHttpMethodDecorator("get");
|
||||
export const Post = createHttpMethodDecorator("post");
|
||||
export const Put = createHttpMethodDecorator("put");
|
||||
export const Patch = createHttpMethodDecorator("patch");
|
||||
export const Delete = createHttpMethodDecorator("delete");
|
||||
|
||||
/**
|
||||
* Middleware decorator
|
||||
* @param middleware
|
||||
* @returns
|
||||
*/
|
||||
export function Middleware(middleware: RequestHandler): MethodDecorator {
|
||||
return function (target: object, propertyKey: string | symbol) {
|
||||
const middlewares = Reflect.getMetadata("middlewares", target, propertyKey) || [];
|
||||
middlewares.push(middleware);
|
||||
Reflect.defineMetadata("middlewares", middlewares, target, propertyKey);
|
||||
};
|
||||
}
|
||||
13
packages/decorators/src/websocket.ts
Normal file
13
packages/decorators/src/websocket.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import "reflect-metadata";
|
||||
|
||||
/**
|
||||
* WebSocket method decorator
|
||||
* @param route
|
||||
* @returns
|
||||
*/
|
||||
export function WebSocket(route: string): MethodDecorator {
|
||||
return function (target: object, propertyKey: string | symbol) {
|
||||
Reflect.defineMetadata("method", "ws", target, propertyKey);
|
||||
Reflect.defineMetadata("route", route, target, propertyKey);
|
||||
};
|
||||
}
|
||||
15
packages/decorators/tsconfig.json
Normal file
15
packages/decorators/tsconfig.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"extends": "@plane/typescript-config/node-library.json",
|
||||
"compilerOptions": {
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"lib": ["ES2020"],
|
||||
"rootDir": ".",
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["./src", "./*.ts"],
|
||||
"exclude": ["dist", "build", "node_modules"]
|
||||
}
|
||||
11
packages/decorators/tsdown.config.ts
Normal file
11
packages/decorators/tsdown.config.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { defineConfig } from "tsdown";
|
||||
|
||||
export default defineConfig({
|
||||
entry: ["src/index.ts"],
|
||||
outDir: "dist",
|
||||
format: ["esm", "cjs"],
|
||||
exports: true,
|
||||
dts: true,
|
||||
clean: true,
|
||||
sourcemap: false,
|
||||
});
|
||||
4
packages/editor/.eslintignore
Normal file
4
packages/editor/.eslintignore
Normal file
@@ -0,0 +1,4 @@
|
||||
node_modules
|
||||
build/*
|
||||
dist/*
|
||||
out/*
|
||||
4
packages/editor/.eslintrc.cjs
Normal file
4
packages/editor/.eslintrc.cjs
Normal file
@@ -0,0 +1,4 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
extends: ["@plane/eslint-config/library.js"],
|
||||
};
|
||||
6
packages/editor/.prettierignore
Normal file
6
packages/editor/.prettierignore
Normal file
@@ -0,0 +1,6 @@
|
||||
.next
|
||||
.vercel
|
||||
.tubro
|
||||
out/
|
||||
dist/
|
||||
build/
|
||||
5
packages/editor/.prettierrc
Normal file
5
packages/editor/.prettierrc
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"printWidth": 120,
|
||||
"tabWidth": 2,
|
||||
"trailingComma": "es5"
|
||||
}
|
||||
82
packages/editor/Readme.md
Normal file
82
packages/editor/Readme.md
Normal file
@@ -0,0 +1,82 @@
|
||||
# @plane/editor
|
||||
|
||||
## Description
|
||||
|
||||
The `@plane/editor` package serves as the foundation for our editor system. It provides the base functionality for our other editor packages, but it will not be used directly in any of the projects but only for extending other editors.
|
||||
|
||||
## Utilities
|
||||
|
||||
We provide a wide range of utilities for extending the core itself.
|
||||
|
||||
1. Merging classes and custom styling
|
||||
2. Adding new extensions
|
||||
3. Adding custom props
|
||||
4. Base menu items, and their commands
|
||||
|
||||
This allows for extensive customization and flexibility in the Editors created using our `editor-core` package.
|
||||
|
||||
### Here's a detailed overview of what's exported
|
||||
|
||||
1. useEditor - A hook that you can use to extend the Plane editor.
|
||||
|
||||
| Prop | Type | Description |
|
||||
| ------------------------- | ---------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `extensions` | `Extension[]` | An array of custom extensions you want to add into the editor to extend it's core features |
|
||||
| `editorProps` | `EditorProps` | Extend the editor props by passing in a custom props object |
|
||||
| `uploadFile` | `(file: File) => Promise<string>` | A function that handles file upload. It takes a file as input and handles the process of uploading that file. |
|
||||
| `deleteFile` | `(assetUrlWithWorkspaceId: string) => Promise<any>` | A function that handles deleting an image. It takes the asset url from your bucket and handles the process of deleting that image. |
|
||||
| `value` | `html string` | The initial content of the editor. |
|
||||
| `debouncedUpdatesEnabled` | `boolean` | If set to true, the `onChange` event handler is debounced, meaning it will only be invoked after the specified delay (default 1500ms) once the user has stopped typing. |
|
||||
| `onChange` | `(json: any, html: string) => void` | This function is invoked whenever the content of the editor changes. It is passed the new content in both JSON and HTML formats. |
|
||||
| `setIsSubmitting` | `(isSubmitting: "submitting" \| "submitted" \| "saved") => void` | This function is called to update the submission status. |
|
||||
| `setShouldShowAlert` | `(showAlert: boolean) => void` | This function is used to show or hide an alert in case of content not being "saved". |
|
||||
| `forwardedRef` | `any` | Pass this in whenever you want to control the editor's state from an external component |
|
||||
|
||||
2. useReadOnlyEditor - A hook that can be used to extend a Read Only instance of the core editor.
|
||||
|
||||
| Prop | Type | Description |
|
||||
| -------------- | ------------- | ------------------------------------------------------------------------------------------ |
|
||||
| `value` | `string` | The initial content of the editor. |
|
||||
| `forwardedRef` | `any` | Pass this in whenever you want to control the editor's state from an external component |
|
||||
| `extensions` | `Extension[]` | An array of custom extensions you want to add into the editor to extend it's core features |
|
||||
| `editorProps` | `EditorProps` | Extend the editor props by passing in a custom props object |
|
||||
|
||||
3. Items and Commands - H1, H2, H3, task list, quote, code block, etc's methods.
|
||||
|
||||
4. UI Wrappers
|
||||
|
||||
- `EditorContainer` - Wrap your Editor Container with this to apply base classes and styles.
|
||||
- `EditorContentWrapper` - Use this to get Editor's Content and base menus.
|
||||
|
||||
5. Extending with Custom Styles
|
||||
|
||||
```ts
|
||||
const customEditorClassNames = getEditorClassNames({
|
||||
noBorder,
|
||||
borderOnFocus,
|
||||
customClassName,
|
||||
});
|
||||
```
|
||||
|
||||
## Core features
|
||||
|
||||
- **Content Trimming**: The Editor’s content is now automatically trimmed of empty line breaks from the start and end before submitting it to the backend. This ensures cleaner, more consistent data.
|
||||
- **Value Cleaning**: The Editor’s value is cleaned at the editor core level, eliminating the need for additional validation before sending from our app. This results in cleaner code and less potential for errors.
|
||||
- **Turbo Pipeline**: Added a turbo pipeline for both dev and build tasks for projects depending on the editor package.
|
||||
|
||||
## Base extensions included
|
||||
|
||||
- BulletList
|
||||
- OrderedList
|
||||
- Blockquote
|
||||
- Code
|
||||
- Gapcursor
|
||||
- Link
|
||||
- Image
|
||||
- Basic Marks
|
||||
- Underline
|
||||
- TextStyle
|
||||
- Color
|
||||
- TaskList
|
||||
- Markdown
|
||||
- Table
|
||||
102
packages/editor/package.json
Normal file
102
packages/editor/package.json
Normal file
@@ -0,0 +1,102 @@
|
||||
{
|
||||
"name": "@plane/editor",
|
||||
"version": "1.1.0",
|
||||
"description": "Core Editor that powers Plane",
|
||||
"license": "AGPL-3.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "./dist/index.cjs",
|
||||
"module": "./dist/index.js",
|
||||
"types": "./dist/index.d.cts",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./dist/index.js",
|
||||
"require": "./dist/index.cjs"
|
||||
},
|
||||
"./lib": {
|
||||
"import": "./dist/lib.js",
|
||||
"require": "./dist/lib.cjs"
|
||||
},
|
||||
"./package.json": "./package.json",
|
||||
"./styles.css": "./dist/styles/index.css",
|
||||
"./styles": "./dist/styles/index.css"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc && tsdown",
|
||||
"dev": "tsdown --watch",
|
||||
"check:lint": "eslint . --max-warnings 30",
|
||||
"check:types": "tsc --noEmit",
|
||||
"check:format": "prettier --check \"**/*.{ts,tsx,md,json,css,scss}\"",
|
||||
"fix:lint": "eslint . --fix",
|
||||
"fix:format": "prettier --write \"**/*.{ts,tsx,md,json,css,scss}\"",
|
||||
"clean": "rm -rf .turbo && rm -rf .next && rm -rf node_modules && rm -rf dist"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "catalog:",
|
||||
"react-dom": "catalog:"
|
||||
},
|
||||
"dependencies": {
|
||||
"@floating-ui/dom": "^1.7.1",
|
||||
"@floating-ui/react": "^0.26.4",
|
||||
"@headlessui/react": "^1.7.3",
|
||||
"@hocuspocus/provider": "2.15.2",
|
||||
"@plane/constants": "workspace:*",
|
||||
"@plane/hooks": "workspace:*",
|
||||
"@plane/types": "workspace:*",
|
||||
"@plane/ui": "workspace:*",
|
||||
"@plane/propel": "workspace:*",
|
||||
"@plane/utils": "workspace:*",
|
||||
"@tiptap/core": "catalog:",
|
||||
"@tiptap/extension-blockquote": "^2.22.3",
|
||||
"@tiptap/extension-character-count": "^2.22.3",
|
||||
"@tiptap/extension-collaboration": "^2.22.3",
|
||||
"@tiptap/extension-emoji": "^2.22.3",
|
||||
"@tiptap/extension-image": "^2.22.3",
|
||||
"@tiptap/extension-list-item": "^2.22.3",
|
||||
"@tiptap/extension-mention": "^2.22.3",
|
||||
"@tiptap/extension-placeholder": "^2.22.3",
|
||||
"@tiptap/extension-task-item": "^2.22.3",
|
||||
"@tiptap/extension-task-list": "^2.22.3",
|
||||
"@tiptap/extension-text-align": "^2.22.3",
|
||||
"@tiptap/extension-text-style": "^2.22.3",
|
||||
"@tiptap/extension-underline": "^2.22.3",
|
||||
"@tiptap/html": "catalog:",
|
||||
"@tiptap/pm": "^2.22.3",
|
||||
"@tiptap/react": "^2.22.3",
|
||||
"@tiptap/starter-kit": "^2.22.3",
|
||||
"@tiptap/suggestion": "^2.22.3",
|
||||
"emoji-regex": "^10.3.0",
|
||||
"highlight.js": "^11.8.0",
|
||||
"is-emoji-supported": "^0.0.5",
|
||||
"jsx-dom-cjs": "^8.0.3",
|
||||
"linkifyjs": "^4.3.2",
|
||||
"lowlight": "^3.0.0",
|
||||
"lucide-react": "catalog:",
|
||||
"prosemirror-codemark": "^0.4.2",
|
||||
"tippy.js": "^6.3.7",
|
||||
"tiptap-markdown": "^0.8.10",
|
||||
"uuid": "catalog:",
|
||||
"y-indexeddb": "^9.0.12",
|
||||
"y-prosemirror": "^1.2.15",
|
||||
"y-protocols": "^1.0.6",
|
||||
"yjs": "^13.6.20"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@plane/eslint-config": "workspace:*",
|
||||
"@plane/tailwind-config": "workspace:*",
|
||||
"@plane/typescript-config": "workspace:*",
|
||||
"@types/node": "catalog:",
|
||||
"@types/react": "catalog:",
|
||||
"@types/react-dom": "catalog:",
|
||||
"postcss": "^8.4.38",
|
||||
"tsdown": "catalog:",
|
||||
"typescript": "catalog:"
|
||||
},
|
||||
"keywords": [
|
||||
"editor",
|
||||
"rich-text",
|
||||
"markdown",
|
||||
"nextjs",
|
||||
"react"
|
||||
]
|
||||
}
|
||||
9
packages/editor/postcss.config.js
Normal file
9
packages/editor/postcss.config.js
Normal file
@@ -0,0 +1,9 @@
|
||||
// If you want to use other PostCSS plugins, see the following:
|
||||
// https://tailwindcss.com/docs/using-with-preprocessors
|
||||
|
||||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,12 @@
|
||||
import { type Editor } from "@tiptap/core";
|
||||
import type { ReactElement } from "react";
|
||||
import type { IEditorPropsExtended } from "@/types";
|
||||
|
||||
export type DocumentEditorSideEffectsProps = {
|
||||
editor: Editor;
|
||||
id: string;
|
||||
updatePageProperties?: unknown;
|
||||
extendedEditorProps?: IEditorPropsExtended;
|
||||
};
|
||||
|
||||
export const DocumentEditorSideEffects = (_props: DocumentEditorSideEffectsProps): ReactElement | null => null;
|
||||
14
packages/editor/src/ce/components/link-container.tsx
Normal file
14
packages/editor/src/ce/components/link-container.tsx
Normal file
@@ -0,0 +1,14 @@
|
||||
import { Editor } from "@tiptap/core";
|
||||
import { LinkViewContainer } from "@/components/editors/link-view-container";
|
||||
|
||||
export const LinkContainer = ({
|
||||
editor,
|
||||
containerRef,
|
||||
}: {
|
||||
editor: Editor;
|
||||
containerRef: React.RefObject<HTMLDivElement>;
|
||||
}) => (
|
||||
<>
|
||||
<LinkViewContainer editor={editor} containerRef={containerRef} />
|
||||
</>
|
||||
);
|
||||
6
packages/editor/src/ce/constants/assets.ts
Normal file
6
packages/editor/src/ce/constants/assets.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
// helpers
|
||||
import { TAssetMetaDataRecord } from "@/helpers/assets";
|
||||
// local imports
|
||||
import { ADDITIONAL_EXTENSIONS } from "./extensions";
|
||||
|
||||
export const ADDITIONAL_ASSETS_META_DATA_RECORD: Partial<Record<ADDITIONAL_EXTENSIONS, TAssetMetaDataRecord>> = {};
|
||||
1
packages/editor/src/ce/constants/extensions.ts
Normal file
1
packages/editor/src/ce/constants/extensions.ts
Normal file
@@ -0,0 +1 @@
|
||||
export enum ADDITIONAL_EXTENSIONS {}
|
||||
22
packages/editor/src/ce/constants/utility.ts
Normal file
22
packages/editor/src/ce/constants/utility.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
// plane imports
|
||||
import { ADDITIONAL_EXTENSIONS, CORE_EXTENSIONS } from "@plane/utils";
|
||||
// plane editor imports
|
||||
import type { ExtensionFileSetStorageKey } from "@/plane-editor/types/storage";
|
||||
|
||||
export type NodeFileMapType = Partial<
|
||||
Record<
|
||||
CORE_EXTENSIONS | ADDITIONAL_EXTENSIONS,
|
||||
{
|
||||
fileSetName: ExtensionFileSetStorageKey;
|
||||
}
|
||||
>
|
||||
>;
|
||||
|
||||
export const NODE_FILE_MAP: NodeFileMapType = {
|
||||
[CORE_EXTENSIONS.IMAGE]: {
|
||||
fileSetName: "deletedImageSet",
|
||||
},
|
||||
[CORE_EXTENSIONS.CUSTOM_IMAGE]: {
|
||||
fileSetName: "deletedImageSet",
|
||||
},
|
||||
};
|
||||
13
packages/editor/src/ce/extensions/core/extensions.ts
Normal file
13
packages/editor/src/ce/extensions/core/extensions.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import type { Extensions } from "@tiptap/core";
|
||||
// types
|
||||
import type { IEditorProps } from "@/types";
|
||||
|
||||
export type TCoreAdditionalExtensionsProps = Pick<
|
||||
IEditorProps,
|
||||
"disabledExtensions" | "flaggedExtensions" | "fileHandler" | "extendedEditorProps"
|
||||
>;
|
||||
|
||||
export const CoreEditorAdditionalExtensions = (props: TCoreAdditionalExtensionsProps): Extensions => {
|
||||
const {} = props;
|
||||
return [];
|
||||
};
|
||||
1
packages/editor/src/ce/extensions/core/index.ts
Normal file
1
packages/editor/src/ce/extensions/core/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from "./extensions";
|
||||
3
packages/editor/src/ce/extensions/core/without-props.ts
Normal file
3
packages/editor/src/ce/extensions/core/without-props.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import { Extensions } from "@tiptap/core";
|
||||
|
||||
export const CoreEditorAdditionalExtensionsWithoutProps: Extensions = [];
|
||||
37
packages/editor/src/ce/extensions/document-extensions.tsx
Normal file
37
packages/editor/src/ce/extensions/document-extensions.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import type { HocuspocusProvider } from "@hocuspocus/provider";
|
||||
import type { AnyExtension } from "@tiptap/core";
|
||||
import { SlashCommands } from "@/extensions";
|
||||
// types
|
||||
import type { IEditorProps, TExtensions, TUserDetails } from "@/types";
|
||||
|
||||
export type TDocumentEditorAdditionalExtensionsProps = Pick<
|
||||
IEditorProps,
|
||||
"disabledExtensions" | "flaggedExtensions" | "fileHandler" | "extendedEditorProps"
|
||||
> & {
|
||||
isEditable: boolean;
|
||||
provider?: HocuspocusProvider;
|
||||
userDetails: TUserDetails;
|
||||
};
|
||||
|
||||
export type TDocumentEditorAdditionalExtensionsRegistry = {
|
||||
isEnabled: (disabledExtensions: TExtensions[], flaggedExtensions: TExtensions[]) => boolean;
|
||||
getExtension: (props: TDocumentEditorAdditionalExtensionsProps) => AnyExtension;
|
||||
};
|
||||
|
||||
const extensionRegistry: TDocumentEditorAdditionalExtensionsRegistry[] = [
|
||||
{
|
||||
isEnabled: (disabledExtensions) => !disabledExtensions.includes("slash-commands"),
|
||||
getExtension: ({ disabledExtensions, flaggedExtensions }) =>
|
||||
SlashCommands({ disabledExtensions, flaggedExtensions }),
|
||||
},
|
||||
];
|
||||
|
||||
export const DocumentEditorAdditionalExtensions = (props: TDocumentEditorAdditionalExtensionsProps) => {
|
||||
const { disabledExtensions, flaggedExtensions } = props;
|
||||
|
||||
const documentExtensions = extensionRegistry
|
||||
.filter((config) => config.isEnabled(disabledExtensions, flaggedExtensions))
|
||||
.map((config) => config.getExtension(props));
|
||||
|
||||
return documentExtensions;
|
||||
};
|
||||
3
packages/editor/src/ce/extensions/index.ts
Normal file
3
packages/editor/src/ce/extensions/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export * from "./core";
|
||||
export * from "./document-extensions";
|
||||
export * from "./slash-commands";
|
||||
42
packages/editor/src/ce/extensions/rich-text-extensions.tsx
Normal file
42
packages/editor/src/ce/extensions/rich-text-extensions.tsx
Normal file
@@ -0,0 +1,42 @@
|
||||
import { AnyExtension, Extensions } from "@tiptap/core";
|
||||
// extensions
|
||||
import { SlashCommands } from "@/extensions/slash-commands/root";
|
||||
// types
|
||||
import { IEditorProps, TExtensions } from "@/types";
|
||||
|
||||
export type TRichTextEditorAdditionalExtensionsProps = Pick<
|
||||
IEditorProps,
|
||||
"disabledExtensions" | "flaggedExtensions" | "fileHandler" | "extendedEditorProps"
|
||||
>;
|
||||
|
||||
/**
|
||||
* Registry entry configuration for extensions
|
||||
*/
|
||||
export type TRichTextEditorAdditionalExtensionsRegistry = {
|
||||
/** Determines if the extension should be enabled based on disabled extensions */
|
||||
isEnabled: (disabledExtensions: TExtensions[], flaggedExtensions: TExtensions[]) => boolean;
|
||||
/** Returns the extension instance(s) when enabled */
|
||||
getExtension: (props: TRichTextEditorAdditionalExtensionsProps) => AnyExtension | undefined;
|
||||
};
|
||||
|
||||
const extensionRegistry: TRichTextEditorAdditionalExtensionsRegistry[] = [
|
||||
{
|
||||
isEnabled: (disabledExtensions) => !disabledExtensions.includes("slash-commands"),
|
||||
getExtension: ({ disabledExtensions, flaggedExtensions }) =>
|
||||
SlashCommands({
|
||||
disabledExtensions,
|
||||
flaggedExtensions,
|
||||
}),
|
||||
},
|
||||
];
|
||||
|
||||
export const RichTextEditorAdditionalExtensions = (props: TRichTextEditorAdditionalExtensionsProps) => {
|
||||
const { disabledExtensions, flaggedExtensions } = props;
|
||||
|
||||
const extensions: Extensions = extensionRegistry
|
||||
.filter((config) => config.isEnabled(disabledExtensions, flaggedExtensions))
|
||||
.map((config) => config.getExtension(props))
|
||||
.filter((extension): extension is AnyExtension => extension !== undefined);
|
||||
|
||||
return extensions;
|
||||
};
|
||||
12
packages/editor/src/ce/extensions/slash-commands.tsx
Normal file
12
packages/editor/src/ce/extensions/slash-commands.tsx
Normal file
@@ -0,0 +1,12 @@
|
||||
// extensions
|
||||
import type { TSlashCommandAdditionalOption } from "@/extensions";
|
||||
// types
|
||||
import type { IEditorProps } from "@/types";
|
||||
|
||||
type Props = Pick<IEditorProps, "disabledExtensions" | "flaggedExtensions">;
|
||||
|
||||
export const coreEditorAdditionalSlashCommandOptions = (props: Props): TSlashCommandAdditionalOption[] => {
|
||||
const {} = props;
|
||||
const options: TSlashCommandAdditionalOption[] = [];
|
||||
return options;
|
||||
};
|
||||
19
packages/editor/src/ce/helpers/parser.ts
Normal file
19
packages/editor/src/ce/helpers/parser.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* @description function to extract all additional assets from HTML content
|
||||
* @param htmlContent
|
||||
* @returns {string[]} array of additional asset sources
|
||||
*/
|
||||
export const extractAdditionalAssetsFromHTMLContent = (_htmlContent: string): string[] => [];
|
||||
|
||||
/**
|
||||
* @description function to replace additional assets in HTML content with new IDs
|
||||
* @param props
|
||||
* @returns {string} HTML content with replaced additional assets
|
||||
*/
|
||||
export const replaceAdditionalAssetsInHTMLContent = (props: {
|
||||
htmlContent: string;
|
||||
assetMap: Record<string, string>;
|
||||
}): string => {
|
||||
const { htmlContent } = props;
|
||||
return htmlContent;
|
||||
};
|
||||
1
packages/editor/src/ce/types/asset.ts
Normal file
1
packages/editor/src/ce/types/asset.ts
Normal file
@@ -0,0 +1 @@
|
||||
export type TAdditionalEditorAsset = never;
|
||||
1
packages/editor/src/ce/types/config.ts
Normal file
1
packages/editor/src/ce/types/config.ts
Normal file
@@ -0,0 +1 @@
|
||||
export type TExtendedFileHandler = object;
|
||||
11
packages/editor/src/ce/types/editor-extended.ts
Normal file
11
packages/editor/src/ce/types/editor-extended.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
export type IEditorExtensionOptions = unknown;
|
||||
|
||||
export type IEditorPropsExtended = unknown;
|
||||
|
||||
export type ICollaborativeDocumentEditorPropsExtended = unknown;
|
||||
|
||||
export type TExtendedEditorCommands = never;
|
||||
|
||||
export type TExtendedCommandExtraProps = unknown;
|
||||
|
||||
export type TExtendedEditorRefApi = unknown;
|
||||
3
packages/editor/src/ce/types/index.ts
Normal file
3
packages/editor/src/ce/types/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export * from "./issue-embed";
|
||||
export * from "./editor-extended";
|
||||
export * from "./config";
|
||||
17
packages/editor/src/ce/types/issue-embed.ts
Normal file
17
packages/editor/src/ce/types/issue-embed.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
export type TEmbedConfig = {
|
||||
issue?: TIssueEmbedConfig;
|
||||
};
|
||||
|
||||
export type TReadOnlyEmbedConfig = TEmbedConfig;
|
||||
|
||||
export type TIssueEmbedConfig = {
|
||||
widgetCallback: ({
|
||||
issueId,
|
||||
projectId,
|
||||
workspaceSlug,
|
||||
}: {
|
||||
issueId: string;
|
||||
projectId: string | undefined;
|
||||
workspaceSlug: string | undefined;
|
||||
}) => React.ReactNode;
|
||||
};
|
||||
4
packages/editor/src/ce/types/storage.ts
Normal file
4
packages/editor/src/ce/types/storage.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
// extensions
|
||||
import type { ImageExtensionStorage } from "@/extensions/image";
|
||||
|
||||
export type ExtensionFileSetStorageKey = Extract<keyof ImageExtensionStorage, "deletedImageSet">;
|
||||
1
packages/editor/src/ce/types/utils.ts
Normal file
1
packages/editor/src/ce/types/utils.ts
Normal file
@@ -0,0 +1 @@
|
||||
export type TAdditionalActiveDropbarExtensions = never;
|
||||
@@ -0,0 +1,116 @@
|
||||
import React from "react";
|
||||
// plane imports
|
||||
import { cn } from "@plane/utils";
|
||||
// components
|
||||
import { PageRenderer } from "@/components/editors";
|
||||
// constants
|
||||
import { DEFAULT_DISPLAY_CONFIG } from "@/constants/config";
|
||||
// helpers
|
||||
import { getEditorClassNames } from "@/helpers/common";
|
||||
// hooks
|
||||
import { useCollaborativeEditor } from "@/hooks/use-collaborative-editor";
|
||||
// constants
|
||||
import { DocumentEditorSideEffects } from "@/plane-editor/components/document-editor-side-effects";
|
||||
// types
|
||||
import type { EditorRefApi, ICollaborativeDocumentEditorProps } from "@/types";
|
||||
|
||||
const CollaborativeDocumentEditor: React.FC<ICollaborativeDocumentEditorProps> = (props) => {
|
||||
const {
|
||||
aiHandler,
|
||||
bubbleMenuEnabled = true,
|
||||
containerClassName,
|
||||
documentLoaderClassName,
|
||||
extensions = [],
|
||||
disabledExtensions,
|
||||
displayConfig = DEFAULT_DISPLAY_CONFIG,
|
||||
editable,
|
||||
editorClassName = "",
|
||||
editorProps,
|
||||
extendedEditorProps,
|
||||
fileHandler,
|
||||
flaggedExtensions,
|
||||
forwardedRef,
|
||||
handleEditorReady,
|
||||
id,
|
||||
dragDropEnabled = true,
|
||||
isTouchDevice,
|
||||
mentionHandler,
|
||||
onAssetChange,
|
||||
onChange,
|
||||
onEditorFocus,
|
||||
onTransaction,
|
||||
placeholder,
|
||||
realtimeConfig,
|
||||
serverHandler,
|
||||
tabIndex,
|
||||
user,
|
||||
extendedDocumentEditorProps,
|
||||
} = props;
|
||||
|
||||
// use document editor
|
||||
const { editor, hasServerConnectionFailed, hasServerSynced } = useCollaborativeEditor({
|
||||
disabledExtensions,
|
||||
editable,
|
||||
editorClassName,
|
||||
editorProps,
|
||||
extendedEditorProps,
|
||||
extensions,
|
||||
fileHandler,
|
||||
flaggedExtensions,
|
||||
forwardedRef,
|
||||
handleEditorReady,
|
||||
id,
|
||||
dragDropEnabled,
|
||||
isTouchDevice,
|
||||
mentionHandler,
|
||||
onAssetChange,
|
||||
onChange,
|
||||
onEditorFocus,
|
||||
onTransaction,
|
||||
placeholder,
|
||||
realtimeConfig,
|
||||
serverHandler,
|
||||
tabIndex,
|
||||
user,
|
||||
extendedDocumentEditorProps,
|
||||
});
|
||||
|
||||
const editorContainerClassNames = getEditorClassNames({
|
||||
noBorder: true,
|
||||
borderOnFocus: false,
|
||||
containerClassName,
|
||||
});
|
||||
|
||||
if (!editor) return null;
|
||||
|
||||
return (
|
||||
<>
|
||||
<DocumentEditorSideEffects editor={editor} id={id} extendedEditorProps={extendedEditorProps} />
|
||||
<PageRenderer
|
||||
aiHandler={aiHandler}
|
||||
bubbleMenuEnabled={bubbleMenuEnabled}
|
||||
displayConfig={displayConfig}
|
||||
documentLoaderClassName={documentLoaderClassName}
|
||||
editor={editor}
|
||||
editorContainerClassName={cn(editorContainerClassNames, "document-editor")}
|
||||
id={id}
|
||||
isTouchDevice={!!isTouchDevice}
|
||||
isLoading={!hasServerSynced && !hasServerConnectionFailed}
|
||||
tabIndex={tabIndex}
|
||||
flaggedExtensions={flaggedExtensions}
|
||||
disabledExtensions={disabledExtensions}
|
||||
extendedDocumentEditorProps={extendedDocumentEditorProps}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const CollaborativeDocumentEditorWithRef = React.forwardRef<EditorRefApi, ICollaborativeDocumentEditorProps>(
|
||||
(props, ref) => (
|
||||
<CollaborativeDocumentEditor {...props} forwardedRef={ref as React.MutableRefObject<EditorRefApi | null>} />
|
||||
)
|
||||
);
|
||||
|
||||
CollaborativeDocumentEditorWithRef.displayName = "CollaborativeDocumentEditorWithRef";
|
||||
|
||||
export { CollaborativeDocumentEditorWithRef };
|
||||
107
packages/editor/src/core/components/editors/document/editor.tsx
Normal file
107
packages/editor/src/core/components/editors/document/editor.tsx
Normal file
@@ -0,0 +1,107 @@
|
||||
import { Extensions } from "@tiptap/core";
|
||||
import { forwardRef, MutableRefObject, useMemo } from "react";
|
||||
// plane imports
|
||||
import { cn } from "@plane/utils";
|
||||
// components
|
||||
import { PageRenderer } from "@/components/editors";
|
||||
// constants
|
||||
import { DEFAULT_DISPLAY_CONFIG } from "@/constants/config";
|
||||
// extensions
|
||||
import { HeadingListExtension, SideMenuExtension } from "@/extensions";
|
||||
// helpers
|
||||
import { getEditorClassNames } from "@/helpers/common";
|
||||
// hooks
|
||||
import { useEditor } from "@/hooks/use-editor";
|
||||
// plane editor extensions
|
||||
import { DocumentEditorAdditionalExtensions } from "@/plane-editor/extensions";
|
||||
// types
|
||||
import { EditorRefApi, IDocumentEditorProps } from "@/types";
|
||||
|
||||
const DocumentEditor = (props: IDocumentEditorProps) => {
|
||||
const {
|
||||
bubbleMenuEnabled = false,
|
||||
containerClassName,
|
||||
disabledExtensions,
|
||||
displayConfig = DEFAULT_DISPLAY_CONFIG,
|
||||
editable,
|
||||
editorClassName = "",
|
||||
extendedEditorProps,
|
||||
fileHandler,
|
||||
flaggedExtensions,
|
||||
forwardedRef,
|
||||
id,
|
||||
isTouchDevice,
|
||||
handleEditorReady,
|
||||
mentionHandler,
|
||||
onChange,
|
||||
user,
|
||||
value,
|
||||
} = props;
|
||||
const extensions: Extensions = useMemo(() => {
|
||||
const additionalExtensions: Extensions = [];
|
||||
additionalExtensions.push(
|
||||
SideMenuExtension({
|
||||
aiEnabled: !disabledExtensions?.includes("ai"),
|
||||
dragDropEnabled: true,
|
||||
}),
|
||||
HeadingListExtension,
|
||||
...DocumentEditorAdditionalExtensions({
|
||||
disabledExtensions,
|
||||
extendedEditorProps,
|
||||
flaggedExtensions,
|
||||
isEditable: editable,
|
||||
fileHandler,
|
||||
userDetails: user ?? {
|
||||
id: "",
|
||||
name: "",
|
||||
color: "",
|
||||
},
|
||||
})
|
||||
);
|
||||
return additionalExtensions;
|
||||
}, [disabledExtensions, editable, extendedEditorProps, fileHandler, flaggedExtensions, user]);
|
||||
|
||||
const editor = useEditor({
|
||||
disabledExtensions,
|
||||
editable,
|
||||
editorClassName,
|
||||
enableHistory: true,
|
||||
extendedEditorProps,
|
||||
extensions,
|
||||
fileHandler,
|
||||
flaggedExtensions,
|
||||
forwardedRef,
|
||||
handleEditorReady,
|
||||
id,
|
||||
initialValue: value,
|
||||
mentionHandler,
|
||||
onChange,
|
||||
});
|
||||
|
||||
const editorContainerClassName = getEditorClassNames({
|
||||
containerClassName,
|
||||
});
|
||||
|
||||
if (!editor) return null;
|
||||
|
||||
return (
|
||||
<PageRenderer
|
||||
bubbleMenuEnabled={bubbleMenuEnabled}
|
||||
displayConfig={displayConfig}
|
||||
editor={editor}
|
||||
editorContainerClassName={cn(editorContainerClassName, "document-editor")}
|
||||
id={id}
|
||||
flaggedExtensions={flaggedExtensions}
|
||||
disabledExtensions={disabledExtensions}
|
||||
isTouchDevice={!!isTouchDevice}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const DocumentEditorWithRef = forwardRef<EditorRefApi, IDocumentEditorProps>((props, ref) => (
|
||||
<DocumentEditor {...props} forwardedRef={ref as MutableRefObject<EditorRefApi | null>} />
|
||||
));
|
||||
|
||||
DocumentEditorWithRef.displayName = "DocumentEditorWithRef";
|
||||
|
||||
export { DocumentEditorWithRef };
|
||||
@@ -0,0 +1,4 @@
|
||||
export * from "./collaborative-editor";
|
||||
export * from "./editor";
|
||||
export * from "./loader";
|
||||
export * from "./page-renderer";
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user