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

Synced from upstream: 8853637e981ed7d8a6cff32bd98e7afe20f54362
This commit is contained in:
chuan
2025-11-07 00:00:52 +08:00
commit 8ebde8aa05
4886 changed files with 462270 additions and 0 deletions

View File

@@ -0,0 +1,4 @@
module.exports = {
root: true,
extends: ["@plane/eslint-config/library.js"],
};

View File

@@ -0,0 +1,7 @@
.turbo
out/
dist/
build/
.next
.vercel
.turbo

View File

@@ -0,0 +1,5 @@
{
"printWidth": 120,
"tabWidth": 2,
"trailingComma": "es5"
}

View File

@@ -0,0 +1,38 @@
{
"name": "@plane/types",
"version": "1.1.0",
"license": "AGPL-3.0",
"private": true,
"exports": {
".": {
"import": "./dist/index.mjs",
"require": "./dist/index.js"
},
"./package.json": "./package.json"
},
"scripts": {
"dev": "tsdown --watch",
"build": "tsdown",
"check:lint": "eslint . --max-warnings 36",
"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:"
},
"devDependencies": {
"@plane/eslint-config": "workspace:*",
"@plane/typescript-config": "workspace:*",
"@types/react": "catalog:",
"@types/react-dom": "catalog:",
"tsdown": "catalog:",
"typescript": "catalog:"
},
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts"
}

View File

@@ -0,0 +1,30 @@
export type TBaseActivity<TFieldKey extends string = string, TVerbKey extends string = string> = {
id: string;
field: TFieldKey | undefined;
epoch: number;
verb: TVerbKey;
comment: string | undefined;
// updates
old_value: string | undefined;
new_value: string | undefined;
old_identifier: string | undefined;
new_identifier: string | undefined;
// actor detail
actor: string;
// timestamp
created_at: string;
updated_at: string;
};
export type TWorkspaceBaseActivity<K extends string = string, V extends string = string> = TBaseActivity<K, V> & {
workspace: string;
};
export type TProjectBaseActivity<K extends string = string, V extends string = string> = TWorkspaceBaseActivity<
K,
V
> & {
project: string;
};
export type TBaseActivityVerbs = "created" | "updated" | "deleted";

10
packages/types/src/ai.ts Normal file
View File

@@ -0,0 +1,10 @@
import { IProjectLite } from "./project";
import { IWorkspaceLite } from "./workspace";
export interface IGptResponse {
response: string;
response_html: string;
count: number;
project_detail: IProjectLite;
workspace_detail: IWorkspaceLite;
}

View File

@@ -0,0 +1,90 @@
import { TChartData } from "./charts";
export enum ChartXAxisProperty {
STATES = "STATES",
STATE_GROUPS = "STATE_GROUPS",
LABELS = "LABELS",
ASSIGNEES = "ASSIGNEES",
ESTIMATE_POINTS = "ESTIMATE_POINTS",
CYCLES = "CYCLES",
MODULES = "MODULES",
PRIORITY = "PRIORITY",
START_DATE = "START_DATE",
TARGET_DATE = "TARGET_DATE",
CREATED_AT = "CREATED_AT",
COMPLETED_AT = "COMPLETED_AT",
CREATED_BY = "CREATED_BY",
WORK_ITEM_TYPES = "WORK_ITEM_TYPES",
PROJECTS = "PROJECTS",
EPICS = "EPICS",
}
export enum ChartYAxisMetric {
WORK_ITEM_COUNT = "WORK_ITEM_COUNT",
ESTIMATE_POINT_COUNT = "ESTIMATE_POINT_COUNT",
PENDING_WORK_ITEM_COUNT = "PENDING_WORK_ITEM_COUNT",
COMPLETED_WORK_ITEM_COUNT = "COMPLETED_WORK_ITEM_COUNT",
IN_PROGRESS_WORK_ITEM_COUNT = "IN_PROGRESS_WORK_ITEM_COUNT",
WORK_ITEM_DUE_THIS_WEEK_COUNT = "WORK_ITEM_DUE_THIS_WEEK_COUNT",
WORK_ITEM_DUE_TODAY_COUNT = "WORK_ITEM_DUE_TODAY_COUNT",
BLOCKED_WORK_ITEM_COUNT = "BLOCKED_WORK_ITEM_COUNT",
EPIC_WORK_ITEM_COUNT = "EPIC_WORK_ITEM_COUNT",
}
export type TAnalyticsTabsBase = "overview" | "work-items";
export type TAnalyticsGraphsBase = "projects" | "work-items" | "custom-work-items";
export interface AnalyticsTab {
key: TAnalyticsTabsBase;
label: string;
content: React.FC;
isDisabled: boolean;
}
export type TAnalyticsFilterParams = {
project_ids?: string;
cycle_id?: string;
module_id?: string;
};
// service types
export interface IAnalyticsResponse {
[key: string]: any;
}
export interface IAnalyticsResponseFields {
count: number;
filter_count: number;
}
// chart types
export interface IChartResponse {
schema: Record<string, string>;
data: TChartData<string, string>[];
}
// table types
export interface WorkItemInsightColumns {
project_id?: string;
project__name?: string;
cancelled_work_items: number;
completed_work_items: number;
backlog_work_items: number;
un_started_work_items: number;
started_work_items: number;
// in case of peek view, we will display the display_name instead of project__name
display_name?: string;
avatar_url?: string;
assignee_id?: string;
}
export type AnalyticsTableDataMap = {
"work-items": WorkItemInsightColumns;
};
export interface IAnalyticsParams {
x_axis: ChartXAxisProperty;
y_axis: ChartYAxisMetric;
group_by?: ChartXAxisProperty;
}

View File

@@ -0,0 +1,16 @@
export interface IApiToken {
created_at: string;
created_by: string;
description: string;
expired_at: string | null;
id: string;
is_active: boolean;
label: string;
last_used: string | null;
updated_at: string;
updated_by: string;
user: string;
user_type: number;
token?: string;
workspace: string;
}

View File

@@ -0,0 +1,31 @@
export type TEmailCheckTypes = "magic_code" | "password";
export interface IEmailCheckData {
email: string;
}
export interface IEmailCheckResponse {
status: "MAGIC_CODE" | "CREDENTIAL";
existing: boolean;
is_password_autoset: boolean;
}
export interface ILoginTokenResponse {
access_token: string;
refresh_token: string;
}
export interface IMagicSignInData {
email: string;
key: string;
token: string;
}
export interface IPasswordSignInData {
email: string;
password: string;
}
export interface ICsrfTokenData {
csrf_token: string;
}

View File

@@ -0,0 +1,101 @@
import type { ReactNode } from "react";
// Base Types
export interface IBaseLayoutsBaseItem {
id: string;
[key: string]: unknown;
}
export interface IBaseLayoutsBaseGroup {
id: string;
name: string;
icon?: ReactNode;
payload?: Record<string, unknown>;
count?: number;
}
// Drag & Drop Types
export interface IDragDropHandlers<T extends IBaseLayoutsBaseItem> {
enableDragDrop?: boolean;
onDrop?: (
sourceId: string,
destinationId: string | null,
sourceGroupId: string,
destinationGroupId: string
) => Promise<void>;
canDrag?: (item: T) => boolean;
}
// Render Props
export interface IItemRenderProps<T extends IBaseLayoutsBaseItem> {
renderItem: (item: T, groupId: string) => ReactNode;
}
export interface IGroupHeaderControls {
isCollapsed: boolean;
onToggleGroup: (groupId: string) => void;
}
export interface IGroupHeaderProps extends IGroupHeaderControls {
group: IBaseLayoutsBaseGroup;
itemCount: number;
}
export interface IGroupRenderProps {
renderGroupHeader?: (props: IGroupHeaderProps) => ReactNode;
}
export interface IRenderProps<T extends IBaseLayoutsBaseItem> extends IItemRenderProps<T>, IGroupRenderProps {}
// Layout Configuration
export type TBaseLayoutType = "list" | "kanban";
export interface IBaseLayoutConfig {
key: TBaseLayoutType;
icon: React.ComponentType<React.SVGProps<SVGSVGElement>>;
label: string;
}
// Base Layout Props
export interface IBaseLayoutsBaseProps<T extends IBaseLayoutsBaseItem> extends IDragDropHandlers<T>, IRenderProps<T> {
items: Record<string, T>;
groupedItemIds: Record<string, string[]>;
groups: IBaseLayoutsBaseGroup[];
collapsedGroups?: string[];
onToggleGroup?: (groupId: string) => void;
isLoading?: boolean;
loadMoreItems?: (groupId: string) => void;
showEmptyGroups?: boolean;
className?: string;
}
// Group Props
export interface IBaseLayoutsBaseGroupProps<T extends IBaseLayoutsBaseItem>
extends IDragDropHandlers<T>,
IRenderProps<T> {
group: IBaseLayoutsBaseGroup;
itemIds: string[];
items: Record<string, T>;
isCollapsed: boolean;
onToggleGroup: (groupId: string) => void;
loadMoreItems?: (groupId: string) => void;
}
// Item Props
export interface IBaseLayoutsBaseItemProps<T extends IBaseLayoutsBaseItem>
extends IDragDropHandlers<T>,
IItemRenderProps<T> {
item: T;
index: number;
groupId: string;
isLast: boolean;
}

View File

@@ -0,0 +1,3 @@
export * from "./base";
export * from "./list";
export * from "./kanban";

View File

@@ -0,0 +1,24 @@
import type {
IBaseLayoutsBaseItem,
IBaseLayoutsBaseProps,
IBaseLayoutsBaseGroupProps,
IBaseLayoutsBaseItemProps,
} from "./base";
export type IBaseLayoutsKanbanItem = IBaseLayoutsBaseItem;
// Main Kanban Layout Props
export interface IBaseLayoutsKanbanProps<T extends IBaseLayoutsKanbanItem> extends IBaseLayoutsBaseProps<T> {
groupClassName?: string;
}
// Kanban Column/Group Props
export interface IBaseLayoutsKanbanGroupProps<T extends IBaseLayoutsKanbanItem> extends IBaseLayoutsBaseGroupProps<T> {
groupClassName?: string;
}
// Kanban Card/Item Props
export type IBaseLayoutsKanbanItemProps<T extends IBaseLayoutsKanbanItem> = IBaseLayoutsBaseItemProps<T>;

View File

@@ -0,0 +1,20 @@
import type {
IBaseLayoutsBaseItem,
IBaseLayoutsBaseProps,
IBaseLayoutsBaseGroupProps,
IBaseLayoutsBaseItemProps,
} from "./base";
export type IBaseLayoutsListItem = IBaseLayoutsBaseItem;
// Main List Layout Props
export type IBaseLayoutsListProps<T extends IBaseLayoutsListItem> = IBaseLayoutsBaseProps<T>;
// Group component props
export type IBaseLayoutsListGroupProps<T extends IBaseLayoutsListItem> = IBaseLayoutsBaseGroupProps<T>;
// Item component props
export type IBaseLayoutsListItemProps<T extends IBaseLayoutsListItem> = IBaseLayoutsBaseItemProps<T>;

View File

@@ -0,0 +1,29 @@
export interface ICalendarRange {
startDate: Date;
endDate: Date;
}
export interface ICalendarDate {
date: Date;
year: number;
month: number;
day: number;
week: number; // week number wrt year, eg- 51, 52
is_current_month: boolean;
is_current_week: boolean;
is_today: boolean;
}
export interface ICalendarWeek {
[date: string]: ICalendarDate;
}
export interface ICalendarMonth {
[monthIndex: string]: {
[weekNumber: string]: ICalendarWeek;
};
}
export interface ICalendarPayload {
[year: string]: ICalendarMonth;
}

View File

@@ -0,0 +1,12 @@
export type TChartColorScheme = "modern" | "horizon" | "earthen";
export type TChartDatum = {
key: string;
name: string;
count: number;
} & Record<string, number>;
export type TChart = {
data: TChartDatum[];
schema: Record<string, string>;
};

View File

@@ -0,0 +1,244 @@
// ============================================================
// Chart Base
// ============================================================
export * from "./common";
export type TChartLegend = {
align: "left" | "center" | "right";
verticalAlign: "top" | "middle" | "bottom";
layout: "horizontal" | "vertical";
wrapperStyles?: React.CSSProperties;
};
export type TChartMargin = {
top?: number;
right?: number;
bottom?: number;
left?: number;
};
export type TChartData<K extends string, T extends string> = {
// required key
[key in K]: string | number;
} & Record<T, any>;
export type TBaseChartProps<K extends string, T extends string> = {
data: TChartData<K, T>[];
className?: string;
legend?: TChartLegend;
margin?: TChartMargin;
showTooltip?: boolean;
customTooltipContent?: (props: { active?: boolean; label: string; payload: any }) => React.ReactNode;
};
// Props specific to charts with X and Y axes
export type TAxisChartProps<K extends string, T extends string> = TBaseChartProps<K, T> & {
xAxis: {
key: keyof TChartData<K, T>;
label?: string;
strokeColor?: string;
dy?: number;
};
yAxis: {
allowDecimals?: boolean;
domain?: [number, number];
key: keyof TChartData<K, T>;
label?: string;
strokeColor?: string;
offset?: number;
dx?: number;
};
tickCount?: {
x?: number;
y?: number;
};
customTicks?: {
x?: React.ComponentType<unknown>;
y?: React.ComponentType<unknown>;
};
};
// ============================================================
// Bar Chart
// ============================================================
export type TBarChartShapeVariant = "bar" | "lollipop" | "lollipop-dotted";
export type TBarItem<T extends string> = {
key: T;
label: string;
fill: string | ((payload: any) => string);
textClassName: string;
showPercentage?: boolean;
stackId: string;
showTopBorderRadius?: (barKey: string, payload: any) => boolean;
showBottomBorderRadius?: (barKey: string, payload: any) => boolean;
shapeVariant?: TBarChartShapeVariant;
};
export type TBarChartProps<K extends string, T extends string> = TAxisChartProps<K, T> & {
bars: TBarItem<T>[];
barSize?: number;
};
// ============================================================
// Line Chart
// ============================================================
export type TLineItem<T extends string> = {
key: T;
label: string;
dashedLine: boolean;
fill: string;
showDot: boolean;
smoothCurves: boolean;
stroke: string;
style?: Record<string, string | number>;
};
export type TLineChartProps<K extends string, T extends string> = TAxisChartProps<K, T> & {
lines: TLineItem<T>[];
};
// ============================================================
// Scatter Chart
// ============================================================
export type TScatterPointItem<T extends string> = {
key: T;
label: string;
fill: string;
stroke: string;
};
export type TScatterChartProps<K extends string, T extends string> = TAxisChartProps<K, T> & {
scatterPoints: TScatterPointItem<T>[];
};
// ============================================================
// Area Chart
// ============================================================
export type TAreaItem<T extends string> = {
key: T;
label: string;
stackId: string;
fill: string;
fillOpacity: number;
showDot: boolean;
smoothCurves: boolean;
strokeColor: string;
strokeOpacity: number;
style?: Record<string, string | number>;
};
export type TAreaChartProps<K extends string, T extends string> = TAxisChartProps<K, T> & {
areas: TAreaItem<T>[];
comparisonLine?: {
dashedLine: boolean;
strokeColor: string;
};
};
// ============================================================
// Pie Chart
// ============================================================
export type TCellItem<T extends string> = {
key: T;
fill: string;
};
export type TPieChartProps<K extends string, T extends string> = Pick<
TBaseChartProps<K, T>,
"className" | "data" | "showTooltip" | "legend" | "margin"
> & {
dataKey: T;
cells: TCellItem<T>[];
innerRadius?: number | string;
outerRadius?: number | string;
cornerRadius?: number;
paddingAngle?: number;
showLabel: boolean;
customLabel?: (value: any) => string;
centerLabel?: {
className?: string;
fill: string;
style?: React.CSSProperties;
text?: string | number;
};
tooltipLabel?: string | ((payload: any) => string);
customLegend?: (props: any) => React.ReactNode;
};
// ============================================================
// Tree Map
// ============================================================
export type TreeMapItem = {
name: string;
value: number;
label?: string;
textClassName?: string;
icon?: React.ReactElement;
} & (
| {
fillColor: string;
}
| {
fillClassName: string;
}
);
export type TreeMapChartProps = {
data: TreeMapItem[];
className?: string;
isAnimationActive?: boolean;
showTooltip?: boolean;
};
export type TTopSectionConfig = {
showIcon: boolean;
showName: boolean;
nameTruncated: boolean;
};
export type TBottomSectionConfig = {
show: boolean;
showValue: boolean;
showLabel: boolean;
labelTruncated: boolean;
};
export type TContentVisibility = {
top: TTopSectionConfig;
bottom: TBottomSectionConfig;
};
// ============================================================
// Radar Chart
// ============================================================
export type TRadarItem<T extends string> = {
key: T;
name: string;
fill?: string;
stroke?: string;
fillOpacity?: number;
dot?: {
r: number;
fillOpacity: number;
};
};
export type TRadarChartProps<K extends string, T extends string> = Pick<
TBaseChartProps<K, T>,
"className" | "showTooltip" | "margin" | "data" | "legend"
> & {
dataKey: T;
radars: TRadarItem<T>[];
angleAxis: {
key: keyof TChartData<K, T>;
label?: string;
strokeColor?: string;
};
};

View File

@@ -0,0 +1,12 @@
export type TCommandPaletteActionList = Record<string, { title: string; description: string; action: () => void }>;
export type TCommandPaletteShortcutList = {
key: string;
title: string;
shortcuts: TCommandPaletteShortcut[];
};
export type TCommandPaletteShortcut = {
keys: string; // comma separated keys
description: string;
};

View File

@@ -0,0 +1,36 @@
export type TPaginationInfo = {
count: number;
extra_stats: string | null;
next_cursor: string;
next_page_results: boolean;
prev_cursor: string;
prev_page_results: boolean;
total_pages: number;
per_page?: number;
total_results: number;
};
export type TLogoProps = {
in_use: "emoji" | "icon";
emoji?: {
value?: string;
url?: string;
};
icon?: {
name?: string;
color?: string;
background_color?: string;
};
};
export type TNameDescriptionLoader = "submitting" | "submitted" | "saved";
export type TFetchStatus = "partial" | "complete" | undefined;
export type ICustomSearchSelectOption = {
value: any;
query: string;
content: React.ReactNode;
disabled?: boolean;
tooltip?: string | React.ReactNode;
};

View File

@@ -0,0 +1 @@
export * from "./profile";

View File

@@ -0,0 +1,30 @@
export type TUserProfile = {
id: string | undefined;
user: string | undefined;
role: string | undefined;
last_workspace_id: string | undefined;
theme: {
theme: string | undefined;
};
onboarding_step: {
workspace_join: boolean;
profile_complete: boolean;
workspace_create: boolean;
workspace_invite: boolean;
};
is_onboarded: boolean;
is_tour_completed: boolean;
use_case: string | undefined;
billing_address_country: string | undefined;
billing_address: string | undefined;
has_billing_address: boolean;
has_marketing_email_consent: boolean;
created_at: Date | string;
updated_at: Date | string;
};

View File

@@ -0,0 +1,152 @@
import type { TIssue } from "../issues/issue";
import type { IIssueFilterOptions } from "../view-props";
export type TCycleGroups = "current" | "upcoming" | "completed" | "draft";
export type TCycleCompletionChartDistribution = {
[key: string]: number | null;
};
export type TCycleDistributionBase = {
total_issues: number;
pending_issues: number;
completed_issues: number;
};
export type TCycleEstimateDistributionBase = {
total_estimates: number;
pending_estimates: number;
completed_estimates: number;
};
export type TCycleAssigneesDistribution = {
assignee_id: string | null;
avatar_url: string | null;
first_name: string | null;
last_name: string | null;
display_name: string | null;
};
export type TCycleLabelsDistribution = {
color: string | null;
label_id: string | null;
label_name: string | null;
};
export type TCycleDistribution = {
assignees: (TCycleAssigneesDistribution & TCycleDistributionBase)[];
completion_chart: TCycleCompletionChartDistribution;
labels: (TCycleLabelsDistribution & TCycleDistributionBase)[];
};
export type TCycleEstimateDistribution = {
assignees: (TCycleAssigneesDistribution & TCycleEstimateDistributionBase)[];
completion_chart: TCycleCompletionChartDistribution;
labels: (TCycleLabelsDistribution & TCycleEstimateDistributionBase)[];
};
export type TCycleProgress = {
date: string;
started: number;
actual: number;
pending: number;
ideal: number | null;
scope: number;
completed: number;
unstarted: number;
backlog: number;
cancelled: number;
};
export type TProgressSnapshot = {
total_issues: number;
completed_issues: number;
backlog_issues: number;
started_issues: number;
unstarted_issues: number;
cancelled_issues: number;
total_estimate_points?: number;
completed_estimate_points?: number;
backlog_estimate_points: number;
started_estimate_points: number;
unstarted_estimate_points: number;
cancelled_estimate_points: number;
distribution?: TCycleDistribution;
estimate_distribution?: TCycleEstimateDistribution;
};
export interface IProjectDetails {
id: string;
}
export interface ICycle extends TProgressSnapshot {
progress_snapshot: TProgressSnapshot | undefined;
created_at?: string;
created_by?: string;
description: string;
end_date: string | null;
id: string;
is_favorite?: boolean;
name: string;
owned_by_id: string;
project_id: string;
status?: TCycleGroups;
sort_order: number;
start_date: string | null;
sub_issues?: number;
updated_at?: string;
updated_by?: string;
archived_at: string | null;
assignee_ids?: string[];
view_props: {
filters: IIssueFilterOptions;
};
workspace_id: string;
project_detail: IProjectDetails;
progress: any[];
version: number;
}
export interface CycleIssueResponse {
id: string;
issue_detail: TIssue;
created_at: Date;
updated_at: Date;
created_by: string;
updated_by: string;
project: string;
workspace: string;
issue: string;
cycle: string;
sub_issues_count: number;
}
export type SelectCycleType = (ICycle & { actionType: "edit" | "delete" | "create-issue" }) | undefined;
export type CycleDateCheckData = {
start_date: string;
end_date: string;
cycle_id?: string;
};
export type TCycleEstimateType = "issues" | "points";
export type TCyclePlotType = "burndown" | "burnup";
export type TPublicCycle = {
id: string;
name: string;
status: string;
};
export type TProgressChartData = {
date: string;
scope: number;
completed: number;
backlog: number;
started: number;
unstarted: number;
cancelled: number;
pending: number;
ideal: number;
actual: number;
}[];

View File

@@ -0,0 +1,24 @@
export type TCycleTabOptions = "active" | "all";
export type TCycleLayoutOptions = "list" | "board" | "gantt";
export type TCycleDisplayFilters = {
active_tab?: TCycleTabOptions;
layout?: TCycleLayoutOptions;
};
export type TCycleFilters = {
end_date?: string[] | null;
start_date?: string[] | null;
status?: string[] | null;
};
export type TCycleFiltersByState = {
default: TCycleFilters;
archived: TCycleFilters;
};
export type TCycleStoredFilters = {
display_filters?: TCycleDisplayFilters;
filters?: TCycleFilters;
};

View File

@@ -0,0 +1,2 @@
export * from "./cycle_filters";
export * from "./cycle";

View File

@@ -0,0 +1,181 @@
import { EDurationFilters } from "./enums";
import { IIssueActivity, TIssuePriorities } from "./issues";
import { TIssue } from "./issues/issue";
import { TIssueRelationTypes } from "./issues/issue_relation";
import { TStateGroups } from "./state";
export type TWidgetKeys =
| "overview_stats"
| "assigned_issues"
| "created_issues"
| "issues_by_state_groups"
| "issues_by_priority"
| "recent_activity"
| "recent_projects"
| "recent_collaborators";
export type TIssuesListTypes = "pending" | "upcoming" | "overdue" | "completed";
// widget filters
export type TAssignedIssuesWidgetFilters = {
custom_dates?: string[];
duration?: EDurationFilters;
tab?: TIssuesListTypes;
};
export type TCreatedIssuesWidgetFilters = {
custom_dates?: string[];
duration?: EDurationFilters;
tab?: TIssuesListTypes;
};
export type TIssuesByStateGroupsWidgetFilters = {
duration?: EDurationFilters;
custom_dates?: string[];
};
export type TIssuesByPriorityWidgetFilters = {
custom_dates?: string[];
duration?: EDurationFilters;
};
export type TWidgetFiltersFormData =
| {
widgetKey: "assigned_issues";
filters: Partial<TAssignedIssuesWidgetFilters>;
}
| {
widgetKey: "created_issues";
filters: Partial<TCreatedIssuesWidgetFilters>;
}
| {
widgetKey: "issues_by_state_groups";
filters: Partial<TIssuesByStateGroupsWidgetFilters>;
}
| {
widgetKey: "issues_by_priority";
filters: Partial<TIssuesByPriorityWidgetFilters>;
};
export type TWidget = {
id: string;
is_visible: boolean;
key: TWidgetKeys;
readonly widget_filters: // only for read
TAssignedIssuesWidgetFilters &
TCreatedIssuesWidgetFilters &
TIssuesByStateGroupsWidgetFilters &
TIssuesByPriorityWidgetFilters;
filters: // only for write
TAssignedIssuesWidgetFilters &
TCreatedIssuesWidgetFilters &
TIssuesByStateGroupsWidgetFilters &
TIssuesByPriorityWidgetFilters;
};
export type TWidgetStatsRequestParams =
| {
widget_key: TWidgetKeys;
}
| {
target_date: string;
issue_type: TIssuesListTypes;
widget_key: "assigned_issues";
expand?: "issue_relation";
}
| {
target_date: string;
issue_type: TIssuesListTypes;
widget_key: "created_issues";
}
| {
target_date: string;
widget_key: "issues_by_state_groups";
}
| {
target_date: string;
widget_key: "issues_by_priority";
}
| {
cursor: string;
per_page: number;
search?: string;
widget_key: "recent_collaborators";
};
export type TWidgetIssue = TIssue & {
issue_relation: {
id: string;
project_id: string;
relation_type: TIssueRelationTypes;
sequence_id: number;
type_id: string | null;
}[];
};
// widget stats responses
export type TOverviewStatsWidgetResponse = {
assigned_issues_count: number;
completed_issues_count: number;
created_issues_count: number;
pending_issues_count: number;
};
export type TAssignedIssuesWidgetResponse = {
issues: TWidgetIssue[];
count: number;
};
export type TCreatedIssuesWidgetResponse = {
issues: TWidgetIssue[];
count: number;
};
export type TIssuesByStateGroupsWidgetResponse = {
count: number;
state: TStateGroups;
};
export type TIssuesByPriorityWidgetResponse = {
count: number;
priority: TIssuePriorities;
};
export type TRecentActivityWidgetResponse = IIssueActivity;
export type TRecentProjectsWidgetResponse = string[];
export type TRecentCollaboratorsWidgetResponse = {
active_issue_count: number;
user_id: string;
};
export type TWidgetStatsResponse =
| TOverviewStatsWidgetResponse
| TIssuesByStateGroupsWidgetResponse[]
| TIssuesByPriorityWidgetResponse[]
| TAssignedIssuesWidgetResponse
| TCreatedIssuesWidgetResponse
| TRecentActivityWidgetResponse[]
| TRecentProjectsWidgetResponse
| TRecentCollaboratorsWidgetResponse[];
// dashboard
export type TDeprecatedDashboard = {
created_at: string;
created_by: string | null;
description_html: string;
id: string;
identifier: string | null;
is_default: boolean;
name: string;
owned_by: string;
type: string;
updated_at: string;
updated_by: string | null;
};
export type THomeDashboardResponse = {
dashboard: TDeprecatedDashboard;
widgets: TWidget[];
};

View File

@@ -0,0 +1,24 @@
import { TIssuePriorities } from "./issues";
export type TDuplicateIssuePayload = {
title: string;
workspace_id: string;
issue_id?: string | null;
project_id?: string;
description_stripped?: string;
};
export type TDeDupeIssue = {
id: string;
type_id: string | null;
project_id: string;
sequence_id: number;
name: string;
priority: TIssuePriorities;
state_id: string;
created_by: string;
};
export type TDuplicateIssueResponse = {
dupes: TDeDupeIssue[];
};

View File

@@ -0,0 +1,29 @@
export type TDescriptionVersion = {
created_at: string;
created_by: string | null;
id: string;
last_saved_at: string;
owned_by: string;
project: string;
updated_at: string;
updated_by: string | null;
};
export type TDescriptionVersionDetails = TDescriptionVersion & {
description_binary: string | null;
description_html: string | null;
description_json: object | null;
description_stripped: string | null;
};
export type TDescriptionVersionsListResponse = {
cursor: string;
next_cursor: string | null;
next_page_results: boolean;
page_count: number;
prev_cursor: string | null;
prev_page_results: boolean;
results: TDescriptionVersion[];
total_pages: number;
total_results: number;
};

View File

@@ -0,0 +1,20 @@
/**
* Editor content types - locally defined to avoid external dependencies
*/
export type JSONContent = {
type?: string;
attrs?: Record<string, unknown>;
content?: JSONContent[];
marks?: {
type: string;
attrs?: Record<string, unknown>;
[key: string]: unknown;
}[];
text?: string;
[key: string]: unknown;
};
export type HTMLContent = string;
export type Content = HTMLContent | JSONContent | JSONContent[] | null;

View File

@@ -0,0 +1 @@
export type { JSONContent, HTMLContent, Content } from "./editor-content";

View File

@@ -0,0 +1,85 @@
export enum EUserPermissions {
ADMIN = 20,
MEMBER = 15,
GUEST = 5,
}
export type TUserPermissions = EUserPermissions.ADMIN | EUserPermissions.MEMBER | EUserPermissions.GUEST;
// project network
export enum EProjectNetwork {
PRIVATE = 0,
PUBLIC = 2,
}
// project pages
export enum EPageAccess {
PUBLIC = 0,
PRIVATE = 1,
}
export enum EDurationFilters {
NONE = "none",
TODAY = "today",
THIS_WEEK = "this_week",
THIS_MONTH = "this_month",
THIS_YEAR = "this_year",
CUSTOM = "custom",
}
export enum EIssueCommentAccessSpecifier {
EXTERNAL = "EXTERNAL",
INTERNAL = "INTERNAL",
}
// estimates
export enum EEstimateSystem {
POINTS = "points",
CATEGORIES = "categories",
TIME = "time",
}
export enum EEstimateUpdateStages {
CREATE = "create",
EDIT = "edit",
SWITCH = "switch",
}
// workspace notifications
export enum ENotificationFilterType {
CREATED = "created",
ASSIGNED = "assigned",
SUBSCRIBED = "subscribed",
}
export enum EFileAssetType {
COMMENT_DESCRIPTION = "COMMENT_DESCRIPTION",
ISSUE_ATTACHMENT = "ISSUE_ATTACHMENT",
ISSUE_DESCRIPTION = "ISSUE_DESCRIPTION",
DRAFT_ISSUE_DESCRIPTION = "DRAFT_ISSUE_DESCRIPTION",
PAGE_DESCRIPTION = "PAGE_DESCRIPTION",
PROJECT_COVER = "PROJECT_COVER",
USER_AVATAR = "USER_AVATAR",
USER_COVER = "USER_COVER",
WORKSPACE_LOGO = "WORKSPACE_LOGO",
TEAM_SPACE_DESCRIPTION = "TEAM_SPACE_DESCRIPTION",
INITIATIVE_DESCRIPTION = "INITIATIVE_DESCRIPTION",
PROJECT_DESCRIPTION = "PROJECT_DESCRIPTION",
TEAM_SPACE_COMMENT_DESCRIPTION = "TEAM_SPACE_COMMENT_DESCRIPTION",
}
export type TEditorAssetType =
| EFileAssetType.COMMENT_DESCRIPTION
| EFileAssetType.ISSUE_DESCRIPTION
| EFileAssetType.DRAFT_ISSUE_DESCRIPTION
| EFileAssetType.PAGE_DESCRIPTION
| EFileAssetType.TEAM_SPACE_DESCRIPTION
| EFileAssetType.INITIATIVE_DESCRIPTION
| EFileAssetType.PROJECT_DESCRIPTION
| EFileAssetType.TEAM_SPACE_COMMENT_DESCRIPTION;
export enum EUpdateStatus {
OFF_TRACK = "OFF-TRACK",
ON_TRACK = "ON-TRACK",
AT_RISK = "AT-RISK",
}

View File

@@ -0,0 +1,16 @@
export type TEpicAnalyticsGroup =
| "backlog_issues"
| "unstarted_issues"
| "started_issues"
| "completed_issues"
| "cancelled_issues"
| "overdue_issues";
export type TEpicAnalytics = {
backlog_issues: number;
unstarted_issues: number;
started_issues: number;
completed_issues: number;
cancelled_issues: number;
overdue_issues: number;
};

View File

@@ -0,0 +1,84 @@
import { EEstimateSystem, EEstimateUpdateStages } from "./enums";
export interface IEstimatePoint {
id: string | undefined;
key: number | undefined;
value: string | undefined;
description: string | undefined;
workspace: string | undefined;
project: string | undefined;
estimate: string | undefined;
created_at: Date | undefined;
updated_at: Date | undefined;
created_by: string | undefined;
updated_by: string | undefined;
}
export type TEstimateSystemKeys = EEstimateSystem.POINTS | EEstimateSystem.CATEGORIES | EEstimateSystem.TIME;
export interface IEstimate {
id: string | undefined;
name: string | undefined;
description: string | undefined;
type: TEstimateSystemKeys | undefined; // categories, points, time
points: IEstimatePoint[] | undefined;
workspace: string | undefined;
project: string | undefined;
last_used: boolean | undefined;
created_at: Date | undefined;
updated_at: Date | undefined;
created_by: string | undefined;
updated_by: string | undefined;
}
export interface IEstimateFormData {
estimate?: {
name?: string;
type?: string;
last_used?: boolean;
};
estimate_points: {
id?: string | undefined;
key: number;
value: string;
}[];
}
export type TEstimatePointsObject = {
id?: string | undefined;
key: number;
value: string;
};
export type TTemplateValues = {
title: string;
i18n_title: string;
values: TEstimatePointsObject[];
hide?: boolean;
};
export type TEstimateSystem = {
name: string;
i18n_name: string;
templates: Record<string, TTemplateValues>;
is_available: boolean;
is_ee: boolean;
};
export type TEstimateSystems = {
[K in TEstimateSystemKeys]: TEstimateSystem;
};
// update estimates
export type TEstimateUpdateStageKeys =
| EEstimateUpdateStages.CREATE
| EEstimateUpdateStages.EDIT
| EEstimateUpdateStages.SWITCH;
export type TEstimateTypeErrorObject = {
oldValue: string;
newValue: string;
message: string | undefined;
};
export type TEstimateTypeError = Record<number, TEstimateTypeErrorObject> | undefined;

View File

@@ -0,0 +1,19 @@
import { TLogoProps } from "../common";
export type IFavorite = {
id: string;
name: string;
entity_type: string;
entity_data: {
id?: string;
name: string;
logo_props?: TLogoProps | undefined;
};
is_folder: boolean;
sort_order: number;
parent: string | null;
entity_identifier?: string | null;
children: IFavorite[];
project_id: string | null;
sequence: number;
};

View File

@@ -0,0 +1 @@
export * from "./favorite";

View File

@@ -0,0 +1,41 @@
import { EFileAssetType } from "./enums";
export type TFileMetaDataLite = {
name: string;
// file size in bytes
size: number;
type: string;
};
export type TFileEntityInfo = {
entity_identifier: string;
entity_type: EFileAssetType;
};
export type TFileMetaData = TFileMetaDataLite & TFileEntityInfo;
export type TFileSignedURLResponse = {
asset_id: string;
asset_url: string;
upload_data: {
url: string;
fields: {
"Content-Type": string;
key: string;
"x-amz-algorithm": string;
"x-amz-credential": string;
"x-amz-date": string;
policy: string;
"x-amz-signature": string;
};
};
};
export type TDuplicateAssetData = {
entity_id: string;
entity_type: EFileAssetType;
project_id?: string;
asset_ids: string[];
};
export type TDuplicateAssetResponse = Record<string, string>; // asset_id -> new_asset_id

View File

@@ -0,0 +1,77 @@
import { TLogoProps } from "./common";
import { TIssuePriorities } from "./issues";
export type TRecentActivityFilterKeys = "all item" | "issue" | "page" | "project" | "workspace_page";
export type THomeWidgetKeys = "quick_links" | "recents" | "my_stickies" | "quick_tutorial" | "new_at_plane";
export type THomeWidgetProps = {
workspaceSlug: string;
};
export type TPageEntityData = {
id: string;
name: string;
logo_props: TLogoProps;
project_id?: string;
owned_by: string;
project_identifier?: string;
};
export type TProjectEntityData = {
id: string;
name: string;
logo_props: TLogoProps;
project_members: string[];
identifier: string;
};
export type TIssueEntityData = {
id: string;
name: string;
state: string;
priority: TIssuePriorities;
assignees: string[];
type: string | null;
sequence_id: number;
project_id: string;
project_identifier: string;
is_epic: boolean;
};
export type TActivityEntityData = {
id: string;
entity_name: "page" | "project" | "issue" | "workspace_page";
entity_identifier: string;
visited_at: string;
entity_data: TPageEntityData | TProjectEntityData | TIssueEntityData;
};
export type TLinkEditableFields = {
title: string;
url: string;
};
export type TLink = TLinkEditableFields & {
created_by_id: string;
id: string;
metadata: any;
workspace_slug: string;
//need
created_at: Date;
};
export type TLinkMap = {
[workspace_slug: string]: TLink;
};
export type TLinkIdMap = {
[workspace_slug: string]: string[];
};
export type TWidgetEntityData = {
key: THomeWidgetKeys;
name: string;
is_enabled: boolean;
sort_order: number;
};

View File

@@ -0,0 +1,33 @@
export interface IGithubServiceImportFormData {
metadata: {
owner: string;
name: string;
repository_id: number;
url: string;
};
data: {
users: {
username: string;
import: boolean | "invite" | "map";
email: string;
}[];
};
config: {
sync: boolean;
};
project_id: string;
}
export interface IGithubRepoCollaborator {
avatar_url: string;
html_url: string;
id: number;
login: string;
url: string;
}
export interface IGithubRepoInfo {
issue_count: number;
labels: number;
collaborators: IGithubRepoCollaborator[];
}

View File

@@ -0,0 +1,58 @@
export * from "./github-importer";
export * from "./jira-importer";
import { IProjectLite } from "../project";
// types
import { IUserLite } from "../users";
export interface IImporterService {
created_at: string;
config: {
sync: boolean;
};
created_by: string | null;
data: {
users: [];
};
id: string;
initiated_by: string;
initiated_by_detail: IUserLite;
metadata: {
name: string;
owner: string;
repository_id: number;
url: string;
};
project: string;
project_detail: IProjectLite;
service: string;
status: "processing" | "completed" | "failed";
updated_at: string;
updated_by: string;
token: string;
workspace: string;
}
export interface IExportData {
id: string;
created_at: string;
updated_at: string;
project: string[];
provider: string;
status: string;
url: string;
token: string;
created_by: string;
updated_by: string;
initiated_by_detail: IUserLite;
}
export interface IExportServiceResponse {
count: number;
extra_stats: null;
next_cursor: string;
next_page_results: boolean;
prev_cursor: string;
prev_page_results: boolean;
results: IExportData[];
total_pages: number;
}

View File

@@ -0,0 +1,58 @@
export interface IJiraImporterForm {
metadata: IJiraMetadata;
config: IJiraConfig;
data: IJiraData;
project_id: string;
}
export interface IJiraConfig {
epics_to_modules: boolean;
}
export interface IJiraData {
users: User[];
invite_users: boolean;
total_issues: number;
total_labels: number;
total_states: number;
total_modules: number;
}
export interface User {
username: string;
import: "invite" | "map" | false;
email: string;
}
export interface IJiraMetadata {
cloud_hostname: string;
api_token: string;
project_key: string;
email: string;
}
export interface IJiraResponse {
issues: number;
modules: number;
labels: number;
states: number;
users: IJiraResponseUser[];
}
export interface IJiraResponseUser {
self: string;
accountId: string;
accountType: string;
emailAddress: string;
avatarUrls: IJiraResponseAvatarUrls;
displayName: string;
active: boolean;
locale: string;
}
export interface IJiraResponseAvatarUrls {
"48x48": string;
"24x24": string;
"16x16": string;
"32x32": string;
}

117
packages/types/src/inbox.ts Normal file
View File

@@ -0,0 +1,117 @@
// plane types
import { TPaginationInfo } from "./common";
import { TIssuePriorities } from "./issues";
import { TIssue } from "./issues/issue";
export enum EInboxIssueCurrentTab {
OPEN = "open",
CLOSED = "closed",
}
export type TInboxIssueCurrentTab = EInboxIssueCurrentTab;
export enum EInboxIssueStatus {
PENDING = -2,
DECLINED = -1,
SNOOZED = 0,
ACCEPTED = 1,
DUPLICATE = 2,
}
export enum EInboxIssueSource {
IN_APP = "IN_APP",
FORMS = "FORMS",
EMAIL = "EMAIL",
}
export type TInboxIssueStatus = EInboxIssueStatus;
export type TInboxIssue = {
id: string;
status: TInboxIssueStatus;
snoozed_till: Date | null;
duplicate_to: string | undefined;
source: EInboxIssueSource | undefined;
issue: TIssue;
created_by: string;
duplicate_issue_detail: TInboxDuplicateIssueDetails | undefined;
};
// filters
export type TInboxIssueFilterMemberKeys = "assignees" | "created_by";
export type TInboxIssueFilterDateKeys = "created_at" | "updated_at";
export type TInboxIssueFilter = {
[key in TInboxIssueFilterMemberKeys]: string[] | undefined;
} & {
[key in TInboxIssueFilterDateKeys]: string[] | undefined;
} & {
state: string[] | undefined;
status: TInboxIssueStatus[] | undefined;
priority: TIssuePriorities[] | undefined;
labels: string[] | undefined;
};
// sorting filters
export type TInboxIssueSortingKeys = "order_by" | "sort_by";
export type TInboxIssueSortingOrderByKeys = "issue__created_at" | "issue__updated_at" | "issue__sequence_id";
export type TInboxIssueSortingSortByKeys = "asc" | "desc";
export type TInboxIssueSorting = {
order_by: TInboxIssueSortingOrderByKeys | undefined;
sort_by: TInboxIssueSortingSortByKeys | undefined;
};
// filtering and sorting types for query params
export type TInboxIssueSortingOrderByQueryParamKeys =
| "issue__created_at"
| "-issue__created_at"
| "issue__updated_at"
| "-issue__updated_at"
| "issue__sequence_id"
| "-issue__sequence_id";
export type TInboxIssueSortingOrderByQueryParam = {
order_by: TInboxIssueSortingOrderByQueryParamKeys;
};
export type TInboxIssuesQueryParams = {
[key in keyof TInboxIssueFilter]: string;
} & TInboxIssueSortingOrderByQueryParam & {
per_page: number;
cursor: string;
};
// inbox issue types
export type TInboxDuplicateIssueDetails = {
id: string;
sequence_id: string;
name: string;
};
export type TInboxIssuePaginationInfo = TPaginationInfo & {
total_results: number;
};
export type TInboxIssueWithPagination = TInboxIssuePaginationInfo & {
results: TInboxIssue[];
};
export type TAnchors = { [key: string]: string };
export type TInboxForm = {
anchors: TAnchors;
id: string;
is_in_app_enabled: boolean;
is_form_enabled: boolean;
};
export type TInboxIssueForm = {
name: string;
description: string;
username: string;
email: string;
};

View File

@@ -0,0 +1,50 @@
export * from "./activity";
export * from "./ai";
export * from "./analytics";
export * from "./api_token";
export * from "./auth";
export * from "./calendar";
export * from "./charts";
export * from "./command-palette";
export * from "./common";
export * from "./cycle";
export * from "./dashboard";
export * from "./de-dupe";
export * from "./description_version";
export * from "./editor";
export * from "./enums";
export * from "./epics";
export * from "./estimate";
export * from "./favorite";
export * from "./file";
export * from "./home";
export * from "./importer";
export * from "./inbox";
export * from "./instance";
export * from "./integration";
export * from "./issues";
export * from "./issues/base"; // TODO: Remove this after development and the refactor/mobx-store-issue branch is stable
export * from "./layout";
export * from "./module";
export * from "./page";
export * from "./payment";
export * from "./pragmatic";
export * from "./project";
export * from "./publish";
export * from "./reaction";
export * from "./rich-filters";
export * from "./search";
export * from "./state";
export * from "./stickies";
export * from "./timezone";
export * from "./users";
export * from "./utils";
export * from "./view-props";
export * from "./views";
export * from "./waitlist";
export * from "./webhook";
export * from "./workspace";
export * from "./workspace-draft-issues/base";
export * from "./workspace-notifications";
export * from "./workspace-views";
export * from "./base-layouts";

View File

@@ -0,0 +1 @@
export type TInstanceAIConfigurationKeys = "LLM_API_KEY" | "LLM_MODEL";

View File

@@ -0,0 +1,45 @@
export type TInstanceAuthenticationModes = {
key: string;
name: string;
description: string;
icon: React.ReactNode;
config: React.ReactNode;
unavailable?: boolean;
};
export type TInstanceAuthenticationMethodKeys =
| "ENABLE_SIGNUP"
| "ENABLE_MAGIC_LINK_LOGIN"
| "ENABLE_EMAIL_PASSWORD"
| "IS_GOOGLE_ENABLED"
| "IS_GITHUB_ENABLED"
| "IS_GITLAB_ENABLED"
| "IS_GITEA_ENABLED";
export type TInstanceGoogleAuthenticationConfigurationKeys = "GOOGLE_CLIENT_ID" | "GOOGLE_CLIENT_SECRET";
export type TInstanceGithubAuthenticationConfigurationKeys =
| "GITHUB_CLIENT_ID"
| "GITHUB_CLIENT_SECRET"
| "GITHUB_ORGANIZATION_ID";
export type TInstanceGitlabAuthenticationConfigurationKeys =
| "GITLAB_HOST"
| "GITLAB_CLIENT_ID"
| "GITLAB_CLIENT_SECRET";
export type TInstanceGiteaAuthenticationConfigurationKeys = "GITEA_HOST" | "GITEA_CLIENT_ID" | "GITEA_CLIENT_SECRET";
export type TInstanceAuthenticationConfigurationKeys =
| TInstanceGoogleAuthenticationConfigurationKeys
| TInstanceGithubAuthenticationConfigurationKeys
| TInstanceGitlabAuthenticationConfigurationKeys
| TInstanceGiteaAuthenticationConfigurationKeys;
export type TInstanceAuthenticationKeys = TInstanceAuthenticationMethodKeys | TInstanceAuthenticationConfigurationKeys;
export type TGetBaseAuthenticationModeProps = {
disabled: boolean;
updateConfig: (key: TInstanceAuthenticationMethodKeys, value: string) => void;
resolvedTheme: string | undefined;
};

View File

@@ -0,0 +1,99 @@
import { IUserLite } from "../users";
import {
TInstanceAIConfigurationKeys,
TInstanceEmailConfigurationKeys,
TInstanceImageConfigurationKeys,
TInstanceAuthenticationKeys,
TInstanceWorkspaceConfigurationKeys,
} from "./";
export interface IInstanceInfo {
instance: IInstance;
config: IInstanceConfig;
}
export interface IInstance {
id: string;
created_at: string;
updated_at: string;
instance_name: string | undefined;
whitelist_emails: string | undefined;
instance_id: string | undefined;
license_key: string | undefined;
current_version: string | undefined;
latest_version: string | undefined;
last_checked_at: string | undefined;
namespace: string | undefined;
is_telemetry_enabled: boolean;
is_support_required: boolean;
is_activated: boolean;
is_setup_done: boolean;
is_signup_screen_visited: boolean;
user_count: number | undefined;
is_verified: boolean;
created_by: string | undefined;
updated_by: string | undefined;
workspaces_exist: boolean;
}
export interface IInstanceConfig {
enable_signup: boolean;
is_workspace_creation_disabled: boolean;
is_google_enabled: boolean;
is_github_enabled: boolean;
is_gitlab_enabled: boolean;
is_gitea_enabled: boolean;
is_magic_login_enabled: boolean;
is_email_password_enabled: boolean;
github_app_name: string | undefined;
slack_client_id: string | undefined;
posthog_api_key: string | undefined;
posthog_host: string | undefined;
has_unsplash_configured: boolean;
has_llm_configured: boolean;
file_size_limit: number | undefined;
is_smtp_configured: boolean;
app_base_url: string | undefined;
space_base_url: string | undefined;
admin_base_url: string | undefined;
// intercom
is_intercom_enabled: boolean;
intercom_app_id: string | undefined;
instance_changelog_url?: string;
}
export interface IInstanceAdmin {
created_at: string;
created_by: string;
id: string;
instance: string;
role: string;
updated_at: string;
updated_by: string;
user: string;
user_detail: IUserLite;
}
export type TInstanceIntercomConfigurationKeys = "IS_INTERCOM_ENABLED" | "INTERCOM_APP_ID";
export type TInstanceConfigurationKeys =
| TInstanceAIConfigurationKeys
| TInstanceEmailConfigurationKeys
| TInstanceImageConfigurationKeys
| TInstanceAuthenticationKeys
| TInstanceIntercomConfigurationKeys
| TInstanceWorkspaceConfigurationKeys;
export interface IInstanceConfiguration {
id: string;
created_at: string;
updated_at: string;
key: TInstanceConfigurationKeys;
value: string;
created_by: string | null;
updated_by: string | null;
}
export type IFormattedInstanceConfiguration = {
[key in TInstanceConfigurationKeys]: string;
};

View File

@@ -0,0 +1,9 @@
export type TInstanceEmailConfigurationKeys =
| "EMAIL_HOST"
| "EMAIL_PORT"
| "EMAIL_HOST_USER"
| "EMAIL_HOST_PASSWORD"
| "EMAIL_USE_TLS"
| "EMAIL_USE_SSL"
| "EMAIL_FROM"
| "ENABLE_SMTP";

View File

@@ -0,0 +1 @@
export type TInstanceImageConfigurationKeys = "UNSPLASH_ACCESS_KEY";

View File

@@ -0,0 +1,6 @@
export * from "./ai";
export * from "./auth";
export * from "./base";
export * from "./email";
export * from "./image";
export * from "./workspace";

View File

@@ -0,0 +1 @@
export type TInstanceWorkspaceConfigurationKeys = "DISABLE_WORKSPACE_CREATION";

View File

@@ -0,0 +1,75 @@
// All the app integrations that are available
export interface IAppIntegration {
author: string;
avatar_url: string | null;
created_at: string;
created_by: string | null;
description: any;
id: string;
metadata: any;
network: number;
provider: string;
redirect_url: string;
title: string;
updated_at: string;
updated_by: string | null;
verified: boolean;
webhook_secret: string;
webhook_url: string;
}
export interface IWorkspaceIntegration {
actor: string;
api_token: string;
config: any;
created_at: string;
created_by: string;
id: string;
integration: string;
integration_detail: IAppIntegration;
metadata: any;
updated_at: string;
updated_by: string;
workspace: string;
}
// slack integration
export interface ISlackIntegration {
id: string;
created_at: string;
updated_at: string;
access_token: string;
scopes: string;
bot_user_id: string;
webhook_url: string;
data: ISlackIntegrationData;
team_id: string;
team_name: string;
created_by: string;
updated_by: string;
project: string;
workspace: string;
workspace_integration: string;
}
export interface ISlackIntegrationData {
ok: boolean;
team: {
id: string;
name: string;
};
scope: string;
app_id: string;
enterprise: any;
token_type: string;
authed_user: string;
bot_user_id: string;
access_token: string;
incoming_webhook: {
url: string;
channel: string;
channel_id: string;
configuration_url: string;
};
is_enterprise_install: boolean;
}

View File

@@ -0,0 +1,232 @@
import { ICycle } from "./cycle";
import { TIssue } from "./issues/issue";
import { IModule } from "./module";
import { IProjectLite } from "./project";
import { IStateLite } from "./state";
import { IUserLite } from "./users";
import {
IIssueDisplayProperties,
TIssueExtraOptions,
TIssueGroupByOptions,
TIssueGroupingFilters,
TIssueOrderByOptions,
} from "./view-props";
import { IWorkspaceLite, Properties } from "./workspace";
export interface IIssueCycle {
id: string;
cycle_detail: ICycle;
created_at: Date;
updated_at: Date;
created_by: string;
updated_by: string;
project: string;
workspace: string;
issue: string;
cycle: string;
}
export interface IIssueModule {
created_at: Date;
created_by: string;
id: string;
issue: string;
module: string;
module_detail: IModule;
project: string;
updated_at: Date;
updated_by: string;
workspace: string;
}
export interface IIssueParent {
description: any;
id: string;
name: string;
priority: string | null;
project_detail: IProjectLite;
sequence_id: number;
start_date: string | null;
state_detail: IStateLite;
target_date: string | null;
}
export interface IIssueLink {
title: string;
url: string;
}
export interface ILinkDetails {
created_at: Date;
created_by: string;
id: string;
metadata: any;
title: string;
url: string;
}
export interface ISubIssuesState {
backlog: number;
unstarted: number;
started: number;
completed: number;
cancelled: number;
}
export interface ISubIssueResponse {
state_distribution: ISubIssuesState;
sub_issues: TIssue[];
}
export interface BlockeIssueDetail {
id: string;
name: string;
sequence_id: number;
project_detail: IProjectLite;
}
export type IssuePriorities = {
id: string;
created_at: Date;
updated_at: Date;
uuid: string;
properties: Properties;
created_by: number;
updated_by: number;
user: string;
};
export interface IIssueLabel {
id: string;
name: string;
color: string;
project_id: string;
workspace_id: string;
parent: string | null;
sort_order: number;
}
export interface IIssueLabelTree extends IIssueLabel {
children: IIssueLabel[] | undefined;
}
export interface IIssueActivity {
access?: "EXTERNAL" | "INTERNAL";
actor: string;
actor_detail: IUserLite;
attachments: any[];
comment?: string;
comment_html?: string;
comment_stripped?: string;
created_at: Date;
created_by: string;
field: string | null;
id: string;
issue: string | null;
issue_comment?: string | null;
issue_detail: {
description_html: string;
id: string;
name: string;
priority: string | null;
sequence_id: string;
type_id: string;
} | null;
new_identifier: string | null;
new_value: string | null;
old_identifier: string | null;
old_value: string | null;
project: string;
project_detail: IProjectLite;
updated_at: Date;
updated_by: string;
verb: string;
workspace: string;
workspace_detail?: IWorkspaceLite;
}
export interface IIssueLite {
id: string;
name: string;
project_id: string;
start_date?: string | null;
target_date?: string | null;
workspace__slug: string;
}
export interface IIssueAttachment {
asset: string;
attributes: {
name: string;
size: number;
};
created_at: string;
created_by: string;
id: string;
issue: string;
project: string;
updated_at: string;
updated_by: string;
workspace: string;
}
export type TIssuePriorities = "urgent" | "high" | "medium" | "low" | "none";
export interface ViewFlags {
enableQuickAdd: boolean;
enableIssueCreation: boolean;
enableInlineEditing: boolean;
}
export type GroupByColumnTypes =
| "project"
| "cycle"
| "module"
| "state"
| "state_detail.group"
| "priority"
| "labels"
| "assignees"
| "created_by"
| "team_project";
export type TGetColumns = {
isWorkspaceLevel?: boolean;
projectId?: string;
};
export interface IGroupByColumn {
id: string;
name: string;
icon?: React.ReactElement | undefined;
payload: Partial<TIssue>;
isDropDisabled?: boolean;
dropErrorMessage?: string;
}
export interface IIssueMap {
[key: string]: TIssue;
}
export interface IIssueListRow {
id: string;
groupId: string;
type: "HEADER" | "NO_ISSUES" | "QUICK_ADD" | "ISSUE";
name?: string;
icon?: React.ReactElement | undefined;
payload?: Partial<TIssue>;
}
export interface ILayoutDisplayFiltersOptions {
display_properties: (keyof IIssueDisplayProperties)[];
display_filters: {
group_by?: TIssueGroupByOptions[];
sub_group_by?: TIssueGroupByOptions[];
order_by?: TIssueOrderByOptions[];
type?: TIssueGroupingFilters[];
};
extra_options: {
access: boolean;
values: TIssueExtraOptions[];
};
}

View File

@@ -0,0 +1,83 @@
export * from "./issue_activity";
export * from "./issue_comment";
export * from "./issue_comment_reaction";
import { TIssuePriorities } from "../../issues";
// root types
export type TIssueActivityWorkspaceDetail = {
name: string;
slug: string;
id: string;
};
export type TIssueActivityProjectDetail = {
id: string;
identifier: string;
name: string;
cover_image: string;
description: string | null;
emoji: string | null;
icon_prop: {
name: string;
color: string;
} | null;
};
export type TIssueActivityIssueDetail = {
id: string;
sequence_id: number;
sort_order: boolean;
name: string;
description_html: string;
priority: TIssuePriorities;
start_date: string;
target_date: string;
is_draft: boolean;
};
export type TIssueActivityUserDetail = {
id: string;
first_name: string;
last_name: string;
avatar_url: string;
is_bot: boolean;
display_name: string;
};
export type TIssueActivityComment =
| {
id: string;
activity_type: "COMMENT";
created_at?: string;
}
| {
id: string;
activity_type: "ACTIVITY";
created_at?: string;
}
| {
id: string;
activity_type: "STATE";
created_at?: string;
}
| {
id: string;
activity_type: "ASSIGNEE";
created_at?: string;
}
| {
id: string;
activity_type: "DEFAULT";
created_at?: string;
}
| {
id: string;
activity_type: "WORKLOG";
created_at?: string;
}
| {
id: string;
activity_type: "ISSUE_ADDITIONAL_PROPERTIES_ACTIVITY";
created_at?: string;
};

View File

@@ -0,0 +1,50 @@
// local imports
import { EInboxIssueSource } from "../../inbox";
import {
TIssueActivityWorkspaceDetail,
TIssueActivityProjectDetail,
TIssueActivityIssueDetail,
TIssueActivityUserDetail,
} from "./base";
export type TIssueActivity = {
id: string;
workspace: string;
workspace_detail: TIssueActivityWorkspaceDetail;
project: string;
project_detail: TIssueActivityProjectDetail;
issue: string;
issue_detail: TIssueActivityIssueDetail;
actor: string;
actor_detail: TIssueActivityUserDetail;
created_at: string;
updated_at: string;
created_by: string | undefined;
updated_by: string | undefined;
attachments: any[];
verb: string;
field: string | undefined;
old_value: string | undefined;
new_value: string | undefined;
comment: string | undefined;
old_identifier: string | undefined;
new_identifier: string | undefined;
epoch: number;
issue_comment: string | null;
source_data: {
source: EInboxIssueSource;
source_email?: string;
extra: {
username?: string;
};
};
};
export type TIssueActivityMap = {
[issue_id: string]: TIssueActivity;
};
export type TIssueActivityIdMap = {
[issue_id: string]: string[];
};

View File

@@ -0,0 +1,146 @@
import { JSONContent } from "../../editor";
import { EIssueCommentAccessSpecifier } from "../../enums";
import { TFileSignedURLResponse } from "../../file";
import { IUserLite } from "../../users";
import { IWorkspaceLite } from "../../workspace";
import {
TIssueActivityWorkspaceDetail,
TIssueActivityProjectDetail,
TIssueActivityIssueDetail,
TIssueActivityUserDetail,
} from "./base";
export type TCommentReaction = {
id: string;
reaction: string;
actor: string;
actor_detail: IUserLite;
};
export type TIssueComment = {
id: string;
workspace: string;
workspace_detail: TIssueActivityWorkspaceDetail;
project: string;
project_detail: TIssueActivityProjectDetail;
issue: string;
issue_detail: TIssueActivityIssueDetail;
actor: string;
actor_detail: TIssueActivityUserDetail;
created_at: string;
edited_at?: string | undefined;
updated_at: string;
created_by: string | undefined;
updated_by: string | undefined;
attachments: any[];
comment_reactions: any[];
comment_stripped: string;
comment_html: string;
comment_json: JSONContent;
external_id: string | undefined;
external_source: string | undefined;
access: EIssueCommentAccessSpecifier;
};
export type TCommentsOperations = {
copyCommentLink: (commentId: string) => void;
createComment: (data: Partial<TIssueComment>) => Promise<Partial<TIssueComment> | undefined>;
updateComment: (commentId: string, data: Partial<TIssueComment>) => Promise<void>;
removeComment: (commentId: string) => Promise<void>;
uploadCommentAsset: (blockId: string, file: File, commentId?: string) => Promise<TFileSignedURLResponse>;
addCommentReaction: (commentId: string, reactionEmoji: string) => Promise<void>;
deleteCommentReaction: (commentId: string, reactionEmoji: string) => Promise<void>;
react: (commentId: string, reactionEmoji: string, userReactions: string[]) => Promise<void>;
reactionIds: (commentId: string) =>
| {
[reaction: string]: string[];
}
| undefined;
userReactions: (commentId: string) => string[] | undefined;
getReactionUsers: (reaction: string, reactionIds: Record<string, string[]>) => string;
};
export type TIssueCommentMap = {
[issue_id: string]: TIssueComment;
};
export type TIssueCommentIdMap = {
[issue_id: string]: string[];
};
export interface ActorDetail {
avatar_url?: string;
display_name?: string;
first_name?: string;
is_bot?: boolean;
id?: string;
last_name?: string;
}
export interface IssueDetail {
id: string;
name: string;
description: Description;
description_html: string;
priority: string;
start_date: null;
target_date: null;
sequence_id: number;
sort_order: number;
}
export interface Description {
type: string;
content: DescriptionContent[];
}
export interface DescriptionContent {
type: string;
attrs?: Attrs;
content: ContentContent[];
}
export interface Attrs {
level: number;
}
export interface ContentContent {
text: string;
type: string;
}
export interface ProjectDetail {
id: string;
identifier: string;
name: string;
cover_image: string;
icon_prop: null;
emoji: string;
description: string;
}
export type TIssuePublicComment = {
actor_detail: ActorDetail;
access: string;
actor: string;
attachments: any[];
comment_html: string;
comment_reactions: {
actor_detail: ActorDetail;
comment: string;
id: string;
reaction: string;
}[];
comment_stripped: string;
created_at: Date;
created_by: string;
id: string;
is_member: boolean;
issue: string;
issue_detail: IssueDetail;
project: string;
project_detail: ProjectDetail;
updated_at: Date;
updated_by: string;
workspace: string;
workspace_detail: IWorkspaceLite;
};

View File

@@ -0,0 +1,21 @@
export type TIssueCommentReaction = {
id: string;
comment: string;
actor: string;
reaction: string;
workspace: string;
project: string;
created_at: Date;
updated_at: Date;
created_by: string;
updated_by: string;
display_name: string;
};
export type TIssueCommentReactionMap = {
[reaction_id: string]: TIssueCommentReaction;
};
export type TIssueCommentReactionIdMap = {
[comment_id: string]: { [reaction: string]: string[] };
};

View File

@@ -0,0 +1,36 @@
// issues
export * from "./issue";
export * from "./issue_reaction";
export * from "./issue_link";
export * from "./issue_attachment";
export * from "./issue_relation";
export * from "./issue_sub_issues";
export * from "./activity/base";
export type TLoader = "init-loader" | "mutation" | "pagination" | "loaded" | undefined;
export type TGroupedIssues = {
[group_id: string]: string[];
};
export type TSubGroupedIssues = {
[sub_grouped_id: string]: TGroupedIssues;
};
export type TIssues = TGroupedIssues | TSubGroupedIssues;
export type TPaginationData = {
nextCursor: string;
prevCursor: string;
nextPageResults: boolean;
};
export type TIssuePaginationData = {
[group_id: string]: TPaginationData;
};
export type TGroupedIssueCount = {
[group_id: string]: number;
};
export type TUnGroupedIssues = string[];

View File

@@ -0,0 +1,219 @@
import { TIssuePriorities } from "../issues";
import { TIssuePublicComment } from "./activity/issue_comment";
import { TIssueAttachment } from "./issue_attachment";
import { TIssueLink } from "./issue_link";
import { TIssueReaction, IIssuePublicReaction, IPublicVote } from "./issue_reaction";
import { TIssueRelationTypes } from "./issue_relation";
export enum EIssueLayoutTypes {
LIST = "list",
KANBAN = "kanban",
CALENDAR = "calendar",
GANTT = "gantt_chart",
SPREADSHEET = "spreadsheet",
}
export enum EIssueServiceType {
ISSUES = "issues",
EPICS = "epics",
WORK_ITEMS = "work-items",
}
export enum EIssuesStoreType {
GLOBAL = "GLOBAL",
PROFILE = "PROFILE",
TEAM = "TEAM",
PROJECT = "PROJECT",
CYCLE = "CYCLE",
MODULE = "MODULE",
TEAM_VIEW = "TEAM_VIEW",
PROJECT_VIEW = "PROJECT_VIEW",
ARCHIVED = "ARCHIVED",
DEFAULT = "DEFAULT",
WORKSPACE_DRAFT = "WORKSPACE_DRAFT",
EPIC = "EPIC",
TEAM_PROJECT_WORK_ITEMS = "TEAM_PROJECT_WORK_ITEMS",
}
export type TBaseIssue = {
id: string;
sequence_id: number;
name: string;
sort_order: number;
state_id: string | null;
priority: TIssuePriorities | null;
label_ids: string[];
assignee_ids: string[];
estimate_point: string | null;
sub_issues_count: number;
attachment_count: number;
link_count: number;
project_id: string | null;
parent_id: string | null;
cycle_id: string | null;
module_ids: string[] | null;
type_id: string | null;
created_at: string;
updated_at: string;
start_date: string | null;
target_date: string | null;
completed_at: string | null;
archived_at: string | null;
created_by: string;
updated_by: string;
is_draft: boolean;
is_epic?: boolean;
is_intake?: boolean;
};
export type IssueRelation = {
id: string;
name: string;
project_id: string;
relation_type: TIssueRelationTypes;
sequence_id: number;
};
export type TIssue = TBaseIssue & {
description_html?: string;
is_subscribed?: boolean;
parent?: Partial<TBaseIssue>;
issue_reactions?: TIssueReaction[];
issue_attachments?: TIssueAttachment[];
issue_link?: TIssueLink[];
issue_relation?: IssueRelation[];
issue_related?: IssueRelation[];
// tempId is used for optimistic updates. It is not a part of the API response.
tempId?: string;
// sourceIssueId is used to store the original issue id when creating a copy of an issue. Used in cloning property values. It is not a part of the API response.
sourceIssueId?: string;
state__group?: string | null;
};
export type TIssueMap = {
[issue_id: string]: TIssue;
};
export type TIssueResponseResults =
| TBaseIssue[]
| {
[key: string]: {
results:
| TBaseIssue[]
| {
[key: string]: {
results: TBaseIssue[];
total_results: number;
};
};
total_results: number;
};
};
export type TIssuesResponse = {
grouped_by: string;
next_cursor: string;
prev_cursor: string;
next_page_results: boolean;
prev_page_results: boolean;
total_count: number;
count: number;
total_pages: number;
extra_stats: null;
results: TIssueResponseResults;
total_results: number;
};
export type TBulkIssueProperties = Pick<
TIssue,
| "state_id"
| "priority"
| "label_ids"
| "assignee_ids"
| "start_date"
| "target_date"
| "module_ids"
| "cycle_id"
| "estimate_point"
>;
export type TBulkOperationsPayload = {
issue_ids: string[];
properties: Partial<TBulkIssueProperties>;
};
export type TWorkItemWidgets = "sub-work-items" | "relations" | "links" | "attachments";
export type TIssueServiceType = EIssueServiceType.ISSUES | EIssueServiceType.EPICS | EIssueServiceType.WORK_ITEMS;
export interface IPublicIssue
extends Pick<
TIssue,
| "description_html"
| "created_at"
| "updated_at"
| "created_by"
| "id"
| "name"
| "priority"
| "state_id"
| "project_id"
| "sequence_id"
| "sort_order"
| "start_date"
| "target_date"
| "cycle_id"
| "module_ids"
| "label_ids"
| "assignee_ids"
| "attachment_count"
| "sub_issues_count"
| "link_count"
| "estimate_point"
> {
comments: TIssuePublicComment[];
reaction_items: IIssuePublicReaction[];
vote_items: IPublicVote[];
}
export type TPublicIssueResponseResults =
| IPublicIssue[]
| {
[key: string]: {
results:
| IPublicIssue[]
| {
[key: string]: {
results: IPublicIssue[];
total_results: number;
};
};
total_results: number;
};
};
export type TPublicIssuesResponse = {
grouped_by: string;
next_cursor: string;
prev_cursor: string;
next_page_results: boolean;
prev_page_results: boolean;
total_count: number;
count: number;
total_pages: number;
extra_stats: null;
results: TPublicIssueResponseResults;
};
export interface IWorkItemPeekOverview {
embedIssue?: boolean;
embedRemoveCurrentNotification?: () => void;
is_draft?: boolean;
storeType?: EIssuesStoreType;
}

View File

@@ -0,0 +1,27 @@
import { TFileSignedURLResponse } from "../file";
export type TIssueAttachment = {
id: string;
attributes: {
name: string;
size: number;
};
asset_url: string;
issue_id: string;
// required
updated_at: string;
updated_by: string;
created_by: string;
};
export type TIssueAttachmentUploadResponse = TFileSignedURLResponse & {
attachment: TIssueAttachment;
};
export type TIssueAttachmentMap = {
[issue_id: string]: TIssueAttachment;
};
export type TIssueAttachmentIdMap = {
[issue_id: string]: string[];
};

View File

@@ -0,0 +1,22 @@
export type TIssueLinkEditableFields = {
title: string;
url: string;
};
export type TIssueLink = TIssueLinkEditableFields & {
created_by_id: string;
id: string;
metadata: any;
issue_id: string;
//need
created_at: Date;
};
export type TIssueLinkMap = {
[issue_id: string]: TIssueLink;
};
export type TIssueLinkIdMap = {
[issue_id: string]: string[];
};

View File

@@ -0,0 +1,27 @@
import { IUserLite } from "../users";
export type TIssueReaction = {
actor: string;
id: string;
issue: string;
reaction: string;
display_name: string;
};
export interface IIssuePublicReaction {
actor_details: IUserLite;
reaction: string;
}
export type TIssueReactionMap = {
[reaction_id: string]: TIssueReaction;
};
export type TIssueReactionIdMap = {
[issue_id: string]: { [reaction: string]: string[] };
};
export interface IPublicVote {
vote: -1 | 1;
actor_details: IUserLite;
}

View File

@@ -0,0 +1,11 @@
import { TIssue } from "./issue";
export type TIssueRelation = Record<TIssueRelationTypes, TIssue[]>;
export type TIssueRelationMap = {
[issue_id: string]: Record<TIssueRelationTypes, string[]>;
};
export type TIssueRelationIdMap = Record<TIssueRelationTypes, string[]>;
export type TIssueRelationTypes = "blocking" | "blocked_by" | "duplicate" | "relates_to";

View File

@@ -0,0 +1,41 @@
import { TIssue } from "./issue";
export type TSubIssuesStateDistribution = {
backlog: string[];
unstarted: string[];
started: string[];
completed: string[];
cancelled: string[];
};
export type TIssueSubIssues = {
state_distribution: TSubIssuesStateDistribution;
sub_issues: TSubIssueResponse;
};
export type TSubIssueResponse = TIssue[] | { [key: string]: TIssue[] };
export type TIssueSubIssuesStateDistributionMap = {
[issue_id: string]: TSubIssuesStateDistribution;
};
export type TIssueSubIssuesIdMap = {
[issue_id: string]: string[];
};
export type TSubIssueOperations = {
copyLink: (path: string) => void;
fetchSubIssues: (workspaceSlug: string, projectId: string, parentIssueId: string) => Promise<void>;
addSubIssue: (workspaceSlug: string, projectId: string, parentIssueId: string, issueIds: string[]) => Promise<void>;
updateSubIssue: (
workspaceSlug: string,
projectId: string,
parentIssueId: string,
issueId: string,
issueData: Partial<TIssue>,
oldIssue?: Partial<TIssue>,
fromModal?: boolean
) => Promise<void>;
removeSubIssue: (workspaceSlug: string, projectId: string, parentIssueId: string, issueId: string) => Promise<void>;
deleteSubIssue: (workspaceSlug: string, projectId: string, parentIssueId: string, issueId: string) => Promise<void>;
};

View File

@@ -0,0 +1,60 @@
export enum EGanttBlockType {
EPIC = "epic",
PROJECT = "project",
ISSUE = "issue",
}
export interface IGanttBlock {
data: any;
id: string;
name: string;
position?: {
marginLeft: number;
width: number;
};
sort_order: number | undefined;
start_date: string | undefined;
target_date: string | undefined;
meta?: Record<string, any>;
}
export interface IBlockUpdateData {
sort_order?: {
destinationIndex: number;
newSortOrder: number;
sourceIndex: number;
};
start_date?: string;
target_date?: string;
meta?: Record<string, any>;
}
export interface IBlockUpdateDependencyData {
id: string;
start_date?: string;
target_date?: string;
meta?: Record<string, any>;
}
export type TGanttViews = "week" | "month" | "quarter";
// chart render types
export interface WeekMonthDataType {
key: number;
shortTitle: string;
title: string;
abbreviation: string;
}
export interface ChartDataType {
key: string;
i18n_title: string;
data: ChartDataTypeData;
}
export interface ChartDataTypeData {
startDate: Date;
currentDate: Date;
endDate: Date;
approxFilterRange: number;
dayWidth: number;
}

View File

@@ -0,0 +1 @@
export * from "./gantt";

View File

@@ -0,0 +1,2 @@
export * from "./module_filters";
export * from "./modules";

View File

@@ -0,0 +1,38 @@
export type TModuleOrderByOptions =
| "name"
| "-name"
| "progress"
| "-progress"
| "issues_length"
| "-issues_length"
| "target_date"
| "-target_date"
| "created_at"
| "-created_at"
| "sort_order";
export type TModuleLayoutOptions = "list" | "board" | "gantt";
export type TModuleDisplayFilters = {
favorites?: boolean;
layout?: TModuleLayoutOptions;
order_by?: TModuleOrderByOptions;
};
export type TModuleFilters = {
lead?: string[] | null;
members?: string[] | null;
start_date?: string[] | null;
status?: string[] | null;
target_date?: string[] | null;
};
export type TModuleFiltersByState = {
default: TModuleFilters;
archived: TModuleFilters;
};
export type TModuleStoredFilters = {
display_filters?: TModuleDisplayFilters;
filters?: TModuleFilters;
};

View File

@@ -0,0 +1,118 @@
import type { ILinkDetails } from "../issues";
import type { TIssue } from "../issues/issue";
import type { IIssueFilterOptions } from "../view-props";
export type TModuleStatus = "backlog" | "planned" | "in-progress" | "paused" | "completed" | "cancelled";
export type TModuleCompletionChartDistribution = {
[key: string]: number | null;
};
export type TModuleDistributionBase = {
total_issues: number;
pending_issues: number;
completed_issues: number;
};
export type TModuleEstimateDistributionBase = {
total_estimates: number;
pending_estimates: number;
completed_estimates: number;
};
export type TModuleAssigneesDistribution = {
assignee_id: string | null;
avatar_url: string | null;
first_name: string | null;
last_name: string | null;
display_name: string | null;
};
export type TModuleLabelsDistribution = {
color: string | null;
label_id: string | null;
label_name: string | null;
};
export type TModuleDistribution = {
assignees: (TModuleAssigneesDistribution & TModuleDistributionBase)[];
completion_chart: TModuleCompletionChartDistribution;
labels: (TModuleLabelsDistribution & TModuleDistributionBase)[];
};
export type TModuleEstimateDistribution = {
assignees: (TModuleAssigneesDistribution & TModuleEstimateDistributionBase)[];
completion_chart: TModuleCompletionChartDistribution;
labels: (TModuleLabelsDistribution & TModuleEstimateDistributionBase)[];
};
export interface IModule {
total_issues: number;
completed_issues: number;
backlog_issues: number;
started_issues: number;
unstarted_issues: number;
cancelled_issues: number;
total_estimate_points?: number;
completed_estimate_points?: number;
backlog_estimate_points: number;
started_estimate_points: number;
unstarted_estimate_points: number;
cancelled_estimate_points: number;
distribution?: TModuleDistribution;
estimate_distribution?: TModuleEstimateDistribution;
id: string;
name: string;
description: string;
description_text: any;
description_html: any;
workspace_id: string;
project_id: string;
lead_id: string | null;
member_ids: string[];
link_module?: ILinkDetails[];
sub_issues?: number;
is_favorite: boolean;
sort_order: number;
view_props: {
filters: IIssueFilterOptions;
};
status?: TModuleStatus;
archived_at: string | null;
start_date: string | null;
target_date: string | null;
created_at: string;
updated_at: string;
created_by?: string;
updated_by?: string;
}
export interface ModuleIssueResponse {
created_at: Date;
created_by: string;
id: string;
issue: string;
issue_detail: TIssue;
module: string;
module_detail: IModule;
project: string;
updated_at: Date;
updated_by: string;
workspace: string;
sub_issues_count: number;
}
export type ModuleLink = {
title: string;
url: string;
};
export type SelectModuleType = (IModule & { actionType: "edit" | "delete" | "create-issue" }) | undefined;
export type TModulePlotType = "burndown" | "points";
export type TPublicModule = {
id: string;
name: string;
};

View File

@@ -0,0 +1,77 @@
import { TLogoProps } from "../common";
import { EPageAccess } from "../enums";
import { TPageExtended } from "./extended";
export type TPage = {
access: EPageAccess | undefined;
archived_at: string | null | undefined;
color: string | undefined;
created_at: Date | undefined;
created_by: string | undefined;
description: object | undefined;
description_html: string | undefined;
id: string | undefined;
is_favorite: boolean;
is_locked: boolean;
label_ids: string[] | undefined;
name: string | undefined;
owned_by: string | undefined;
project_ids?: string[] | undefined;
updated_at: Date | undefined;
updated_by: string | undefined;
workspace: string | undefined;
logo_props: TLogoProps | undefined;
deleted_at: Date | undefined;
} & TPageExtended;
// page filters
export type TPageNavigationTabs = "public" | "private" | "archived";
export type TPageFiltersSortKey = "name" | "created_at" | "updated_at" | "opened_at";
export type TPageFiltersSortBy = "asc" | "desc";
export type TPageFilterProps = {
created_at?: string[] | null;
created_by?: string[] | null;
favorites?: boolean;
labels?: string[] | null;
};
export type TPageFilters = {
searchQuery: string;
sortKey: TPageFiltersSortKey;
sortBy: TPageFiltersSortBy;
filters?: TPageFilterProps;
};
export type TPageEmbedType = "mention" | "issue";
export type TPageVersion = {
created_at: string;
created_by: string;
deleted_at: string | null;
description_binary?: string | null;
description_html?: string | null;
description_json?: object;
id: string;
last_saved_at: string;
owned_by: string;
page: string;
updated_at: string;
updated_by: string;
workspace: string;
};
export type TDocumentPayload = {
description_binary: string;
description_html: string;
description: object;
};
export type TWebhookConnectionQueryParams = {
documentType: "project_page" | "team_page" | "workspace_page";
projectId?: string;
teamId?: string;
workspaceSlug: string;
};

View File

@@ -0,0 +1 @@
export type TPageExtended = object;

View File

@@ -0,0 +1,2 @@
export * from "./core";
export * from "./extended";

View File

@@ -0,0 +1,42 @@
export enum EProductSubscriptionEnum {
FREE = "FREE",
ONE = "ONE",
PRO = "PRO",
BUSINESS = "BUSINESS",
ENTERPRISE = "ENTERPRISE",
}
export type TBillingFrequency = "month" | "year";
export type IPaymentProductPrice = {
currency: string;
id: string;
product: string;
recurring: TBillingFrequency;
unit_amount: number;
workspace_amount: number;
};
export type TProductSubscriptionType = "FREE" | "ONE" | "PRO" | "BUSINESS" | "ENTERPRISE";
export type IPaymentProduct = {
description: string;
id: string;
name: string;
type: Omit<TProductSubscriptionType, "FREE">;
payment_quantity: number;
prices: IPaymentProductPrice[];
is_active: boolean;
};
export type TSubscriptionPrice = {
key: string;
id: string | undefined;
currency: string;
price: number;
recurring: TBillingFrequency;
};
export type TProductBillingFrequency = {
[key in EProductSubscriptionEnum]: TBillingFrequency | undefined;
};

View File

@@ -0,0 +1,29 @@
export type TDropTarget = {
element: Element;
data: Record<string | symbol, unknown>;
};
export type TDropTargetMiscellaneousData = {
dropEffect: string;
isActiveDueToStickiness: boolean;
};
export interface IPragmaticPayloadLocation {
initial: {
dropTargets: (TDropTarget & TDropTargetMiscellaneousData)[];
};
current: {
dropTargets: (TDropTarget & TDropTargetMiscellaneousData)[];
};
previous: {
dropTargets: (TDropTarget & TDropTargetMiscellaneousData)[];
};
}
export interface IPragmaticDropPayload {
location: IPragmaticPayloadLocation;
source: TDropTarget;
self: TDropTarget & TDropTargetMiscellaneousData;
}
export type InstructionType = "reparent" | "reorder-above" | "reorder-below" | "make-child" | "instruction-blocked";

View File

@@ -0,0 +1,3 @@
export * from "./project_filters";
export * from "./projects";
export * from "./project_link";

View File

@@ -0,0 +1,28 @@
export type TProjectOrderByOptions =
| "sort_order"
| "name"
| "-name"
| "created_at"
| "-created_at"
| "members_length"
| "-members_length";
export type TProjectDisplayFilters = {
my_projects?: boolean;
archived_projects?: boolean;
order_by?: TProjectOrderByOptions;
};
export type TProjectAppliedDisplayFilterKeys = "my_projects" | "archived_projects";
export type TProjectFilters = {
access?: string[] | null;
lead?: string[] | null;
members?: string[] | null;
created_at?: string[] | null;
};
export type TProjectStoredFilters = {
display_filters?: TProjectDisplayFilters;
filters?: TProjectFilters;
};

View File

@@ -0,0 +1,22 @@
export type TProjectLinkEditableFields = {
title: string;
url: string;
};
export type TProjectLink = TProjectLinkEditableFields & {
created_by_id: string;
id: string;
metadata: any;
project_id: string;
//need
created_at: Date;
};
export type TProjectLinkMap = {
[project_id: string]: TProjectLink;
};
export type TProjectLinkIdMap = {
[project_id: string]: string[];
};

View File

@@ -0,0 +1,155 @@
import { TLogoProps } from "../common";
import { TUserPermissions } from "../enums";
import { TStateGroups } from "../state";
import type { IUser, IUserLite } from "../users";
import type { IWorkspace } from "../workspace";
export enum EUserProjectRoles {
ADMIN = 20,
MEMBER = 15,
GUEST = 5,
}
export interface IPartialProject {
id: string;
name: string;
identifier: string;
sort_order: number | null;
logo_props: TLogoProps;
member_role?: TUserPermissions | EUserProjectRoles | null;
archived_at: string | null;
workspace: IWorkspace | string;
cycle_view: boolean;
issue_views_view: boolean;
module_view: boolean;
page_view: boolean;
inbox_view: boolean;
guest_view_all_features?: boolean;
project_lead?: IUserLite | string | null;
network?: number;
// Timestamps
created_at?: Date;
updated_at?: Date;
// actor
created_by?: string;
updated_by?: string;
}
export interface IProject extends IPartialProject {
archive_in?: number;
close_in?: number;
// only for uploading the cover image
cover_image_asset?: null;
cover_image?: string;
// only for rendering the cover image
readonly cover_image_url?: string;
default_assignee?: IUser | string | null;
default_state?: string | null;
description?: string;
estimate?: string | null;
anchor?: string | null;
is_favorite?: boolean;
members?: string[];
timezone?: string;
}
export type TProjectAnalyticsCountParams = {
project_ids?: string;
fields?: string;
};
export type TProjectAnalyticsCount = Pick<IProject, "id"> & {
total_issues?: number;
completed_issues?: number;
total_cycles?: number;
total_members?: number;
total_modules?: number;
};
export interface IProjectLite {
id: string;
name: string;
identifier: string;
logo_props: TLogoProps;
}
export type ProjectPreferences = {
pages: {
block_display: boolean;
};
};
export interface IProjectMap {
[id: string]: IProject;
}
export interface IProjectMemberLite {
id: string;
member__avatar_url: string;
member__display_name: string;
member_id: string;
}
export type TProjectMembership = {
member: string;
role: TUserPermissions | EUserProjectRoles;
} & (
| {
id: string;
original_role: EUserProjectRoles;
created_at: string;
}
| {
id: null;
original_role: null;
created_at: null;
}
);
export interface IProjectBulkAddFormData {
members: { role: TUserPermissions | EUserProjectRoles; member_id: string }[];
}
export interface IGithubRepository {
id: string;
full_name: string;
html_url: string;
url: string;
}
export interface GithubRepositoriesResponse {
repositories: IGithubRepository[];
total_count: number;
}
export type TProjectIssuesSearchParams = {
search: string;
parent?: boolean;
issue_relation?: boolean;
cycle?: boolean;
module?: string;
sub_issue?: boolean;
issue_id?: string;
workspace_search: boolean;
target_date?: string;
epic?: boolean;
};
export interface ISearchIssueResponse {
id: string;
name: string;
project_id: string;
project__identifier: string;
project__name: string;
sequence_id: number;
start_date: string | null;
state__color: string;
state__group: TStateGroups;
state__name: string;
workspace__slug: string;
type_id: string;
}
export type TPartialProject = IPartialProject;
export type TProject = TPartialProject & IProject;

View File

@@ -0,0 +1,39 @@
import { IProject, IProjectLite } from "./project";
import { IWorkspaceLite } from "./workspace";
export type TPublishEntityType = "project" | "page";
export type TProjectPublishLayouts = "calendar" | "gantt" | "kanban" | "list" | "spreadsheet";
export type TProjectPublishViewProps = {
calendar?: boolean;
gantt?: boolean;
kanban?: boolean;
list?: boolean;
spreadsheet?: boolean;
};
export type TProjectDetails = IProjectLite & Pick<IProject, "cover_image" | "logo_props" | "description">;
export type TPublishSettings = {
anchor: string | undefined;
created_at: string | undefined;
created_by: string | undefined;
entity_identifier: string | undefined;
entity_name: TPublishEntityType | undefined;
id: string | undefined;
inbox: unknown;
is_comments_enabled: boolean;
is_reactions_enabled: boolean;
is_votes_enabled: boolean;
project: string | undefined;
project_details: TProjectDetails | undefined;
updated_at: string | undefined;
updated_by: string | undefined;
workspace: string | undefined;
workspace_detail: IWorkspaceLite | undefined;
};
export type TProjectPublishSettings = TPublishSettings & {
view_props: TProjectPublishViewProps | undefined;
};

View File

@@ -0,0 +1,36 @@
import { IUserLite } from "./users";
export interface IIssueReaction {
actor: string;
actor_detail: IUserLite;
created_at: Date;
created_by: string;
id: string;
issue: string;
project: string;
reaction: string;
updated_at: Date;
updated_by: string;
workspace: string;
}
export interface IssueReactionForm {
reaction: string;
}
export interface IssueCommentReaction {
id: string;
created_at: Date;
updated_at: Date;
reaction: string;
created_by: string;
updated_by: string;
project: string;
workspace: string;
actor: string;
comment: string;
}
export interface IssueCommentReactionForm {
reaction: string;
}

View File

@@ -0,0 +1,23 @@
// local imports
import { TFilterExpression, TFilterProperty } from "./expression";
/**
* External filter format
*/
export type TExternalFilter = Record<string, unknown> | undefined | null;
/**
* Adapter for converting between internal filter trees and external formats.
* @template P - Filter property type (e.g., 'state_id', 'priority', 'assignee')
* @template E - External filter format type (e.g., work item filters, automation filters)
*/
export interface IFilterAdapter<P extends TFilterProperty, E extends TExternalFilter> {
/**
* Converts external format to internal filter tree.
*/
toInternal(externalFilter: E): TFilterExpression<P> | null;
/**
* Converts internal filter tree to external format.
*/
toExternal(internalFilter: TFilterExpression<P> | null): E;
}

View File

@@ -0,0 +1,29 @@
import { SingleOrArray } from "../utils";
import { IFilterAdapter, TExternalFilter } from "./adapter";
import { TFilterProperty, TFilterValue } from "./expression";
import { TAllAvailableOperatorsForDisplay } from "./operators";
/**
* Condition payload for building filter expressions.
* @template P - Property key type
* @template V - Value type
*/
export type TFilterConditionForBuild<P extends TFilterProperty, V extends TFilterValue> = {
property: P;
operator: TAllAvailableOperatorsForDisplay;
value: SingleOrArray<V>;
};
/**
* Parameters for building filter expressions from multiple conditions.
* @template P - Property key type
* @template V - Value type
*/
export type TBuildFilterExpressionParams<
P extends TFilterProperty,
V extends TFilterValue,
E extends TExternalFilter,
> = {
conditions: TFilterConditionForBuild<P, V>[];
adapter: IFilterAdapter<P, E>;
};

View File

@@ -0,0 +1,20 @@
import { TFilterProperty, TFilterValue } from "../expression";
import { TOperatorConfigMap } from "../operator-configs";
/**
* Main filter configuration type for different properties.
* This is the primary configuration type used throughout the application.
*
* @template P - Property key type (e.g., 'state_id', 'priority', 'assignee')
* @template V - Value type for the filter
*/
export type TFilterConfig<P extends TFilterProperty, V extends TFilterValue = TFilterValue> = {
id: P;
label: string;
icon?: React.FC<React.SVGAttributes<SVGElement>>;
isEnabled: boolean;
allowMultipleFilters?: boolean;
supportedOperatorConfigsMap: TOperatorConfigMap<V>;
rightContent?: React.ReactNode; // content to display on the right side of the filter option in the dropdown
tooltipContent?: React.ReactNode; // content to display when hovering over the applied filter item in the filter list
};

View File

@@ -0,0 +1 @@
export * from "./filter-config";

View File

@@ -0,0 +1,77 @@
import { TFilterValue } from "../expression";
import {
TDateFilterFieldConfig,
TDateRangeFilterFieldConfig,
TSingleSelectFilterFieldConfig,
TMultiSelectFilterFieldConfig,
} from "../field-types";
import { TCoreOperatorSpecificConfigs } from "../operator-configs";
import { TFilterOperatorHelper } from "./shared";
// -------- DATE FILTER OPERATORS --------
/**
* Union type representing all core operators that support single date filter types.
*/
export type TCoreSupportedSingleDateFilterOperators<V extends TFilterValue = TFilterValue> = {
[K in keyof TCoreOperatorSpecificConfigs<V>]: TFilterOperatorHelper<
TCoreOperatorSpecificConfigs<V>,
K,
TDateFilterFieldConfig<V>
>;
}[keyof TCoreOperatorSpecificConfigs<V>];
/**
* Union type representing all core operators that support range date filter types.
*/
export type TCoreSupportedRangeDateFilterOperators<V extends TFilterValue = TFilterValue> = {
[K in keyof TCoreOperatorSpecificConfigs<V>]: TFilterOperatorHelper<
TCoreOperatorSpecificConfigs<V>,
K,
TDateRangeFilterFieldConfig<V>
>;
}[keyof TCoreOperatorSpecificConfigs<V>];
/**
* Union type representing all core operators that support date filter types.
*/
export type TCoreSupportedDateFilterOperators<V extends TFilterValue = TFilterValue> =
| TCoreSupportedSingleDateFilterOperators<V>
| TCoreSupportedRangeDateFilterOperators<V>;
export type TCoreAllAvailableDateFilterOperatorsForDisplay<V extends TFilterValue = TFilterValue> =
TCoreSupportedDateFilterOperators<V>;
// -------- SELECT FILTER OPERATORS --------
/**
* Union type representing all core operators that support single select filter types.
*/
export type TCoreSupportedSingleSelectFilterOperators<V extends TFilterValue = TFilterValue> = {
[K in keyof TCoreOperatorSpecificConfigs<V>]: TFilterOperatorHelper<
TCoreOperatorSpecificConfigs<V>,
K,
TSingleSelectFilterFieldConfig<V>
>;
}[keyof TCoreOperatorSpecificConfigs<V>];
/**
* Union type representing all core operators that support multi select filter types.
*/
export type TCoreSupportedMultiSelectFilterOperators<V extends TFilterValue = TFilterValue> = {
[K in keyof TCoreOperatorSpecificConfigs<V>]: TFilterOperatorHelper<
TCoreOperatorSpecificConfigs<V>,
K,
TMultiSelectFilterFieldConfig<V>
>;
}[keyof TCoreOperatorSpecificConfigs<V>];
/**
* Union type representing all core operators that support any select filter types.
*/
export type TCoreSupportedSelectFilterOperators<V extends TFilterValue = TFilterValue> =
| TCoreSupportedSingleSelectFilterOperators<V>
| TCoreSupportedMultiSelectFilterOperators<V>;
export type TCoreAllAvailableSelectFilterOperatorsForDisplay<V extends TFilterValue = TFilterValue> =
TCoreSupportedSelectFilterOperators<V>;

View File

@@ -0,0 +1,19 @@
import { TFilterValue } from "../expression";
// -------- DATE FILTER OPERATORS --------
/**
* Union type representing all extended operators that support date filter types.
*/
export type TExtendedSupportedDateFilterOperators<_V extends TFilterValue = TFilterValue> = never;
export type TExtendedAllAvailableDateFilterOperatorsForDisplay<_V extends TFilterValue = TFilterValue> = never;
// -------- SELECT FILTER OPERATORS --------
/**
* Union type representing all extended operators that support select filter types.
*/
export type TExtendedSupportedSelectFilterOperators<_V extends TFilterValue = TFilterValue> = never;
export type TExtendedAllAvailableSelectFilterOperatorsForDisplay<_V extends TFilterValue = TFilterValue> = never;

View File

@@ -0,0 +1,43 @@
import { TFilterValue } from "../expression";
import {
TCoreAllAvailableDateFilterOperatorsForDisplay,
TCoreAllAvailableSelectFilterOperatorsForDisplay,
TCoreSupportedDateFilterOperators,
TCoreSupportedSelectFilterOperators,
} from "./core";
import {
TExtendedAllAvailableDateFilterOperatorsForDisplay,
TExtendedAllAvailableSelectFilterOperatorsForDisplay,
TExtendedSupportedDateFilterOperators,
TExtendedSupportedSelectFilterOperators,
} from "./extended";
// -------- COMPOSED SUPPORT TYPES --------
/**
* All supported date filter operators.
*/
export type TSupportedDateFilterOperators<V extends TFilterValue = TFilterValue> =
| TCoreSupportedDateFilterOperators<V>
| TExtendedSupportedDateFilterOperators<V>;
export type TAllAvailableDateFilterOperatorsForDisplay<V extends TFilterValue = TFilterValue> =
| TCoreAllAvailableDateFilterOperatorsForDisplay<V>
| TExtendedAllAvailableDateFilterOperatorsForDisplay<V>;
/**
* All supported select filter operators.
*/
export type TSupportedSelectFilterOperators<V extends TFilterValue = TFilterValue> =
| TCoreSupportedSelectFilterOperators<V>
| TExtendedSupportedSelectFilterOperators<V>;
export type TAllAvailableSelectFilterOperatorsForDisplay<V extends TFilterValue = TFilterValue> =
| TCoreAllAvailableSelectFilterOperatorsForDisplay<V>
| TExtendedAllAvailableSelectFilterOperatorsForDisplay<V>;
// -------- RE-EXPORTS --------
export * from "./shared";
export * from "./core";
export * from "./extended";

View File

@@ -0,0 +1,9 @@
/**
* Generic utility type to check if a configuration type supports specific filter types.
* Returns the operator key if any member of the union includes the target filter types, never otherwise.
*/
export type TFilterOperatorHelper<
TOperatorConfigs,
K extends keyof TOperatorConfigs,
TTargetFilter,
> = TTargetFilter extends TOperatorConfigs[K] ? K : TOperatorConfigs[K] extends TTargetFilter ? K : never;

View File

@@ -0,0 +1,110 @@
// local imports
import { SingleOrArray } from "../utils";
import { TSupportedOperators, LOGICAL_OPERATOR, TAllAvailableOperatorsForDisplay } from "./operators";
/**
* Filter node types for building hierarchical filter trees.
* - CONDITION: Single filter for one field (e.g., "state is backlog")
* - GROUP: Logical container combining multiple filters with AND/OR or single filter/group with NOT
*/
export const FILTER_NODE_TYPE = {
CONDITION: "condition",
GROUP: "group",
} as const;
export type TFilterNodeType = (typeof FILTER_NODE_TYPE)[keyof typeof FILTER_NODE_TYPE];
/**
* Field property key that can be filtered (e.g., "state", "assignee", "created_at").
*/
export type TFilterProperty = string;
/**
* Allowed filter values - primitives plus null/undefined for empty states.
*/
export type TFilterValue = string | number | Date | boolean | null | undefined;
/**
* Base properties shared by all filter nodes.
* - id: Unique identifier for the node
* - type: Node type (condition or group)
*/
type TBaseFilterNode = {
id: string;
type: TFilterNodeType;
};
/**
* Leaf node representing a single filter condition (e.g., "state is backlog").
* - type: Node type (condition)
* - property: Field being filtered
* - operator: Comparison operator (is, is not, between, not between, etc.)
* - value: Filter value(s) - array for operators that support multiple values
* @template P - Property key type
* @template V - Value type
*/
export type TFilterConditionNode<P extends TFilterProperty, V extends TFilterValue> = TBaseFilterNode & {
type: typeof FILTER_NODE_TYPE.CONDITION;
property: P;
operator: TSupportedOperators;
value: SingleOrArray<V>;
};
/**
* Filter condition node for display purposes.
*/
export type TFilterConditionNodeForDisplay<P extends TFilterProperty, V extends TFilterValue> = Omit<
TFilterConditionNode<P, V>,
"operator"
> & {
operator: TAllAvailableOperatorsForDisplay;
};
/**
* Container node that combines multiple conditions with AND logical operator.
* - type: Node type (group)
* - logicalOperator: AND operator for combining child filters
* - children: Child conditions and/or nested groups (minimum 2 for meaningful operations)
* @template P - Property key type
*/
export type TFilterAndGroupNode<P extends TFilterProperty> = TBaseFilterNode & {
type: typeof FILTER_NODE_TYPE.GROUP;
logicalOperator: typeof LOGICAL_OPERATOR.AND;
children: TFilterExpression<P>[];
};
/**
* Union type for all group node types - AND, OR, and NOT groups.
* @template P - Property key type
*/
export type TFilterGroupNode<P extends TFilterProperty> = TFilterAndGroupNode<P>;
/**
* Union type for any filter node - either a single condition or a group container.
* @template P - Property key type
* @template V - Value type
*/
export type TFilterExpression<P extends TFilterProperty, V extends TFilterValue = TFilterValue> =
| TFilterConditionNode<P, V>
| TFilterGroupNode<P>;
/**
* Payload for creating/updating condition nodes - excludes base node properties.
* @template P - Property key type
* @template V - Value type
*/
export type TFilterConditionPayload<P extends TFilterProperty, V extends TFilterValue> = Omit<
TFilterConditionNode<P, V>,
keyof TBaseFilterNode
>;
/**
* Payload for creating/updating AND group nodes - excludes base node properties.
* @template P - Property key type
*/
export type TFilterAndGroupPayload<P extends TFilterProperty> = Omit<TFilterAndGroupNode<P>, keyof TBaseFilterNode>;
/**
* Union payload type for creating/updating any group node - excludes base node properties.
* @template P - Property key type
*/
export type TFilterGroupPayload<P extends TFilterProperty> = TFilterAndGroupPayload<P>;

View File

@@ -0,0 +1,79 @@
import { TFilterValue } from "../expression";
import { TSupportedOperators } from "../operators";
import { TBaseFilterFieldConfig, IFilterOption } from "./shared";
/**
* Core filter types
*/
export const CORE_FILTER_FIELD_TYPE = {
DATE: "date",
DATE_RANGE: "date_range",
SINGLE_SELECT: "single_select",
MULTI_SELECT: "multi_select",
} as const;
// -------- DATE FILTER CONFIGURATIONS --------
type TBaseDateFilterFieldConfig = TBaseFilterFieldConfig & {
min?: Date;
max?: Date;
};
/**
* Date filter configuration - for temporal filtering.
* - defaultValue: Initial date/time value
* - min: Minimum allowed date
* - max: Maximum allowed date
*/
export type TDateFilterFieldConfig<V extends TFilterValue> = TBaseDateFilterFieldConfig & {
type: typeof CORE_FILTER_FIELD_TYPE.DATE;
defaultValue?: V;
};
/**
* Date range filter configuration - for temporal filtering.
* - defaultValue: Initial date/time range values
* - min: Minimum allowed date
* - max: Maximum allowed date
*/
export type TDateRangeFilterFieldConfig<V extends TFilterValue> = TBaseDateFilterFieldConfig & {
type: typeof CORE_FILTER_FIELD_TYPE.DATE_RANGE;
defaultValue?: V[];
};
// -------- SELECT FILTER CONFIGURATIONS --------
/**
* Single-select filter configuration - dropdown with one selectable option.
* - defaultValue: Initial selected value
* - getOptions: Options as static array or async function
*/
export type TSingleSelectFilterFieldConfig<V extends TFilterValue> = TBaseFilterFieldConfig & {
type: typeof CORE_FILTER_FIELD_TYPE.SINGLE_SELECT;
defaultValue?: V;
getOptions: IFilterOption<V>[] | (() => IFilterOption<V>[] | Promise<IFilterOption<V>[]>);
};
/**
* Multi-select filter configuration - allows selecting multiple options.
* - defaultValue: Initial selected values array
* - getOptions: Options as static array or async function
* - singleValueOperator: Operator to show when single value is selected
*/
export type TMultiSelectFilterFieldConfig<V extends TFilterValue> = TBaseFilterFieldConfig & {
type: typeof CORE_FILTER_FIELD_TYPE.MULTI_SELECT;
defaultValue?: V[];
getOptions: IFilterOption<V>[] | (() => IFilterOption<V>[] | Promise<IFilterOption<V>[]>);
singleValueOperator: TSupportedOperators;
};
// -------- UNION TYPES --------
/**
* All core filter configurations
*/
export type TCoreFilterFieldConfigs<V extends TFilterValue = TFilterValue> =
| TDateFilterFieldConfig<V>
| TDateRangeFilterFieldConfig<V>
| TSingleSelectFilterFieldConfig<V>
| TMultiSelectFilterFieldConfig<V>;

View File

@@ -0,0 +1,13 @@
import { TFilterValue } from "../expression";
/**
* Extended filter types
*/
export const EXTENDED_FILTER_FIELD_TYPE = {} as const;
// -------- UNION TYPES --------
/**
* All extended filter configurations
*/
export type TExtendedFilterFieldConfigs<_V extends TFilterValue = TFilterValue> = never;

View File

@@ -0,0 +1,27 @@
import { TFilterValue } from "../expression";
import { CORE_FILTER_FIELD_TYPE, TCoreFilterFieldConfigs } from "./core";
import { EXTENDED_FILTER_FIELD_TYPE, TExtendedFilterFieldConfigs } from "./extended";
// -------- COMPOSED FILTER TYPES --------
export const FILTER_FIELD_TYPE = {
...CORE_FILTER_FIELD_TYPE,
...EXTENDED_FILTER_FIELD_TYPE,
} as const;
export type TFilterFieldType = (typeof FILTER_FIELD_TYPE)[keyof typeof FILTER_FIELD_TYPE];
// -------- COMPOSED CONFIGURATIONS --------
/**
* All supported filter configurations.
*/
export type TSupportedFilterFieldConfigs<V extends TFilterValue = TFilterValue> =
| TCoreFilterFieldConfigs<V>
| TExtendedFilterFieldConfigs<V>;
// -------- RE-EXPORTS --------
export * from "./shared";
export * from "./core";
export * from "./extended";

View File

@@ -0,0 +1,38 @@
import { TFilterValue } from "../expression";
/**
* Negative operator configuration for operators.
* - allowNegative: Whether the operator supports negation
* - negOperatorLabel: Label to use when the operator is negated
*/
export type TNegativeOperatorConfig = { allowNegative: true; negOperatorLabel?: string } | { allowNegative?: false };
/**
* Base filter configuration shared by all filter types.
* - operatorLabel: Label to use for the operator
* - negativeOperatorConfig: Configuration for negative operators
*/
export type TBaseFilterFieldConfig = {
isOperatorEnabled?: boolean;
operatorLabel?: string;
} & TNegativeOperatorConfig;
/**
* Individual option for select/multi-select filters.
* - id: Unique identifier for the option
* - label: Display text shown to users
* - value: Actual value used in filtering
* - icon: Optional icon component
* - iconClassName: CSS class for icon styling
* - disabled: Whether option can be selected
* - description: Additional context to be displayed in the filter dropdown
*/
export interface IFilterOption<V extends TFilterValue> {
id: string;
label: string;
value: V;
icon?: React.ReactNode;
iconClassName?: string;
disabled?: boolean;
description?: string;
}

View File

@@ -0,0 +1,8 @@
export * from "./adapter";
export * from "./builder";
export * from "./config";
export * from "./derived";
export * from "./expression";
export * from "./operator-configs";
export * from "./operators";
export * from "./field-types";

View File

@@ -0,0 +1,26 @@
import { TFilterValue } from "../expression";
import {
TDateFilterFieldConfig,
TDateRangeFilterFieldConfig,
TSingleSelectFilterFieldConfig,
TMultiSelectFilterFieldConfig,
} from "../field-types";
import { CORE_COLLECTION_OPERATOR, CORE_COMPARISON_OPERATOR, CORE_EQUALITY_OPERATOR } from "../operators";
// ----------------------------- EXACT Operator -----------------------------
export type TCoreExactOperatorConfigs<V extends TFilterValue> =
| TSingleSelectFilterFieldConfig<V>
| TDateFilterFieldConfig<V>;
// ----------------------------- IN Operator -----------------------------
export type TCoreInOperatorConfigs<V extends TFilterValue> = TMultiSelectFilterFieldConfig<V>;
// ----------------------------- RANGE Operator -----------------------------
export type TCoreRangeOperatorConfigs<V extends TFilterValue> = TDateRangeFilterFieldConfig<V>;
// ----------------------------- Core Operator Specific Configs -----------------------------
export type TCoreOperatorSpecificConfigs<V extends TFilterValue> = {
[CORE_EQUALITY_OPERATOR.EXACT]: TCoreExactOperatorConfigs<V>;
[CORE_COLLECTION_OPERATOR.IN]: TCoreInOperatorConfigs<V>;
[CORE_COMPARISON_OPERATOR.RANGE]: TCoreRangeOperatorConfigs<V>;
};

View File

@@ -0,0 +1,13 @@
import { TFilterValue } from "../expression";
// ----------------------------- EXACT Operator -----------------------------
export type TExtendedExactOperatorConfigs<_V extends TFilterValue> = never;
// ----------------------------- IN Operator -----------------------------
export type TExtendedInOperatorConfigs<_V extends TFilterValue> = never;
// ----------------------------- RANGE Operator -----------------------------
export type TExtendedRangeOperatorConfigs<_V extends TFilterValue> = never;
// ----------------------------- Extended Operator Specific Configs -----------------------------
export type TExtendedOperatorSpecificConfigs<_V extends TFilterValue> = unknown;

View File

@@ -0,0 +1,56 @@
import { TFilterValue } from "../expression";
import { EQUALITY_OPERATOR, COLLECTION_OPERATOR, COMPARISON_OPERATOR } from "../operators";
import { TCoreExactOperatorConfigs, TCoreInOperatorConfigs, TCoreRangeOperatorConfigs } from "./core";
import {
TExtendedExactOperatorConfigs,
TExtendedInOperatorConfigs,
TExtendedOperatorSpecificConfigs,
TExtendedRangeOperatorConfigs,
} from "./extended";
// ----------------------------- Composed Operator Configs -----------------------------
/**
* EXACT operator - combines core and extended configurations
*/
export type TExactOperatorConfigs<V extends TFilterValue> =
| TCoreExactOperatorConfigs<V>
| TExtendedExactOperatorConfigs<V>;
/**
* IN operator - combines core and extended configurations
*/
export type TInOperatorConfigs<V extends TFilterValue> = TCoreInOperatorConfigs<V> | TExtendedInOperatorConfigs<V>;
/**
* RANGE operator - combines core and extended configurations
*/
export type TRangeOperatorConfigs<V extends TFilterValue> =
| TCoreRangeOperatorConfigs<V>
| TExtendedRangeOperatorConfigs<V>;
// ----------------------------- Final Operator Specific Configs -----------------------------
/**
* Type-safe mapping of specific operators to their supported filter type configurations.
* Each operator maps to its composed (core + extended) configurations.
*/
export type TOperatorSpecificConfigs<V extends TFilterValue> = {
[EQUALITY_OPERATOR.EXACT]: TExactOperatorConfigs<V>;
[COLLECTION_OPERATOR.IN]: TInOperatorConfigs<V>;
[COMPARISON_OPERATOR.RANGE]: TRangeOperatorConfigs<V>;
} & TExtendedOperatorSpecificConfigs<V>;
/**
* Operator filter configuration mapping - for different operators.
* Provides type-safe mapping of operators to their specific supported configurations.
*/
export type TOperatorConfigMap<V extends TFilterValue> = Map<
keyof TOperatorSpecificConfigs<V>,
TOperatorSpecificConfigs<V>[keyof TOperatorSpecificConfigs<V>]
>;
// -------- RE-EXPORTS --------
export * from "./core";
export * from "./extended";

View File

@@ -0,0 +1,46 @@
/**
* Core logical operators
*/
export const CORE_LOGICAL_OPERATOR = {
AND: "and",
} as const;
/**
* Core equality operators
*/
export const CORE_EQUALITY_OPERATOR = {
EXACT: "exact",
} as const;
/**
* Core collection operators
*/
export const CORE_COLLECTION_OPERATOR = {
IN: "in",
} as const;
/**
* Core comparison operators
*/
export const CORE_COMPARISON_OPERATOR = {
RANGE: "range",
} as const;
/**
* Core operators that support multiple values
*/
export const CORE_MULTI_VALUE_OPERATORS = [CORE_COLLECTION_OPERATOR.IN, CORE_COMPARISON_OPERATOR.RANGE] as const;
/**
* All core operators
*/
export const CORE_OPERATORS = {
...CORE_EQUALITY_OPERATOR,
...CORE_COLLECTION_OPERATOR,
...CORE_COMPARISON_OPERATOR,
} as const;
/**
* All core operators that can be used in filter conditions
*/
export type TCoreSupportedOperators = (typeof CORE_OPERATORS)[keyof typeof CORE_OPERATORS];

View File

@@ -0,0 +1,37 @@
/**
* Extended logical operators
*/
export const EXTENDED_LOGICAL_OPERATOR = {} as const;
/**
* Extended equality operators
*/
export const EXTENDED_EQUALITY_OPERATOR = {} as const;
/**
* Extended collection operators
*/
export const EXTENDED_COLLECTION_OPERATOR = {} as const;
/**
* Extended comparison operators
*/
export const EXTENDED_COMPARISON_OPERATOR = {} as const;
/**
* Extended operators that support multiple values
*/
export const EXTENDED_MULTI_VALUE_OPERATORS = [] as const;
/**
* All extended operators
*/
export const EXTENDED_OPERATORS = {
...EXTENDED_EQUALITY_OPERATOR,
...EXTENDED_COLLECTION_OPERATOR,
...EXTENDED_COMPARISON_OPERATOR,
} as const;
/**
* All extended operators that can be used in filter conditions
*/
export type TExtendedSupportedOperators = (typeof EXTENDED_OPERATORS)[keyof typeof EXTENDED_OPERATORS];

View File

@@ -0,0 +1,66 @@
import {
CORE_LOGICAL_OPERATOR,
CORE_EQUALITY_OPERATOR,
CORE_COLLECTION_OPERATOR,
CORE_COMPARISON_OPERATOR,
TCoreSupportedOperators,
CORE_MULTI_VALUE_OPERATORS,
} from "./core";
import {
EXTENDED_LOGICAL_OPERATOR,
EXTENDED_EQUALITY_OPERATOR,
EXTENDED_COLLECTION_OPERATOR,
EXTENDED_COMPARISON_OPERATOR,
TExtendedSupportedOperators,
EXTENDED_MULTI_VALUE_OPERATORS,
} from "./extended";
// -------- COMPOSED OPERATORS --------
export const LOGICAL_OPERATOR = {
...CORE_LOGICAL_OPERATOR,
...EXTENDED_LOGICAL_OPERATOR,
} as const;
export const EQUALITY_OPERATOR = {
...CORE_EQUALITY_OPERATOR,
...EXTENDED_EQUALITY_OPERATOR,
} as const;
export const COLLECTION_OPERATOR = {
...CORE_COLLECTION_OPERATOR,
...EXTENDED_COLLECTION_OPERATOR,
} as const;
export const COMPARISON_OPERATOR = {
...CORE_COMPARISON_OPERATOR,
...EXTENDED_COMPARISON_OPERATOR,
} as const;
export const MULTI_VALUE_OPERATORS: ReadonlyArray<TSupportedOperators> = [
...CORE_MULTI_VALUE_OPERATORS,
...EXTENDED_MULTI_VALUE_OPERATORS,
] as const;
// -------- COMPOSED TYPES --------
export type TLogicalOperator = (typeof LOGICAL_OPERATOR)[keyof typeof LOGICAL_OPERATOR];
export type TEqualityOperator = (typeof EQUALITY_OPERATOR)[keyof typeof EQUALITY_OPERATOR];
export type TCollectionOperator = (typeof COLLECTION_OPERATOR)[keyof typeof COLLECTION_OPERATOR];
export type TComparisonOperator = (typeof COMPARISON_OPERATOR)[keyof typeof COMPARISON_OPERATOR];
/**
* Union type representing all operators that can be used in a filter condition.
* Combines core and extended operators.
*/
export type TSupportedOperators = TCoreSupportedOperators | TExtendedSupportedOperators;
/**
* All operators available for use in rich filters UI, including negated versions.
*/
export type TAllAvailableOperatorsForDisplay = TSupportedOperators;
// -------- RE-EXPORTS --------
export * from "./core";
export * from "./extended";

View File

@@ -0,0 +1,78 @@
import { ICycle } from "./cycle";
import { TIssue } from "./issues/issue";
import { IModule } from "./module";
import { TPage } from "./page";
import { IProject } from "./project";
import { IUser } from "./users";
import { IWorkspace } from "./workspace";
export type TSearchEntities = "user_mention" | "issue" | "project" | "cycle" | "module" | "page";
export type TUserSearchResponse = {
member__avatar_url: IUser["avatar_url"];
member__display_name: IUser["display_name"];
member__id: IUser["id"];
};
export type TProjectSearchResponse = {
name: IProject["name"];
id: IProject["id"];
identifier: IProject["identifier"];
logo_props: IProject["logo_props"];
workspace__slug: IWorkspace["slug"];
};
export type TIssueSearchResponse = {
name: TIssue["name"];
id: TIssue["id"];
sequence_id: TIssue["sequence_id"];
project__identifier: IProject["identifier"];
project_id: TIssue["project_id"];
priority: TIssue["priority"];
state_id: TIssue["state_id"];
type_id: TIssue["type_id"];
};
export type TCycleSearchResponse = {
name: ICycle["name"];
id: ICycle["id"];
project_id: ICycle["project_id"];
project__identifier: IProject["identifier"];
status: ICycle["status"];
workspace__slug: IWorkspace["slug"];
};
export type TModuleSearchResponse = {
name: IModule["name"];
id: IModule["id"];
project_id: IModule["project_id"];
project__identifier: IProject["identifier"];
status: IModule["status"];
workspace__slug: IWorkspace["slug"];
};
export type TPageSearchResponse = {
name: TPage["name"];
id: TPage["id"];
logo_props: TPage["logo_props"];
projects__id: TPage["project_ids"];
workspace__slug: IWorkspace["slug"];
};
export type TSearchResponse = {
cycle?: TCycleSearchResponse[];
issue?: TIssueSearchResponse[];
module?: TModuleSearchResponse[];
page?: TPageSearchResponse[];
project?: TProjectSearchResponse[];
user_mention?: TUserSearchResponse[];
};
export type TSearchEntityRequestPayload = {
count: number;
project_id?: string;
query_type: TSearchEntities[];
query: string;
team_id?: string;
issue_id?: string;
};

View File

@@ -0,0 +1,33 @@
export type TStateGroups = "backlog" | "unstarted" | "started" | "completed" | "cancelled";
export interface IState {
readonly id: string;
color: string;
default: boolean;
description: string;
group: TStateGroups;
name: string;
project_id: string;
sequence: number;
workspace_id: string;
order: number;
}
export interface IStateLite {
color: string;
group: TStateGroups;
id: string;
name: string;
}
export interface IStateResponse {
[key: string]: IState[];
}
export type TStateOperationsCallbacks = {
createState: (data: Partial<IState>) => Promise<IState>;
updateState: (stateId: string, data: Partial<IState>) => Promise<IState | undefined>;
deleteState: (stateId: string) => Promise<void>;
moveStatePosition: (stateId: string, data: Partial<IState>) => Promise<void>;
markStateAsDefault: (stateId: string) => Promise<void>;
};

View File

@@ -0,0 +1,16 @@
import { TLogoProps } from "./common";
export type TSticky = {
created_at?: string | undefined;
created_by?: string | undefined;
background_color?: string | null | undefined;
description?: object | undefined;
description_html?: string | undefined;
id: string;
logo_props: TLogoProps | undefined;
name?: string;
sort_order: number | undefined;
updated_at?: string | undefined;
updated_by?: string | undefined;
workspace: string | undefined;
};

Some files were not shown because too many files have changed in this diff Show More