feature / Video Extraction UI v2 (#68)
* refactor of existing features should work perfect * redo undo of adding points works * multi session fix * undo redo implemented correctly, include exclusion button * exclusion point functional * point stack object * clear extraction data from video node as well
This commit is contained in:
16 files changed
+1056
-537
No files matched your search
@@ -33,7 +33,7 @@ import { ToolbarNodeButtonNames } from "~/components/features/ToolbarNode/enums"
|
||||
import { NavigateFunction } from "react-router-dom";
|
||||
import { LoadingVideosProvider } from "./EngineUtitlities/LoadingVideosProvider";
|
||||
import { MediaFile } from "~/Classes/ApiManager/models/MediaFile";
|
||||
import { VideoExtractionHandler } from "./EngineUtitlities/VideoExtractionHandler";
|
||||
import { VideoExtractionHandler } from "./EngineUtitlities/VideoExtractionHandler/VideoExtractionHandler";
|
||||
|
||||
// for testing loading files from system
|
||||
// import { FileUtilities } from "./FileUtilities/FileUtilities";
|
||||
@@ -460,9 +460,7 @@ export class Engine {
|
||||
});
|
||||
// Listen to other toolbars
|
||||
// VideoExtraction Toolbar
|
||||
uiEvents.toolbarVideoExtraction.DONE.onClick(() => {
|
||||
this.videoExtractionHandler.endVideoExtraction();
|
||||
});
|
||||
this.videoExtractionHandler.listenToToolbarEvents();
|
||||
|
||||
// Listen to other requests coming from the UI
|
||||
uiEvents.onGetStagedImage((image) => {
|
||||
|
||||
@@ -1,166 +0,0 @@
|
||||
import { uiAccess } from "~/signals";
|
||||
import { VideoNode } from "../Nodes";
|
||||
import {
|
||||
NodeIsolator,
|
||||
SelectionManager,
|
||||
SelectorSquare,
|
||||
} from "../NodesManagers";
|
||||
import { RGBColor } from "../types";
|
||||
import { UndoStackManager } from "../UndoRedo";
|
||||
import { CommandManager } from "./CommandManager";
|
||||
import {
|
||||
VideoExtractionEventDetails,
|
||||
VideoExtractionEvents,
|
||||
} from "../types/events";
|
||||
|
||||
export class VideoExtractionHandler {
|
||||
private node?: VideoNode;
|
||||
private prevIsChroma?: boolean;
|
||||
private prevChromaColor?: RGBColor;
|
||||
// engine subclass references
|
||||
private commandManagerRef: CommandManager;
|
||||
private nodeIsolatorRef: NodeIsolator;
|
||||
private selectionManagerRef: SelectionManager;
|
||||
private selectorSquareRef: SelectorSquare;
|
||||
private undoStackManagerRef: UndoStackManager;
|
||||
|
||||
constructor({
|
||||
commandManagerRef,
|
||||
nodeIsolatorRef,
|
||||
selectionManagerRef,
|
||||
selectorSquareRef,
|
||||
undoStackManagerRef,
|
||||
}: {
|
||||
commandManagerRef: CommandManager;
|
||||
nodeIsolatorRef: NodeIsolator;
|
||||
selectionManagerRef: SelectionManager;
|
||||
selectorSquareRef: SelectorSquare;
|
||||
undoStackManagerRef: UndoStackManager;
|
||||
}) {
|
||||
this.commandManagerRef = commandManagerRef;
|
||||
this.nodeIsolatorRef = nodeIsolatorRef;
|
||||
this.selectionManagerRef = selectionManagerRef;
|
||||
this.selectorSquareRef = selectorSquareRef;
|
||||
this.undoStackManagerRef = undoStackManagerRef;
|
||||
}
|
||||
|
||||
private updateLoadingBar({
|
||||
detail,
|
||||
}: CustomEvent<VideoExtractionEventDetails>) {
|
||||
const { progress, status, message } = detail;
|
||||
const disabled = progress !== 100;
|
||||
const shouldShow = status !== VideoExtractionEvents.SESSION_CLOSED;
|
||||
uiAccess.toolbarVideoExtraction.update({
|
||||
isShowing: shouldShow,
|
||||
disabled: disabled,
|
||||
loadingBarState: {
|
||||
progress: progress,
|
||||
status: status,
|
||||
message: message,
|
||||
},
|
||||
});
|
||||
}
|
||||
public async startVideoExtraction(node: VideoNode) {
|
||||
console.log("VideoExtraction on node", node);
|
||||
if (this.node || this.prevIsChroma || this.prevChromaColor) {
|
||||
if (import.meta.env.DEV) {
|
||||
console.error("Video Extraction: Handler already has node");
|
||||
}
|
||||
return;
|
||||
}
|
||||
this.node = node;
|
||||
this.prevIsChroma = node.isChroma;
|
||||
this.prevChromaColor = node.chromaColor;
|
||||
this.node.progressEvent.addEventListener(
|
||||
"videoextraction",
|
||||
this.updateLoadingBar as EventListener,
|
||||
);
|
||||
// when the button is pressed to enter extraction mode
|
||||
console.log("ENGEINE prepare Extraction Session.", node);
|
||||
// disable most of the UI before we get a session
|
||||
document.body.style.cursor = "wait";
|
||||
this.selectionManagerRef.disable();
|
||||
this.selectorSquareRef.disable();
|
||||
node.lock();
|
||||
this.undoStackManagerRef.setDisabled(true);
|
||||
// if the video has chroma, disable it
|
||||
if (this.prevIsChroma) {
|
||||
node.setChroma(false);
|
||||
}
|
||||
// if the video is already using extraction
|
||||
// bring the original video back
|
||||
if (node.extractionUrl === node.videoComponent.src) {
|
||||
await node.loadVideoFromUrl({
|
||||
videoUrl: node.mediaFileUrl,
|
||||
hasExistingTransform: true,
|
||||
});
|
||||
}
|
||||
// actually start and wait for session
|
||||
await node.startSegmentation();
|
||||
this.nodeIsolatorRef.enterIsolation(node);
|
||||
node.videoSegmentationMode(true);
|
||||
this.selectionManagerRef.updateContextComponents();
|
||||
uiAccess.toolbarVideoExtraction.update({
|
||||
isShowing: true,
|
||||
disabled: false,
|
||||
loadingBarState: {
|
||||
progress: 0,
|
||||
status: VideoExtractionEvents.SESSION_IDLE,
|
||||
message: "Select Points for Extraction",
|
||||
},
|
||||
});
|
||||
document.body.style.cursor = "default";
|
||||
}
|
||||
|
||||
public async endVideoExtraction() {
|
||||
// when the button is pressed to exit extraction mode
|
||||
console.log("ENGINE Attemping to close Extraction Session.");
|
||||
document.body.style.cursor = "wait";
|
||||
if (
|
||||
!this.node ||
|
||||
this.prevIsChroma === undefined ||
|
||||
!this.prevChromaColor
|
||||
) {
|
||||
if (import.meta.env.DEV) {
|
||||
console.error("Video Extraction: node or chroma info unavailable");
|
||||
}
|
||||
return;
|
||||
}
|
||||
uiAccess.toolbarVideoExtraction.disable();
|
||||
const endSessionResult = await this.node.endSession();
|
||||
if (typeof endSessionResult === "string") {
|
||||
this.node.videoSegmentationMode(false);
|
||||
this.node.progressEvent.removeEventListener(
|
||||
"videoextraction",
|
||||
this.updateLoadingBar as EventListener,
|
||||
);
|
||||
this.commandManagerRef.useVideoExtraction({
|
||||
videoNode: this.node,
|
||||
extractionUrl: endSessionResult,
|
||||
prevIsChroma: this.prevIsChroma,
|
||||
prevChromaColor: this.prevChromaColor,
|
||||
});
|
||||
this.nodeIsolatorRef.exitIsolation();
|
||||
|
||||
// unlock the ui
|
||||
this.undoStackManagerRef.setDisabled(false);
|
||||
|
||||
this.selectorSquareRef.enable();
|
||||
this.node.unlock();
|
||||
this.selectionManagerRef.updateContextComponents();
|
||||
this.selectionManagerRef.enable();
|
||||
uiAccess.toolbarVideoExtraction.update({
|
||||
isShowing: false,
|
||||
disabled: false,
|
||||
});
|
||||
this.node = undefined;
|
||||
this.prevIsChroma = undefined;
|
||||
this.prevChromaColor = undefined;
|
||||
// to close off the session.
|
||||
} else {
|
||||
uiAccess.toolbarVideoExtraction.enable();
|
||||
console.log("Busy Processing Video.");
|
||||
}
|
||||
document.body.style.cursor = "default";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
import { Coordinates } from "~/Classes/ApiManager/SegmentationApi";
|
||||
import { ICommand } from "~/KonvaApp/UndoRedo/ICommand";
|
||||
import { uiAccess } from "~/signals";
|
||||
import { VideoExtractionEvents } from "~/KonvaApp/types/events";
|
||||
import { NodeUtilities } from "~/KonvaApp/Nodes/NodeUtilities";
|
||||
import { VideoNode } from "~/KonvaApp/Nodes";
|
||||
import { SegmentationApi } from "~/Classes/ApiManager/SegmentationApi";
|
||||
import { PointsStack } from "./PointsStack";
|
||||
|
||||
export class AddPointsCommand implements ICommand {
|
||||
private prevPreviewUrl: string | undefined;
|
||||
private selectedPointsRef: PointsStack;
|
||||
private nodeRef: VideoNode;
|
||||
private newPoint: Coordinates;
|
||||
private newPreviewUrl: string | undefined;
|
||||
private api: SegmentationApi;
|
||||
private sessionId: string;
|
||||
|
||||
constructor({
|
||||
selectedPointsRef,
|
||||
nodeRef,
|
||||
newPoint,
|
||||
api,
|
||||
sessionId,
|
||||
}: {
|
||||
selectedPointsRef: PointsStack;
|
||||
nodeRef: VideoNode;
|
||||
newPoint: Coordinates;
|
||||
api: SegmentationApi;
|
||||
sessionId: string;
|
||||
}) {
|
||||
this.selectedPointsRef = selectedPointsRef;
|
||||
this.newPoint = newPoint;
|
||||
this.nodeRef = nodeRef;
|
||||
this.prevPreviewUrl = this.nodeRef.extractionPreviewUrl;
|
||||
this.api = api;
|
||||
this.sessionId = sessionId;
|
||||
}
|
||||
async execute() {
|
||||
this.selectedPointsRef.addPoint(this.newPoint);
|
||||
|
||||
if (this.newPreviewUrl) {
|
||||
// case of redo, no need to do the server calls
|
||||
await this.nodeRef.setVideoExtractionPreview(this.newPreviewUrl);
|
||||
return true;
|
||||
}
|
||||
|
||||
// request for a new point.
|
||||
uiAccess.toolbarVideoExtraction.update({
|
||||
loadingBarState: {
|
||||
progress: 25,
|
||||
status: VideoExtractionEvents.EXTRACTION_POINT_REQUEST,
|
||||
message: "Start Processing Extraction...",
|
||||
},
|
||||
});
|
||||
|
||||
try {
|
||||
console.log("Requesting");
|
||||
const response = await this.api.addPointsToSession(
|
||||
this.sessionId,
|
||||
24,
|
||||
[
|
||||
{
|
||||
timestamp: 0,
|
||||
objects: [
|
||||
{
|
||||
style: {
|
||||
color: [0, 0, 1],
|
||||
},
|
||||
object_id: 0,
|
||||
points: this.selectedPointsRef.get(),
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
false,
|
||||
);
|
||||
uiAccess.toolbarVideoExtraction.update({
|
||||
loadingBarState: {
|
||||
progress: 50,
|
||||
status: VideoExtractionEvents.EXTRACTION_POINT_REQUEST,
|
||||
message: "Start Processing Extraction...",
|
||||
},
|
||||
});
|
||||
const previewImageUrl = response.frames[0].preview_image_url;
|
||||
|
||||
// TODO: we assumed success of the loading of the AssetUrl
|
||||
await NodeUtilities.isAssetUrlAvailable({ url: previewImageUrl });
|
||||
uiAccess.toolbarVideoExtraction.update({
|
||||
loadingBarState: {
|
||||
progress: 75,
|
||||
status: VideoExtractionEvents.EXTRACTION_POINT_REQUEST,
|
||||
message: "Processing Extraction Points...",
|
||||
},
|
||||
});
|
||||
this.newPreviewUrl = previewImageUrl;
|
||||
await this.nodeRef.setVideoExtractionPreview(previewImageUrl);
|
||||
uiAccess.toolbarVideoExtraction.update({
|
||||
loadingBarState: {
|
||||
progress: 100,
|
||||
status: VideoExtractionEvents.EXTRACTION_POINT_REQUEST,
|
||||
message: "Extraction of Region Done",
|
||||
},
|
||||
});
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
("Extraction of Region Done");
|
||||
uiAccess.toolbarVideoExtraction.update({
|
||||
loadingBarState: {
|
||||
progress: 0,
|
||||
status: VideoExtractionEvents.EXTRACTION_POINT_REQUEST,
|
||||
message: `Error:${error} Please try picking extraction points again`,
|
||||
},
|
||||
});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
async undo() {
|
||||
this.selectedPointsRef.pop();
|
||||
|
||||
if (this.prevPreviewUrl) {
|
||||
await this.nodeRef.setVideoExtractionPreview(this.prevPreviewUrl);
|
||||
} else {
|
||||
await this.nodeRef.loadVideoFromUrl({
|
||||
videoUrl: this.nodeRef.mediaFileUrl,
|
||||
hasExistingTransform: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import { Coordinates } from "~/Classes/ApiManager/SegmentationApi";
|
||||
import { uiAccess } from "~/signals";
|
||||
export class PointsStack {
|
||||
private points: Coordinates[];
|
||||
constructor() {
|
||||
this.points = [];
|
||||
}
|
||||
public get() {
|
||||
return this.points;
|
||||
}
|
||||
public addPoint(point: Coordinates) {
|
||||
this.points.push(point);
|
||||
uiAccess.toolbarVideoExtraction.setReady(true);
|
||||
}
|
||||
public pop() {
|
||||
this.points.pop();
|
||||
if (this.points.length === 0) {
|
||||
uiAccess.toolbarVideoExtraction.setReady(false);
|
||||
}
|
||||
}
|
||||
public removePoint(point: Coordinates) {
|
||||
this.points = this.points.filter(
|
||||
(curr) =>
|
||||
curr.coordinates[0] !== point.coordinates[0] &&
|
||||
curr.coordinates[1] != point.coordinates[1],
|
||||
);
|
||||
if (this.points.length === 0) {
|
||||
uiAccess.toolbarVideoExtraction.setReady(false);
|
||||
}
|
||||
}
|
||||
public clear() {
|
||||
this.points = [];
|
||||
uiAccess.toolbarVideoExtraction.setReady(false);
|
||||
}
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
import { UndoStackManager } from "~/KonvaApp/UndoRedo";
|
||||
import { VideoNode } from "~/KonvaApp/Nodes";
|
||||
|
||||
import {
|
||||
SegmentationApi,
|
||||
Coordinates,
|
||||
} from "~/Classes/ApiManager/SegmentationApi";
|
||||
|
||||
import { AddPointsCommand } from "./AddPointsCommand";
|
||||
import { PointsStack } from "./PointsStack";
|
||||
|
||||
export class VideoExtractionCommandsManager {
|
||||
private undoStack: UndoStackManager;
|
||||
private selectedPointsRef: PointsStack;
|
||||
private api: SegmentationApi;
|
||||
private nodeRef: VideoNode;
|
||||
private sessionId: string;
|
||||
|
||||
constructor({
|
||||
selectedPointsRef,
|
||||
api,
|
||||
nodeRef,
|
||||
sessionId,
|
||||
}: {
|
||||
selectedPointsRef: PointsStack;
|
||||
api: SegmentationApi;
|
||||
nodeRef: VideoNode;
|
||||
sessionId: string;
|
||||
}) {
|
||||
this.selectedPointsRef = selectedPointsRef;
|
||||
this.undoStack = new UndoStackManager();
|
||||
this.api = api;
|
||||
this.nodeRef = nodeRef;
|
||||
this.sessionId = sessionId;
|
||||
}
|
||||
public async addPoint(newPoint: Coordinates) {
|
||||
const command = new AddPointsCommand({
|
||||
selectedPointsRef: this.selectedPointsRef,
|
||||
nodeRef: this.nodeRef,
|
||||
newPoint: newPoint,
|
||||
api: this.api,
|
||||
sessionId: this.sessionId,
|
||||
});
|
||||
await this.undoStack.executeCommand(command);
|
||||
}
|
||||
// private removeInclusionPoint() {}
|
||||
public clear() {
|
||||
this.undoStack.clear();
|
||||
}
|
||||
public undo() {
|
||||
console.log("ve should undo");
|
||||
this.undoStack.undo();
|
||||
}
|
||||
public redo() {
|
||||
console.log("ve should redo");
|
||||
this.undoStack.redo();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,430 @@
|
||||
import { uiAccess, uiEvents } from "~/signals";
|
||||
import { VideoNode } from "../../Nodes";
|
||||
import {
|
||||
NodeIsolator,
|
||||
SelectionManager,
|
||||
SelectorSquare,
|
||||
} from "../../NodesManagers";
|
||||
import { RGBColor } from "../../types";
|
||||
import { UndoStackManager } from "../../UndoRedo";
|
||||
import { CommandManager } from "../CommandManager";
|
||||
import {
|
||||
VideoExtractionEventDetails,
|
||||
VideoExtractionEvents,
|
||||
} from "../../types/events";
|
||||
import { NodeUtilities } from "../../Nodes/NodeUtilities";
|
||||
import { SegmentationApi } from "~/Classes/ApiManager/SegmentationApi";
|
||||
import { VideoExtractionCommandsManager } from "./VideoExtractionCommandsManager";
|
||||
import { VideoExtractionMode } from "./type";
|
||||
import { PointsStack } from "./PointsStack";
|
||||
|
||||
export class VideoExtractionHandler {
|
||||
private videoExtractionAPI = new SegmentationApi();
|
||||
private videoExtractionSession: { session_id: string } | undefined =
|
||||
undefined;
|
||||
private isProcessing: boolean = false;
|
||||
private selectedPoints: PointsStack;
|
||||
private mode: VideoExtractionMode;
|
||||
private videoExtractionCommandsManager?: VideoExtractionCommandsManager;
|
||||
|
||||
//node references
|
||||
private node?: VideoNode;
|
||||
private prevIsChroma?: boolean;
|
||||
private prevChromaColor?: RGBColor;
|
||||
|
||||
// engine subclass references
|
||||
private commandManagerRef: CommandManager;
|
||||
private nodeIsolatorRef: NodeIsolator;
|
||||
private selectionManagerRef: SelectionManager;
|
||||
private selectorSquareRef: SelectorSquare;
|
||||
private undoStackManagerRef: UndoStackManager;
|
||||
|
||||
constructor({
|
||||
commandManagerRef,
|
||||
nodeIsolatorRef,
|
||||
selectionManagerRef,
|
||||
selectorSquareRef,
|
||||
undoStackManagerRef,
|
||||
}: {
|
||||
commandManagerRef: CommandManager;
|
||||
nodeIsolatorRef: NodeIsolator;
|
||||
selectionManagerRef: SelectionManager;
|
||||
selectorSquareRef: SelectorSquare;
|
||||
undoStackManagerRef: UndoStackManager;
|
||||
}) {
|
||||
this.commandManagerRef = commandManagerRef;
|
||||
this.nodeIsolatorRef = nodeIsolatorRef;
|
||||
this.selectionManagerRef = selectionManagerRef;
|
||||
this.selectorSquareRef = selectorSquareRef;
|
||||
this.undoStackManagerRef = undoStackManagerRef;
|
||||
this.mode = VideoExtractionMode.INCLUSION;
|
||||
this.selectedPoints = new PointsStack();
|
||||
uiAccess.toolbarVideoExtraction;
|
||||
}
|
||||
private setMode(mode: VideoExtractionMode) {
|
||||
this.mode = mode;
|
||||
uiAccess.toolbarVideoExtraction.setMode(mode);
|
||||
}
|
||||
private updateLoadingBar({
|
||||
detail,
|
||||
}: CustomEvent<VideoExtractionEventDetails>) {
|
||||
const { progress, status, message } = detail;
|
||||
const disabled = progress !== 100;
|
||||
const shouldShow = status !== VideoExtractionEvents.SESSION_CLOSED;
|
||||
uiAccess.toolbarVideoExtraction.update({
|
||||
isShowing: shouldShow,
|
||||
disabled: disabled,
|
||||
loadingBarState: {
|
||||
progress: progress,
|
||||
status: status,
|
||||
message: message,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
public async startVideoExtraction(node: VideoNode) {
|
||||
console.log("VideoExtraction on node", node);
|
||||
if (this.node || this.prevIsChroma || this.prevChromaColor) {
|
||||
if (import.meta.env.DEV) {
|
||||
console.error("Video Extraction: Handler already has node");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (this.videoExtractionSession) {
|
||||
if (import.meta.env.DEV) {
|
||||
console.error("Video Extraction: Session already exists");
|
||||
}
|
||||
return;
|
||||
}
|
||||
this.node = node;
|
||||
this.prevIsChroma = node.isChroma;
|
||||
this.prevChromaColor = node.chromaColor;
|
||||
this.node.progressEvent.addEventListener(
|
||||
"videoextraction",
|
||||
this.updateLoadingBar as EventListener,
|
||||
);
|
||||
// when the button is pressed to enter extraction mode
|
||||
console.log("ENGEINE prepare Extraction Session.", node);
|
||||
// disable most of the UI before we get a session
|
||||
document.body.style.cursor = "wait";
|
||||
this.selectionManagerRef.disable();
|
||||
this.selectorSquareRef.disable();
|
||||
node.lock();
|
||||
this.undoStackManagerRef.setDisabled(true);
|
||||
// if the video has chroma, disable it
|
||||
if (this.prevIsChroma) {
|
||||
node.setChroma(false);
|
||||
}
|
||||
// if the video is already using extraction
|
||||
// bring the original video back
|
||||
if (node.extractionUrl === node.videoComponent.src) {
|
||||
await node.loadVideoFromUrl({
|
||||
videoUrl: node.mediaFileUrl,
|
||||
hasExistingTransform: true,
|
||||
});
|
||||
}
|
||||
node.videoComponent.pause();
|
||||
node.videoComponent.currentTime = 0;
|
||||
|
||||
// actually start and wait for session
|
||||
// await node.startSegmentation();
|
||||
|
||||
uiAccess.toolbarVideoExtraction.update({
|
||||
isShowing: true,
|
||||
disabled: true,
|
||||
loadingBarState: {
|
||||
progress: 25,
|
||||
status: VideoExtractionEvents.SESSION_CREATING,
|
||||
message: "Loading Video Extractor...",
|
||||
},
|
||||
});
|
||||
const blob = await NodeUtilities.urlToBlob(node.mediaFileUrl);
|
||||
uiAccess.toolbarVideoExtraction.update({
|
||||
loadingBarState: {
|
||||
progress: 75,
|
||||
status: VideoExtractionEvents.SESSION_CREATING,
|
||||
message: "Loading Video Extractor...",
|
||||
},
|
||||
});
|
||||
this.videoExtractionSession =
|
||||
await this.videoExtractionAPI.createSession(blob);
|
||||
uiAccess.toolbarVideoExtraction.update({
|
||||
loadingBarState: {
|
||||
progress: 100,
|
||||
status: VideoExtractionEvents.SESSION_CREATING,
|
||||
message: "Loading Video Extractor...",
|
||||
},
|
||||
});
|
||||
|
||||
this.nodeIsolatorRef.enterIsolation(node);
|
||||
node.enableExtractionMode(this.handleExtraction.bind(this));
|
||||
this.selectionManagerRef.updateContextComponents();
|
||||
uiAccess.toolbarVideoExtraction.update({
|
||||
disabled: false,
|
||||
loadingBarState: {
|
||||
progress: 0,
|
||||
status: VideoExtractionEvents.SESSION_IDLE,
|
||||
message: "Select Points for Extraction",
|
||||
},
|
||||
});
|
||||
this.videoExtractionCommandsManager = new VideoExtractionCommandsManager({
|
||||
selectedPointsRef: this.selectedPoints,
|
||||
api: this.videoExtractionAPI,
|
||||
nodeRef: this.node,
|
||||
sessionId: this.videoExtractionSession.session_id,
|
||||
});
|
||||
document.body.style.cursor = "default";
|
||||
}
|
||||
|
||||
public async endVideoExtraction() {
|
||||
// when the button is pressed to exit extraction mode
|
||||
console.log("ENGINE Attemping to close Extraction Session.");
|
||||
document.body.style.cursor = "wait";
|
||||
if (
|
||||
!this.node ||
|
||||
this.prevIsChroma === undefined ||
|
||||
!this.prevChromaColor
|
||||
) {
|
||||
if (import.meta.env.DEV) {
|
||||
console.error("Video Extraction: node or chroma info unavailable");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (this.isProcessing) {
|
||||
console.warn(
|
||||
"Video Extraction: Cannot close while still processing frame, please wait",
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
this.isProcessing = true;
|
||||
uiAccess.toolbarVideoExtraction.update({
|
||||
disabled: true,
|
||||
loadingBarState: {
|
||||
progress: 100,
|
||||
status: VideoExtractionEvents.SESSION_CLOSING,
|
||||
message: "Processing Video...",
|
||||
},
|
||||
});
|
||||
|
||||
const endSessionResult = await this.endSession();
|
||||
|
||||
if (typeof endSessionResult === "string") {
|
||||
this.commandManagerRef.useVideoExtraction({
|
||||
videoNode: this.node,
|
||||
extractionUrl: endSessionResult,
|
||||
prevIsChroma: this.prevIsChroma,
|
||||
prevChromaColor: this.prevChromaColor,
|
||||
});
|
||||
this.unsetUi();
|
||||
} else {
|
||||
uiAccess.toolbarVideoExtraction.enable();
|
||||
console.log("Busy Processing Video.");
|
||||
}
|
||||
document.body.style.cursor = "default";
|
||||
}
|
||||
|
||||
private async endSession(): Promise<boolean | string> {
|
||||
if (!this.videoExtractionSession || !this.node) {
|
||||
if (import.meta.env.DEV) {
|
||||
console.error("Video Extraction: Session does not exist");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
console.log("Requesting a close");
|
||||
const response = await this.videoExtractionAPI.addPointsToSession(
|
||||
this.videoExtractionSession.session_id,
|
||||
24,
|
||||
[
|
||||
{
|
||||
timestamp: 0,
|
||||
objects: [
|
||||
{
|
||||
style: {
|
||||
color: [0, 0, 1],
|
||||
},
|
||||
object_id: 0,
|
||||
points: this.selectedPoints.get(),
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
true, // propagation
|
||||
// propagation = true = this requests the entire video to be processed
|
||||
);
|
||||
uiAccess.toolbarVideoExtraction.update({
|
||||
loadingBarState: {
|
||||
progress: 50,
|
||||
status: VideoExtractionEvents.SESSION_CLOSING,
|
||||
message: "Processing Video...",
|
||||
},
|
||||
});
|
||||
// replace the video component and reregister all the other elements.
|
||||
console.log(
|
||||
"Extracted Video URL",
|
||||
response["masked_video_cdn_url"],
|
||||
response,
|
||||
);
|
||||
// TODO: we assume the URL to be checked will eventually return true
|
||||
const extractionUrl = response["masked_video_cdn_url"];
|
||||
await NodeUtilities.isAssetUrlAvailable({
|
||||
url: extractionUrl,
|
||||
sleepDurationMs: 2000,
|
||||
});
|
||||
uiAccess.toolbarVideoExtraction.update({
|
||||
loadingBarState: {
|
||||
progress: 75,
|
||||
status: VideoExtractionEvents.SESSION_CLOSING,
|
||||
message: "Processing Video...",
|
||||
},
|
||||
});
|
||||
this.node.extractionUrl = extractionUrl;
|
||||
// set chroma automatically.
|
||||
this.node.isChroma = true;
|
||||
await this.node.loadVideoFromUrl({
|
||||
videoUrl: extractionUrl,
|
||||
hasExistingTransform: true,
|
||||
});
|
||||
uiAccess.toolbarVideoExtraction.update({
|
||||
loadingBarState: {
|
||||
progress: 100,
|
||||
status: VideoExtractionEvents.SESSION_CLOSING,
|
||||
message: "Done Processing Video",
|
||||
},
|
||||
});
|
||||
this.isProcessing = false;
|
||||
|
||||
return extractionUrl;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
this.isProcessing = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public async cancelVideoExtraction() {
|
||||
// when the button is pressed to exit extraction mode
|
||||
console.log("ENGINE cancel Extraction Session.");
|
||||
|
||||
if (!this.node) {
|
||||
// this case should not happen, without a node nothing could be done
|
||||
if (import.meta.env.DEV) {
|
||||
console.error("Video Extraction: node or chroma info unavailable");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (this.prevIsChroma === undefined || !this.prevChromaColor) {
|
||||
// this case should not happen, but could proceed
|
||||
if (import.meta.env.DEV) {
|
||||
console.error("Video Extraction: chroma info unavailable");
|
||||
}
|
||||
}
|
||||
|
||||
await this.node.loadVideoFromUrl({
|
||||
videoUrl: this.node.mediaFileUrl,
|
||||
hasExistingTransform: true,
|
||||
});
|
||||
this.unsetUi();
|
||||
this.isProcessing = false;
|
||||
document.body.style.cursor = "default";
|
||||
}
|
||||
private async handleExtraction() {
|
||||
console.log("Handle Extraction");
|
||||
if (!this.node) {
|
||||
console.log("Video Extraction does not have VideoNode");
|
||||
return;
|
||||
}
|
||||
if (!this.videoExtractionSession) {
|
||||
console.log("Video Extraction Session Not Ready");
|
||||
return;
|
||||
}
|
||||
if (this.isProcessing) {
|
||||
console.log("Still Processing");
|
||||
return;
|
||||
}
|
||||
|
||||
this.isProcessing = true;
|
||||
document.body.style.cursor = "wait";
|
||||
|
||||
// Get the local coordinates of the click relative to the rectangle
|
||||
const kNode = this.node.kNode;
|
||||
const localPos = kNode.getRelativePointerPosition();
|
||||
const fileSize = this.node.mediaFileSize;
|
||||
console.log("Local coordinates:mediaFileSize", localPos);
|
||||
console.log("mediaFileSize:", this.node.mediaFileSize);
|
||||
if (!localPos || !fileSize) {
|
||||
// TODO: error handling
|
||||
return;
|
||||
}
|
||||
const adjustedLocalPos = {
|
||||
x: (localPos.x / kNode.width()) * kNode.scaleX() * fileSize.width,
|
||||
y: (localPos.y / kNode.height()) * kNode.scaleY() * fileSize.height,
|
||||
};
|
||||
|
||||
if (this.videoExtractionCommandsManager) {
|
||||
await this.videoExtractionCommandsManager.addPoint({
|
||||
coordinates: [adjustedLocalPos.x, adjustedLocalPos.y],
|
||||
include: this.mode === "inclusion",
|
||||
});
|
||||
}
|
||||
|
||||
document.body.style.cursor = "default";
|
||||
this.isProcessing = false;
|
||||
}
|
||||
public undo() {
|
||||
this.videoExtractionCommandsManager?.undo();
|
||||
}
|
||||
public redo() {
|
||||
this.videoExtractionCommandsManager?.redo();
|
||||
}
|
||||
|
||||
private unsetUi() {
|
||||
// unlock the ui
|
||||
this.nodeIsolatorRef.exitIsolation();
|
||||
this.undoStackManagerRef.setDisabled(false);
|
||||
this.selectorSquareRef.enable();
|
||||
if (this.node) {
|
||||
this.node.disableExtractionMode();
|
||||
this.node.progressEvent.removeEventListener(
|
||||
"videoextraction",
|
||||
this.updateLoadingBar as EventListener,
|
||||
);
|
||||
this.node.unlock();
|
||||
}
|
||||
this.selectionManagerRef.updateContextComponents();
|
||||
this.selectionManagerRef.enable();
|
||||
uiAccess.toolbarVideoExtraction.update({
|
||||
isShowing: false,
|
||||
disabled: false,
|
||||
});
|
||||
|
||||
// reset to close off the session.
|
||||
this.videoExtractionCommandsManager?.clear();
|
||||
this.selectedPoints.clear();
|
||||
this.node = undefined;
|
||||
this.prevIsChroma = undefined;
|
||||
this.prevChromaColor = undefined;
|
||||
this.videoExtractionSession = undefined;
|
||||
}
|
||||
public listenToToolbarEvents() {
|
||||
uiEvents.toolbarVideoExtraction.INCLUSION_MODE.onClick(() => {
|
||||
this.setMode(VideoExtractionMode.INCLUSION);
|
||||
});
|
||||
uiEvents.toolbarVideoExtraction.EXCLUSION_MODE.onClick(() => {
|
||||
this.setMode(VideoExtractionMode.EXCLUSION);
|
||||
});
|
||||
uiEvents.toolbarVideoExtraction.UNDO.onClick(() => {
|
||||
this.undo();
|
||||
});
|
||||
uiEvents.toolbarVideoExtraction.REDO.onClick(() => {
|
||||
this.redo();
|
||||
});
|
||||
uiEvents.toolbarVideoExtraction.DONE.onClick(() => {
|
||||
this.endVideoExtraction();
|
||||
});
|
||||
uiEvents.toolbarVideoExtraction.CANCEL.onClick(() => {
|
||||
this.cancelVideoExtraction();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export enum VideoExtractionMode {
|
||||
INCLUSION = "inclusion",
|
||||
EXCLUSION = "exclusion",
|
||||
}
|
||||
@@ -33,7 +33,7 @@ export abstract class NetworkedNode extends BaseNode {
|
||||
protected localFile?: File;
|
||||
protected mediaFileToken?: string;
|
||||
protected mediaFileUrl?: string;
|
||||
protected mediaFileSize?: Size;
|
||||
public mediaFileSize?: Size;
|
||||
|
||||
// loading screen
|
||||
protected loadingVideosProviderRef?: LoadingVideosProvider;
|
||||
|
||||
@@ -15,13 +15,8 @@ import {
|
||||
} from "../../types";
|
||||
import { NodeUtilities } from "../NodeUtilities";
|
||||
|
||||
import {
|
||||
Coordinates,
|
||||
SegmentationApi,
|
||||
} from "~/Classes/ApiManager/SegmentationApi";
|
||||
|
||||
import { LoadingVideosProvider } from "~/KonvaApp/EngineUtitlities/LoadingVideosProvider";
|
||||
import { VideoExtractionEvents } from "~/KonvaApp/types/events";
|
||||
|
||||
interface VideoNodeContructor {
|
||||
mediaLayerRef: Konva.Layer;
|
||||
selectionManagerRef: SelectionManager;
|
||||
@@ -38,6 +33,7 @@ export class VideoNode extends NetworkedNode {
|
||||
public kNode: Konva.Image;
|
||||
public mediaFileUrl: string;
|
||||
public extractionUrl: string | undefined;
|
||||
public extractionPreviewUrl: string | undefined;
|
||||
public currentUrl: string;
|
||||
public videoComponent: HTMLVideoElement;
|
||||
protected _isVideoEventListening: boolean = false;
|
||||
@@ -58,15 +54,8 @@ export class VideoNode extends NetworkedNode {
|
||||
isChroma: boolean;
|
||||
chromaColor: RGBColor;
|
||||
|
||||
// todo move to seg manager
|
||||
selectedPointsForSegmentation: Coordinates[] = [];
|
||||
|
||||
private videoSegmentationAPI = new SegmentationApi();
|
||||
|
||||
private frameDidFinishSeeking: Promise<void>;
|
||||
|
||||
public isSegmentationMode: boolean = false;
|
||||
private segmentationSession: { session_id: string } | undefined = undefined;
|
||||
public videoExtractionClickCallback?: () => void;
|
||||
|
||||
constructor({
|
||||
mediaLayerRef,
|
||||
@@ -285,7 +274,8 @@ export class VideoNode extends NetworkedNode {
|
||||
if (this.isProcessing == true) {
|
||||
return;
|
||||
}
|
||||
if (this.isSegmentationMode) {
|
||||
if (this.videoExtractionClickCallback) {
|
||||
// if (this.isSegmentationMode) {
|
||||
// console.log("Not Playing because Segmenting");
|
||||
return;
|
||||
}
|
||||
@@ -458,246 +448,22 @@ export class VideoNode extends NetworkedNode {
|
||||
}
|
||||
}
|
||||
|
||||
public videoSegmentationMode(on: boolean) {
|
||||
if (on) {
|
||||
this.removeListenToBaseKNode();
|
||||
this.kNode.on("click", this.handleSegmentation.bind(this));
|
||||
this.isSegmentationMode = true;
|
||||
} else {
|
||||
this.isSegmentationMode = false;
|
||||
this.kNode.off("click", this.handleSegmentation.bind(this));
|
||||
this.listenToBaseKNode();
|
||||
public enableExtractionMode(callback: () => void) {
|
||||
this.removeListenToBaseKNode();
|
||||
this.kNode.on("click", callback);
|
||||
this.videoExtractionClickCallback = callback;
|
||||
}
|
||||
public disableExtractionMode() {
|
||||
if (this.videoExtractionClickCallback) {
|
||||
this.kNode.off("click", this.videoExtractionClickCallback);
|
||||
}
|
||||
this.extractionPreviewUrl = undefined;
|
||||
this.videoExtractionClickCallback = undefined;
|
||||
this.listenToBaseKNode();
|
||||
}
|
||||
|
||||
public async startSegmentation() {
|
||||
if (this.segmentationSession === undefined) {
|
||||
this.didFinishLoading = false;
|
||||
this.videoComponent.pause();
|
||||
this.videoComponent.currentTime = 0;
|
||||
this.setProgress({
|
||||
name: "videoextraction",
|
||||
progress: 25,
|
||||
status: VideoExtractionEvents.SESSION_CREATING,
|
||||
message: "Loading Video Extractor...",
|
||||
});
|
||||
|
||||
const blob = await NodeUtilities.urlToBlob(this.mediaFileUrl);
|
||||
this.setProgress({
|
||||
name: "videoextraction",
|
||||
progress: 75,
|
||||
status: VideoExtractionEvents.SESSION_CREATING,
|
||||
message: "Loading Video Extractor...",
|
||||
});
|
||||
|
||||
this.segmentationSession =
|
||||
await this.videoSegmentationAPI.createSession(blob);
|
||||
this.setProgress({
|
||||
name: "videoextraction",
|
||||
progress: 100,
|
||||
status: VideoExtractionEvents.SESSION_CREATING,
|
||||
message: "Loaded Video Extractor",
|
||||
});
|
||||
console.log("Sessions", this.segmentationSession);
|
||||
}
|
||||
}
|
||||
|
||||
private isStillProcessingSegmentationEvent: Boolean = false;
|
||||
|
||||
public async handleSegmentation() {
|
||||
if (!this.isSegmentationMode) {
|
||||
console.log("Segmentation Mode Not On");
|
||||
return;
|
||||
}
|
||||
if (!this.segmentationSession) {
|
||||
console.log("Segmentation Session Not Ready");
|
||||
return;
|
||||
}
|
||||
if (this.isStillProcessingSegmentationEvent) {
|
||||
console.log("Still Processing");
|
||||
return;
|
||||
}
|
||||
|
||||
this.isStillProcessingSegmentationEvent = true;
|
||||
|
||||
// Get the local coordinates of the click relative to the rectangle
|
||||
const localPos = this.kNode.getRelativePointerPosition();
|
||||
console.log("Local coordinates:", localPos);
|
||||
console.log("mediaFileSize:", this.mediaFileSize);
|
||||
if (!localPos || !this.mediaFileSize) {
|
||||
// TODO: error handling
|
||||
return;
|
||||
}
|
||||
document.body.style.cursor = "wait";
|
||||
|
||||
const adjustedLocalPos = {
|
||||
x:
|
||||
(localPos.x / this.kNode.width()) *
|
||||
this.kNode.scaleX() *
|
||||
this.mediaFileSize.width,
|
||||
y:
|
||||
(localPos.y / this.kNode.height()) *
|
||||
this.kNode.scaleY() *
|
||||
this.mediaFileSize.height,
|
||||
};
|
||||
// handle undo as well.
|
||||
this.selectedPointsForSegmentation.push({
|
||||
coordinates: [adjustedLocalPos.x, adjustedLocalPos.y],
|
||||
include: true,
|
||||
});
|
||||
this.setProgress({
|
||||
name: "videoextraction",
|
||||
progress: 25,
|
||||
status: VideoExtractionEvents.EXTRACTION_POINT_REQUEST,
|
||||
message: "Start Processing Extraction...",
|
||||
});
|
||||
|
||||
try {
|
||||
console.log("Requesting");
|
||||
const response = await this.videoSegmentationAPI.addPointsToSession(
|
||||
this.segmentationSession.session_id,
|
||||
24,
|
||||
[
|
||||
{
|
||||
timestamp: 0,
|
||||
objects: [
|
||||
{
|
||||
style: {
|
||||
color: [0, 0, 1],
|
||||
},
|
||||
object_id: 0,
|
||||
points: this.selectedPointsForSegmentation,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
false,
|
||||
);
|
||||
this.setProgress({
|
||||
name: "videoextraction",
|
||||
progress: 50,
|
||||
status: VideoExtractionEvents.EXTRACTION_POINT_REQUEST,
|
||||
message: "Processing Extraction Point...",
|
||||
});
|
||||
const previewImageUrl = response.frames[0].preview_image_url;
|
||||
|
||||
// TODO: we assumed success of the loading of the AssetUrl
|
||||
await NodeUtilities.isAssetUrlAvailable({ url: previewImageUrl });
|
||||
this.setProgress({
|
||||
name: "videoextraction",
|
||||
progress: 75,
|
||||
status: VideoExtractionEvents.EXTRACTION_POINT_REQUEST,
|
||||
message: "Processing Extraction Point...",
|
||||
});
|
||||
await this.setSegementationPreview(previewImageUrl);
|
||||
this.setProgress({
|
||||
name: "videoextraction",
|
||||
progress: 100,
|
||||
status: VideoExtractionEvents.EXTRACTION_POINT_REQUEST,
|
||||
message: "Extraction of Region Done",
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
this.setProgress({
|
||||
name: "videoextraction",
|
||||
progress: 0,
|
||||
status: VideoExtractionEvents.EXTRACTION_POINT_REQUEST,
|
||||
message: `Error:${error} Please try picking extraction points again`,
|
||||
});
|
||||
}
|
||||
document.body.style.cursor = "default";
|
||||
this.isStillProcessingSegmentationEvent = false;
|
||||
}
|
||||
|
||||
async endSession(): Promise<boolean | string> {
|
||||
// wait for url to come through and fake load
|
||||
// edge case
|
||||
if (this.isStillProcessingSegmentationEvent) {
|
||||
console.log("Still Processing Frame Cannot Clip Please Wait");
|
||||
return false;
|
||||
}
|
||||
// prevent requests to add points while doing this.
|
||||
this.isStillProcessingSegmentationEvent = true;
|
||||
this.setProgress({
|
||||
name: "videoextraction",
|
||||
progress: 25,
|
||||
status: VideoExtractionEvents.SESSION_CLOSING,
|
||||
message: "Processing Video...",
|
||||
});
|
||||
if (!this.segmentationSession) {
|
||||
console.log("Segmentation Session Lost?");
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
console.log("Requesting a close");
|
||||
const response = await this.videoSegmentationAPI.addPointsToSession(
|
||||
this.segmentationSession.session_id,
|
||||
24,
|
||||
[
|
||||
{
|
||||
timestamp: 0,
|
||||
objects: [
|
||||
{
|
||||
style: {
|
||||
color: [0, 0, 1],
|
||||
},
|
||||
object_id: 0,
|
||||
points: this.selectedPointsForSegmentation,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
true, // propagation = true, this requests the entire video to be processed
|
||||
);
|
||||
this.setProgress({
|
||||
name: "videoextraction",
|
||||
progress: 50,
|
||||
status: VideoExtractionEvents.SESSION_CLOSING,
|
||||
message: "Processing Video...",
|
||||
});
|
||||
// replace the video component and reregister all the other elements.
|
||||
console.log(
|
||||
"Extracted Video URL",
|
||||
response["masked_video_cdn_url"],
|
||||
response,
|
||||
);
|
||||
// TODO: we assume the URL to be checked will eventually return true
|
||||
const extractionUrl = response["masked_video_cdn_url"];
|
||||
await NodeUtilities.isAssetUrlAvailable({
|
||||
url: extractionUrl,
|
||||
sleepDurationMs: 2000,
|
||||
});
|
||||
this.setProgress({
|
||||
name: "videoextraction",
|
||||
progress: 75,
|
||||
status: VideoExtractionEvents.SESSION_CLOSING,
|
||||
message: "Processing Video...",
|
||||
});
|
||||
this.extractionUrl = extractionUrl;
|
||||
// set chroma automatically.
|
||||
this.isChroma = true;
|
||||
await this.loadVideoFromUrl({
|
||||
videoUrl: extractionUrl,
|
||||
hasExistingTransform: true,
|
||||
});
|
||||
this.setProgress({
|
||||
name: "videoextraction",
|
||||
progress: 100,
|
||||
status: VideoExtractionEvents.SESSION_CLOSING,
|
||||
message: "Done Processing Video",
|
||||
});
|
||||
this.isStillProcessingSegmentationEvent = false;
|
||||
|
||||
return extractionUrl;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
this.isStillProcessingSegmentationEvent = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private async setSegementationPreview(previewImageUrl: string) {
|
||||
public async setVideoExtractionPreview(previewImageUrl: string) {
|
||||
this.extractionPreviewUrl = previewImageUrl;
|
||||
const imageObj = new Image();
|
||||
|
||||
const imageLoadPromise = new Promise<void>((resolve, reject) => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export interface ICommand {
|
||||
execute(): void | boolean;
|
||||
execute(): void | boolean | Promise<boolean>;
|
||||
undo(): void;
|
||||
}
|
||||
@@ -12,8 +12,8 @@ export class UndoStackManager {
|
||||
isDisabled() {
|
||||
return this.disabled;
|
||||
}
|
||||
executeCommand(command: ICommand) {
|
||||
const result = command.execute();
|
||||
async executeCommand(command: ICommand) {
|
||||
const result = await command.execute();
|
||||
if (result !== undefined && result === false) {
|
||||
//command is not executed if it deliberatly returned false;
|
||||
//in that case, no need to do anything
|
||||
@@ -31,7 +31,10 @@ export class UndoStackManager {
|
||||
}
|
||||
console.log("command stack:", this.undoStack);
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.undoStack = [];
|
||||
this.redoStack = [];
|
||||
}
|
||||
undo() {
|
||||
if (this.disabled) {
|
||||
return;
|
||||
|
||||
@@ -48,6 +48,8 @@ export const SignaledToolbarVideoExtraction = () => {
|
||||
show={toolbarVideoExtraction.signal.value.isShowing}
|
||||
>
|
||||
<ToolbarVideoExtraction
|
||||
readyToSubmit={toolbarVideoExtraction.signal.value.ready}
|
||||
extractionMode={toolbarVideoExtraction.signal.value.mode}
|
||||
disabled={toolbarVideoExtraction.signal.value.disabled}
|
||||
buttonsProps={buttonProps}
|
||||
loadingBarProps={loadingBarProps}
|
||||
|
||||
@@ -1,8 +1,20 @@
|
||||
// import { useState } from "react";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
import { faScalpel } from "@fortawesome/pro-solid-svg-icons";
|
||||
import { LoadingBar, LoadingBarStatus, LoadingBarProps } from "~/components/ui";
|
||||
import {
|
||||
// ToolbarButton,
|
||||
faCircleMinus,
|
||||
faCirclePlus,
|
||||
faRotateLeft,
|
||||
faRotateRight,
|
||||
faScalpel,
|
||||
} from "@fortawesome/pro-solid-svg-icons";
|
||||
import {
|
||||
LoadingBar,
|
||||
LoadingBarStatus,
|
||||
LoadingBarProps,
|
||||
// Slider,
|
||||
} from "~/components/ui";
|
||||
import {
|
||||
ToolbarButton,
|
||||
ToolbarButtonProps,
|
||||
} from "~/components/features/ToolbarButton";
|
||||
import { paperWrapperStyles } from "~/components/styles";
|
||||
@@ -10,6 +22,8 @@ import { ToolbarVideoExtractionButtonNames } from "./enums";
|
||||
import { Button, Tooltip } from "~/components/ui";
|
||||
|
||||
export interface ToolbarVideoExtractionProps {
|
||||
extractionMode: "inclusion" | "exclusion";
|
||||
readyToSubmit: boolean;
|
||||
disabled?: boolean;
|
||||
buttonsProps: {
|
||||
[key in ToolbarVideoExtractionButtonNames]: ToolbarButtonProps;
|
||||
@@ -17,10 +31,13 @@ export interface ToolbarVideoExtractionProps {
|
||||
loadingBarProps?: Partial<LoadingBarProps>;
|
||||
}
|
||||
export const ToolbarVideoExtraction = ({
|
||||
extractionMode = "inclusion",
|
||||
readyToSubmit = false,
|
||||
disabled,
|
||||
buttonsProps,
|
||||
loadingBarProps,
|
||||
}: ToolbarVideoExtractionProps) => {
|
||||
// const [frame, setFrame] = useState(0);
|
||||
const loadingBar = {
|
||||
colReverse: true,
|
||||
progress: 0,
|
||||
@@ -33,19 +50,103 @@ export const ToolbarVideoExtraction = ({
|
||||
className={twMerge(
|
||||
paperWrapperStyles,
|
||||
disabled && "pointer-events-none cursor-default bg-ui-border shadow-md",
|
||||
"flex items-center justify-center gap-2 pr-4 transition",
|
||||
"flex flex-col items-center justify-center gap-2 pr-4 transition",
|
||||
)}
|
||||
>
|
||||
<div className="w-72 p-2">
|
||||
<div className="w-full p-2">
|
||||
<LoadingBar {...loadingBar} />
|
||||
{/* <Slider
|
||||
min={0}
|
||||
max={100}
|
||||
onChange={(val) => {
|
||||
console.log(val);
|
||||
}}
|
||||
step={1}
|
||||
value={frame}
|
||||
/> */}
|
||||
</div>
|
||||
<div className="flex w-full items-center justify-center gap-2">
|
||||
<Tooltip
|
||||
tip={
|
||||
extractionMode === "inclusion"
|
||||
? "Using Inclusion Points"
|
||||
: "Use Inclusion Points"
|
||||
}
|
||||
>
|
||||
<div>
|
||||
<ToolbarButton
|
||||
icon={faCirclePlus}
|
||||
buttonProps={{
|
||||
...buttonsProps.INCLUSION_MODE,
|
||||
active: extractionMode === "inclusion",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Tooltip>
|
||||
<Tooltip
|
||||
tip={
|
||||
extractionMode === "exclusion"
|
||||
? "Using Exclusion Points"
|
||||
: "Use Exclusion Points"
|
||||
}
|
||||
>
|
||||
<div>
|
||||
<ToolbarButton
|
||||
icon={faCircleMinus}
|
||||
buttonProps={{
|
||||
...buttonsProps.EXCLUSION_MODE,
|
||||
active: extractionMode === "exclusion",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Tooltip>
|
||||
<ToolbarButton
|
||||
icon={faRotateLeft}
|
||||
tooltip="Undo"
|
||||
buttonProps={buttonsProps.UNDO}
|
||||
/>
|
||||
<ToolbarButton
|
||||
icon={faRotateRight}
|
||||
tooltip="Redo"
|
||||
buttonProps={buttonsProps.REDO}
|
||||
/>
|
||||
<DoneButton {...buttonsProps.DONE} ready={readyToSubmit} />
|
||||
<CancelButton {...buttonsProps.CANCEL} />
|
||||
</div>
|
||||
|
||||
<DoneButton {...buttonsProps.DONE} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
const CancelButton = (buttonProps: ToolbarButtonProps) => {
|
||||
const {
|
||||
className: customButtonClassNames,
|
||||
disabled,
|
||||
active,
|
||||
hidden,
|
||||
onClick,
|
||||
...restButtonProps
|
||||
} = buttonProps;
|
||||
|
||||
const DoneButton = (buttonProps: ToolbarButtonProps) => {
|
||||
return (
|
||||
<Button
|
||||
className="text-nowrap"
|
||||
variant="secondary"
|
||||
disabled={disabled}
|
||||
{...restButtonProps}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
if (onClick) {
|
||||
onClick(e);
|
||||
}
|
||||
}}
|
||||
{...restButtonProps}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
type DoneButtonProps = { ready: boolean } & ToolbarButtonProps;
|
||||
const DoneButton = ({ ready, ...buttonProps }: DoneButtonProps) => {
|
||||
const {
|
||||
className: customButtonClassNames,
|
||||
disabled,
|
||||
@@ -58,9 +159,9 @@ const DoneButton = (buttonProps: ToolbarButtonProps) => {
|
||||
return (
|
||||
<Tooltip tip="Click to Complete Extraction">
|
||||
<Button
|
||||
className="text-nowrap p-4"
|
||||
className="text-nowrap"
|
||||
icon={faScalpel}
|
||||
disabled={disabled}
|
||||
disabled={disabled || !ready}
|
||||
{...restButtonProps}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
export enum ToolbarVideoExtractionButtonNames {
|
||||
INCLUSION_MODE = "INCLUSION_MODE",
|
||||
EXCLUSION_MODE = "EXCLUSION_MODE",
|
||||
REDO = "REDO",
|
||||
UNDO = "UNDO",
|
||||
DONE = "DONE",
|
||||
CANCEL = "CANCEL",
|
||||
}
|
||||
@@ -10,11 +10,15 @@ type ButtonStates = {
|
||||
export interface ToolbarVideoExtractionProps {
|
||||
isShowing: boolean;
|
||||
disabled: boolean;
|
||||
mode: "inclusion" | "exclusion";
|
||||
ready: boolean;
|
||||
buttonStates: ButtonStates;
|
||||
loadingBarState: LoadingBarState;
|
||||
}
|
||||
|
||||
const toolbarVideoExtractionSignal = signal<ToolbarVideoExtractionProps>({
|
||||
ready: false,
|
||||
mode: "inclusion",
|
||||
isShowing: false,
|
||||
disabled: false,
|
||||
buttonStates: initButtonStates(),
|
||||
@@ -33,6 +37,18 @@ export const toolbarVideoExtraction = {
|
||||
...updateProps,
|
||||
};
|
||||
},
|
||||
setReady(ready: boolean) {
|
||||
toolbarVideoExtractionSignal.value = {
|
||||
...toolbarVideoExtractionSignal.value,
|
||||
ready,
|
||||
};
|
||||
},
|
||||
setMode(mode: "inclusion" | "exclusion") {
|
||||
toolbarVideoExtractionSignal.value = {
|
||||
...toolbarVideoExtractionSignal.value,
|
||||
mode,
|
||||
};
|
||||
},
|
||||
updateProgress(newLoadingBarState: LoadingBarState) {
|
||||
toolbarVideoExtractionSignal.value = {
|
||||
...toolbarVideoExtractionSignal.value,
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.4.tgz"
|
||||
integrity sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ==
|
||||
|
||||
"@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.24.5":
|
||||
"@babel/core@^7.24.5":
|
||||
version "7.25.2"
|
||||
resolved "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz"
|
||||
integrity sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==
|
||||
@@ -222,6 +222,116 @@
|
||||
resolved "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz"
|
||||
integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==
|
||||
|
||||
"@esbuild/aix-ppc64@0.21.5":
|
||||
version "0.21.5"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz#c7184a326533fcdf1b8ee0733e21c713b975575f"
|
||||
integrity sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==
|
||||
|
||||
"@esbuild/android-arm64@0.21.5":
|
||||
version "0.21.5"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz#09d9b4357780da9ea3a7dfb833a1f1ff439b4052"
|
||||
integrity sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==
|
||||
|
||||
"@esbuild/android-arm@0.21.5":
|
||||
version "0.21.5"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.21.5.tgz#9b04384fb771926dfa6d7ad04324ecb2ab9b2e28"
|
||||
integrity sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==
|
||||
|
||||
"@esbuild/android-x64@0.21.5":
|
||||
version "0.21.5"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.21.5.tgz#29918ec2db754cedcb6c1b04de8cd6547af6461e"
|
||||
integrity sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==
|
||||
|
||||
"@esbuild/darwin-arm64@0.21.5":
|
||||
version "0.21.5"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz#e495b539660e51690f3928af50a76fb0a6ccff2a"
|
||||
integrity sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==
|
||||
|
||||
"@esbuild/darwin-x64@0.21.5":
|
||||
version "0.21.5"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz#c13838fa57372839abdddc91d71542ceea2e1e22"
|
||||
integrity sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==
|
||||
|
||||
"@esbuild/freebsd-arm64@0.21.5":
|
||||
version "0.21.5"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz#646b989aa20bf89fd071dd5dbfad69a3542e550e"
|
||||
integrity sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==
|
||||
|
||||
"@esbuild/freebsd-x64@0.21.5":
|
||||
version "0.21.5"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz#aa615cfc80af954d3458906e38ca22c18cf5c261"
|
||||
integrity sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==
|
||||
|
||||
"@esbuild/linux-arm64@0.21.5":
|
||||
version "0.21.5"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz#70ac6fa14f5cb7e1f7f887bcffb680ad09922b5b"
|
||||
integrity sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==
|
||||
|
||||
"@esbuild/linux-arm@0.21.5":
|
||||
version "0.21.5"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz#fc6fd11a8aca56c1f6f3894f2bea0479f8f626b9"
|
||||
integrity sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==
|
||||
|
||||
"@esbuild/linux-ia32@0.21.5":
|
||||
version "0.21.5"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz#3271f53b3f93e3d093d518d1649d6d68d346ede2"
|
||||
integrity sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==
|
||||
|
||||
"@esbuild/linux-loong64@0.21.5":
|
||||
version "0.21.5"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz#ed62e04238c57026aea831c5a130b73c0f9f26df"
|
||||
integrity sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==
|
||||
|
||||
"@esbuild/linux-mips64el@0.21.5":
|
||||
version "0.21.5"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz#e79b8eb48bf3b106fadec1ac8240fb97b4e64cbe"
|
||||
integrity sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==
|
||||
|
||||
"@esbuild/linux-ppc64@0.21.5":
|
||||
version "0.21.5"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz#5f2203860a143b9919d383ef7573521fb154c3e4"
|
||||
integrity sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==
|
||||
|
||||
"@esbuild/linux-riscv64@0.21.5":
|
||||
version "0.21.5"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz#07bcafd99322d5af62f618cb9e6a9b7f4bb825dc"
|
||||
integrity sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==
|
||||
|
||||
"@esbuild/linux-s390x@0.21.5":
|
||||
version "0.21.5"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz#b7ccf686751d6a3e44b8627ababc8be3ef62d8de"
|
||||
integrity sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==
|
||||
|
||||
"@esbuild/linux-x64@0.21.5":
|
||||
version "0.21.5"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz#6d8f0c768e070e64309af8004bb94e68ab2bb3b0"
|
||||
integrity sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==
|
||||
|
||||
"@esbuild/netbsd-x64@0.21.5":
|
||||
version "0.21.5"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz#bbe430f60d378ecb88decb219c602667387a6047"
|
||||
integrity sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==
|
||||
|
||||
"@esbuild/openbsd-x64@0.21.5":
|
||||
version "0.21.5"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz#99d1cf2937279560d2104821f5ccce220cb2af70"
|
||||
integrity sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==
|
||||
|
||||
"@esbuild/sunos-x64@0.21.5":
|
||||
version "0.21.5"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz#08741512c10d529566baba837b4fe052c8f3487b"
|
||||
integrity sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==
|
||||
|
||||
"@esbuild/win32-arm64@0.21.5":
|
||||
version "0.21.5"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz#675b7385398411240735016144ab2e99a60fc75d"
|
||||
integrity sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==
|
||||
|
||||
"@esbuild/win32-ia32@0.21.5":
|
||||
version "0.21.5"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz#1bfc3ce98aa6ca9a0969e4d2af72144c59c1193b"
|
||||
integrity sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==
|
||||
|
||||
"@esbuild/win32-x64@0.21.5":
|
||||
version "0.21.5"
|
||||
resolved "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz"
|
||||
@@ -263,7 +373,7 @@
|
||||
minimatch "^3.1.2"
|
||||
strip-json-comments "^3.1.1"
|
||||
|
||||
"@eslint/js@^9.9.0", "@eslint/js@9.9.1":
|
||||
"@eslint/js@9.9.1", "@eslint/js@^9.9.0":
|
||||
version "9.9.1"
|
||||
resolved "https://registry.npmjs.org/@eslint/js/-/js-9.9.1.tgz"
|
||||
integrity sha512-xIDQRsfg5hNBqHz04H1R3scSVwmI+KUbqjsQKHKQ1DAUSaUjYPReZZmS/5PNiKu1fUvzDd6H7DEDKACSEhu+TQ==
|
||||
@@ -314,7 +424,7 @@
|
||||
resolved "https://npm.fontawesome.com/@fortawesome/fontawesome-common-types/-/6.6.0/fontawesome-common-types-6.6.0.tgz"
|
||||
integrity sha512-xyX0X9mc0kyz9plIyryrRbl7ngsA9jz77mCZJsUkLl+ZKs0KWObgaEBoSgQiYWAsSmjz/yjl0F++Got0Mdp4Rw==
|
||||
|
||||
"@fortawesome/fontawesome-svg-core@^6.6.0", "@fortawesome/fontawesome-svg-core@~1 || ~6":
|
||||
"@fortawesome/fontawesome-svg-core@^6.6.0":
|
||||
version "6.6.0"
|
||||
resolved "https://npm.fontawesome.com/@fortawesome/fontawesome-svg-core/-/6.6.0/fontawesome-svg-core-6.6.0.tgz"
|
||||
integrity sha512-KHwPkCk6oRT4HADE7smhfsKudt9N/9lm6EJ5BVg0tD1yPA5hht837fB87F8pn15D8JfTqQOjhKTktwmLMiD7Kg==
|
||||
@@ -419,7 +529,7 @@
|
||||
"@nodelib/fs.stat" "2.0.5"
|
||||
run-parallel "^1.1.9"
|
||||
|
||||
"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5":
|
||||
"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2":
|
||||
version "2.0.5"
|
||||
resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz"
|
||||
integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
|
||||
@@ -741,6 +851,81 @@
|
||||
resolved "https://registry.npmjs.org/@remix-run/router/-/router-1.19.1.tgz"
|
||||
integrity sha512-S45oynt/WH19bHbIXjtli6QmwNYvaz+vtnubvNpNDvUOoA/OWh6j1OikIP3G+v5GHdxyC6EXoChG3HgYGEUfcg==
|
||||
|
||||
"@rollup/rollup-android-arm-eabi@4.24.0":
|
||||
version "4.24.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.0.tgz#1661ff5ea9beb362795304cb916049aba7ac9c54"
|
||||
integrity sha512-Q6HJd7Y6xdB48x8ZNVDOqsbh2uByBhgK8PiQgPhwkIw/HC/YX5Ghq2mQY5sRMZWHb3VsFkWooUVOZHKr7DmDIA==
|
||||
|
||||
"@rollup/rollup-android-arm64@4.24.0":
|
||||
version "4.24.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.24.0.tgz#2ffaa91f1b55a0082b8a722525741aadcbd3971e"
|
||||
integrity sha512-ijLnS1qFId8xhKjT81uBHuuJp2lU4x2yxa4ctFPtG+MqEE6+C5f/+X/bStmxapgmwLwiL3ih122xv8kVARNAZA==
|
||||
|
||||
"@rollup/rollup-darwin-arm64@4.24.0":
|
||||
version "4.24.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.24.0.tgz#627007221b24b8cc3063703eee0b9177edf49c1f"
|
||||
integrity sha512-bIv+X9xeSs1XCk6DVvkO+S/z8/2AMt/2lMqdQbMrmVpgFvXlmde9mLcbQpztXm1tajC3raFDqegsH18HQPMYtA==
|
||||
|
||||
"@rollup/rollup-darwin-x64@4.24.0":
|
||||
version "4.24.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.24.0.tgz#0605506142b9e796c370d59c5984ae95b9758724"
|
||||
integrity sha512-X6/nOwoFN7RT2svEQWUsW/5C/fYMBe4fnLK9DQk4SX4mgVBiTA9h64kjUYPvGQ0F/9xwJ5U5UfTbl6BEjaQdBQ==
|
||||
|
||||
"@rollup/rollup-linux-arm-gnueabihf@4.24.0":
|
||||
version "4.24.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.24.0.tgz#62dfd196d4b10c0c2db833897164d2d319ee0cbb"
|
||||
integrity sha512-0KXvIJQMOImLCVCz9uvvdPgfyWo93aHHp8ui3FrtOP57svqrF/roSSR5pjqL2hcMp0ljeGlU4q9o/rQaAQ3AYA==
|
||||
|
||||
"@rollup/rollup-linux-arm-musleabihf@4.24.0":
|
||||
version "4.24.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.24.0.tgz#53ce72aeb982f1f34b58b380baafaf6a240fddb3"
|
||||
integrity sha512-it2BW6kKFVh8xk/BnHfakEeoLPv8STIISekpoF+nBgWM4d55CZKc7T4Dx1pEbTnYm/xEKMgy1MNtYuoA8RFIWw==
|
||||
|
||||
"@rollup/rollup-linux-arm64-gnu@4.24.0":
|
||||
version "4.24.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.24.0.tgz#1632990f62a75c74f43e4b14ab3597d7ed416496"
|
||||
integrity sha512-i0xTLXjqap2eRfulFVlSnM5dEbTVque/3Pi4g2y7cxrs7+a9De42z4XxKLYJ7+OhE3IgxvfQM7vQc43bwTgPwA==
|
||||
|
||||
"@rollup/rollup-linux-arm64-musl@4.24.0":
|
||||
version "4.24.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.24.0.tgz#8c03a996efb41e257b414b2e0560b7a21f2d9065"
|
||||
integrity sha512-9E6MKUJhDuDh604Qco5yP/3qn3y7SLXYuiC0Rpr89aMScS2UAmK1wHP2b7KAa1nSjWJc/f/Lc0Wl1L47qjiyQw==
|
||||
|
||||
"@rollup/rollup-linux-powerpc64le-gnu@4.24.0":
|
||||
version "4.24.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.24.0.tgz#5b98729628d5bcc8f7f37b58b04d6845f85c7b5d"
|
||||
integrity sha512-2XFFPJ2XMEiF5Zi2EBf4h73oR1V/lycirxZxHZNc93SqDN/IWhYYSYj8I9381ikUFXZrz2v7r2tOVk2NBwxrWw==
|
||||
|
||||
"@rollup/rollup-linux-riscv64-gnu@4.24.0":
|
||||
version "4.24.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.24.0.tgz#48e42e41f4cabf3573cfefcb448599c512e22983"
|
||||
integrity sha512-M3Dg4hlwuntUCdzU7KjYqbbd+BLq3JMAOhCKdBE3TcMGMZbKkDdJ5ivNdehOssMCIokNHFOsv7DO4rlEOfyKpg==
|
||||
|
||||
"@rollup/rollup-linux-s390x-gnu@4.24.0":
|
||||
version "4.24.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.24.0.tgz#e0b4f9a966872cb7d3e21b9e412a4b7efd7f0b58"
|
||||
integrity sha512-mjBaoo4ocxJppTorZVKWFpy1bfFj9FeCMJqzlMQGjpNPY9JwQi7OuS1axzNIk0nMX6jSgy6ZURDZ2w0QW6D56g==
|
||||
|
||||
"@rollup/rollup-linux-x64-gnu@4.24.0":
|
||||
version "4.24.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.24.0.tgz#78144741993100f47bd3da72fce215e077ae036b"
|
||||
integrity sha512-ZXFk7M72R0YYFN5q13niV0B7G8/5dcQ9JDp8keJSfr3GoZeXEoMHP/HlvqROA3OMbMdfr19IjCeNAnPUG93b6A==
|
||||
|
||||
"@rollup/rollup-linux-x64-musl@4.24.0":
|
||||
version "4.24.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.24.0.tgz#d9fe32971883cd1bd858336bd33a1c3ca6146127"
|
||||
integrity sha512-w1i+L7kAXZNdYl+vFvzSZy8Y1arS7vMgIy8wusXJzRrPyof5LAb02KGr1PD2EkRcl73kHulIID0M501lN+vobQ==
|
||||
|
||||
"@rollup/rollup-win32-arm64-msvc@4.24.0":
|
||||
version "4.24.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.24.0.tgz#71fa3ea369316db703a909c790743972e98afae5"
|
||||
integrity sha512-VXBrnPWgBpVDCVY6XF3LEW0pOU51KbaHhccHw6AS6vBWIC60eqsH19DAeeObl+g8nKAz04QFdl/Cefta0xQtUQ==
|
||||
|
||||
"@rollup/rollup-win32-ia32-msvc@4.24.0":
|
||||
version "4.24.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.24.0.tgz#653f5989a60658e17d7576a3996deb3902e342e2"
|
||||
integrity sha512-xrNcGDU0OxVcPTH/8n/ShH4UevZxKIO6HJFK0e15XItZP2UcaiLFd5kiX7hJnqCbSztUF8Qot+JWBC/QXRPYWQ==
|
||||
|
||||
"@rollup/rollup-win32-x64-msvc@4.24.0":
|
||||
version "4.24.0"
|
||||
resolved "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.24.0.tgz"
|
||||
@@ -872,7 +1057,7 @@
|
||||
resolved "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz"
|
||||
integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==
|
||||
|
||||
"@types/node@^18.0.0 || >=20.0.0", "@types/node@>=13.7.0":
|
||||
"@types/node@>=13.7.0":
|
||||
version "22.5.5"
|
||||
resolved "https://registry.npmjs.org/@types/node/-/node-22.5.5.tgz"
|
||||
integrity sha512-Xjs4y5UPO/CLdzpgR6GirZJx36yScjh73+2NlLlkFRSoQN8B0DpfXPdZGnvVmLRLOsqDpOfTNv7D9trgGhmOIA==
|
||||
@@ -919,7 +1104,7 @@
|
||||
natural-compare "^1.4.0"
|
||||
ts-api-utils "^1.3.0"
|
||||
|
||||
"@typescript-eslint/parser@^8.0.0 || ^8.0.0-alpha.0", "@typescript-eslint/parser@8.3.0":
|
||||
"@typescript-eslint/parser@8.3.0":
|
||||
version "8.3.0"
|
||||
resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.3.0.tgz"
|
||||
integrity sha512-h53RhVyLu6AtpUzVCYLPhZGL5jzTD9fZL+SYf/+hYOx2bDkyQXztXSc4tbvKYHzfMXExMLiL9CWqJmVz6+78IQ==
|
||||
@@ -1011,7 +1196,7 @@ acorn-jsx@^5.3.2:
|
||||
resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz"
|
||||
integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
|
||||
|
||||
"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^8.12.0:
|
||||
acorn@^8.12.0:
|
||||
version "8.12.1"
|
||||
resolved "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz"
|
||||
integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==
|
||||
@@ -1058,14 +1243,7 @@ ansi-styles@^3.2.1:
|
||||
dependencies:
|
||||
color-convert "^1.9.0"
|
||||
|
||||
ansi-styles@^4.0.0:
|
||||
version "4.3.0"
|
||||
resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz"
|
||||
integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
|
||||
dependencies:
|
||||
color-convert "^2.0.1"
|
||||
|
||||
ansi-styles@^4.1.0:
|
||||
ansi-styles@^4.0.0, ansi-styles@^4.1.0:
|
||||
version "4.3.0"
|
||||
resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz"
|
||||
integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
|
||||
@@ -1232,12 +1410,7 @@ bin-links@^4.0.4:
|
||||
read-cmd-shim "^4.0.0"
|
||||
write-file-atomic "^5.0.0"
|
||||
|
||||
binary-extensions@^2.0.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz"
|
||||
integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==
|
||||
|
||||
binary-extensions@^2.3.0:
|
||||
binary-extensions@^2.0.0, binary-extensions@^2.3.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz"
|
||||
integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==
|
||||
@@ -1264,7 +1437,7 @@ braces@^3.0.3, braces@~3.0.2:
|
||||
dependencies:
|
||||
fill-range "^7.1.1"
|
||||
|
||||
browserslist@^4.23.1, browserslist@^4.23.3, "browserslist@>= 4.21.0":
|
||||
browserslist@^4.23.1, browserslist@^4.23.3:
|
||||
version "4.23.3"
|
||||
resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz"
|
||||
integrity sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==
|
||||
@@ -1414,16 +1587,16 @@ color-convert@^2.0.1:
|
||||
dependencies:
|
||||
color-name "~1.1.4"
|
||||
|
||||
color-name@~1.1.4:
|
||||
version "1.1.4"
|
||||
resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz"
|
||||
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
|
||||
|
||||
color-name@1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz"
|
||||
integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
|
||||
|
||||
color-name@~1.1.4:
|
||||
version "1.1.4"
|
||||
resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz"
|
||||
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
|
||||
|
||||
commander@^4.0.0:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz"
|
||||
@@ -1509,7 +1682,7 @@ data-view-byte-offset@^1.0.0:
|
||||
es-errors "^1.3.0"
|
||||
is-data-view "^1.0.1"
|
||||
|
||||
debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@4:
|
||||
debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4:
|
||||
version "4.3.6"
|
||||
resolved "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz"
|
||||
integrity sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==
|
||||
@@ -1839,12 +2012,7 @@ eslint-scope@^8.0.2:
|
||||
esrecurse "^4.3.0"
|
||||
estraverse "^5.2.0"
|
||||
|
||||
eslint-visitor-keys@^3.3.0:
|
||||
version "3.4.3"
|
||||
resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz"
|
||||
integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
|
||||
|
||||
eslint-visitor-keys@^3.4.3:
|
||||
eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.3:
|
||||
version "3.4.3"
|
||||
resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz"
|
||||
integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
|
||||
@@ -1854,7 +2022,7 @@ eslint-visitor-keys@^4.0.0:
|
||||
resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz"
|
||||
integrity sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==
|
||||
|
||||
"eslint@^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7", "eslint@^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0", "eslint@^6.0.0 || ^7.0.0 || >=8.0.0", "eslint@^8.57.0 || ^9.0.0", eslint@^9.9.0, eslint@>=7:
|
||||
eslint@^9.9.0:
|
||||
version "9.9.1"
|
||||
resolved "https://registry.npmjs.org/eslint/-/eslint-9.9.1.tgz"
|
||||
integrity sha512-dHvhrbfr4xFQ9/dq+jcVneZMyRYLjggWjk6RVsIiHsP8Rz6yZ8LvZ//iU4TrZF+SXWG+JkNF2OyiZRvzgRDqMg==
|
||||
@@ -2058,6 +2226,11 @@ fs-minipass@^3.0.0, fs-minipass@^3.0.3:
|
||||
dependencies:
|
||||
minipass "^7.0.3"
|
||||
|
||||
fsevents@~2.3.2, fsevents@~2.3.3:
|
||||
version "2.3.3"
|
||||
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6"
|
||||
integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
|
||||
|
||||
function-bind@^1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz"
|
||||
@@ -2103,7 +2276,7 @@ get-symbol-description@^1.0.2:
|
||||
es-errors "^1.3.0"
|
||||
get-intrinsic "^1.2.4"
|
||||
|
||||
glob-parent@^5.1.2:
|
||||
glob-parent@^5.1.2, glob-parent@~5.1.2:
|
||||
version "5.1.2"
|
||||
resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz"
|
||||
integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
|
||||
@@ -2117,13 +2290,6 @@ glob-parent@^6.0.2:
|
||||
dependencies:
|
||||
is-glob "^4.0.3"
|
||||
|
||||
glob-parent@~5.1.2:
|
||||
version "5.1.2"
|
||||
resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz"
|
||||
integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
|
||||
dependencies:
|
||||
is-glob "^4.0.1"
|
||||
|
||||
glob@^10.2.2, glob@^10.3.10, glob@^10.4.5:
|
||||
version "10.4.5"
|
||||
resolved "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz"
|
||||
@@ -2171,12 +2337,7 @@ gopd@^1.0.1:
|
||||
dependencies:
|
||||
get-intrinsic "^1.1.3"
|
||||
|
||||
graceful-fs@^4.1.6, graceful-fs@^4.2.0:
|
||||
version "4.2.11"
|
||||
resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz"
|
||||
integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
|
||||
|
||||
graceful-fs@^4.2.11, graceful-fs@^4.2.6:
|
||||
graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.11, graceful-fs@^4.2.6:
|
||||
version "4.2.11"
|
||||
resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz"
|
||||
integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
|
||||
@@ -2591,7 +2752,7 @@ jackspeak@^3.1.2:
|
||||
optionalDependencies:
|
||||
"@pkgjs/parseargs" "^0.11.0"
|
||||
|
||||
jiti@*, jiti@^1.21.0:
|
||||
jiti@^1.21.0:
|
||||
version "1.21.6"
|
||||
resolved "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz"
|
||||
integrity sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==
|
||||
@@ -2960,16 +3121,16 @@ minipass@^3.0.0:
|
||||
dependencies:
|
||||
yallist "^4.0.0"
|
||||
|
||||
"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.2, minipass@^7.0.3, minipass@^7.1.1, minipass@^7.1.2:
|
||||
version "7.1.2"
|
||||
resolved "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz"
|
||||
integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==
|
||||
|
||||
minipass@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz"
|
||||
integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==
|
||||
|
||||
"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.2, minipass@^7.0.3, minipass@^7.1.1, minipass@^7.1.2:
|
||||
version "7.1.2"
|
||||
resolved "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz"
|
||||
integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==
|
||||
|
||||
minizlib@^2.1.1, minizlib@^2.1.2:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz"
|
||||
@@ -2983,16 +3144,16 @@ mkdirp@^1.0.3:
|
||||
resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz"
|
||||
integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
|
||||
|
||||
ms@^2.1.2:
|
||||
version "2.1.3"
|
||||
resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz"
|
||||
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
|
||||
|
||||
ms@2.1.2:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz"
|
||||
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
|
||||
|
||||
ms@^2.1.2:
|
||||
version "2.1.3"
|
||||
resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz"
|
||||
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
|
||||
|
||||
mute-stream@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz"
|
||||
@@ -3470,15 +3631,7 @@ postcss-nested@^6.0.1:
|
||||
dependencies:
|
||||
postcss-selector-parser "^6.1.1"
|
||||
|
||||
postcss-selector-parser@^6.0.10:
|
||||
version "6.1.2"
|
||||
resolved "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz"
|
||||
integrity sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==
|
||||
dependencies:
|
||||
cssesc "^3.0.0"
|
||||
util-deprecate "^1.0.2"
|
||||
|
||||
postcss-selector-parser@^6.0.11, postcss-selector-parser@^6.1.1:
|
||||
postcss-selector-parser@^6.0.10, postcss-selector-parser@^6.0.11, postcss-selector-parser@^6.1.1:
|
||||
version "6.1.2"
|
||||
resolved "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz"
|
||||
integrity sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==
|
||||
@@ -3491,7 +3644,7 @@ postcss-value-parser@^4.0.0, postcss-value-parser@^4.0.2, postcss-value-parser@^
|
||||
resolved "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz"
|
||||
integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
|
||||
|
||||
postcss@^8.0.0, postcss@^8.1.0, postcss@^8.2.14, postcss@^8.4.21, postcss@^8.4.23, postcss@^8.4.41, postcss@^8.4.43, postcss@>=8.0.9:
|
||||
postcss@^8.4.23, postcss@^8.4.41, postcss@^8.4.43:
|
||||
version "8.4.47"
|
||||
resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz"
|
||||
integrity sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==
|
||||
@@ -3525,7 +3678,7 @@ prettier-plugin-tailwindcss@^0.6.6:
|
||||
resolved "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.6.6.tgz"
|
||||
integrity sha512-OPva5S7WAsPLEsOuOWXATi13QrCKACCiIonFgIR6V4lYv4QLp++UXVhZSzRbZxXGimkQtQT86CC6fQqTOybGng==
|
||||
|
||||
prettier@^3.0, prettier@^3.3.3:
|
||||
prettier@^3.3.3:
|
||||
version "3.3.3"
|
||||
resolved "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz"
|
||||
integrity sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==
|
||||
@@ -3617,7 +3770,7 @@ react-colorful@^5.6.1:
|
||||
resolved "https://registry.npmjs.org/react-colorful/-/react-colorful-5.6.1.tgz"
|
||||
integrity sha512-1exovf0uGTGyq5mXQT0zgQ80uvj2PCwvF8zY1RN9/vbJVSjSo3fsB/4L3ObbF7u70NduSiK4xu4Y6q1MHoUGEw==
|
||||
|
||||
"react-dom@^16.8.0 || ^17.0.0 || ^18.0.0", react-dom@^18, react-dom@^18.0.0, react-dom@^18.3.1, "react-dom@>= 16.8.0", react-dom@>=16.4.0, react-dom@>=16.8, react-dom@>=16.8.0:
|
||||
react-dom@^18.3.1:
|
||||
version "18.3.1"
|
||||
resolved "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz"
|
||||
integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==
|
||||
@@ -3641,7 +3794,7 @@ react-easy-crop@^5.1.0:
|
||||
normalize-wheel "^1.0.1"
|
||||
tslib "^2.0.1"
|
||||
|
||||
react-is@^16.13.1, react-is@^16.7.0, "react-is@>= 16.8.0":
|
||||
react-is@^16.13.1, react-is@^16.7.0:
|
||||
version "16.13.1"
|
||||
resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz"
|
||||
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
|
||||
@@ -3666,7 +3819,7 @@ react-router@6.26.1:
|
||||
dependencies:
|
||||
"@remix-run/router" "1.19.1"
|
||||
|
||||
"react@^16.14.0 || 17.x || 18.x", "react@^16.8.0 || ^17.0.0 || ^18.0.0", "react@^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", react@^18, react@^18.0.0, react@^18.3.1, "react@>= 16.8.0", react@>=16.3, react@>=16.4.0, react@>=16.8, react@>=16.8.0:
|
||||
react@^18.3.1:
|
||||
version "18.3.1"
|
||||
resolved "https://registry.npmjs.org/react/-/react-18.3.1.tgz"
|
||||
integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==
|
||||
@@ -3735,16 +3888,7 @@ resolve-from@^4.0.0:
|
||||
resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz"
|
||||
integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
|
||||
|
||||
resolve@^1.1.7:
|
||||
version "1.22.8"
|
||||
resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz"
|
||||
integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==
|
||||
dependencies:
|
||||
is-core-module "^2.13.0"
|
||||
path-parse "^1.0.7"
|
||||
supports-preserve-symlinks-flag "^1.0.0"
|
||||
|
||||
resolve@^1.22.2:
|
||||
resolve@^1.1.7, resolve@^1.22.2:
|
||||
version "1.22.8"
|
||||
resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz"
|
||||
integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==
|
||||
@@ -3840,12 +3984,7 @@ semver@^6.3.1:
|
||||
resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz"
|
||||
integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
|
||||
|
||||
semver@^7.1.1, semver@^7.3.5, semver@^7.3.7, semver@^7.5.3, semver@^7.6.3:
|
||||
version "7.6.3"
|
||||
resolved "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz"
|
||||
integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==
|
||||
|
||||
semver@^7.6.0:
|
||||
semver@^7.1.1, semver@^7.3.5, semver@^7.3.7, semver@^7.5.3, semver@^7.6.0, semver@^7.6.3:
|
||||
version "7.6.3"
|
||||
resolved "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz"
|
||||
integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==
|
||||
@@ -3973,7 +4112,9 @@ spdx-expression-parse@^4.0.0:
|
||||
spdx-license-ids "^3.0.0"
|
||||
|
||||
spdx-license-ids@^3.0.0:
|
||||
version "3.0.18"
|
||||
version "3.0.20"
|
||||
resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.20.tgz#e44ed19ed318dd1e5888f93325cee800f0f51b89"
|
||||
integrity sha512-jg25NiDV/1fLtSgEgyvVyDunvaNHbuwF9lfNV17gSmPFAlYzdfNBlLtLzXTevwkPj7DhGbmN9VnmJIgLnhvaBw==
|
||||
|
||||
sprintf-js@^1.1.3:
|
||||
version "1.1.3"
|
||||
@@ -4101,7 +4242,7 @@ strip-json-comments@^3.1.1:
|
||||
resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz"
|
||||
integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
|
||||
|
||||
styled-components@^5.3.0, "styled-components@>= 2":
|
||||
styled-components@^5.3.0:
|
||||
version "5.3.11"
|
||||
resolved "https://registry.npmjs.org/styled-components/-/styled-components-5.3.11.tgz"
|
||||
integrity sha512-uuzIIfnVkagcVHv9nE0VPlHPSCmXIUGKfJ42LNjxCCTDTL5sgnJ8Z7GZBq0EnLYGln77tPpEpExt2+qa+cZqSw==
|
||||
@@ -4204,12 +4345,7 @@ tar@^6.1.11, tar@^6.2.1:
|
||||
mkdirp "^1.0.3"
|
||||
yallist "^4.0.0"
|
||||
|
||||
text-table@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz"
|
||||
integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==
|
||||
|
||||
text-table@~0.2.0:
|
||||
text-table@^0.2.0, text-table@~0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz"
|
||||
integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==
|
||||
@@ -4339,7 +4475,7 @@ typescript-eslint@^8.0.1:
|
||||
"@typescript-eslint/parser" "8.3.0"
|
||||
"@typescript-eslint/utils" "8.3.0"
|
||||
|
||||
typescript@^5.0.0, typescript@^5.5.3, typescript@>=4.2.0:
|
||||
typescript@^5.5.3:
|
||||
version "5.5.4"
|
||||
resolved "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz"
|
||||
integrity sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==
|
||||
@@ -4440,7 +4576,7 @@ vite-tsconfig-paths@^5.0.1:
|
||||
globrex "^0.1.2"
|
||||
tsconfck "^3.0.3"
|
||||
|
||||
vite@*, "vite@^4.2.0 || ^5.0.0", vite@^5.0.0, vite@^5.4.1:
|
||||
vite@^5.4.1:
|
||||
version "5.4.10"
|
||||
resolved "https://registry.npmjs.org/vite/-/vite-5.4.10.tgz"
|
||||
integrity sha512-1hvaPshuPUtxeQ0hsVH3Mud0ZanOLwVTneA1EgbAM5LhaZEqyPWGRQ7BtaMvUrTDeEaC8pxtj6a6jku3x4z6SQ==
|
||||
|
||||
Reference in new issue
Block a user