add upgrader to migrate data from old version

This commit is contained in:
marlon-erler
2024-07-27 00:33:42 +02:00
parent 1a1649bbb9
commit 78040b2d16
8 changed files with 551 additions and 12 deletions
+222 -3
View File
@@ -325,7 +325,7 @@
const stringEntryObjectValue = stringEntryObject[referenceKey]; const stringEntryObjectValue = stringEntryObject[referenceKey];
if (referenceValue == void 0) return false; if (referenceValue == void 0) return false;
if (referenceValue[0] == "-") { if (referenceValue[0] == "-") {
const strippedReferenceValue = referenceValue.substring(1); const strippedReferenceValue = referenceValue.toString().substring(1);
if (strippedReferenceValue == "" && stringEntryObjectValue != void 0 && stringEntryObjectValue != "") { if (strippedReferenceValue == "" && stringEntryObjectValue != void 0 && stringEntryObjectValue != "") {
return false; return false;
} }
@@ -352,7 +352,7 @@
const stringEntryObjectValue = stringEntryObject[key]; const stringEntryObjectValue = stringEntryObject[key];
if (stringEntryObjectValue == void 0 || stringEntryObjectValue == "") if (stringEntryObjectValue == void 0 || stringEntryObjectValue == "")
continue; continue;
values.add(stringEntryObjectValue); values.add(stringEntryObjectValue.toString());
} }
return [...values.values()]; return [...values.values()];
} }
@@ -361,7 +361,7 @@
const stringsInObject = getStringsOfObject(object); const stringsInObject = getStringsOfObject(object);
const wordsInObject = []; const wordsInObject = [];
for (const string of stringsInObject) { for (const string of stringsInObject) {
const lowercaseWordsInString = string.toLocaleLowerCase().split(" ").filter((word) => word != ""); const lowercaseWordsInString = string.toString().toLowerCase().split(" ").filter((word) => word != "");
wordsInObject.push(...lowercaseWordsInString); wordsInObject.push(...lowercaseWordsInString);
} }
const lowercaseWordsInQuery = query.toLowerCase().split(" ").filter((word) => word != ""); const lowercaseWordsInQuery = query.toLowerCase().split(" ").filter((word) => word != "");
@@ -418,6 +418,12 @@
this.itemToString = itemToString; this.itemToString = itemToString;
} }
}; };
function getLocalStorageItemAndClear(key) {
const value = localStorage.getItem(key);
localStorage.removeItem(key);
console.log(localStorage.getItem(key));
return value;
}
function stringify(data) { function stringify(data) {
return JSON.stringify(data, null, 4); return JSON.stringify(data, null, 4);
} }
@@ -441,6 +447,18 @@
if (doesMatchReference == false) return null; if (doesMatchReference == false) return null;
return parsed; return parsed;
} }
function parseOrFallback(inputString) {
try {
return JSON.parse(inputString);
} catch {
return inputString;
}
}
function parseArray(inputString) {
const parsed = parseOrFallback(inputString);
if (Array.isArray(parsed) == false) return [];
return parsed;
}
function localeCompare(a, b) { function localeCompare(a, b) {
return a.localeCompare(b); return a.localeCompare(b);
} }
@@ -2446,6 +2464,9 @@
// src/View/translations.ts // src/View/translations.ts
var englishTranslations = { var englishTranslations = {
updater: {
migrated: "Migrated"
},
general: { general: {
deleteItemButtonAudioLabel: "delete item", deleteItemButtonAudioLabel: "delete item",
searchButtonAudioLabel: "search", searchButtonAudioLabel: "search",
@@ -4634,6 +4655,203 @@
}; };
}; };
// src/Upgrader/v1.ts
var v1Upgrader = class {
// init
constructor(settingsModel2, connectionModel2, chatListModel2) {
this.settingsModel = settingsModel2;
this.connectionModel = connectionModel2;
this.chatListModel = chatListModel2;
this.migrateSettings();
this.migrateConnections();
this.migrateChats();
}
// general
migrateSettings = () => {
const name = getLocalStorageItemAndClear("sender-name");
if (name != null) {
const parsedName = parseOrFallback(name);
this.settingsModel.setName(parsedName);
}
const firstDayOfWeek = getLocalStorageItemAndClear("first-day-of-week");
if (firstDayOfWeek != null) {
const parsedFirstDayOfWeek = parseOrFallback(firstDayOfWeek);
this.settingsModel.setFirstDayOfWeek(parsedFirstDayOfWeek);
}
};
migrateConnections = () => {
const previousAddressString = getLocalStorageItemAndClear("previous-addresses");
if (previousAddressString == null) return;
const previousAddresses = parseArray(previousAddressString);
for (const address of previousAddresses) {
if (typeof address != "string") continue;
this.connectionModel.storeAddress(address);
}
};
// chats
migrateChats = () => {
const chatIdString = getLocalStorageItemAndClear("chat-ids");
if (chatIdString == null) return;
const chatIds = parseArray(chatIdString);
for (const chatId of chatIds) {
if (typeof chatId != "string") continue;
this.migrateChatById(chatId);
}
};
migrateChatById = (id) => {
const primaryChannel = getLocalStorageItemAndClear(
storageKeys.primaryChannel(id)
);
if (primaryChannel == null) return;
const parsedPriamryChannel = parseOrFallback(primaryChannel);
const chatModel = this.chatListModel.createChat(parsedPriamryChannel);
const secondaryChannelString = getLocalStorageItemAndClear(
storageKeys.secondaryChannels(id)
);
if (secondaryChannelString != null) {
const potentialSecondaryChannels = parseArray(
secondaryChannelString
);
const confirmedSecondaryChannels = [];
for (const secondaryChannel of potentialSecondaryChannels) {
if (typeof secondaryChannel != "string") continue;
confirmedSecondaryChannels.push(secondaryChannel);
}
chatModel.setSecondaryChannels(confirmedSecondaryChannels);
}
const encryptionKey = getLocalStorageItemAndClear(
storageKeys.encyptionKey(id)
);
if (encryptionKey != null) {
const parsedEncryptionKey = parseOrFallback(encryptionKey);
chatModel.setEncryptionKey(parsedEncryptionKey);
}
const messagesString = getLocalStorageItemAndClear(storageKeys.messages(id)) ?? "";
const messageOutboxString = getLocalStorageItemAndClear(storageKeys.outbox(id)) ?? "";
const potentialMessages = parseArray(messagesString);
const potentialMessagesInOutbox = parseArray(messageOutboxString);
const addMessages = (potentialMessages2, status) => {
for (const potentialMessage of potentialMessages2) {
const isV1ChatMessage = checkMatchesObjectStructure(
potentialMessage,
V1ChatMessageReference
);
if (isV1ChatMessage == false) continue;
const v1ChatMessage = potentialMessage;
const convertedChatMessage = {
dataVersion: "v2",
id: v4_default(),
channel: v1ChatMessage.channel,
sender: v1ChatMessage.sender,
body: v1ChatMessage.body,
dateSent: v1ChatMessage.isoDate,
status,
stringifiedFile: ""
};
chatModel.addMessage(convertedChatMessage);
if (status == "outbox" /* Outbox */) {
this.connectionModel.sendMessageOrStore(convertedChatMessage);
}
}
};
addMessages(potentialMessages, "received" /* Received */);
addMessages(potentialMessagesInOutbox, "outbox" /* Outbox */);
const objectsString = getLocalStorageItemAndClear(storageKeys.objects(id)) ?? "";
const objectOutboxString = getLocalStorageItemAndClear(storageKeys.itemOutbox(id)) ?? "";
const potentialObjects = parseArray(objectsString);
const potentialObjectsInOutbox = parseArray(objectOutboxString);
const addObjects = (potentialObjects2) => {
const board = chatModel.fileModel.boardsAndTasksModel.createBoard(
translations.updater.migrated
);
chatModel.fileModel.boardsAndTasksModel.updateBoard(board);
for (const potentialObjectEntry of potentialObjects2) {
const potentialObject = potentialObjectEntry[1];
const isV1MessageObject = checkIsV1MessageObject(potentialObject);
if (isV1MessageObject == false) continue;
const objectId = potentialObject.id;
const objectName = potentialObject.title;
const contentVersions = Object.values(
potentialObject.contentVersions
);
for (const potentialVersion of contentVersions) {
const isV1MessageObjectContent = checkIsV1MessageObjectContent(potentialVersion);
if (isV1MessageObjectContent == false) continue;
const convertedTaskFileContent = {
dataVersion: "v2",
fileId: objectId,
fileContentId: FileModel2.generateFileContentId(
potentialVersion.isoDateVersionCreated
),
creationDate: potentialVersion.isoDateVersionCreated,
type: "task",
name: objectName ?? "",
boardId: board.fileId ?? "",
description: potentialVersion.noteContent ?? "",
category: potentialVersion.categoryName ?? "",
status: potentialVersion.status ?? "",
priority: potentialVersion.priority ?? "",
date: potentialVersion.date ?? "",
time: potentialVersion.time ?? ""
};
console.log(convertedTaskFileContent);
chatModel.fileModel.handleFileContent(convertedTaskFileContent);
}
}
};
addObjects([...potentialObjects, ...potentialObjectsInOutbox]);
};
};
var storageKeys = {
viewType(id) {
return id + "view-type";
},
hasUnread(id) {
return id + "has-unread-messages";
},
primaryChannel(id) {
return id + "primary-channel";
},
secondaryChannels(id) {
return id + "secondary-channels";
},
encyptionKey(id) {
return id + "encryption-key";
},
messages(id) {
return id + "messages";
},
objects(id) {
return id + "items";
},
outbox(id) {
return id + "outbox";
},
itemOutbox(id) {
return id + "item-outbox";
},
composingMessage(id) {
return id + "composing-message";
}
};
var V1ChatMessageReference = {
channel: "",
sender: "",
body: "",
isoDate: ""
};
function checkIsV1MessageObject(object) {
if (object.id == void 0) return false;
if (object.title == void 0) return false;
if (object.contentVersions == void 0) return false;
return true;
}
function checkIsV1MessageObjectContent(object) {
if (object.id == void 0) return false;
if (object.isoDateVersionCreated == void 0) return false;
return true;
}
// src/index.tsx // src/index.tsx
var storageModel = new StorageModel(); var storageModel = new StorageModel();
var settingsModel = new SettingsModel(storageModel); var settingsModel = new SettingsModel(storageModel);
@@ -4643,6 +4861,7 @@
settingsModel, settingsModel,
connectionModel connectionModel
); );
new v1Upgrader(settingsModel, connectionModel, chatListModel);
var coreVieWModel = new CoreViewModel(); var coreVieWModel = new CoreViewModel();
var storageViewModel = new StorageViewModel(coreVieWModel, storageModel); var storageViewModel = new StorageViewModel(coreVieWModel, storageModel);
var settingsViewModel = new SettingsViewModel(coreVieWModel, settingsModel); var settingsViewModel = new SettingsViewModel(coreVieWModel, settingsModel);
+1
View File
@@ -316,6 +316,7 @@ export enum ChatMessageStatus {
Outbox = "outbox", Outbox = "outbox",
Sent = "sent", Sent = "sent",
Received = "received", Received = "received",
Other = "other",
} }
export interface ChatMessage extends ValidObject { export interface ChatMessage extends ValidObject {
+1 -1
View File
@@ -154,7 +154,7 @@ export default class FileModel {
} }
// utility // utility
static generateFileContentId = (creationDate): string => { static generateFileContentId = (creationDate: string): string => {
return creationDate + v4(); return creationDate + v4();
}; };
+1 -1
View File
@@ -1,7 +1,7 @@
// this file is responsible for managing UDN connections. // this file is responsible for managing UDN connections.
import { ChatMessage, ChatMessageReference } from "../Chat/chatModel"; import { ChatMessage, ChatMessageReference } from "../Chat/chatModel";
import { Handler, HandlerManager, stringify } from "../Utility/utility"; import { HandlerManager, stringify } from "../Utility/utility";
import StorageModel, { StorageModelSubPath, filePaths } from "./storageModel"; import StorageModel, { StorageModelSubPath, filePaths } from "./storageModel";
import UDNFrontend, { Message } from "udn-frontend"; import UDNFrontend, { Message } from "udn-frontend";
+37 -7
View File
@@ -1,12 +1,16 @@
import { checkIsValidObject, checkMatchesObjectStructure } from "./typeSafety"; import { checkIsValidObject, checkMatchesObjectStructure } from "./typeSafety";
export interface Stringifiable {
toString(): string;
}
// date // date
export function createTimestamp(): string { export function createTimestamp(): string {
return new Date().toISOString(); return new Date().toISOString();
} }
// filters etc // filters etc
export type StringEntryObject = { [key: string]: string | undefined }; export type StringEntryObject = { [key: string]: Stringifiable | undefined };
export function filterObjectsByStringEntries<T>( export function filterObjectsByStringEntries<T>(
reference: StringEntryObject, reference: StringEntryObject,
@@ -34,13 +38,15 @@ export function checkDoesObjectMatchReference(
reference reference
)) { )) {
const [referenceKey, referenceValue] = referenceEntry; const [referenceKey, referenceValue] = referenceEntry;
const stringEntryObjectValue: string | undefined = const stringEntryObjectValue: Stringifiable | undefined =
stringEntryObject[referenceKey]; stringEntryObject[referenceKey];
if (referenceValue == undefined) return false; if (referenceValue == undefined) return false;
if (referenceValue[0] == "-") { if (referenceValue[0] == "-") {
const strippedReferenceValue: string = referenceValue.substring(1); const strippedReferenceValue: string = referenceValue
.toString()
.substring(1);
// property may not exist // property may not exist
if ( if (
strippedReferenceValue == "" && strippedReferenceValue == "" &&
@@ -83,11 +89,12 @@ export function collectObjectValuesForKey<T>(
for (const object of objects) { for (const object of objects) {
const stringEntryObject: StringEntryObject = converter(object); const stringEntryObject: StringEntryObject = converter(object);
const stringEntryObjectValue: string | undefined = stringEntryObject[key]; const stringEntryObjectValue: Stringifiable | undefined =
stringEntryObject[key];
if (stringEntryObjectValue == undefined || stringEntryObjectValue == "") if (stringEntryObjectValue == undefined || stringEntryObjectValue == "")
continue; continue;
values.add(stringEntryObjectValue); values.add(stringEntryObjectValue.toString());
} }
return [...values.values()]; return [...values.values()];
@@ -123,7 +130,8 @@ export function checkDoesObjectMatchSearch<T>(
const wordsInObject: string[] = []; const wordsInObject: string[] = [];
for (const string of stringsInObject) { for (const string of stringsInObject) {
const lowercaseWordsInString = string const lowercaseWordsInString = string
.toLocaleLowerCase() .toString()
.toLowerCase()
.split(" ") .split(" ")
.filter((word) => word != ""); .filter((word) => word != "");
wordsInObject.push(...lowercaseWordsInString); wordsInObject.push(...lowercaseWordsInString);
@@ -204,7 +212,15 @@ export class IndexManager<T> {
} }
} }
// string // storage
export function getLocalStorageItemAndClear(key: string): string | null {
const value: string | null = localStorage.getItem(key);
localStorage.removeItem(key);
console.log(localStorage.getItem(key));
return value;
}
// string & parsing
export function stringify(data: any): string { export function stringify(data: any): string {
return JSON.stringify(data, null, 4); return JSON.stringify(data, null, 4);
} }
@@ -234,6 +250,20 @@ export function parseValidObject<T>(string: string, reference: T): T | null {
return parsed; return parsed;
} }
export function parseOrFallback(inputString: string): any {
try {
return JSON.parse(inputString);
} catch {
return inputString;
}
}
export function parseArray(inputString: string): any[] {
const parsed: any = parseOrFallback(inputString);
if (Array.isArray(parsed) == false) return [];
return parsed;
}
// sort // sort
export function localeCompare(a: string, b: string): number { export function localeCompare(a: string, b: string): number {
return a.localeCompare(b); return a.localeCompare(b);
+281
View File
@@ -0,0 +1,281 @@
// this file is responsible for migrating data from v1 to v2.
import {
BoardInfoFileContent,
TaskFileContent,
} from "../Model/Files/boardsAndTasksModel";
import ChatModel, {
ChatMessage,
ChatMessageStatus,
} from "../Model/Chat/chatModel";
import { getLocalStorageItemAndClear, parseArray, parseOrFallback } from "../Model/Utility/utility";
import ChatListModel from "../Model/Chat/chatListModel";
import ConnectionModel from "../Model/Global/connectionModel";
import FileModel from "../Model/Files/fileModel";
import SettingsModel from "../Model/Global/settingsModel";
import { checkMatchesObjectStructure } from "../Model/Utility/typeSafety";
import { translations } from "../View/translations";
import { v4 } from "uuid";
export default class v1Upgrader {
// general
migrateSettings = (): void => {
const name: string | null = getLocalStorageItemAndClear("sender-name");
if (name != null) {
const parsedName: string = parseOrFallback(name);
this.settingsModel.setName(parsedName);
}
const firstDayOfWeek: string | null =
getLocalStorageItemAndClear("first-day-of-week");
if (firstDayOfWeek != null) {
const parsedFirstDayOfWeek: string = parseOrFallback(firstDayOfWeek);
this.settingsModel.setFirstDayOfWeek(parsedFirstDayOfWeek);
}
};
migrateConnections = (): void => {
const previousAddressString: string | null =
getLocalStorageItemAndClear("previous-addresses");
if (previousAddressString == null) return;
const previousAddresses: any[] = parseArray(previousAddressString);
for (const address of previousAddresses) {
if (typeof address != "string") continue;
this.connectionModel.storeAddress(address);
}
};
// chats
migrateChats = (): void => {
const chatIdString: string | null = getLocalStorageItemAndClear("chat-ids");
if (chatIdString == null) return;
const chatIds: any[] = parseArray(chatIdString);
for (const chatId of chatIds) {
if (typeof chatId != "string") continue;
this.migrateChatById(chatId);
}
};
migrateChatById = (id: string): void => {
// get primary channel
const primaryChannel: string | null = getLocalStorageItemAndClear(
storageKeys.primaryChannel(id)
);
if (primaryChannel == null) return;
const parsedPriamryChannel: string = parseOrFallback(primaryChannel);
// create chat
const chatModel: ChatModel =
this.chatListModel.createChat(parsedPriamryChannel);
// secondary channels
const secondaryChannelString: string | null = getLocalStorageItemAndClear(
storageKeys.secondaryChannels(id)
);
if (secondaryChannelString != null) {
const potentialSecondaryChannels: any[] = parseArray(
secondaryChannelString
);
const confirmedSecondaryChannels: string[] = [];
for (const secondaryChannel of potentialSecondaryChannels) {
if (typeof secondaryChannel != "string") continue;
confirmedSecondaryChannels.push(secondaryChannel);
}
chatModel.setSecondaryChannels(confirmedSecondaryChannels);
}
// encryption key
const encryptionKey: string | null = getLocalStorageItemAndClear(
storageKeys.encyptionKey(id)
);
if (encryptionKey != null) {
const parsedEncryptionKey: string = parseOrFallback(encryptionKey);
chatModel.setEncryptionKey(parsedEncryptionKey);
}
// messages
const messagesString: string =
getLocalStorageItemAndClear(storageKeys.messages(id)) ?? "";
const messageOutboxString: string =
getLocalStorageItemAndClear(storageKeys.outbox(id)) ?? "";
const potentialMessages: any[] = parseArray(messagesString);
const potentialMessagesInOutbox: any[] = parseArray(messageOutboxString);
const addMessages = (
potentialMessages: any[],
status: ChatMessageStatus
) => {
for (const potentialMessage of potentialMessages) {
const isV1ChatMessage: boolean = checkMatchesObjectStructure(
potentialMessage,
V1ChatMessageReference
);
if (isV1ChatMessage == false) continue;
const v1ChatMessage: typeof V1ChatMessageReference = potentialMessage;
const convertedChatMessage: ChatMessage = {
dataVersion: "v2",
id: v4(),
channel: v1ChatMessage.channel,
sender: v1ChatMessage.sender,
body: v1ChatMessage.body,
dateSent: v1ChatMessage.isoDate,
status,
stringifiedFile: "",
};
chatModel.addMessage(convertedChatMessage);
if (status == ChatMessageStatus.Outbox) {
this.connectionModel.sendMessageOrStore(convertedChatMessage);
}
}
};
addMessages(potentialMessages, ChatMessageStatus.Received);
addMessages(potentialMessagesInOutbox, ChatMessageStatus.Outbox);
// objects
const objectsString: string =
getLocalStorageItemAndClear(storageKeys.objects(id)) ?? "";
const objectOutboxString: string =
getLocalStorageItemAndClear(storageKeys.itemOutbox(id)) ?? "";
const potentialObjects: any[] = parseArray(objectsString);
const potentialObjectsInOutbox: any[] = parseArray(objectOutboxString);
const addObjects = (potentialObjects: any[]): void => {
const board: BoardInfoFileContent =
chatModel.fileModel.boardsAndTasksModel.createBoard(
translations.updater.migrated
);
chatModel.fileModel.boardsAndTasksModel.updateBoard(board);
for (const potentialObjectEntry of potentialObjects) {
const potentialObject = potentialObjectEntry[1];
const isV1MessageObject: boolean =
checkIsV1MessageObject(potentialObject);
if (isV1MessageObject == false) continue;
const objectId: string = potentialObject.id;
const objectName: string = potentialObject.title;
const contentVersions: any[] = Object.values(
potentialObject.contentVersions
);
for (const potentialVersion of contentVersions) {
const isV1MessageObjectContent: boolean =
checkIsV1MessageObjectContent(potentialVersion);
if (isV1MessageObjectContent == false) continue;
const convertedTaskFileContent: TaskFileContent = {
dataVersion: "v2",
fileId: objectId,
fileContentId: FileModel.generateFileContentId(
potentialVersion.isoDateVersionCreated
),
creationDate: potentialVersion.isoDateVersionCreated,
type: "task",
name: objectName ?? "",
boardId: board.fileId ?? "",
description: potentialVersion.noteContent ?? "",
category: potentialVersion.categoryName ?? "",
status: potentialVersion.status ?? "",
priority: potentialVersion.priority ?? "",
date: potentialVersion.date ?? "",
time: potentialVersion.time ?? "",
};
console.log(convertedTaskFileContent);
chatModel.fileModel.handleFileContent(convertedTaskFileContent);
}
}
};
addObjects([...potentialObjects, ...potentialObjectsInOutbox]);
};
// init
constructor(
public settingsModel: SettingsModel,
public connectionModel: ConnectionModel,
public chatListModel: ChatListModel
) {
this.migrateSettings();
this.migrateConnections();
this.migrateChats();
}
}
const storageKeys = {
viewType(id: string): string {
return id + "view-type";
},
hasUnread(id: string): string {
return id + "has-unread-messages";
},
primaryChannel(id: string): string {
return id + "primary-channel";
},
secondaryChannels(id: string): string {
return id + "secondary-channels";
},
encyptionKey(id: string): string {
return id + "encryption-key";
},
messages(id: string): string {
return id + "messages";
},
objects(id: string): string {
return id + "items";
},
outbox(id: string): string {
return id + "outbox";
},
itemOutbox(id: string): string {
return id + "item-outbox";
},
composingMessage(id: string): string {
return id + "composing-message";
},
};
const V1ChatMessageReference = {
channel: "",
sender: "",
body: "",
isoDate: "",
};
function checkIsV1MessageObject(object: any): boolean {
if (object.id == undefined) return false;
if (object.title == undefined) return false;
if (object.contentVersions == undefined) return false;
return true;
}
function checkIsV1MessageObjectContent(object: any): boolean {
if (object.id == undefined) return false;
if (object.isoDateVersionCreated == undefined) return false;
return true;
}
+4
View File
@@ -1,4 +1,8 @@
const englishTranslations = { const englishTranslations = {
updater: {
migrated: "Migrated",
},
general: { general: {
deleteItemButtonAudioLabel: "delete item", deleteItemButtonAudioLabel: "delete item",
searchButtonAudioLabel: "search", searchButtonAudioLabel: "search",
+4
View File
@@ -17,6 +17,7 @@ import SettingsViewModel from "./ViewModel/Global/settingsViewModel";
import { StorageModal } from "./View/Modals/storageModal"; import { StorageModal } from "./View/Modals/storageModal";
import StorageModel from "./Model/Global/storageModel"; import StorageModel from "./Model/Global/storageModel";
import StorageViewModel from "./ViewModel/Global/storageViewModel"; import StorageViewModel from "./ViewModel/Global/storageViewModel";
import v1Upgrader from "./Upgrader/v1";
// models // models
const storageModel = new StorageModel(); const storageModel = new StorageModel();
@@ -28,6 +29,9 @@ const chatListModel = new ChatListModel(
connectionModel connectionModel
); );
// upgrade
new v1Upgrader(settingsModel, connectionModel, chatListModel);
// viewModels // viewModels
const coreVieWModel = new CoreViewModel(); const coreVieWModel = new CoreViewModel();