feat: init
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled

This commit is contained in:
chuan
2025-11-11 01:56:44 +08:00
commit bba4bb40c8
4638 changed files with 447437 additions and 0 deletions

View File

@@ -0,0 +1,122 @@
"use client";
import type { FC } from "react";
import { useState } from "react";
import { observer } from "mobx-react";
import { Loader, X } from "lucide-react";
// plane imports
import { STATE_TRACKER_EVENTS, STATE_TRACKER_ELEMENTS } from "@plane/constants";
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
import { Tooltip } from "@plane/propel/tooltip";
import type { IState, TStateOperationsCallbacks } from "@plane/types";
import { AlertModalCore } from "@plane/ui";
import { cn } from "@plane/utils";
// hooks
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
import { usePlatformOS } from "@/hooks/use-platform-os";
type TStateDelete = {
totalStates: number;
state: IState;
deleteStateCallback: TStateOperationsCallbacks["deleteState"];
shouldTrackEvents: boolean;
};
export const StateDelete: FC<TStateDelete> = observer((props) => {
const { totalStates, state, deleteStateCallback, shouldTrackEvents } = props;
// hooks
const { isMobile } = usePlatformOS();
// states
const [isDeleteModal, setIsDeleteModal] = useState(false);
const [isDelete, setIsDelete] = useState(false);
// derived values
const isDeleteDisabled = state.default ? true : totalStates === 1 ? true : false;
const handleDeleteState = async () => {
if (isDeleteDisabled) return;
setIsDelete(true);
try {
await deleteStateCallback(state.id);
if (shouldTrackEvents) {
captureSuccess({
eventName: STATE_TRACKER_EVENTS.delete,
payload: {
id: state.id,
},
});
}
setIsDelete(false);
} catch (error) {
const errorStatus = error as unknown as { status: number; data: { error: string } };
if (shouldTrackEvents) {
captureError({
eventName: STATE_TRACKER_EVENTS.delete,
payload: {
id: state.id,
},
});
}
if (errorStatus.status === 400) {
setToast({
type: TOAST_TYPE.ERROR,
title: "Error!",
message:
"This state contains some work items within it, please move them to some other state to delete this state.",
});
} else {
setToast({
type: TOAST_TYPE.ERROR,
title: "Error!",
message: "State could not be deleted. Please try again.",
});
}
setIsDelete(false);
}
};
return (
<>
<AlertModalCore
handleClose={() => setIsDeleteModal(false)}
handleSubmit={handleDeleteState}
isSubmitting={isDelete}
isOpen={isDeleteModal}
title="Delete State"
content={
<>
Are you sure you want to delete state-{" "}
<span className="font-medium text-custom-text-100">{state?.name}</span>? All of the data related to the
state will be permanently removed. This action cannot be undone.
</>
}
/>
<button
type="button"
className={cn(
"flex-shrink-0 w-5 h-5 rounded flex justify-center items-center overflow-hidden transition-colors cursor-pointer focus:outline-none",
isDeleteDisabled
? "bg-custom-background-90 text-custom-text-200"
: "text-red-500 hover:bg-custom-background-80"
)}
disabled={isDeleteDisabled}
onClick={() => setIsDeleteModal(true)}
data-ph-element={STATE_TRACKER_ELEMENTS.STATE_LIST_DELETE_BUTTON}
>
<Tooltip
tooltipContent={
state.default ? "Cannot delete the default state." : totalStates === 1 ? `Cannot have an empty group.` : ``
}
isMobile={isMobile}
disabled={!isDeleteDisabled}
className="focus:outline-none"
>
{isDelete ? <Loader className="w-3.5 h-3.5 text-custom-text-200" /> : <X className="w-3.5 h-3.5" />}
</Tooltip>
</button>
</>
);
});

View File

@@ -0,0 +1,2 @@
export * from "./mark-as-default";
export * from "./delete";

View File

@@ -0,0 +1,46 @@
"use client";
import type { FC } from "react";
import { useState } from "react";
import { observer } from "mobx-react";
// plane imports
import type { TStateOperationsCallbacks } from "@plane/types";
import { cn } from "@plane/utils";
type TStateMarksAsDefault = {
stateId: string;
isDefault: boolean;
markStateAsDefaultCallback: TStateOperationsCallbacks["markStateAsDefault"];
};
export const StateMarksAsDefault: FC<TStateMarksAsDefault> = observer((props) => {
const { stateId, isDefault, markStateAsDefaultCallback } = props;
// states
const [isLoading, setIsLoading] = useState(false);
const handleMarkAsDefault = async () => {
if (!stateId || isDefault) return;
setIsLoading(true);
try {
setIsLoading(false);
await markStateAsDefaultCallback(stateId);
setIsLoading(false);
} catch {
setIsLoading(false);
}
};
return (
<button
className={cn(
"text-xs whitespace-nowrap transition-colors",
isDefault ? "text-custom-text-300" : "text-custom-text-200 hover:text-custom-text-100"
)}
disabled={isDefault || isLoading}
onClick={handleMarkAsDefault}
>
{isLoading ? "Marking as default" : isDefault ? `Default` : `Mark as default`}
</button>
);
});