implement auto reconnect

This commit is contained in:
marlon-erler
2026-04-01 08:29:39 +00:00
parent c52d7b7685
commit 9d400a9929
82 changed files with 8340 additions and 7641 deletions
+278 -270
View File
@@ -1,8 +1,8 @@
// this file is responsible for managing boards within chats and tasks within boards.
import {
DATA_VERSION,
checkMatchesObjectStructure,
DATA_VERSION,
checkMatchesObjectStructure,
} from "../Utility/typeSafety";
import FileModel, { FileContent, FileModelSubPath } from "./fileModel";
@@ -15,316 +15,324 @@ import StorageModel from "../Global/storageModel";
import { v4 } from "uuid";
export default class BoardsAndTasksModel {
storageModel: StorageModel;
settingsModel: SettingsModel;
chatModel: ChatModel;
fileModel: FileModel;
storageModel: StorageModel;
settingsModel: SettingsModel;
chatModel: ChatModel;
fileModel: FileModel;
calendarModel: CalendarModel;
calendarModel: CalendarModel;
// data
boardHandlerManager: HandlerManager<BoardInfoFileContent> =
new HandlerManager();
taskHandlerManager: HandlerManager<TaskFileContent> = new HandlerManager();
// data
boardHandlerManager: HandlerManager<BoardInfoFileContent> =
new HandlerManager();
taskHandlerManager: HandlerManager<TaskFileContent> = new HandlerManager();
// paths
getBasePath = (): string[] => {
return this.fileModel.getModelContainerPath(FileModelSubPath.ModelTask);
};
// paths
getBasePath = (): string[] => {
return this.fileModel.getModelContainerPath(FileModelSubPath.ModelTask);
};
getViewPath = (): string[] => {
return [...this.getBasePath(), FileModelSubPath.ModelView];
};
getViewPath = (): string[] => {
return [...this.getBasePath(), FileModelSubPath.ModelView];
};
getBoardFilePath = (boardId: string): string[] => {
return [...this.fileModel.getFilePath(boardId)];
};
getBoardFilePath = (boardId: string): string[] => {
return [...this.fileModel.getFilePath(boardId)];
};
getTaskFilePath = (taskId: string): string[] => {
return [...this.fileModel.getFilePath(taskId)];
};
getTaskFilePath = (taskId: string): string[] => {
return [...this.fileModel.getFilePath(taskId)];
};
getBoardContainerPath = (): string[] => {
return [...this.getBasePath(), TaskModelSubPaths.Boards];
};
getBoardContainerPath = (): string[] => {
return [...this.getBasePath(), TaskModelSubPaths.Boards];
};
getBoardDirectoryPath = (boardId: string): string[] => {
return [...this.getBoardContainerPath(), boardId];
};
getBoardDirectoryPath = (boardId: string): string[] => {
return [...this.getBoardContainerPath(), boardId];
};
getTaskContainerPath = (boardId: string): string[] => {
return [
...this.getBoardDirectoryPath(boardId),
TaskModelSubPaths.BoardTasks,
];
};
getTaskContainerPath = (boardId: string): string[] => {
return [
...this.getBoardDirectoryPath(boardId),
TaskModelSubPaths.BoardTasks,
];
};
getTaskReferencePath = (boardId: string, fileId: string): string[] => {
return [...this.getTaskContainerPath(boardId), fileId];
};
getTaskReferencePath = (boardId: string, fileId: string): string[] => {
return [...this.getTaskContainerPath(boardId), fileId];
};
// handlers
handleFileContent = (fileContent: FileContent<string>): void => {
if (
checkMatchesObjectStructure(fileContent, BoardInfoFileContentReference) ==
true
// handlers
handleFileContent = (fileContent: FileContent<string>): void => {
if (
checkMatchesObjectStructure(
fileContent,
BoardInfoFileContentReference,
) == true
) {
this.handleBoard(fileContent as BoardInfoFileContent);
} else if (
checkMatchesObjectStructure(
fileContent,
TaskFileContentReference,
) == true
) {
this.handleTask(fileContent as TaskFileContent);
}
};
handleBoard = (boardInfoFileContent: BoardInfoFileContent) => {
this.updateBoard(boardInfoFileContent);
};
handleTask = (taskFileContent: TaskFileContent) => {
this.updateTask(taskFileContent);
};
// boards
createBoard = (name: string): BoardInfoFileContent => {
const boardInfoFileContent: BoardInfoFileContent =
BoardsAndTasksModel.createBoardInfoFileContent(
v4(),
name,
Color.Standard,
);
return boardInfoFileContent;
};
updateBoard = (boardInfoFileContent: BoardInfoFileContent): void => {
this.storeBoard(boardInfoFileContent);
this.boardHandlerManager.trigger(boardInfoFileContent);
};
updateBoardAndSend = (boardInfoFileContent: BoardInfoFileContent): void => {
this.updateBoard(boardInfoFileContent);
this.chatModel.sendMessage("", boardInfoFileContent);
};
storeBoard = (boardInfoFileContent: BoardInfoFileContent): void => {
// store info
this.fileModel.storeFileContent(boardInfoFileContent);
// add to list
const boardDirectoryPath: string[] = this.getBoardDirectoryPath(
boardInfoFileContent.fileId,
);
this.storageModel.write(boardDirectoryPath, "");
};
deleteBoard = (boardId: string): void => {
const boardFilePath: string[] = this.getBoardFilePath(boardId);
const boardDirectoryPath: string[] =
this.getBoardDirectoryPath(boardId);
this.storageModel.removeRecursively(boardFilePath);
this.storageModel.removeRecursively(boardDirectoryPath);
};
listBoardIds = (): string[] => {
const boardContainerPath: string[] = this.getBoardContainerPath();
const boardIds: string[] = this.storageModel.list(boardContainerPath);
return boardIds;
};
getBoardInfo = (fileId: string): BoardInfoFileContent | null => {
const boardInfoFileContentOrNull: BoardInfoFileContent | null =
this.fileModel.getLatestFileContent(
fileId,
BoardInfoFileContentReference,
);
return boardInfoFileContentOrNull;
};
getBoardName = (boardId: string): string => {
const boardInfo: BoardInfoFileContent | null =
this.getBoardInfo(boardId);
if (boardInfo == null) return "";
return boardInfo.name;
};
//tasks
createTask = (boardId: string): TaskFileContent => {
const taskFileContent: TaskFileContent =
BoardsAndTasksModel.createTaskFileContent(v4(), "", boardId);
return taskFileContent;
};
updateTask = (taskFileContent: TaskFileContent): void => {
this.storeTask(taskFileContent);
this.taskHandlerManager.trigger(taskFileContent);
};
updateTaskAndSend = (taskFileContent: TaskFileContent): void => {
this.updateTask(taskFileContent);
this.chatModel.sendMessage("", taskFileContent);
};
storeTask = (taskFileContent: TaskFileContent): void => {
// store info
this.fileModel.storeFileContent(taskFileContent);
// add to board
const taskReferencePath: string[] = this.getTaskReferencePath(
taskFileContent.boardId,
taskFileContent.fileId,
);
this.storageModel.write(taskReferencePath, "");
// add to calendar
this.calendarModel.storeTaskReference(taskFileContent);
};
listTaskIds = (boardId: string): string[] => {
const taskContainerPath: string[] = this.getTaskContainerPath(boardId);
const fileIds: string[] = this.storageModel.list(taskContainerPath);
return fileIds;
};
listTaskVersionIds = (taskId: string): string[] => {
const versionIds: string[] = this.fileModel.listFileContentIds(taskId);
return versionIds;
};
getLatestTaskFileContent = (taskId: string): TaskFileContent | null => {
const taskFileContentOrNull: TaskFileContent | null =
this.fileModel.getLatestFileContent(
taskId,
TaskFileContentReference,
);
return taskFileContentOrNull;
};
getSpecificTaskFileContent = (
taskId: string,
versionId: string,
): TaskFileContent | null => {
const taskFileContentOrNull: TaskFileContent | null =
this.fileModel.getFileContent(
taskId,
versionId,
TaskFileContentReference,
);
return taskFileContentOrNull;
};
deleteTask = (boardId: string, taskId: string): void => {
const taskFilePath: string[] = this.getTaskFilePath(taskId);
this.storageModel.removeRecursively(taskFilePath);
this.deleteTaskReference(boardId, taskId);
};
deleteTaskReference = (boardId: string, taskId: string): void => {
const taskReferencePath: string[] = this.getTaskReferencePath(
boardId,
taskId,
);
this.storageModel.removeRecursively(taskReferencePath);
};
// init
constructor(
storageModel: StorageModel,
settingsModel: SettingsModel,
chatModel: ChatModel,
fileModel: FileModel,
) {
this.handleBoard(fileContent as BoardInfoFileContent);
} else if (
checkMatchesObjectStructure(fileContent, TaskFileContentReference) == true
) {
this.handleTask(fileContent as TaskFileContent);
this.storageModel = storageModel;
this.settingsModel = settingsModel;
this.chatModel = chatModel;
this.fileModel = fileModel;
this.calendarModel = new CalendarModel(
this.storageModel,
this.settingsModel,
this.fileModel,
);
}
};
handleBoard = (boardInfoFileContent: BoardInfoFileContent) => {
this.updateBoard(boardInfoFileContent);
};
// utility
static createBoardInfoFileContent = (
fileId: string,
name: string,
color: Color,
): BoardInfoFileContent => {
const fileContent: FileContent<"board-info"> =
FileModel.createFileContent(fileId, "board-info");
return {
...fileContent,
handleTask = (taskFileContent: TaskFileContent) => {
this.updateTask(taskFileContent);
};
// boards
createBoard = (name: string): BoardInfoFileContent => {
const boardInfoFileContent: BoardInfoFileContent =
BoardsAndTasksModel.createBoardInfoFileContent(
v4(),
name,
Color.Standard
);
return boardInfoFileContent;
};
updateBoard = (boardInfoFileContent: BoardInfoFileContent): void => {
this.storeBoard(boardInfoFileContent);
this.boardHandlerManager.trigger(boardInfoFileContent);
};
updateBoardAndSend = (boardInfoFileContent: BoardInfoFileContent): void => {
this.updateBoard(boardInfoFileContent);
this.chatModel.sendMessage("", boardInfoFileContent);
};
storeBoard = (boardInfoFileContent: BoardInfoFileContent): void => {
// store info
this.fileModel.storeFileContent(boardInfoFileContent);
// add to list
const boardDirectoryPath: string[] = this.getBoardDirectoryPath(
boardInfoFileContent.fileId
);
this.storageModel.write(boardDirectoryPath, "");
};
deleteBoard = (boardId: string): void => {
const boardFilePath: string[] = this.getBoardFilePath(boardId);
const boardDirectoryPath: string[] = this.getBoardDirectoryPath(boardId);
this.storageModel.removeRecursively(boardFilePath);
this.storageModel.removeRecursively(boardDirectoryPath);
};
listBoardIds = (): string[] => {
const boardContainerPath: string[] = this.getBoardContainerPath();
const boardIds: string[] = this.storageModel.list(boardContainerPath);
return boardIds;
};
getBoardInfo = (fileId: string): BoardInfoFileContent | null => {
const boardInfoFileContentOrNull: BoardInfoFileContent | null =
this.fileModel.getLatestFileContent(
fileId,
BoardInfoFileContentReference
);
return boardInfoFileContentOrNull;
};
getBoardName = (boardId: string): string => {
const boardInfo: BoardInfoFileContent|null = this.getBoardInfo(boardId);
if (boardInfo == null) return "";
return boardInfo.name;
}
//tasks
createTask = (boardId: string): TaskFileContent => {
const taskFileContent: TaskFileContent =
BoardsAndTasksModel.createTaskFileContent(v4(), "", boardId);
return taskFileContent;
};
updateTask = (taskFileContent: TaskFileContent): void => {
this.storeTask(taskFileContent);
this.taskHandlerManager.trigger(taskFileContent);
};
updateTaskAndSend = (taskFileContent: TaskFileContent): void => {
this.updateTask(taskFileContent);
this.chatModel.sendMessage("", taskFileContent);
};
storeTask = (taskFileContent: TaskFileContent): void => {
// store info
this.fileModel.storeFileContent(taskFileContent);
// add to board
const taskReferencePath: string[] = this.getTaskReferencePath(
taskFileContent.boardId,
taskFileContent.fileId
);
this.storageModel.write(taskReferencePath, "");
// add to calendar
this.calendarModel.storeTaskReference(taskFileContent);
};
listTaskIds = (boardId: string): string[] => {
const taskContainerPath: string[] = this.getTaskContainerPath(boardId);
const fileIds: string[] = this.storageModel.list(taskContainerPath);
return fileIds;
};
listTaskVersionIds = (taskId: string): string[] => {
const versionIds: string[] = this.fileModel.listFileContentIds(taskId);
return versionIds;
};
getLatestTaskFileContent = (taskId: string): TaskFileContent | null => {
const taskFileContentOrNull: TaskFileContent | null =
this.fileModel.getLatestFileContent(taskId, TaskFileContentReference);
return taskFileContentOrNull;
};
getSpecificTaskFileContent = (
taskId: string,
versionId: string
): TaskFileContent | null => {
const taskFileContentOrNull: TaskFileContent | null =
this.fileModel.getFileContent(
taskId,
versionId,
TaskFileContentReference
);
return taskFileContentOrNull;
};
deleteTask = (boardId: string, taskId: string): void => {
const taskFilePath: string[] = this.getTaskFilePath(taskId);
this.storageModel.removeRecursively(taskFilePath);
this.deleteTaskReference(boardId, taskId);
};
deleteTaskReference = (boardId: string, taskId: string): void => {
const taskReferencePath: string[] = this.getTaskReferencePath(
boardId,
taskId
);
this.storageModel.removeRecursively(taskReferencePath);
};
// init
constructor(
storageModel: StorageModel,
settingsModel: SettingsModel,
chatModel: ChatModel,
fileModel: FileModel
) {
this.storageModel = storageModel;
this.settingsModel = settingsModel;
this.chatModel = chatModel;
this.fileModel = fileModel;
this.calendarModel = new CalendarModel(
this.storageModel,
this.settingsModel,
this.fileModel
);
}
// utility
static createBoardInfoFileContent = (
fileId: string,
name: string,
color: Color
): BoardInfoFileContent => {
const fileContent: FileContent<"board-info"> = FileModel.createFileContent(
fileId,
"board-info"
);
return {
...fileContent,
name,
color,
name,
color,
};
};
};
static createTaskFileContent = (
fileId: string,
name: string,
boardId: string
): TaskFileContent => {
const fileContent: FileContent<"task"> = FileModel.createFileContent(
fileId,
"task"
);
return {
...fileContent,
static createTaskFileContent = (
fileId: string,
name: string,
boardId: string,
): TaskFileContent => {
const fileContent: FileContent<"task"> = FileModel.createFileContent(
fileId,
"task",
);
return {
...fileContent,
name,
boardId,
name,
boardId,
};
};
};
}
export enum TaskModelSubPaths {
Boards = "boards",
BoardTasks = "tasks",
Boards = "boards",
BoardTasks = "tasks",
}
// types
export interface BoardInfoFileContent extends FileContent<"board-info"> {
name: string;
color: Color;
name: string;
color: Color;
}
export interface TaskFileContent extends FileContent<"task"> {
name: string;
boardId: string;
name: string;
boardId: string;
description?: string;
description?: string;
category?: string;
status?: string;
priority?: string;
category?: string;
status?: string;
priority?: string;
date?: string;
time?: string;
date?: string;
time?: string;
}
// reference
export const BoardInfoFileContentReference: BoardInfoFileContent = {
dataVersion: DATA_VERSION,
dataVersion: DATA_VERSION,
fileId: "string",
fileContentId: "",
creationDate: "",
fileId: "string",
fileContentId: "",
creationDate: "",
type: "board-info",
type: "board-info",
name: "",
color: "" as Color,
name: "",
color: "" as Color,
};
export const TaskFileContentReference: TaskFileContent = {
dataVersion: DATA_VERSION,
dataVersion: DATA_VERSION,
fileId: "string",
fileContentId: "",
creationDate: "",
type: "task",
fileId: "string",
fileContentId: "",
creationDate: "",
type: "task",
name: "",
boardId: "",
name: "",
boardId: "",
};
+138 -136
View File
@@ -7,158 +7,160 @@ import StorageModel from "../Global/storageModel";
import { TaskFileContent } from "./boardsAndTasksModel";
export default class CalendarModel {
storageModel: StorageModel;
fileModel: FileModel;
settingsModel: SettingsModel;
storageModel: StorageModel;
fileModel: FileModel;
settingsModel: SettingsModel;
// paths
getBasePath = (): string[] => {
return this.fileModel.getModelContainerPath(FileModelSubPath.ModelCalendar);
};
getViewPath = (): string[] => {
return [...this.getBasePath(), FileModelSubPath.ModelView];
};
getMonthContainerPath = (): string[] => {
return [...this.getBasePath(), CalendarModelSubPaths.Months];
};
getMonthPath = (monthString: string): string[] => {
return [...this.getMonthContainerPath(), monthString];
};
// main
storeTaskReference = (taskFileContent: TaskFileContent): void => {
if (taskFileContent.date == undefined) return;
const monthString: string = CalendarModel.isoToMonthString(
taskFileContent.date
);
const monthPath: string[] = this.getMonthPath(monthString);
const referencePath: string[] = [...monthPath, taskFileContent.fileId];
this.storageModel.write(referencePath, "");
};
deleteTaskReference = (monthString: string, taskId: string): void => {
const monthPath: string[] = this.getMonthPath(monthString);
const referencePath: string[] = [...monthPath, taskId];
this.storageModel.write(referencePath, "");
};
listTaskIds = (monthString: string): string[] => {
const monthPath: string[] = this.getMonthPath(monthString);
return this.storageModel.list(monthPath);
};
generateMonthGrid = <T>(
year: number,
month: number,
defaultValueCreator: () => T
): MonthGrid<T> => {
// get today
const date: Date = new Date();
const isCurrentMonth: boolean =
year == date.getFullYear() && month == date.getMonth() + 1;
// get data for offset
date.setDate(1);
date.setMonth(month - 1);
date.setFullYear(year);
const firstWeekdayOfMonth = date.getDay();
const firstDayOfWeekSetting: number = parseInt(
this.settingsModel.firstDayOfWeek
);
const offset: number =
firstWeekdayOfMonth < firstDayOfWeekSetting
? 7 - firstDayOfWeekSetting
: firstWeekdayOfMonth - firstDayOfWeekSetting;
// get total day count
date.setMonth(month);
date.setDate(-1);
const daysInMonth: number = date.getDate() + 1;
const grid: MonthGrid<T> = {
offset,
firstDayOfWeek: parseInt(this.settingsModel.firstDayOfWeek),
isCurrentMonth,
year,
month,
days: {},
// paths
getBasePath = (): string[] => {
return this.fileModel.getModelContainerPath(
FileModelSubPath.ModelCalendar,
);
};
for (let i = 0; i < daysInMonth; i++) {
const paddedDate: string = CalendarModel.padDateOrMonth(
(i + 1).toString()
);
grid.days[paddedDate] = defaultValueCreator();
getViewPath = (): string[] => {
return [...this.getBasePath(), FileModelSubPath.ModelView];
};
getMonthContainerPath = (): string[] => {
return [...this.getBasePath(), CalendarModelSubPaths.Months];
};
getMonthPath = (monthString: string): string[] => {
return [...this.getMonthContainerPath(), monthString];
};
// main
storeTaskReference = (taskFileContent: TaskFileContent): void => {
if (taskFileContent.date == undefined) return;
const monthString: string = CalendarModel.isoToMonthString(
taskFileContent.date,
);
const monthPath: string[] = this.getMonthPath(monthString);
const referencePath: string[] = [...monthPath, taskFileContent.fileId];
this.storageModel.write(referencePath, "");
};
deleteTaskReference = (monthString: string, taskId: string): void => {
const monthPath: string[] = this.getMonthPath(monthString);
const referencePath: string[] = [...monthPath, taskId];
this.storageModel.write(referencePath, "");
};
listTaskIds = (monthString: string): string[] => {
const monthPath: string[] = this.getMonthPath(monthString);
return this.storageModel.list(monthPath);
};
generateMonthGrid = <T>(
year: number,
month: number,
defaultValueCreator: () => T,
): MonthGrid<T> => {
// get today
const date: Date = new Date();
const isCurrentMonth: boolean =
year == date.getFullYear() && month == date.getMonth() + 1;
// get data for offset
date.setDate(1);
date.setMonth(month - 1);
date.setFullYear(year);
const firstWeekdayOfMonth = date.getDay();
const firstDayOfWeekSetting: number = parseInt(
this.settingsModel.firstDayOfWeek,
);
const offset: number =
firstWeekdayOfMonth < firstDayOfWeekSetting
? 7 - firstDayOfWeekSetting
: firstWeekdayOfMonth - firstDayOfWeekSetting;
// get total day count
date.setMonth(month);
date.setDate(-1);
const daysInMonth: number = date.getDate() + 1;
const grid: MonthGrid<T> = {
offset,
firstDayOfWeek: parseInt(this.settingsModel.firstDayOfWeek),
isCurrentMonth,
year,
month,
days: {},
};
for (let i = 0; i < daysInMonth; i++) {
const paddedDate: string = CalendarModel.padDateOrMonth(
(i + 1).toString(),
);
grid.days[paddedDate] = defaultValueCreator();
}
return grid;
};
// init
constructor(
storageModel: StorageModel,
settingsModel: SettingsModel,
fileModel: FileModel,
) {
this.storageModel = storageModel;
this.settingsModel = settingsModel;
this.fileModel = fileModel;
}
return grid;
};
// utility
static isoToMonthString = (dateISOString: string): string => {
const [year, month, _] = dateISOString.split("-");
return CalendarModel.getMonthString(year, month);
};
// init
constructor(
storageModel: StorageModel,
settingsModel: SettingsModel,
fileModel: FileModel
) {
this.storageModel = storageModel;
this.settingsModel = settingsModel;
this.fileModel = fileModel;
}
static isoToDateString = (dateISOString: string): string => {
const [year, month, date, _] = dateISOString.split("-");
const paddedDate = CalendarModel.padDateOrMonth(date ?? "");
return paddedDate;
};
// utility
static isoToMonthString = (dateISOString: string): string => {
const [year, month, _] = dateISOString.split("-");
return CalendarModel.getMonthString(year, month);
};
static getMonthString = (year: string = "", month: string = ""): string => {
const paddedYear: string = year.padStart(4, "0");
const paddedMonth: string = CalendarModel.padDateOrMonth(month);
return `${paddedYear}-${paddedMonth}`;
};
static isoToDateString = (dateISOString: string): string => {
const [year, month, date, _] = dateISOString.split("-");
const paddedDate = CalendarModel.padDateOrMonth(date ?? "");
return paddedDate;
};
static getISODateString = (
year: string,
month: string,
date: string,
): string => {
const monthString: string = CalendarModel.getMonthString(year, month);
const paddedDate: string = CalendarModel.padDateOrMonth(date);
return `${monthString}-${paddedDate}`;
};
static getMonthString = (year: string = "", month: string = ""): string => {
const paddedYear: string = year.padStart(4, "0");
const paddedMonth: string = CalendarModel.padDateOrMonth(month);
return `${paddedYear}-${paddedMonth}`;
};
static getISODateString = (
year: string,
month: string,
date: string
): string => {
const monthString: string = CalendarModel.getMonthString(year, month);
const paddedDate: string = CalendarModel.padDateOrMonth(date);
return `${monthString}-${paddedDate}`;
};
static padDateOrMonth = (input: string): string => {
return input.padStart(2, "0");
};
static padDateOrMonth = (input: string): string => {
return input.padStart(2, "0");
};
}
export enum CalendarModelSubPaths {
Months = "months",
Months = "months",
}
// types
export interface MonthGrid<T> {
offset: number;
firstDayOfWeek: number;
isCurrentMonth: boolean;
offset: number;
firstDayOfWeek: number;
isCurrentMonth: boolean;
year: number;
month: number;
year: number;
month: number;
days: { [date: string]: T };
days: { [date: string]: T };
}
+178 -175
View File
@@ -2,14 +2,14 @@
import { DATA_VERSION, ValidObject } from "../Utility/typeSafety";
import StorageModel, {
StorageModelSubPath,
filePaths,
StorageModelSubPath,
filePaths,
} from "../Global/storageModel";
import {
StringEntryObject,
createTimestamp,
parseValidObject,
stringify,
StringEntryObject,
createTimestamp,
parseValidObject,
stringify,
} from "../Utility/utility";
import BoardsAndTasksModel from "./boardsAndTasksModel";
@@ -18,191 +18,194 @@ import SettingsModel from "../Global/settingsModel";
import { v4 } from "uuid";
export default class FileModel {
storageModel: StorageModel;
settingsModel: SettingsModel;
storageModel: StorageModel;
settingsModel: SettingsModel;
chatModel: ChatModel;
boardsAndTasksModel: BoardsAndTasksModel;
chatModel: ChatModel;
boardsAndTasksModel: BoardsAndTasksModel;
// paths
getBasePath = (): string[] => {
return StorageModel.getPath(
StorageModelSubPath.Chat,
filePaths.chat.files(this.chatModel.id)
);
};
getFileContainerPath = (): string[] => {
return [...this.getBasePath(), FileModelSubPath.Data];
};
getModelContainerPath = (modelName: FileModelSubPath): string[] => {
return [...this.getBasePath(), FileModelSubPath.Model, modelName];
};
getFilePath = (fileId: string): string[] => {
return [...this.getFileContainerPath(), fileId];
};
getFileContentPath = (fileId: string, fileContentId: string): string[] => {
const filePath: string[] = this.getFilePath(fileId);
return [...filePath, fileContentId];
};
// handlers
handleStringifiedFileContent = (stringifiedFileContent: string): void => {
const fileContent: FileContent<string> | null = parseValidObject(
stringifiedFileContent,
FileContentReference
);
if (fileContent == null) return;
this.handleFileContent(fileContent);
};
handleFileContent = (fileContent: FileContent<string>): void => {
const didStore: boolean = this.storeFileContent(fileContent);
if (didStore == false) return;
this.boardsAndTasksModel.handleFileContent(fileContent);
};
// methods
addFileContentAndSend = (fileContent: FileContent<string>): void => {
this.handleFileContent(fileContent);
this.chatModel.sendMessage("", fileContent);
};
// storage
storeFileContent = (fileContent: FileContent<string>): boolean => {
const fileContentPath: string[] = this.getFileContentPath(
fileContent.fileId,
fileContent.fileContentId
);
// check if fileContent already exists
const existingFileContent: string | null =
this.storageModel.read(fileContentPath);
if (existingFileContent != null) return false;
const stringifiedContent: string = stringify(fileContent);
this.storageModel.write(fileContentPath, stringifiedContent);
return true;
};
listFileIds = (): string[] => {
return this.storageModel.list(this.getBasePath());
};
listFileContentIds = (fileId: string): string[] => {
const filePath: string[] = this.getFilePath(fileId);
return this.storageModel.list(filePath);
};
selectLatestFileContentId = (
fileContentIds: string[]
): string | undefined => {
return fileContentIds[fileContentIds.length - 1];
};
getFileContent = <T extends FileContent<string>>(
fileId: string,
fileContentName: string,
reference: T
): T | null => {
const filePath: string[] = this.getFileContentPath(fileId, fileContentName);
const fileContentOrNull: T | null = this.storageModel.readStringifiable(
filePath,
reference
);
return fileContentOrNull;
};
getLatestFileContent = <T extends FileContent<string>>(
fileId: string,
reference: T
): T | null => {
const fileContentsIds: string[] = this.listFileContentIds(fileId);
const latestFileContentId: string | undefined =
this.selectLatestFileContentId(fileContentsIds);
if (latestFileContentId == undefined) return null;
const fileContent: T | null = this.getFileContent(
fileId,
latestFileContentId,
reference
);
return fileContent;
};
// init
constructor(
storageModel: StorageModel,
settingsModel: SettingsModel,
chatModel: ChatModel
) {
this.chatModel = chatModel;
this.settingsModel = settingsModel;
this.storageModel = storageModel;
this.boardsAndTasksModel = new BoardsAndTasksModel(
this.storageModel,
this.settingsModel,
chatModel,
this
);
}
// utility
static generateFileContentId = (creationDate: string): string => {
return creationDate + v4();
};
static createFileContent = <T extends string>(
fileId: string,
type: T
): FileContent<T> => {
const creationDate: string = createTimestamp();
const fileContentId: string = FileModel.generateFileContentId(creationDate);
return {
dataVersion: DATA_VERSION,
fileId,
fileContentId,
creationDate,
type,
// paths
getBasePath = (): string[] => {
return StorageModel.getPath(
StorageModelSubPath.Chat,
filePaths.chat.files(this.chatModel.id),
);
};
getFileContainerPath = (): string[] => {
return [...this.getBasePath(), FileModelSubPath.Data];
};
getModelContainerPath = (modelName: FileModelSubPath): string[] => {
return [...this.getBasePath(), FileModelSubPath.Model, modelName];
};
getFilePath = (fileId: string): string[] => {
return [...this.getFileContainerPath(), fileId];
};
getFileContentPath = (fileId: string, fileContentId: string): string[] => {
const filePath: string[] = this.getFilePath(fileId);
return [...filePath, fileContentId];
};
// handlers
handleStringifiedFileContent = (stringifiedFileContent: string): void => {
const fileContent: FileContent<string> | null = parseValidObject(
stringifiedFileContent,
FileContentReference,
);
if (fileContent == null) return;
this.handleFileContent(fileContent);
};
handleFileContent = (fileContent: FileContent<string>): void => {
const didStore: boolean = this.storeFileContent(fileContent);
if (didStore == false) return;
this.boardsAndTasksModel.handleFileContent(fileContent);
};
// methods
addFileContentAndSend = (fileContent: FileContent<string>): void => {
this.handleFileContent(fileContent);
this.chatModel.sendMessage("", fileContent);
};
// storage
storeFileContent = (fileContent: FileContent<string>): boolean => {
const fileContentPath: string[] = this.getFileContentPath(
fileContent.fileId,
fileContent.fileContentId,
);
// check if fileContent already exists
const existingFileContent: string | null =
this.storageModel.read(fileContentPath);
if (existingFileContent != null) return false;
const stringifiedContent: string = stringify(fileContent);
this.storageModel.write(fileContentPath, stringifiedContent);
return true;
};
listFileIds = (): string[] => {
return this.storageModel.list(this.getBasePath());
};
listFileContentIds = (fileId: string): string[] => {
const filePath: string[] = this.getFilePath(fileId);
return this.storageModel.list(filePath);
};
selectLatestFileContentId = (
fileContentIds: string[],
): string | undefined => {
return fileContentIds[fileContentIds.length - 1];
};
getFileContent = <T extends FileContent<string>>(
fileId: string,
fileContentName: string,
reference: T,
): T | null => {
const filePath: string[] = this.getFileContentPath(
fileId,
fileContentName,
);
const fileContentOrNull: T | null = this.storageModel.readStringifiable(
filePath,
reference,
);
return fileContentOrNull;
};
getLatestFileContent = <T extends FileContent<string>>(
fileId: string,
reference: T,
): T | null => {
const fileContentsIds: string[] = this.listFileContentIds(fileId);
const latestFileContentId: string | undefined =
this.selectLatestFileContentId(fileContentsIds);
if (latestFileContentId == undefined) return null;
const fileContent: T | null = this.getFileContent(
fileId,
latestFileContentId,
reference,
);
return fileContent;
};
// init
constructor(
storageModel: StorageModel,
settingsModel: SettingsModel,
chatModel: ChatModel,
) {
this.chatModel = chatModel;
this.settingsModel = settingsModel;
this.storageModel = storageModel;
this.boardsAndTasksModel = new BoardsAndTasksModel(
this.storageModel,
this.settingsModel,
chatModel,
this,
);
}
// utility
static generateFileContentId = (creationDate: string): string => {
return creationDate + v4();
};
static createFileContent = <T extends string>(
fileId: string,
type: T,
): FileContent<T> => {
const creationDate: string = createTimestamp();
const fileContentId: string =
FileModel.generateFileContentId(creationDate);
return {
dataVersion: DATA_VERSION,
fileId,
fileContentId,
creationDate,
type,
};
};
};
}
// paths
export enum FileModelSubPath {
Data = "data",
Model = "model",
ModelView = "view",
ModelTask = "tasks",
ModelCalendar = "calendar",
Data = "data",
Model = "model",
ModelView = "view",
ModelTask = "tasks",
ModelCalendar = "calendar",
}
// types
export interface FileContent<T extends string>
extends ValidObject,
StringEntryObject {
fileId: string;
fileContentId: string;
creationDate: string;
extends ValidObject, StringEntryObject {
fileId: string;
fileContentId: string;
creationDate: string;
type: T;
type: T;
}
// references
export const FileContentReference: FileContent<string> = {
dataVersion: DATA_VERSION,
dataVersion: DATA_VERSION,
fileId: "",
fileContentId: "",
creationDate: "",
fileId: "",
fileContentId: "",
creationDate: "",
type: "",
type: "",
};