Compare commits

..

4 Commits

Author SHA1 Message Date
NarayanBavisetti 21617234ed chore: removed the entity description version 2025-04-09 18:37:26 +05:30
NarayanBavisetti 58b836dc66 chore: added entity description version 2025-03-27 14:13:13 +05:30
NarayanBavisetti ace317445d chore: changed from foreign key to uuid field 2025-03-05 01:00:29 +05:30
NarayanBavisetti c5df671913 chore: added new fields in page model 2025-03-04 19:26:31 +05:30
42 changed files with 674 additions and 2914 deletions
+2 -2
View File
@@ -88,7 +88,7 @@ jobs:
full_build_push:
if: ${{ needs.branch_build_setup.outputs.do_full_build == 'true' }}
runs-on: ubuntu-22.04
runs-on: ubuntu-20.04
needs: [branch_build_setup]
env:
BUILD_TYPE: full
@@ -148,7 +148,7 @@ jobs:
slim_build_push:
if: ${{ needs.branch_build_setup.outputs.do_slim_build == 'true' }}
runs-on: ubuntu-22.04
runs-on: ubuntu-20.04
needs: [branch_build_setup]
env:
BUILD_TYPE: slim
+1 -1
View File
@@ -51,7 +51,7 @@ jobs:
uses: actions/checkout@v4
full_build_push:
runs-on: ubuntu-22.04
runs-on: ubuntu-20.04
needs: [branch_build_setup]
env:
BUILD_TYPE: full
+1 -1
View File
@@ -11,7 +11,7 @@ env:
jobs:
sync_changes:
runs-on: ubuntu-22.04
runs-on: ubuntu-20.04
permissions:
pull-requests: write
contents: read
@@ -853,7 +853,7 @@ def delete_cycle_issue_activity(
issues = requested_data.get("issues")
for issue in issues:
current_issue = Issue.objects.filter(pk=issue).first()
if current_issue:
if issue:
current_issue.updated_at = timezone.now()
current_issue.save(update_fields=["updated_at"])
issue_activities.append(
@@ -0,0 +1,31 @@
# Generated by Django 4.2.17 on 2025-03-04 19:29
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import uuid
class Migration(migrations.Migration):
dependencies = [
("db", "0092_alter_deprecateddashboardwidget_unique_together_and_more"),
]
operations = [
migrations.AddField(
model_name="page",
name="moved_to_page",
field=models.UUIDField(blank=True, null=True),
),
migrations.AddField(
model_name="page",
name="moved_to_project",
field=models.UUIDField(blank=True, null=True),
),
migrations.AddField(
model_name="pageversion",
name="sub_pages_data",
field=models.JSONField(blank=True, default=dict),
),
]
+1 -1
View File
@@ -82,4 +82,4 @@ from .label import Label
from .device import Device, DeviceSession
from .sticky import Sticky
from .sticky import Sticky
+3
View File
@@ -50,6 +50,8 @@ class Page(BaseModel):
projects = models.ManyToManyField(
"db.Project", related_name="pages", through="db.ProjectPage"
)
moved_to_page = models.UUIDField(null=True, blank=True)
moved_to_project = models.UUIDField(null=True, blank=True)
class Meta:
verbose_name = "Page"
@@ -172,6 +174,7 @@ class PageVersion(BaseModel):
description_html = models.TextField(blank=True, default="<p></p>")
description_stripped = models.TextField(blank=True, null=True)
description_json = models.JSONField(default=dict, blank=True)
sub_pages_data = models.JSONField(default=dict, blank=True)
class Meta:
verbose_name = "Page Version"
+2 -2
View File
@@ -1,9 +1,9 @@
FROM nginx:1.25.0-alpine
RUN rm /etc/nginx/conf.d/default.conf
COPY nginx/nginx.conf.template /etc/nginx/nginx.conf.template
COPY nginx.conf.template /etc/nginx/nginx.conf.template
COPY nginx/env.sh /docker-entrypoint.sh
COPY ./env.sh /docker-entrypoint.sh
RUN chmod +x /docker-entrypoint.sh
# Update all environment variables
@@ -1,9 +1,9 @@
FROM nginx:1.25.0-alpine
RUN rm /etc/nginx/conf.d/default.conf
COPY nginx/nginx.conf.dev /etc/nginx/nginx.conf.template
COPY nginx.conf.dev /etc/nginx/nginx.conf.template
COPY nginx/env.sh /docker-entrypoint.sh
COPY ./env.sh /docker-entrypoint.sh
RUN chmod +x /docker-entrypoint.sh
# Update all environment variables
View File
@@ -1,5 +1,5 @@
import { Editor } from "@tiptap/react";
import { FC, ReactNode } from "react";
import { Editor } from "@tiptap/react";
// plane utils
import { cn } from "@plane/utils";
// constants
@@ -71,7 +71,7 @@ export const EditorContainer: FC<EditorContainerProps> = (props) => {
onClick={handleContainerClick}
onMouseLeave={handleContainerMouseLeave}
className={cn(
`editor-container cursor-text relative line-spacing-${displayConfig.lineSpacing ?? DEFAULT_DISPLAY_CONFIG.lineSpacing}`,
"editor-container cursor-text relative",
{
"active-editor": editor?.isFocused && editor?.isEditable,
},
@@ -4,7 +4,6 @@ import { TDisplayConfig } from "@/types";
export const DEFAULT_DISPLAY_CONFIG: TDisplayConfig = {
fontSize: "large-font",
fontStyle: "sans-serif",
lineSpacing: "regular",
};
export const ACCEPTED_FILE_MIME_TYPES = ["image/jpeg", "image/jpg", "image/png", "image/webp", "image/gif"];
@@ -26,12 +26,12 @@ export const CoreEditorExtensionsWithoutProps = [
StarterKit.configure({
bulletList: {
HTMLAttributes: {
class: "list-disc pl-7 space-y-[--list-spacing-y]",
class: "list-disc pl-7 space-y-2",
},
},
orderedList: {
HTMLAttributes: {
class: "list-decimal pl-7 space-y-[--list-spacing-y]",
class: "list-decimal pl-7 space-y-2",
},
},
listItem: {
@@ -55,12 +55,12 @@ export const CoreEditorExtensions = (args: TArguments): Extensions => {
StarterKit.configure({
bulletList: {
HTMLAttributes: {
class: "list-disc pl-7 space-y-[--list-spacing-y]",
class: "list-disc pl-7 space-y-2",
},
},
orderedList: {
HTMLAttributes: {
class: "list-decimal pl-7 space-y-[--list-spacing-y]",
class: "list-decimal pl-7 space-y-2",
},
},
listItem: {
@@ -46,12 +46,12 @@ export const CoreReadOnlyEditorExtensions = (props: Props): Extensions => {
StarterKit.configure({
bulletList: {
HTMLAttributes: {
class: "list-disc pl-7 space-y-[--list-spacing-y]",
class: "list-disc pl-7 space-y-2",
},
},
orderedList: {
HTMLAttributes: {
class: "list-decimal pl-7 space-y-[--list-spacing-y]",
class: "list-decimal pl-7 space-y-2",
},
},
listItem: {
-3
View File
@@ -23,10 +23,7 @@ export type TEditorFontStyle = "sans-serif" | "serif" | "monospace";
export type TEditorFontSize = "small-font" | "large-font";
export type TEditorLineSpacing = "regular" | "small";
export type TDisplayConfig = {
fontStyle?: TEditorFontStyle;
fontSize?: TEditorFontSize;
lineSpacing?: TEditorLineSpacing;
};
+17 -17
View File
@@ -252,7 +252,7 @@ ul[data-type="taskList"] li[data-checked="true"] {
div[data-type="horizontalRule"] {
line-height: 0;
padding: var(--divider-padding-top) 0 var(--divider-padding-bottom) 0;
padding: 0.25rem 0;
margin-top: 0;
margin-bottom: 0;
@@ -335,10 +335,10 @@ p.editor-paragraph-block {
/* tailwind typography */
.prose :where(h1.editor-heading-block):not(:where([class~="not-prose"], [class~="not-prose"] *)) {
&:not(:first-child) {
padding-top: var(--heading-1-padding-top);
padding-top: 28px;
}
padding-bottom: var(--heading-1-padding-bottom);
padding-bottom: 4px;
font-size: var(--font-size-h1);
line-height: var(--line-height-h1);
font-weight: 600;
@@ -346,10 +346,10 @@ p.editor-paragraph-block {
.prose :where(h2.editor-heading-block):not(:where([class~="not-prose"], [class~="not-prose"] *)) {
&:not(:first-child) {
padding-top: var(--heading-2-padding-top);
padding-top: 28px;
}
padding-bottom: var(--heading-2-padding-bottom);
padding-bottom: 4px;
font-size: var(--font-size-h2);
line-height: var(--line-height-h2);
font-weight: 600;
@@ -357,10 +357,10 @@ p.editor-paragraph-block {
.prose :where(h3.editor-heading-block):not(:where([class~="not-prose"], [class~="not-prose"] *)) {
&:not(:first-child) {
padding-top: var(--heading-3-padding-top);
padding-top: 28px;
}
padding-bottom: var(--heading-3-padding-bottom);
padding-bottom: 4px;
font-size: var(--font-size-h3);
line-height: var(--line-height-h3);
font-weight: 600;
@@ -368,10 +368,10 @@ p.editor-paragraph-block {
.prose :where(h4.editor-heading-block):not(:where([class~="not-prose"], [class~="not-prose"] *)) {
&:not(:first-child) {
padding-top: var(--heading-4-padding-top);
padding-top: 28px;
}
padding-bottom: var(--heading-4-padding-bottom);
padding-bottom: 4px;
font-size: var(--font-size-h4);
line-height: var(--line-height-h4);
font-weight: 600;
@@ -379,10 +379,10 @@ p.editor-paragraph-block {
.prose :where(h5.editor-heading-block):not(:where([class~="not-prose"], [class~="not-prose"] *)) {
&:not(:first-child) {
padding-top: var(--heading-5-padding-top);
padding-top: 20px;
}
padding-bottom: var(--heading-5-padding-bottom);
padding-bottom: 4px;
font-size: var(--font-size-h5);
line-height: var(--line-height-h5);
font-weight: 600;
@@ -390,10 +390,10 @@ p.editor-paragraph-block {
.prose :where(h6.editor-heading-block):not(:where([class~="not-prose"], [class~="not-prose"] *)) {
&:not(:first-child) {
padding-top: var(--heading-6-padding-top);
padding-top: 20px;
}
padding-bottom: var(--heading-6-padding-bottom);
padding-bottom: 4px;
font-size: var(--font-size-h6);
line-height: var(--line-height-h6);
font-weight: 600;
@@ -405,16 +405,16 @@ p.editor-paragraph-block {
}
&:not(:first-child) {
padding-top: var(--paragraph-padding-top);
padding-top: 4px;
}
&:not(td p.editor-paragraph-block, th p.editor-paragraph-block) {
&:last-child {
padding-bottom: var(--paragraph-padding-bottom);
padding-bottom: 4px;
}
&:not(:last-child) {
padding-bottom: var(--paragraph-padding-between);
padding-bottom: 8px;
}
}
@@ -423,7 +423,7 @@ p.editor-paragraph-block {
}
p.editor-paragraph-block + p.editor-paragraph-block {
padding-top: var(--paragraph-padding-between) !important;
padding-top: 8px !important;
}
.prose :where(ol):not(:where([class~="not-prose"], [class~="not-prose"] *)) li p.editor-paragraph-block,
-44
View File
@@ -57,48 +57,4 @@
--font-style: monospace;
}
/* end font styles */
/* spacing */
&.line-spacing-regular {
--heading-1-padding-top: 28px;
--heading-1-padding-bottom: 4px;
--heading-2-padding-top: 28px;
--heading-2-padding-bottom: 4px;
--heading-3-padding-top: 28px;
--heading-3-padding-bottom: 4px;
--heading-4-padding-top: 28px;
--heading-4-padding-bottom: 4px;
--heading-5-padding-top: 20px;
--heading-5-padding-bottom: 4px;
--heading-6-padding-top: 20px;
--heading-6-padding-bottom: 4px;
--paragraph-padding-top: 4px;
--paragraph-padding-bottom: 4px;
--paragraph-padding-between: 8px;
--list-spacing-y: 8px;
--divider-padding-top: 4px;
--divider-padding-bottom: 4px;
}
&.line-spacing-small {
--heading-1-padding-top: 16px;
--heading-1-padding-bottom: 4px;
--heading-2-padding-top: 16px;
--heading-2-padding-bottom: 4px;
--heading-3-padding-top: 16px;
--heading-3-padding-bottom: 4px;
--heading-4-padding-top: 16px;
--heading-4-padding-bottom: 4px;
--heading-5-padding-top: 12px;
--heading-5-padding-bottom: 4px;
--heading-6-padding-top: 12px;
--heading-6-padding-bottom: 4px;
--paragraph-padding-top: 2px;
--paragraph-padding-bottom: 2px;
--paragraph-padding-between: 4px;
--list-spacing-y: 0px;
--divider-padding-top: 0px;
--divider-padding-bottom: 4px;
}
/* end spacing */
}
-1
View File
@@ -9,7 +9,6 @@ export const SUPPORTED_LANGUAGES: ILanguageOption[] = [
{ label: "日本語", value: "ja" },
{ label: "中文", value: "zh-CN" },
{ label: "Русский", value: "ru" },
{ label: "Italian", value: "it" },
];
export const STORAGE_KEY = "userLanguage";
@@ -461,8 +461,6 @@
"states": "States",
"state": "State",
"state_groups": "State groups",
"state_group": "State group",
"priorities": "Priorities",
"priority": "Priority",
"team_project": "Team project",
"project": "Project",
@@ -471,16 +469,12 @@
"module": "Module",
"modules": "Modules",
"labels": "Labels",
"label": "Label",
"assignees": "Assignees",
"assignee": "Assignee",
"created_by": "Created by",
"none": "None",
"link": "Link",
"estimates": "Estimates",
"estimate": "Estimate",
"created_at": "Created at",
"completed_at": "Completed at",
"layout": "Layout",
"filters": "Filters",
"display": "Display",
@@ -523,6 +517,7 @@
"add_more": "Add more",
"defaults": "Defaults",
"add_label": "Add label",
"estimates": "Estimates",
"customize_time_range": "Customize time range",
"loading": "Loading",
"attachments": "Attachments",
@@ -661,6 +656,8 @@
"select": "Select",
"upgrade": "Upgrade",
"add_seats": "Add Seats",
"label": "Label",
"priorities": "Priorities",
"projects": "Projects",
"workspace": "Workspace",
"workspaces": "Workspaces",
@@ -633,8 +633,6 @@
"states": "Estados",
"state": "Estado",
"state_groups": "Grupos de estados",
"state_group": "Grupos de estado",
"priorities": "Prioridades",
"priority": "Prioridad",
"team_project": "Proyecto de equipo",
"project": "Proyecto",
@@ -643,16 +641,12 @@
"module": "Módulo",
"modules": "Módulos",
"labels": "Etiquetas",
"label": "Etiqueta",
"assignees": "Asignados",
"assignee": "Asignado",
"created_by": "Creado por",
"none": "Ninguno",
"link": "Enlace",
"estimates": "Estimaciones",
"estimate": "Estimación",
"created_at": "Creado en",
"completed_at": "Completado en",
"layout": "Diseño",
"filters": "Filtros",
"display": "Mostrar",
@@ -695,6 +689,7 @@
"add_more": "Agregar más",
"defaults": "Valores predeterminados",
"add_label": "Agregar etiqueta",
"estimates": "Estimaciones",
"customize_time_range": "Personalizar rango de tiempo",
"loading": "Cargando",
"attachments": "Archivos adjuntos",
@@ -832,6 +827,8 @@
"select": "Seleccionar",
"upgrade": "Mejorar",
"add_seats": "Agregar asientos",
"label": "Etiqueta",
"priorities": "Prioridades",
"projects": "Proyectos",
"workspace": "Espacio de trabajo",
"workspaces": "Espacios de trabajo",
@@ -631,8 +631,6 @@
"states": "États",
"state": "État",
"state_groups": "Groupes d'états",
"state_group": "Groupe d'état",
"priorities": "Priorités",
"priority": "Priorité",
"team_project": "Projet d'équipe",
"project": "Projet",
@@ -641,16 +639,12 @@
"module": "Module",
"modules": "Modules",
"labels": "Étiquettes",
"label": "Étiquette",
"assignees": "Assignés",
"assignee": "Assigné",
"created_by": "Créé par",
"none": "Aucun",
"link": "Lien",
"estimates": "Estimations",
"estimate": "Estimation",
"created_at": "Créé le",
"completed_at": "Terminé le",
"layout": "Disposition",
"filters": "Filtres",
"display": "Affichage",
@@ -693,6 +687,7 @@
"add_more": "Ajouter plus",
"defaults": "Par défaut",
"add_label": "Ajouter une étiquette",
"estimates": "Estimations",
"customize_time_range": "Personnaliser la plage de temps",
"loading": "Chargement",
"attachments": "Pièces jointes",
@@ -830,6 +825,8 @@
"select": "Sélectionner",
"upgrade": "Mettre à niveau",
"add_seats": "Ajouter des sièges",
"label": "Étiquette",
"priorities": "Priorités",
"projects": "Projets",
"workspace": "Espace de travail",
"workspaces": "Espaces de travail",
File diff suppressed because it is too large Load Diff
@@ -631,8 +631,6 @@
"states": "ステータス",
"state": "ステータス",
"state_groups": "ステータスグループ",
"state_group": "ステート グループ",
"priorities": "優先度",
"priority": "優先度",
"team_project": "チームプロジェクト",
"project": "プロジェクト",
@@ -641,16 +639,12 @@
"module": "モジュール",
"modules": "モジュール",
"labels": "ラベル",
"label": "ラベル",
"assignees": "担当者",
"assignee": "担当者",
"created_by": "作成者",
"none": "なし",
"link": "リンク",
"estimates": "見積もり",
"estimate": "見積もり",
"created_at": "クリエイテッド アット",
"completed_at": "コンプリーテッド アット",
"layout": "レイアウト",
"filters": "フィルター",
"display": "表示",
@@ -693,6 +687,7 @@
"add_more": "さらに追加",
"defaults": "デフォルト",
"add_label": "ラベルを追加",
"estimates": "見積もり",
"customize_time_range": "期間をカスタマイズ",
"loading": "読み込み中",
"attachments": "添付ファイル",
@@ -830,6 +825,8 @@
"select": "選択",
"upgrade": "アップグレード",
"add_seats": "シートを追加",
"label": "ラベル",
"priorities": "優先度",
"projects": "プロジェクト",
"workspace": "ワークスペース",
"workspaces": "ワークスペース",
File diff suppressed because it is too large Load Diff
@@ -631,8 +631,6 @@
"states": "状态",
"state": "状态",
"state_groups": "状态组",
"state_group": "状态组",
"priorities": "优先级",
"priority": "优先级",
"team_project": "团队项目",
"project": "项目",
@@ -641,16 +639,12 @@
"module": "模块",
"modules": "模块",
"labels": "标签",
"label": "标签",
"assignees": "负责人",
"assignee": "负责人",
"created_by": "创建者",
"none": "无",
"link": "链接",
"estimates": "估算",
"estimate": "估算",
"created_at": "创建于",
"completed_at": "完成于",
"layout": "布局",
"filters": "筛选",
"display": "显示",
@@ -693,6 +687,7 @@
"add_more": "添加更多",
"defaults": "默认值",
"add_label": "添加标签",
"estimates": "估算",
"customize_time_range": "自定义时间范围",
"loading": "加载中",
"attachments": "附件",
@@ -830,6 +825,8 @@
"select": "选择",
"upgrade": "升级",
"add_seats": "添加席位",
"label": "标签",
"priorities": "优先级",
"projects": "项目",
"workspace": "工作区",
"workspaces": "工作区",
-2
View File
@@ -149,8 +149,6 @@ export class TranslationStore {
return import("../locales/zh-CN/translations.json");
case "ru":
return import("../locales/ru/translations.json");
case "it":
return import("../locales/it/translations.json");
default:
throw new Error(`Unsupported language: ${language}`);
}
+1 -1
View File
@@ -1,4 +1,4 @@
export type TLanguage = "en" | "fr" | "es" | "ja" | "zh-CN" | "ru" | "it";
export type TLanguage = "en" | "fr" | "es" | "ja" | "zh-CN" | "ru";
export interface ILanguageOption {
label: string;
-1
View File
@@ -1 +0,0 @@
nginx.conf.template
-39
View File
@@ -1,39 +0,0 @@
(plane_proxy) {
request_body {
max_size {$FILE_SIZE_LIMIT}
}
reverse_proxy /spaces/* space:3000
reverse_proxy /god-mode/* admin:3000
reverse_proxy /api/* api:8000
reverse_proxy /auth/* api:8000
reverse_proxy /live/* live:3000
reverse_proxy /{$BUCKET_NAME} plane-minio:9000
reverse_proxy /{$BUCKET_NAME}/* plane-minio:9000
reverse_proxy /* web:3000
}
{
email {$CERT_EMAIL:admin@example.com}
acme_ca {$CERT_ACME_CA}
{$CERT_ACME_DNS}
servers {
timeouts {
read_body 600s
read_header 30s
write 600s
idle 600s
}
max_header_size 25MB
client_ip_headers X-Forwarded-For X-Real-IP
trusted_proxies static {$TRUSTED_PROXIES:0.0.0.0/0}
}
log {
output {$LOG_OUTPUT:stdout}
level {$LOG_LEVEL:INFO}
}
}
{$SITE_ADDRESS} {
import plane_proxy
}
@@ -108,7 +108,7 @@ export const ExtendedProjectSidebar = observer(() => {
<div
ref={extendedProjectSidebarRef}
className={cn(
"absolute top-0 h-full z-[19] flex flex-col gap-2 w-[300px] transform transition-all duration-300 ease-in-out bg-custom-sidebar-background-100 border-r border-custom-sidebar-border-200 shadow-md",
"fixed top-0 h-full z-[19] flex flex-col gap-2 w-[300px] transform transition-all duration-300 ease-in-out bg-custom-sidebar-background-100 border-r border-custom-sidebar-border-200 shadow-md",
{
"translate-x-0 opacity-100 pointer-events-auto": extendedProjectSidebarCollapsed,
"-translate-x-full opacity-0 pointer-events-none": !extendedProjectSidebarCollapsed,
@@ -104,7 +104,7 @@ export const ExtendedAppSidebar = observer(() => {
<div
ref={extendedSidebarRef}
className={cn(
"absolute top-0 h-full z-[19] flex flex-col gap-0.5 w-[300px] transform transition-all duration-300 ease-in-out bg-custom-sidebar-background-100 border-r border-custom-sidebar-border-200 p-4 shadow-md pb-6",
"fixed top-0 h-full z-[19] flex flex-col gap-0.5 w-[300px] transform transition-all duration-300 ease-in-out bg-custom-sidebar-background-100 border-r border-custom-sidebar-border-200 p-4 shadow-md pb-6",
{
"translate-x-0 opacity-100 pointer-events-auto": extendedSidebarCollapsed,
"-translate-x-full opacity-0 pointer-events-none": !extendedSidebarCollapsed,
@@ -3,7 +3,16 @@
import React, { FC, useEffect, useState } from "react";
import { observer } from "mobx-react";
import { Controller, useForm } from "react-hook-form";
import { ArchiveIcon, ArchiveRestoreIcon, ChevronRight, EllipsisIcon, LinkIcon, Trash2 } from "lucide-react";
import {
ArchiveIcon,
ArchiveRestoreIcon,
CalendarCheck2,
CalendarClock,
ChevronRight,
EllipsisIcon,
LinkIcon,
Trash2,
} from "lucide-react";
// types
import { CYCLE_STATUS, CYCLE_UPDATED, EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
import { useTranslation } from "@plane/i18n";
@@ -11,7 +20,7 @@ import { ICycle } from "@plane/types";
// ui
import { CustomMenu, setToast, TOAST_TYPE } from "@plane/ui";
// components
import { DateRangeDropdown } from "@/components/dropdowns";
import { DateDropdown } from "@/components/dropdowns";
// helpers
import { renderFormattedPayloadDate, getDate } from "@/helpers/date-time.helper";
import { copyUrlToClipboard } from "@/helpers/string.helper";
@@ -54,7 +63,7 @@ export const CycleSidebarHeader: FC<Props> = observer((props) => {
const { t } = useTranslation();
// form info
const { control, reset } = useForm({
const { control, reset, getValues } = useForm({
defaultValues,
});
@@ -101,10 +110,10 @@ export const CycleSidebarHeader: FC<Props> = observer((props) => {
});
};
const submitChanges = async (data: Partial<ICycle>, changedProperty: string) => {
const submitChanges = (data: Partial<ICycle>, changedProperty: string) => {
if (!workspaceSlug || !projectId || !cycleDetails.id) return;
await updateCycleDetails(workspaceSlug.toString(), projectId.toString(), cycleDetails.id.toString(), data)
updateCycleDetails(workspaceSlug.toString(), projectId.toString(), cycleDetails.id.toString(), data)
.then((res) => {
captureCycleEvent({
eventName: CYCLE_UPDATED,
@@ -145,22 +154,16 @@ export const CycleSidebarHeader: FC<Props> = observer((props) => {
}
};
const handleDateChange = async (startDate: Date | undefined, endDate: Date | undefined) => {
const handleDateChange = async (payload: { start_date?: string | null; end_date?: string | null }) => {
let isDateValid = false;
const payload = {
start_date: renderFormattedPayloadDate(startDate) || null,
end_date: renderFormattedPayloadDate(endDate) || null,
};
if (payload?.start_date && payload.end_date) {
if (cycleDetails?.start_date && cycleDetails?.end_date)
isDateValid = await dateChecker({
...payload,
cycle_id: cycleDetails.id,
cycle_id: cycleDetails?.id,
});
} else {
isDateValid = true;
}
else isDateValid = await dateChecker(payload);
if (isDateValid) {
submitChanges(payload, "date_range");
setToast({
@@ -174,6 +177,7 @@ export const CycleSidebarHeader: FC<Props> = observer((props) => {
title: t("project_cycles.action.update.failed.title"),
message: t("project_cycles.action.update.error.already_exists"),
});
reset({ ...cycleDetails });
}
return isDateValid;
};
@@ -284,41 +288,79 @@ export const CycleSidebarHeader: FC<Props> = observer((props) => {
</span>
)}
</div>
<div className="flex items-center gap-2">
<Controller
name="start_date"
control={control}
rules={{ required: "Please select a date" }}
render={({ field: { value, onChange } }) => (
<DateDropdown
value={value ?? null}
onChange={async (val) => {
let isDateValid;
const valDate = val ? renderFormattedPayloadDate(val) : null;
if (getValues("end_date")) {
isDateValid = await handleDateChange({
start_date: valDate,
end_date: renderFormattedPayloadDate(getValues("end_date")),
});
} else {
isDateValid = await handleDateChange({
start_date: valDate,
end_date: valDate,
});
}
isDateValid && onChange(renderFormattedPayloadDate(val));
}}
placeholder={t("common.order_by.start_date")}
icon={<CalendarClock className="h-3 w-3 flex-shrink-0" />}
buttonVariant={value ? "border-with-text" : "border-without-text"}
buttonContainerClassName={`h-6 w-full flex ${!isEditingAllowed || isArchived || isCompleted ? "cursor-not-allowed" : "cursor-pointer"} items-center gap-1.5 text-custom-text-300 rounded text-xs`}
optionsClassName="z-10"
disabled={!isEditingAllowed || isArchived || isCompleted}
showTooltip
maxDate={getDate(getValues("end_date"))}
isClearable={false}
/>
)}
/>
<Controller
control={control}
name="start_date"
render={({ field: { value: startDateValue, onChange: onChangeStartDate } }) => (
<Controller
control={control}
name="end_date"
render={({ field: { value: endDateValue, onChange: onChangeEndDate } }) => (
<DateRangeDropdown
className="h-7"
buttonVariant="border-with-text"
minDate={new Date()}
value={{
from: getDate(startDateValue),
to: getDate(endDateValue),
}}
onSelect={async (val) => {
const isDateValid = await handleDateChange(val?.from, val?.to);
if (isDateValid) {
onChangeStartDate(val?.from ? renderFormattedPayloadDate(val.from) : null);
onChangeEndDate(val?.to ? renderFormattedPayloadDate(val.to) : null);
}
}}
placeholder={{
from: "Start date",
to: "End date",
}}
required={cycleDetails.status !== "draft"}
disabled={!isEditingAllowed || isArchived || isCompleted}
/>
)}
/>
)}
/>
<Controller
name="end_date"
control={control}
rules={{ required: "Please select a date" }}
render={({ field: { value, onChange } }) => (
<DateDropdown
value={getDate(value) ?? null}
onChange={async (val) => {
let isDateValid;
const valDate = val ? renderFormattedPayloadDate(val) : null;
if (getValues("start_date")) {
isDateValid = await handleDateChange({
end_date: valDate,
start_date: renderFormattedPayloadDate(getValues("start_date")),
});
} else {
isDateValid = await handleDateChange({
end_date: valDate,
start_date: valDate,
});
}
isDateValid && onChange(renderFormattedPayloadDate(val));
}}
placeholder={t("common.order_by.due_date")}
icon={<CalendarCheck2 className="h-3 w-3 flex-shrink-0" />}
buttonVariant={value ? "border-with-text" : "border-without-text"}
buttonContainerClassName={`h-6 w-full flex ${!isEditingAllowed || isArchived || isCompleted ? "cursor-not-allowed" : "cursor-pointer"} items-center gap-1.5 text-custom-text-300 rounded text-xs`}
optionsClassName="z-10"
disabled={!isEditingAllowed || isArchived || isCompleted}
showTooltip
minDate={getDate(getValues("start_date"))}
isClearable={false}
/>
)}
/>
</div>
</div>
</>
);
@@ -3,21 +3,31 @@
import React, { FC, MouseEvent, useEffect, useMemo, useState } from "react";
import { observer } from "mobx-react";
import { useParams, usePathname, useSearchParams } from "next/navigation";
import { useForm } from "react-hook-form";
import { Eye, Users } from "lucide-react";
import { Controller, useForm } from "react-hook-form";
import { CalendarCheck2, CalendarClock, Eye, Users } from "lucide-react";
// types
import { CYCLE_FAVORITED, CYCLE_UNFAVORITED, EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
import { useTranslation } from "@plane/i18n";
import { ICycle, TCycleGroups } from "@plane/types";
// ui
import { Avatar, AvatarGroup, FavoriteStar, LayersIcon, Tooltip, TransferIcon, setPromiseToast } from "@plane/ui";
import {
Avatar,
AvatarGroup,
FavoriteStar,
LayersIcon,
TOAST_TYPE,
Tooltip,
TransferIcon,
setPromiseToast,
setToast,
} from "@plane/ui";
// components
import { CycleQuickActions, TransferIssuesModal } from "@/components/cycles";
import { DateRangeDropdown } from "@/components/dropdowns";
import { DateDropdown } from "@/components/dropdowns";
import { ButtonAvatars } from "@/components/dropdowns/member/avatar";
// constants
// helpers
import { getDate } from "@/helpers/date-time.helper";
import { getDate, renderFormattedPayloadDate } from "@/helpers/date-time.helper";
import { getFileURL } from "@/helpers/file.helper";
// hooks
import { generateQueryParams } from "@/helpers/router.helper";
@@ -26,7 +36,11 @@ import { useAppRouter } from "@/hooks/use-app-router";
import { usePlatformOS } from "@/hooks/use-platform-os";
// plane web components
import { CycleAdditionalActions } from "@/plane-web/components/cycles";
// plane web constants
// services
import { CycleService } from "@/services/cycle.service";
const cycleService = new CycleService();
type Props = {
workspaceSlug: string;
projectId: string;
@@ -141,6 +155,48 @@ export const CycleListItemAction: FC<Props> = observer((props) => {
});
};
const submitChanges = (data: Partial<ICycle>) => {
if (!workspaceSlug || !projectId || !cycleId) return;
updateCycleDetails(workspaceSlug.toString(), projectId.toString(), cycleId.toString(), data);
};
const dateChecker = async (payload: any) => {
try {
const res = await cycleService.cycleDateCheck(workspaceSlug as string, projectId as string, payload);
return res.status;
} catch {
return false;
}
};
const handleDateChange = async (payload: { start_date?: string | null; end_date?: string | null }) => {
let isDateValid = false;
if (cycleDetails?.start_date && cycleDetails?.end_date)
isDateValid = await dateChecker({
...payload,
cycle_id: cycleDetails?.id,
});
else isDateValid = await dateChecker(payload);
if (isDateValid) {
submitChanges(payload);
setToast({
type: TOAST_TYPE.SUCCESS,
title: t("project_cycles.action.update.success.title"),
message: t("project_cycles.action.update.success.description"),
});
} else {
setToast({
type: TOAST_TYPE.ERROR,
title: t("project_cycles.action.update.failed.title"),
message: t("project_cycles.action.update.error.already_exists"),
});
reset({ ...cycleDetails });
}
return isDateValid;
};
const createdByDetails = cycleDetails.created_by ? getUserDetails(cycleDetails.created_by) : undefined;
useEffect(() => {
@@ -150,6 +206,10 @@ export const CycleListItemAction: FC<Props> = observer((props) => {
});
}, [cycleDetails, reset]);
const isArchived = Boolean(cycleDetails.archived_at);
const isCompleted = cycleStatus === "completed";
const isDisabled = !isEditingAllowed || isArchived || isCompleted;
// handlers
const openCycleOverview = (e: MouseEvent<HTMLButtonElement | HTMLAnchorElement>) => {
e.preventDefault();
@@ -198,27 +258,81 @@ export const CycleListItemAction: FC<Props> = observer((props) => {
</div>
)}
{!isActive && cycleDetails.start_date && (
<DateRangeDropdown
buttonVariant={"transparent-with-text"}
buttonContainerClassName={`h-6 w-full cursor-auto flex items-center gap-1.5 text-custom-text-300 rounded text-xs [&>div]:hover:bg-transparent`}
buttonClassName="p-0"
minDate={new Date()}
value={{
from: getDate(cycleDetails.start_date),
to: getDate(cycleDetails.end_date),
}}
placeholder={{
from: "Start date",
to: "End date",
}}
showTooltip
required={cycleDetails.status !== "draft"}
disabled
hideIcon={{
from: false,
to: false,
}}
{!isActive && (
<Controller
name="start_date"
control={control}
rules={{ required: "Please select a date" }}
render={({ field: { value, onChange } }) => (
<DateDropdown
value={value ?? null}
onChange={async (val) => {
let isDateValid;
const valDate = val ? renderFormattedPayloadDate(val) : null;
if (getValues("end_date")) {
isDateValid = await handleDateChange({
start_date: valDate,
end_date: renderFormattedPayloadDate(getValues("end_date")),
});
} else {
isDateValid = await handleDateChange({
start_date: valDate,
end_date: valDate,
});
}
isDateValid && onChange(renderFormattedPayloadDate(val));
}}
placeholder={t("common.order_by.start_date")}
icon={<CalendarClock className="h-3 w-3 flex-shrink-0" />}
buttonVariant={value ? "border-with-text" : "border-without-text"}
buttonContainerClassName={`h-6 w-full flex ${isDisabled ? "cursor-not-allowed" : "cursor-pointer"} items-center gap-1.5 text-custom-text-300 rounded text-xs`}
optionsClassName="z-10"
disabled={isDisabled}
renderByDefault={isMobile}
showTooltip
maxDate={getDate(getValues("end_date"))}
isClearable={false}
/>
)}
/>
)}
{!isActive && (
<Controller
name="end_date"
control={control}
rules={{ required: "Please select a date" }}
render={({ field: { value, onChange } }) => (
<DateDropdown
value={getDate(value) ?? null}
onChange={async (val) => {
let isDateValid;
const valDate = val ? renderFormattedPayloadDate(val) : null;
if (getValues("start_date")) {
isDateValid = await handleDateChange({
end_date: valDate,
start_date: renderFormattedPayloadDate(getValues("start_date")),
});
} else {
isDateValid = await handleDateChange({
end_date: valDate,
start_date: valDate,
});
}
isDateValid && onChange(renderFormattedPayloadDate(val));
}}
placeholder={t("common.order_by.due_date")}
icon={<CalendarCheck2 className="h-3 w-3 flex-shrink-0" />}
buttonVariant={value ? "border-with-text" : "border-without-text"}
buttonContainerClassName={`h-6 w-full flex ${isDisabled ? "cursor-not-allowed" : "cursor-pointer"} items-center gap-1.5 text-custom-text-300 rounded text-xs`}
optionsClassName="z-10"
disabled={isDisabled}
renderByDefault={isMobile}
showTooltip
minDate={getDate(getValues("start_date"))}
isClearable={false}
/>
)}
/>
)}
+6 -2
View File
@@ -35,7 +35,7 @@ type Props = {
};
minDate?: Date;
maxDate?: Date;
onSelect?: (range: DateRange | undefined) => void;
onSelect: (range: DateRange | undefined) => void;
placeholder?: {
from?: string;
to?: string;
@@ -204,7 +204,11 @@ export const DateRangeDropdown: React.FC<Props> = (props) => {
classNames={{ root: `p-3 rounded-md` }}
selected={dateRange}
onSelect={(val) => {
onSelect?.(val);
onSelect(val);
setDateRange({
from: val?.from ?? undefined,
to: val?.to ?? undefined,
});
}}
mode="range"
disabled={disabledDays}
@@ -6,6 +6,7 @@ import { useParams } from "next/navigation";
import { Controller, useForm } from "react-hook-form";
import {
ArchiveRestoreIcon,
CalendarCheck2,
CalendarClock,
ChevronDown,
ChevronRight,
@@ -42,7 +43,7 @@ import {
TextArea,
} from "@plane/ui";
// components
import { DateRangeDropdown, MemberDropdown } from "@/components/dropdowns";
import { DateDropdown, MemberDropdown } from "@/components/dropdowns";
import {
ArchiveModuleModal,
DeleteModuleModal,
@@ -104,7 +105,7 @@ export const ModuleAnalyticsSidebar: React.FC<Props> = observer((props) => {
const estimateType = areEstimateEnabled && currentActiveEstimateId && estimateById(currentActiveEstimateId);
const isEstimatePointValid = estimateType && estimateType?.type == EEstimateSystem.POINTS ? true : false;
const { reset, control } = useForm({
const { reset, control, getValues } = useForm({
defaultValues,
});
@@ -194,11 +195,8 @@ export const ModuleAnalyticsSidebar: React.FC<Props> = observer((props) => {
});
};
const handleDateChange = async (startDate: Date | undefined, targetDate: Date | undefined) => {
submitChanges({
start_date: startDate ? renderFormattedPayloadDate(startDate) : null,
target_date: targetDate ? renderFormattedPayloadDate(targetDate) : null,
});
const handleDateChange = async (data: Partial<IModule>) => {
submitChanges(data);
setToast({
type: TOAST_TYPE.SUCCESS,
title: "Success!",
@@ -415,40 +413,59 @@ export const ModuleAnalyticsSidebar: React.FC<Props> = observer((props) => {
<div className="flex items-center justify-start gap-1">
<div className="flex w-2/5 items-center justify-start gap-2 text-custom-text-300">
<CalendarClock className="h-4 w-4" />
<span className="text-base">{t("date_range")}</span>
<span className="text-base">Start date</span>
</div>
<div className="h-7">
<div className="flex flex-wrap items-center gap-2">
<Controller
control={control}
name="start_date"
render={({ field: { value: startDateValue, onChange: onChangeStartDate } }) => (
<Controller
control={control}
name="target_date"
render={({ field: { value: endDateValue, onChange: onChangeEndDate } }) => {
const startDate = getDate(startDateValue);
const endDate = getDate(endDateValue);
return (
<DateRangeDropdown
buttonContainerClassName="w-full"
buttonVariant="background-with-text"
value={{
from: startDate,
to: endDate,
}}
onSelect={(val) => {
onChangeStartDate(val?.from ? renderFormattedPayloadDate(val.from) : null);
onChangeEndDate(val?.to ? renderFormattedPayloadDate(val.to) : null);
handleDateChange(val?.from, val?.to);
}}
placeholder={{
from: t("start_date"),
to: t("end_date"),
}}
disabled={!isEditingAllowed || isArchived}
/>
);
control={control}
rules={{ required: "Please select a date" }}
render={({ field: { value, onChange } }) => (
<DateDropdown
value={value ?? null}
onChange={(val) => {
console.log(val);
onChange(renderFormattedPayloadDate(val));
handleDateChange({ start_date: val ? renderFormattedPayloadDate(val) : null });
}}
placeholder={t("common.order_by.start_date")}
icon={<CalendarClock className="h-3 w-3 flex-shrink-0" />}
buttonVariant={value ? "border-with-text" : "border-without-text"}
buttonContainerClassName={`h-6 w-full flex ${!isEditingAllowed || isArchived ? "cursor-not-allowed" : "cursor-pointer"} items-center gap-1.5 text-custom-text-300 rounded text-xs`}
optionsClassName="z-30"
disabled={!isEditingAllowed || isArchived}
showTooltip
maxDate={getDate(getValues("target_date"))}
/>
)}
/>
</div>
</div>
<div className="flex items-center justify-start gap-1">
<div className="flex w-2/5 items-center justify-start gap-2 text-custom-text-300">
<CalendarClock className="h-4 w-4" />
<span className="text-base">Due date</span>
</div>
<div className="flex flex-wrap items-center gap-2">
<Controller
name="target_date"
control={control}
rules={{ required: "Please select a date" }}
render={({ field: { value, onChange } }) => (
<DateDropdown
value={getDate(value) ?? null}
onChange={(val) => {
onChange(renderFormattedPayloadDate(val));
handleDateChange({ target_date: val ? renderFormattedPayloadDate(val) : null });
}}
placeholder={t("common.order_by.due_date")}
icon={<CalendarCheck2 className="h-3 w-3 flex-shrink-0" />}
buttonVariant={value ? "border-with-text" : "border-without-text"}
buttonContainerClassName={`h-6 w-full flex ${!isEditingAllowed || isArchived ? "cursor-not-allowed" : "cursor-pointer"} items-center gap-1.5 text-custom-text-300 rounded text-xs`}
optionsClassName="z-30"
disabled={!isEditingAllowed || isArchived}
showTooltip
minDate={getDate(getValues("start_date"))}
/>
)}
/>
@@ -4,7 +4,7 @@ import React, { SyntheticEvent, useRef } from "react";
import { observer } from "mobx-react";
import Link from "next/link";
import { useParams, usePathname, useSearchParams } from "next/navigation";
import { Info, SquareUser } from "lucide-react";
import { CalendarCheck2, CalendarClock, Info, SquareUser } from "lucide-react";
// plane package imports
import {
MODULE_STATUS,
@@ -14,6 +14,7 @@ import {
EUserPermissions,
EUserPermissionsLevel,
} from "@plane/constants";
import { useTranslation } from "@plane/i18n";
import { IModule } from "@plane/types";
import {
Card,
@@ -26,7 +27,7 @@ import {
setToast,
} from "@plane/ui";
// components
import { DateRangeDropdown } from "@/components/dropdowns";
import { DateDropdown } from "@/components/dropdowns";
import { ButtonAvatars } from "@/components/dropdowns/member/avatar";
import { ModuleQuickActions } from "@/components/modules";
import { ModuleStatusDropdown } from "@/components/modules/module-status-dropdown";
@@ -58,7 +59,7 @@ export const ModuleCardItem: React.FC<Props> = observer((props) => {
const { getModuleById, addModuleToFavorites, removeModuleFromFavorites, updateModuleDetails } = useModule();
const { getUserDetails } = useMember();
const { captureEvent } = useEventTracker();
const { t } = useTranslation();
// derived values
const moduleDetails = getModuleById(moduleId);
const isEditingAllowed = allowPermissions(
@@ -66,7 +67,6 @@ export const ModuleCardItem: React.FC<Props> = observer((props) => {
EUserPermissionsLevel.PROJECT
);
const isDisabled = !isEditingAllowed || !!moduleDetails?.archived_at;
const renderIcon = Boolean(moduleDetails?.start_date) || Boolean(moduleDetails?.target_date);
const { isMobile } = usePlatformOS();
const handleAddToFavorites = (e: React.MouseEvent<HTMLButtonElement>) => {
@@ -236,27 +236,38 @@ export const ModuleCardItem: React.FC<Props> = observer((props) => {
)}
</div>
<LinearProgressIndicator size="lg" data={progressIndicatorData} />
<div className="flex items-center justify-between py-0.5" onClick={handleEventPropagation}>
<DateRangeDropdown
buttonContainerClassName={`h-6 w-full flex ${isDisabled ? "cursor-not-allowed" : "cursor-pointer"} items-center gap-1.5 text-custom-text-300 border-[0.5px] border-custom-border-300 rounded text-xs`}
buttonVariant="transparent-with-text"
className="h-7"
value={{
from: getDate(moduleDetails.start_date),
to: getDate(moduleDetails.target_date),
}}
onSelect={(val) => {
<div className="flex items-center gap-2 py-0.5" onClick={handleEventPropagation}>
<DateDropdown
value={moduleDetails.start_date}
onChange={(val) => {
handleModuleDetailsChange({
start_date: val?.from ? renderFormattedPayloadDate(val.from) : null,
target_date: val?.to ? renderFormattedPayloadDate(val.to) : null,
start_date: val ? renderFormattedPayloadDate(val) : null,
});
}}
placeholder={{
from: "Start date",
to: "End date",
}}
placeholder={t("common.order_by.start_date")}
icon={<CalendarClock className="h-3 w-3 flex-shrink-0" />}
buttonVariant={moduleDetails.start_date ? "border-with-text" : "border-without-text"}
buttonContainerClassName={`h-6 w-full flex ${isDisabled ? "cursor-not-allowed" : "cursor-pointer"} items-center gap-1.5 text-custom-text-300 rounded text-xs`}
optionsClassName="z-10"
disabled={isDisabled}
hideIcon={{ from: renderIcon ?? true, to: renderIcon }}
showTooltip
maxDate={getDate(moduleDetails.target_date)}
/>
<DateDropdown
value={moduleDetails.target_date}
onChange={(val) => {
handleModuleDetailsChange({
target_date: val ? renderFormattedPayloadDate(val) : null,
});
}}
placeholder={t("common.order_by.due_date")}
icon={<CalendarCheck2 className="h-3 w-3 flex-shrink-0" />}
buttonVariant={moduleDetails.target_date ? "border-with-text" : "border-without-text"}
buttonContainerClassName={`h-6 w-full flex ${isDisabled ? "cursor-not-allowed" : "cursor-pointer"} items-center gap-1.5 text-custom-text-300 rounded text-xs`}
optionsClassName="z-10"
disabled={isDisabled}
showTooltip
minDate={getDate(moduleDetails.start_date)}
/>
</div>
</div>
@@ -4,7 +4,7 @@ import React, { FC } from "react";
import { observer } from "mobx-react";
import { useParams } from "next/navigation";
// icons
import { SquareUser } from "lucide-react";
import { CalendarCheck2, CalendarClock, SquareUser } from "lucide-react";
// types
import {
MODULE_STATUS,
@@ -18,7 +18,7 @@ import { IModule } from "@plane/types";
// ui
import { FavoriteStar, TOAST_TYPE, Tooltip, setPromiseToast, setToast } from "@plane/ui";
// components
import { DateRangeDropdown } from "@/components/dropdowns";
import { DateDropdown } from "@/components/dropdowns";
import { ModuleQuickActions } from "@/components/modules";
import { ModuleStatusDropdown } from "@/components/modules/module-status-dropdown";
// constants
@@ -138,28 +138,38 @@ export const ModuleListItemAction: FC<Props> = observer((props) => {
return (
<>
<DateRangeDropdown
buttonContainerClassName={`h-6 w-full flex ${isDisabled ? "cursor-not-allowed" : "cursor-pointer"} items-center gap-1.5 text-custom-text-300 border-[0.5px] border-custom-border-300 rounded text-xs`}
buttonVariant="transparent-with-text"
className="h-7"
value={{
from: getDate(moduleDetails.start_date),
to: getDate(moduleDetails.target_date),
}}
onSelect={(val) => {
<DateDropdown
value={moduleDetails.start_date}
onChange={(val) => {
handleModuleDetailsChange({
start_date: val?.from ? renderFormattedPayloadDate(val.from) : null,
target_date: val?.to ? renderFormattedPayloadDate(val.to) : null,
start_date: val ? renderFormattedPayloadDate(val) : null,
});
}}
placeholder={{
from: t("start_date"),
to: t("end_date"),
}}
placeholder={t("common.order_by.start_date")}
icon={<CalendarClock className="h-3 w-3 flex-shrink-0" />}
buttonVariant={moduleDetails.start_date ? "border-with-text" : "border-without-text"}
buttonContainerClassName={`h-6 w-full flex ${isDisabled ? "cursor-not-allowed" : "cursor-pointer"} items-center gap-1.5 text-custom-text-300 rounded text-xs`}
optionsClassName="z-10"
disabled={isDisabled}
hideIcon={{ from: renderIcon ?? true, to: renderIcon }}
showTooltip
maxDate={getDate(moduleDetails.target_date)}
/>
<DateDropdown
value={moduleDetails.target_date}
onChange={(val) => {
handleModuleDetailsChange({
target_date: val ? renderFormattedPayloadDate(val) : null,
});
}}
placeholder={t("common.order_by.due_date")}
icon={<CalendarCheck2 className="h-3 w-3 flex-shrink-0" />}
buttonVariant={moduleDetails.target_date ? "border-with-text" : "border-without-text"}
buttonContainerClassName={`h-6 w-full flex ${isDisabled ? "cursor-not-allowed" : "cursor-pointer"} items-center gap-1.5 text-custom-text-300 rounded text-xs`}
optionsClassName="z-10"
disabled={isDisabled}
showTooltip
minDate={getDate(moduleDetails.start_date)}
/>
{moduleStatus && (
<ModuleStatusDropdown
isDisabled={isDisabled}