Compare commits
4 Commits
7e0e27c2b6
...
d641b01758
Author | SHA1 | Date | |
---|---|---|---|
|
d641b01758 | ||
|
20fe48974f | ||
|
398d243eac | ||
|
649bccb01e |
@ -3,12 +3,12 @@ import { Account } from "./ImapSync";
|
|||||||
import Imap from "imap";
|
import Imap from "imap";
|
||||||
import { getAllMailboxes, registerMailbox } from "../../db/imap/imap-db";
|
import { getAllMailboxes, registerMailbox } from "../../db/imap/imap-db";
|
||||||
import logger from "../../system/Logger";
|
import logger from "../../system/Logger";
|
||||||
import Box from "./Box";
|
import Mailbox from "./Mailbox";
|
||||||
|
|
||||||
export class ImapInstance {
|
export class ImapInstance {
|
||||||
imap: Imap;
|
imap: Imap;
|
||||||
account: Account;
|
account: Account;
|
||||||
boxes: Box[];
|
boxes: Mailbox[];
|
||||||
|
|
||||||
constructor(account) {
|
constructor(account) {
|
||||||
this.imap = new Imap({
|
this.imap = new Imap({
|
||||||
@ -44,13 +44,13 @@ export class ImapInstance {
|
|||||||
imapReady() {
|
imapReady() {
|
||||||
getAllMailboxes(this.account.id).then((mailboxes) => {
|
getAllMailboxes(this.account.id).then((mailboxes) => {
|
||||||
if (mailboxes.length > 0) {
|
if (mailboxes.length > 0) {
|
||||||
this.boxes.push(new Box(this.imap, mailboxes[0].mailbox_id, mailboxes[0].mailbox_name));
|
this.boxes.push(new Mailbox(this.imap, mailboxes[0].mailbox_id, mailboxes[0].mailbox_name));
|
||||||
} else {
|
} else {
|
||||||
this.imap.getBoxes("", (err, boxes) => {
|
this.imap.getBoxes("", (err, boxes) => {
|
||||||
if (err) logger.err(err);
|
if (err) logger.err(err);
|
||||||
const allBoxName = this.getAllBox(boxes);
|
const allBoxName = this.getAllBox(boxes);
|
||||||
registerMailbox(this.account.id, allBoxName).then((mailboxId) => {
|
registerMailbox(this.account.id, allBoxName).then((mailboxId) => {
|
||||||
this.boxes.push(new Box(this.imap, mailboxId, allBoxName));
|
this.boxes.push(new Mailbox(this.imap, mailboxId, allBoxName));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,47 +1,68 @@
|
|||||||
import Imap, { ImapMessageAttributes, MailBoxes } from "imap";
|
import Imap, { ImapMessageAttributes, Box } from "imap";
|
||||||
import { getMailbox, updateMailbox } from "../../db/imap/imap-db";
|
import { getMailbox, updateMailbox } from "../../db/imap/imap-db";
|
||||||
import { Attrs, AttrsWithEnvelope } from "../../interfaces/mail/attrs.interface";
|
import { Attrs, AttrsWithEnvelope } from "../../interfaces/mail/attrs.interface";
|
||||||
import logger from "../../system/Logger";
|
import logger from "../../system/Logger";
|
||||||
import RegisterMessageInApp from "../saveMessage";
|
import RegisterMessageInApp from "../saveMessage";
|
||||||
import { saveMessage } from "../storeMessage";
|
import { saveMessage } from "../storeMessage";
|
||||||
|
|
||||||
export default class Box {
|
export default class Mailbox {
|
||||||
imap: Imap;
|
imap: Imap;
|
||||||
boxName: string;
|
boxName: string;
|
||||||
id: number;
|
id: number;
|
||||||
box: MailBoxes;
|
box: Box;
|
||||||
|
msgToSync: number;
|
||||||
|
syncing: boolean;
|
||||||
|
|
||||||
constructor(_imap, _boxId, _boxName) {
|
constructor(_imap, _boxId, _boxName) {
|
||||||
this.imap = _imap;
|
this.imap = _imap;
|
||||||
this.boxName = _boxName;
|
this.boxName = _boxName;
|
||||||
this.id = _boxId;
|
this.id = _boxId;
|
||||||
this.box;
|
this.box;
|
||||||
|
this.msgToSync = 0;
|
||||||
|
this.syncing = false;
|
||||||
this.init();
|
this.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
async init() {
|
async init() {
|
||||||
|
// get mailbox from the database
|
||||||
this.box = (await getMailbox(this.id))[0];
|
this.box = (await getMailbox(this.id))[0];
|
||||||
|
|
||||||
const readOnly = true;
|
const readOnly = true;
|
||||||
this.imap.openBox(this.boxName, readOnly, (err, box) => {
|
this.imap.openBox(this.boxName, readOnly, (err, box) => {
|
||||||
if (err) logger.err(err);
|
if (err) logger.err(err);
|
||||||
this.sync(this.box.uidnext, box.uidnext);
|
|
||||||
|
// sync only if has new messages
|
||||||
|
if (this.box.uidnext < box.uidnext) {
|
||||||
|
this.sync(this.box.uidnext, box.uidnext);
|
||||||
|
} else {
|
||||||
|
logger.log("Already up to date")
|
||||||
|
}
|
||||||
|
|
||||||
|
this.imap.on("mail", (numNewMsgs: number) => {
|
||||||
|
if (!this.syncing) {
|
||||||
|
// if not syncing restart a sync
|
||||||
|
this.sync(this.box.uidnext, this.box.uidnext + numNewMsgs);
|
||||||
|
} else {
|
||||||
|
// else save number of message to sync latter
|
||||||
|
this.msgToSync += numNewMsgs;
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
sync(savedUid, currentUid) {
|
async sync(savedUid: number, currentUid: number) {
|
||||||
|
this.syncing = true;
|
||||||
const promises: Promise<unknown>[] = [];
|
const promises: Promise<unknown>[] = [];
|
||||||
const mails: Attrs[] = [];
|
const mails: Attrs[] = [];
|
||||||
logger.log(`Syncing from ${savedUid} to ${currentUid} uid`);
|
logger.log(`Syncing from ${savedUid} to ${currentUid} uid`);
|
||||||
const f = this.imap.seq.fetch(`${savedUid}:${currentUid}`, {
|
const f = this.imap.seq.fetch(`${savedUid}:${currentUid}`, {
|
||||||
// const f = this.imap.seq.fetch(`${savedUid}:${currentUid}`, {
|
|
||||||
size: true,
|
size: true,
|
||||||
envelope: true,
|
envelope: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
f.on("message", (msg, seqno) => {
|
f.on("message", (msg, seqno) => {
|
||||||
msg.once("attributes", (attrs: AttrsWithEnvelope) => {
|
msg.once("attributes", (attrs: AttrsWithEnvelope) => {
|
||||||
console.log(attrs.envelope)
|
console.log(attrs.envelope);
|
||||||
mails.push(attrs);
|
mails.push(attrs);
|
||||||
promises.push(saveMessage(attrs, this.id, this.imap));
|
promises.push(saveMessage(attrs, this.id, this.imap));
|
||||||
});
|
});
|
||||||
@ -53,7 +74,6 @@ export default class Box {
|
|||||||
|
|
||||||
f.once("end", async () => {
|
f.once("end", async () => {
|
||||||
let step = 20;
|
let step = 20;
|
||||||
logger.log(promises.length)
|
|
||||||
for (let i = 0; i < promises.length; i += step) {
|
for (let i = 0; i < promises.length; i += step) {
|
||||||
for (let j = i; j < (i + step && promises.length); j++) {
|
for (let j = i; j < (i + step && promises.length); j++) {
|
||||||
await new Promise((resolve, reject) => {
|
await new Promise((resolve, reject) => {
|
||||||
@ -72,6 +92,16 @@ export default class Box {
|
|||||||
updateMailbox(this.id, mails[i].uid);
|
updateMailbox(this.id, mails[i].uid);
|
||||||
}
|
}
|
||||||
updateMailbox(this.id, currentUid);
|
updateMailbox(this.id, currentUid);
|
||||||
|
this.syncing = false;
|
||||||
|
|
||||||
|
// if has receive new msg during last sync then start a new sync
|
||||||
|
if (this.msgToSync > 0) {
|
||||||
|
const currentUid = this.box.uidnext;
|
||||||
|
this.box.uidnext += this.msgToSync;
|
||||||
|
// reset value to allow to detect new incoming message while syncing
|
||||||
|
this.msgToSync = 0;
|
||||||
|
this.sync(currentUid, this.box.uidnext);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
114
front/package-lock.json
generated
114
front/package-lock.json
generated
@ -16,6 +16,7 @@
|
|||||||
"@babel/core": "^7.12.16",
|
"@babel/core": "^7.12.16",
|
||||||
"@babel/eslint-parser": "^7.12.16",
|
"@babel/eslint-parser": "^7.12.16",
|
||||||
"@babel/preset-typescript": "^7.21.4",
|
"@babel/preset-typescript": "^7.21.4",
|
||||||
|
"@types/dompurify": "^3.0.1",
|
||||||
"@types/jest": "^27.0.1",
|
"@types/jest": "^27.0.1",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.4.0",
|
"@typescript-eslint/eslint-plugin": "^5.4.0",
|
||||||
"@typescript-eslint/parser": "^5.4.0",
|
"@typescript-eslint/parser": "^5.4.0",
|
||||||
@ -2816,6 +2817,17 @@
|
|||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/dompurify": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://repo.plus4u.net/operatorGate/repository/public-javascript/@types/dompurify/-/dompurify-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-ubq8VKmf8W+U48jUOiZO4BoSGS7NnbITPMvrF+7HgMN4L+eezCKv8QBPB8p3o4YPicLMmNeTyDkE5X4c2ViHJQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/jsdom": "*",
|
||||||
|
"@types/trusted-types": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/eslint": {
|
"node_modules/@types/eslint": {
|
||||||
"version": "8.21.0",
|
"version": "8.21.0",
|
||||||
"resolved": "https://registry.npmmirror.com/@types/eslint/-/eslint-8.21.0.tgz",
|
"resolved": "https://registry.npmmirror.com/@types/eslint/-/eslint-8.21.0.tgz",
|
||||||
@ -2935,6 +2947,44 @@
|
|||||||
"pretty-format": "^27.0.0"
|
"pretty-format": "^27.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/jsdom": {
|
||||||
|
"version": "21.1.1",
|
||||||
|
"resolved": "https://repo.plus4u.net/operatorGate/repository/public-javascript/@types/jsdom/-/jsdom-21.1.1.tgz",
|
||||||
|
"integrity": "sha512-cZFuoVLtzKP3gmq9eNosUL1R50U+USkbLtUQ1bYVgl/lKp0FZM7Cq4aIHAL8oIvQ17uSHi7jXPtfDOdjPwBE7A==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "*",
|
||||||
|
"@types/tough-cookie": "*",
|
||||||
|
"parse5": "^7.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/jsdom/node_modules/entities": {
|
||||||
|
"version": "4.4.0",
|
||||||
|
"resolved": "https://repo.plus4u.net/operatorGate/repository/public-javascript/entities/-/entities-4.4.0.tgz",
|
||||||
|
"integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/jsdom/node_modules/parse5": {
|
||||||
|
"version": "7.1.2",
|
||||||
|
"resolved": "https://repo.plus4u.net/operatorGate/repository/public-javascript/parse5/-/parse5-7.1.2.tgz",
|
||||||
|
"integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"entities": "^4.4.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/inikulin/parse5?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/json-schema": {
|
"node_modules/@types/json-schema": {
|
||||||
"version": "7.0.11",
|
"version": "7.0.11",
|
||||||
"resolved": "https://registry.npmmirror.com/@types/json-schema/-/json-schema-7.0.11.tgz",
|
"resolved": "https://registry.npmmirror.com/@types/json-schema/-/json-schema-7.0.11.tgz",
|
||||||
@ -3064,6 +3114,20 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/tough-cookie": {
|
||||||
|
"version": "4.0.2",
|
||||||
|
"resolved": "https://repo.plus4u.net/operatorGate/repository/public-javascript/@types/tough-cookie/-/tough-cookie-4.0.2.tgz",
|
||||||
|
"integrity": "sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@types/trusted-types": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://repo.plus4u.net/operatorGate/repository/public-javascript/@types/trusted-types/-/trusted-types-2.0.3.tgz",
|
||||||
|
"integrity": "sha512-NfQ4gyz38SL8sDNrSixxU2Os1a5xcdFxipAFxYEuLUlvU2uDwS4NUpsImcf1//SlWItCVMMLiylsxbmNMToV/g==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@types/web-bluetooth": {
|
"node_modules/@types/web-bluetooth": {
|
||||||
"version": "0.0.16",
|
"version": "0.0.16",
|
||||||
"resolved": "https://repo.plus4u.net/operatorGate/repository/public-javascript/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz",
|
"resolved": "https://repo.plus4u.net/operatorGate/repository/public-javascript/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz",
|
||||||
@ -17897,6 +17961,16 @@
|
|||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/dompurify": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://repo.plus4u.net/operatorGate/repository/public-javascript/@types/dompurify/-/dompurify-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-ubq8VKmf8W+U48jUOiZO4BoSGS7NnbITPMvrF+7HgMN4L+eezCKv8QBPB8p3o4YPicLMmNeTyDkE5X4c2ViHJQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/jsdom": "*",
|
||||||
|
"@types/trusted-types": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/eslint": {
|
"@types/eslint": {
|
||||||
"version": "8.21.0",
|
"version": "8.21.0",
|
||||||
"resolved": "https://registry.npmmirror.com/@types/eslint/-/eslint-8.21.0.tgz",
|
"resolved": "https://registry.npmmirror.com/@types/eslint/-/eslint-8.21.0.tgz",
|
||||||
@ -18004,6 +18078,34 @@
|
|||||||
"pretty-format": "^27.0.0"
|
"pretty-format": "^27.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/jsdom": {
|
||||||
|
"version": "21.1.1",
|
||||||
|
"resolved": "https://repo.plus4u.net/operatorGate/repository/public-javascript/@types/jsdom/-/jsdom-21.1.1.tgz",
|
||||||
|
"integrity": "sha512-cZFuoVLtzKP3gmq9eNosUL1R50U+USkbLtUQ1bYVgl/lKp0FZM7Cq4aIHAL8oIvQ17uSHi7jXPtfDOdjPwBE7A==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/node": "*",
|
||||||
|
"@types/tough-cookie": "*",
|
||||||
|
"parse5": "^7.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"entities": {
|
||||||
|
"version": "4.4.0",
|
||||||
|
"resolved": "https://repo.plus4u.net/operatorGate/repository/public-javascript/entities/-/entities-4.4.0.tgz",
|
||||||
|
"integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"parse5": {
|
||||||
|
"version": "7.1.2",
|
||||||
|
"resolved": "https://repo.plus4u.net/operatorGate/repository/public-javascript/parse5/-/parse5-7.1.2.tgz",
|
||||||
|
"integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"entities": "^4.4.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/json-schema": {
|
"@types/json-schema": {
|
||||||
"version": "7.0.11",
|
"version": "7.0.11",
|
||||||
"resolved": "https://registry.npmmirror.com/@types/json-schema/-/json-schema-7.0.11.tgz",
|
"resolved": "https://registry.npmmirror.com/@types/json-schema/-/json-schema-7.0.11.tgz",
|
||||||
@ -18116,6 +18218,18 @@
|
|||||||
"integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==",
|
"integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@types/tough-cookie": {
|
||||||
|
"version": "4.0.2",
|
||||||
|
"resolved": "https://repo.plus4u.net/operatorGate/repository/public-javascript/@types/tough-cookie/-/tough-cookie-4.0.2.tgz",
|
||||||
|
"integrity": "sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"@types/trusted-types": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://repo.plus4u.net/operatorGate/repository/public-javascript/@types/trusted-types/-/trusted-types-2.0.3.tgz",
|
||||||
|
"integrity": "sha512-NfQ4gyz38SL8sDNrSixxU2Os1a5xcdFxipAFxYEuLUlvU2uDwS4NUpsImcf1//SlWItCVMMLiylsxbmNMToV/g==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"@types/web-bluetooth": {
|
"@types/web-bluetooth": {
|
||||||
"version": "0.0.16",
|
"version": "0.0.16",
|
||||||
"resolved": "https://repo.plus4u.net/operatorGate/repository/public-javascript/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz",
|
"resolved": "https://repo.plus4u.net/operatorGate/repository/public-javascript/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz",
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
"@babel/core": "^7.12.16",
|
"@babel/core": "^7.12.16",
|
||||||
"@babel/eslint-parser": "^7.12.16",
|
"@babel/eslint-parser": "^7.12.16",
|
||||||
"@babel/preset-typescript": "^7.21.4",
|
"@babel/preset-typescript": "^7.21.4",
|
||||||
|
"@types/dompurify": "^3.0.1",
|
||||||
"@types/jest": "^27.0.1",
|
"@types/jest": "^27.0.1",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.4.0",
|
"@typescript-eslint/eslint-plugin": "^5.4.0",
|
||||||
"@typescript-eslint/parser": "^5.4.0",
|
"@typescript-eslint/parser": "^5.4.0",
|
||||||
|
@ -8,5 +8,6 @@
|
|||||||
--tertiary-background: #2a2a33;
|
--tertiary-background: #2a2a33;
|
||||||
--quaternary-background: #303a46;
|
--quaternary-background: #303a46;
|
||||||
--selected: #41474f;
|
--selected: #41474f;
|
||||||
|
/* 343a46 */
|
||||||
}
|
}
|
||||||
/* .badge-primary { */
|
/* .badge-primary { */
|
27
front/src/components/User.vue
Normal file
27
front/src/components/User.vue
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { defineProps, PropType } from "vue";
|
||||||
|
import { Address } from "@/store/models/model";
|
||||||
|
import Badge from "./Badge.vue";
|
||||||
|
|
||||||
|
const props = defineProps({ address: Object as PropType<Address> });
|
||||||
|
const value = props.address?.name ? props.address?.name : props.address?.email;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="main">
|
||||||
|
{{ value }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.main {
|
||||||
|
align-items: center;
|
||||||
|
background-color: var(--quaternary-background);
|
||||||
|
border-radius: 1.6rem;
|
||||||
|
color: var(--primary-text);
|
||||||
|
display: inline-flex;
|
||||||
|
max-width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 0.1rem 0.4em;
|
||||||
|
}
|
||||||
|
</style>
|
@ -8,6 +8,8 @@ export enum RoomType {
|
|||||||
|
|
||||||
export interface Message {
|
export interface Message {
|
||||||
fromA: string;
|
fromA: string;
|
||||||
|
toA: string;
|
||||||
|
ccA?: string;
|
||||||
subject: string;
|
subject: string;
|
||||||
content: string;
|
content: string;
|
||||||
date: string;
|
date: string;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
export function removeDuplicates(array: []) {
|
export function removeDuplicates(array: any[]) {
|
||||||
const unique: [] = [];
|
const unique: any[] = [];
|
||||||
for (let i = 0; i < array.length; i++) {
|
for (let i = 0; i < array.length; i++) {
|
||||||
if (!unique.includes(array[i])) {
|
if (!unique.includes(array[i])) {
|
||||||
unique.push(array[i]);
|
unique.push(array[i]);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// todo optimize
|
// todo optimize
|
||||||
|
|
||||||
export function decodeEmojis(text: string): string {
|
export function decodeEmojis(text: string | undefined): string {
|
||||||
if (!text) return text;
|
if (!text) return "";
|
||||||
const regex = /\\u{([^}]+)}/g;
|
const regex = /\\u{([^}]+)}/g;
|
||||||
const decodedText = text.replace(regex, (_: string, hex: string) => String.fromCodePoint(parseInt(hex, 16)));
|
const decodedText = text.replace(regex, (_: string, hex: string) => String.fromCodePoint(parseInt(hex, 16)));
|
||||||
return decodedText;
|
return decodedText;
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { defineProps } from "vue";
|
import { defineProps, PropType } from "vue";
|
||||||
import Badge from "@/components/Badge.vue";
|
import Badge from "@/components/Badge.vue";
|
||||||
import { RoomType, Address } from "@/store/models/model";
|
import { RoomType, Address, Room } from "@/store/models/model";
|
||||||
import MemberList from "./MemberList.vue";
|
import MemberList from "./MemberList.vue";
|
||||||
|
|
||||||
const props = defineProps({ id: Number, room: Object });
|
const props = defineProps({ id: Number, room: Object as PropType<Room> });
|
||||||
|
|
||||||
const roomTitle = () => {
|
const roomTitle = () => {
|
||||||
const type = props.room?.roomType;
|
const type = props.room?.roomType;
|
||||||
@ -14,6 +14,7 @@ const roomTitle = () => {
|
|||||||
return props.room?.roomName;
|
return props.room?.roomName;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// todo remove us from list
|
||||||
const to = () => props.room?.members.filter((member: Address) => member.type == "to");
|
const to = () => props.room?.members.filter((member: Address) => member.type == "to");
|
||||||
const cc = () => props.room?.members.filter((member: Address) => member.type == "cc");
|
const cc = () => props.room?.members.filter((member: Address) => member.type == "cc");
|
||||||
</script>
|
</script>
|
||||||
@ -22,21 +23,20 @@ const cc = () => props.room?.members.filter((member: Address) => member.type ==
|
|||||||
<div class="main">
|
<div class="main">
|
||||||
<div class="context">
|
<div class="context">
|
||||||
<div class="infos">
|
<div class="infos">
|
||||||
<Badge :value="RoomType[room?.roomType]" />
|
<Badge :value="RoomType[room?.roomType ?? 0]" />
|
||||||
{{ roomTitle() }}
|
{{ roomTitle() }}
|
||||||
</div>
|
</div>
|
||||||
<div class="action">action: threads message important</div>
|
<div class="action">action: threads message important</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="members" v-if="room?.roomType != RoomType.DM">
|
<div class="members" v-if="room?.roomType != RoomType.DM">
|
||||||
<MemberList v-if="to()?.length > 0" type="to" :members="to()" />
|
<MemberList class="members-list" v-if="to()?.length ?? 0 > 0" type="to" :members="to()" />
|
||||||
<MemberList v-if="cc()?.length > 0" type="cc" :members="cc()" />
|
<MemberList class="members-list" v-if="cc()?.length ?? 0 > 0" type="cc" :members="cc()" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.main {
|
.main {
|
||||||
border-bottom: 1px solid #505050;
|
|
||||||
}
|
}
|
||||||
.context {
|
.context {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -48,6 +48,10 @@ const cc = () => props.room?.members.filter((member: Address) => member.type ==
|
|||||||
height: 35px;
|
height: 35px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.members-list {
|
||||||
|
padding: 3px 5px;
|
||||||
|
border-bottom: 1px solid #505050;
|
||||||
|
}
|
||||||
.members {
|
.members {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,19 +1,37 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import Badge from "@/components/Badge.vue";
|
||||||
|
import User from "@/components/User.vue";
|
||||||
import { Address } from "@/store/models/model";
|
import { Address } from "@/store/models/model";
|
||||||
import { defineProps } from "vue";
|
import { defineProps, PropType } from "vue";
|
||||||
|
|
||||||
const props = defineProps({ type: String, members: Object });
|
const props = defineProps({ type: String, members: Object as PropType<Address[]> });
|
||||||
let emails = "";
|
// const members: Address[] = [];
|
||||||
props.members?.forEach((member: Address) => {
|
|
||||||
emails += member.email + "; ";
|
// for (let i = 0; i < 4; i++) {
|
||||||
});
|
// if (!props.members) continue;
|
||||||
|
// members?.push(props?.members[0]);
|
||||||
|
// }
|
||||||
|
// todo deal with long list and responsive
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="main">
|
<div class="main">
|
||||||
{{ props.type }}:
|
<Badge :value="props.type + ': '" />
|
||||||
{{ emails }}
|
<div class="users">
|
||||||
|
<User class="user" v-for="(member, index) in props?.members" :key="index" :address="member" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped>
|
||||||
|
.main {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
.users {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user {
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@ -1,23 +1,19 @@
|
|||||||
<script setup>
|
<script setup lang="ts">
|
||||||
import { defineProps, onMounted, ref, watch } from "vue";
|
import { defineProps, onMounted, ref, watch, PropType, Prop } from "vue";
|
||||||
import { decodeEmojis } from "../../utils/string";
|
import { decodeEmojis } from "../../utils/string";
|
||||||
import { removeDuplicates } from "../../utils/array";
|
import { removeDuplicates } from "../../utils/array";
|
||||||
import DOMPurify from "dompurify";
|
import DOMPurify from "dompurify";
|
||||||
|
import { Address, Message } from "@/store/models/model";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
data: {
|
msg: Object as PropType<Message>,
|
||||||
fromA: String,
|
members: Array as PropType<Address[]>,
|
||||||
subject: String,
|
|
||||||
content: String,
|
|
||||||
date: String,
|
|
||||||
},
|
|
||||||
members: Array,
|
|
||||||
});
|
});
|
||||||
const iframe = ref(null);
|
const iframe = ref<HTMLIFrameElement>();
|
||||||
|
|
||||||
// todo dompurify
|
// todo dompurify
|
||||||
// background vs color
|
// background vs color
|
||||||
const htmlDefault = (html) => {
|
const htmlDefault = (html: string) => {
|
||||||
return `
|
return `
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
@ -34,8 +30,11 @@ const htmlDefault = (html) => {
|
|||||||
`;
|
`;
|
||||||
};
|
};
|
||||||
|
|
||||||
function setIframeContent(content) {
|
function setIframeContent(content: string | undefined) {
|
||||||
const doc = iframe.value.contentDocument || iframe.value.contentWindow.document;
|
if (!iframe.value) return;
|
||||||
|
if (!content) return;
|
||||||
|
const doc = iframe.value.contentDocument || iframe.value.contentWindow?.document;
|
||||||
|
if (!doc) return;
|
||||||
const html = DOMPurify.sanitize(content);
|
const html = DOMPurify.sanitize(content);
|
||||||
doc.open();
|
doc.open();
|
||||||
doc.write(htmlDefault(html));
|
doc.write(htmlDefault(html));
|
||||||
@ -43,21 +42,22 @@ function setIframeContent(content) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.data,
|
() => props.msg,
|
||||||
(newData) => {
|
(newData: Message | undefined) => {
|
||||||
setIframeContent(newData.content);
|
setIframeContent(newData?.content);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
setIframeContent(props.data.content);
|
setIframeContent(props.msg?.content);
|
||||||
});
|
});
|
||||||
|
|
||||||
const displayAddresses = (addressesId) => {
|
const displayAddresses = (addressIds: string[] | undefined): string => {
|
||||||
addressesId = removeDuplicates(addressesId);
|
if (!addressIds) return "";
|
||||||
|
addressIds = removeDuplicates(addressIds);
|
||||||
let res = "";
|
let res = "";
|
||||||
addressesId.forEach((addressId) => {
|
addressIds.forEach((addressId) => {
|
||||||
const address = props.members.find((member) => member.id == addressId);
|
const address = props.members?.find((member) => member.id === parseInt(addressId));
|
||||||
if (address) res += address.email;
|
if (address) res += address.email;
|
||||||
});
|
});
|
||||||
return res;
|
return res;
|
||||||
@ -72,24 +72,27 @@ const displayAddresses = (addressesId) => {
|
|||||||
<div class="message">
|
<div class="message">
|
||||||
<div id="context">
|
<div id="context">
|
||||||
<div class="left" id="profile">
|
<div class="left" id="profile">
|
||||||
{{ displayAddresses(props.data.fromA?.split(",")) }} - {{ props.data.fromA }}
|
{{ displayAddresses(props.msg?.fromA?.split(",")) }} - {{ props.msg?.fromA }}
|
||||||
</div>
|
</div>
|
||||||
<div class="middle">{{ decodeEmojis(props.data.subject) }}</div>
|
<div class="middle">{{ decodeEmojis(props.msg?.subject) }}</div>
|
||||||
<div class="right" id="date">
|
<div class="right" id="date">
|
||||||
{{
|
{{
|
||||||
new Date(props.data.date).toLocaleString("en-GB", {
|
new Date(props.msg?.date ?? "").toLocaleString("en-GB", {
|
||||||
weekday: "short",
|
weekday: "short",
|
||||||
year: "numeric",
|
year: "numeric",
|
||||||
month: "2-digit",
|
month: "2-digit",
|
||||||
day: "2-digit",
|
day: "2-digit",
|
||||||
hour: "2-digit",
|
hour: "2-digit",
|
||||||
minute: "2-digit",
|
minute: "2-digit",
|
||||||
timezone: "UTC+1",
|
timeZone: "Europe/Paris",
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<iframe ref="iframe"></iframe>
|
<div class="content">
|
||||||
|
<iframe ref="iframe"></iframe>
|
||||||
|
<div class="options">options</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -106,17 +109,7 @@ const displayAddresses = (addressesId) => {
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
background-color: var(--quaternary-background);
|
background-color: var(--quaternary-background);
|
||||||
padding: 3px 10px;
|
padding: 3px 10px;
|
||||||
margin-bottom: 6px;
|
border-radius: 4px 4px 0 0;
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
iframe {
|
|
||||||
overflow-y: auto;
|
|
||||||
max-height: 300px;
|
|
||||||
width: 100%;
|
|
||||||
border: none;
|
|
||||||
max-width: 600px; /* template width being 600px to 640px up to 750px (experiment and test) */
|
|
||||||
background-color: rgb(234, 234, 234);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.left,
|
.left,
|
||||||
@ -128,4 +121,26 @@ iframe {
|
|||||||
margin: 0 10px;
|
margin: 0 10px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
display: flex;
|
||||||
|
padding-top: 6px;
|
||||||
|
flex-direction: row;
|
||||||
|
/* background-color: #ec7a4342;
|
||||||
|
background-color: #353c6261; */
|
||||||
|
}
|
||||||
|
|
||||||
|
iframe {
|
||||||
|
overflow-y: auto;
|
||||||
|
max-height: 300px;
|
||||||
|
flex-basis: 100%;
|
||||||
|
border: none;
|
||||||
|
max-width: 600px; /* template width being 600px to 640px up to 750px (experiment and test) */
|
||||||
|
background-color: rgb(234, 234, 234);
|
||||||
|
}
|
||||||
|
|
||||||
|
.options {
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -1515,6 +1515,14 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@types/node" "*"
|
"@types/node" "*"
|
||||||
|
|
||||||
|
"@types/dompurify@^3.0.1":
|
||||||
|
version "3.0.1"
|
||||||
|
resolved "https://repo.plus4u.net/operatorGate/repository/public-javascript/@types/dompurify/-/dompurify-3.0.1.tgz"
|
||||||
|
integrity sha512-ubq8VKmf8W+U48jUOiZO4BoSGS7NnbITPMvrF+7HgMN4L+eezCKv8QBPB8p3o4YPicLMmNeTyDkE5X4c2ViHJQ==
|
||||||
|
dependencies:
|
||||||
|
"@types/jsdom" "*"
|
||||||
|
"@types/trusted-types" "*"
|
||||||
|
|
||||||
"@types/eslint-scope@^3.7.3":
|
"@types/eslint-scope@^3.7.3":
|
||||||
version "3.7.4"
|
version "3.7.4"
|
||||||
resolved "https://registry.npmmirror.com/@types/eslint-scope/-/eslint-scope-3.7.4.tgz"
|
resolved "https://registry.npmmirror.com/@types/eslint-scope/-/eslint-scope-3.7.4.tgz"
|
||||||
@ -1606,6 +1614,15 @@
|
|||||||
jest-matcher-utils "^27.0.0"
|
jest-matcher-utils "^27.0.0"
|
||||||
pretty-format "^27.0.0"
|
pretty-format "^27.0.0"
|
||||||
|
|
||||||
|
"@types/jsdom@*":
|
||||||
|
version "21.1.1"
|
||||||
|
resolved "https://repo.plus4u.net/operatorGate/repository/public-javascript/@types/jsdom/-/jsdom-21.1.1.tgz"
|
||||||
|
integrity sha512-cZFuoVLtzKP3gmq9eNosUL1R50U+USkbLtUQ1bYVgl/lKp0FZM7Cq4aIHAL8oIvQ17uSHi7jXPtfDOdjPwBE7A==
|
||||||
|
dependencies:
|
||||||
|
"@types/node" "*"
|
||||||
|
"@types/tough-cookie" "*"
|
||||||
|
parse5 "^7.0.0"
|
||||||
|
|
||||||
"@types/json-schema@*", "@types/json-schema@^7.0.4", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9":
|
"@types/json-schema@*", "@types/json-schema@^7.0.4", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9":
|
||||||
version "7.0.11"
|
version "7.0.11"
|
||||||
resolved "https://registry.npmmirror.com/@types/json-schema/-/json-schema-7.0.11.tgz"
|
resolved "https://registry.npmmirror.com/@types/json-schema/-/json-schema-7.0.11.tgz"
|
||||||
@ -1698,6 +1715,16 @@
|
|||||||
resolved "https://repo.plus4u.net/operatorGate/repository/public-javascript/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz"
|
resolved "https://repo.plus4u.net/operatorGate/repository/public-javascript/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz"
|
||||||
integrity sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==
|
integrity sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==
|
||||||
|
|
||||||
|
"@types/tough-cookie@*":
|
||||||
|
version "4.0.2"
|
||||||
|
resolved "https://repo.plus4u.net/operatorGate/repository/public-javascript/@types/tough-cookie/-/tough-cookie-4.0.2.tgz"
|
||||||
|
integrity sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw==
|
||||||
|
|
||||||
|
"@types/trusted-types@*":
|
||||||
|
version "2.0.3"
|
||||||
|
resolved "https://repo.plus4u.net/operatorGate/repository/public-javascript/@types/trusted-types/-/trusted-types-2.0.3.tgz"
|
||||||
|
integrity sha512-NfQ4gyz38SL8sDNrSixxU2Os1a5xcdFxipAFxYEuLUlvU2uDwS4NUpsImcf1//SlWItCVMMLiylsxbmNMToV/g==
|
||||||
|
|
||||||
"@types/web-bluetooth@^0.0.16":
|
"@types/web-bluetooth@^0.0.16":
|
||||||
version "0.0.16"
|
version "0.0.16"
|
||||||
resolved "https://repo.plus4u.net/operatorGate/repository/public-javascript/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz"
|
resolved "https://repo.plus4u.net/operatorGate/repository/public-javascript/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz"
|
||||||
@ -3797,6 +3824,11 @@ entities@^2.0.0:
|
|||||||
resolved "https://registry.npmmirror.com/entities/-/entities-2.2.0.tgz"
|
resolved "https://registry.npmmirror.com/entities/-/entities-2.2.0.tgz"
|
||||||
integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==
|
integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==
|
||||||
|
|
||||||
|
entities@^4.4.0:
|
||||||
|
version "4.4.0"
|
||||||
|
resolved "https://repo.plus4u.net/operatorGate/repository/public-javascript/entities/-/entities-4.4.0.tgz"
|
||||||
|
integrity sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==
|
||||||
|
|
||||||
error-ex@^1.3.1:
|
error-ex@^1.3.1:
|
||||||
version "1.3.2"
|
version "1.3.2"
|
||||||
resolved "https://registry.npmmirror.com/error-ex/-/error-ex-1.3.2.tgz"
|
resolved "https://registry.npmmirror.com/error-ex/-/error-ex-1.3.2.tgz"
|
||||||
@ -6301,6 +6333,13 @@ parse5@^6.0.1:
|
|||||||
resolved "https://registry.npmmirror.com/parse5/-/parse5-6.0.1.tgz"
|
resolved "https://registry.npmmirror.com/parse5/-/parse5-6.0.1.tgz"
|
||||||
integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==
|
integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==
|
||||||
|
|
||||||
|
parse5@^7.0.0:
|
||||||
|
version "7.1.2"
|
||||||
|
resolved "https://repo.plus4u.net/operatorGate/repository/public-javascript/parse5/-/parse5-7.1.2.tgz"
|
||||||
|
integrity sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==
|
||||||
|
dependencies:
|
||||||
|
entities "^4.4.0"
|
||||||
|
|
||||||
parse5@6.0.1:
|
parse5@6.0.1:
|
||||||
version "6.0.1"
|
version "6.0.1"
|
||||||
resolved "https://repo.plus4u.net/operatorGate/repository/public-javascript/parse5/-/parse5-6.0.1.tgz"
|
resolved "https://repo.plus4u.net/operatorGate/repository/public-javascript/parse5/-/parse5-6.0.1.tgz"
|
||||||
|
Loading…
Reference in New Issue
Block a user