fix: update dependencies and improve email view layout in OpsViewEmails component
This commit is contained in:
@ -29,7 +29,7 @@
|
||||
"@api.global/typedserver": "^3.0.74",
|
||||
"@api.global/typedsocket": "^3.0.0",
|
||||
"@apiclient.xyz/cloudflare": "^6.4.1",
|
||||
"@design.estate/dees-catalog": "^1.8.4",
|
||||
"@design.estate/dees-catalog": "^1.8.8",
|
||||
"@design.estate/dees-element": "^2.0.42",
|
||||
"@push.rocks/projectinfo": "^5.0.1",
|
||||
"@push.rocks/qenv": "^6.1.0",
|
||||
@ -41,11 +41,11 @@
|
||||
"@push.rocks/smartjwt": "^2.2.1",
|
||||
"@push.rocks/smartlog": "^3.1.8",
|
||||
"@push.rocks/smartmail": "^2.1.0",
|
||||
"@push.rocks/smartmetrics": "^2.0.9",
|
||||
"@push.rocks/smartmetrics": "^2.0.10",
|
||||
"@push.rocks/smartnetwork": "^4.0.2",
|
||||
"@push.rocks/smartpath": "^5.0.5",
|
||||
"@push.rocks/smartpromise": "^4.0.3",
|
||||
"@push.rocks/smartproxy": "^19.6.2",
|
||||
"@push.rocks/smartproxy": "^19.6.6",
|
||||
"@push.rocks/smartrequest": "^2.1.0",
|
||||
"@push.rocks/smartrule": "^2.0.1",
|
||||
"@push.rocks/smartrx": "^3.0.10",
|
||||
|
70
pnpm-lock.yaml
generated
70
pnpm-lock.yaml
generated
@ -24,8 +24,8 @@ importers:
|
||||
specifier: ^6.4.1
|
||||
version: 6.4.1
|
||||
'@design.estate/dees-catalog':
|
||||
specifier: ^1.8.4
|
||||
version: 1.8.4
|
||||
specifier: ^1.8.8
|
||||
version: 1.8.8
|
||||
'@design.estate/dees-element':
|
||||
specifier: ^2.0.42
|
||||
version: 2.0.42
|
||||
@ -60,8 +60,8 @@ importers:
|
||||
specifier: ^2.1.0
|
||||
version: 2.1.0
|
||||
'@push.rocks/smartmetrics':
|
||||
specifier: ^2.0.9
|
||||
version: 2.0.9
|
||||
specifier: ^2.0.10
|
||||
version: 2.0.10
|
||||
'@push.rocks/smartnetwork':
|
||||
specifier: ^4.0.2
|
||||
version: 4.0.2
|
||||
@ -72,8 +72,8 @@ importers:
|
||||
specifier: ^4.0.3
|
||||
version: 4.2.3
|
||||
'@push.rocks/smartproxy':
|
||||
specifier: ^19.6.2
|
||||
version: 19.6.2(@aws-sdk/credential-providers@3.817.0)(socks@2.8.4)
|
||||
specifier: ^19.6.6
|
||||
version: 19.6.6(@aws-sdk/credential-providers@3.817.0)(socks@2.8.4)
|
||||
'@push.rocks/smartrequest':
|
||||
specifier: ^2.1.0
|
||||
version: 2.1.0
|
||||
@ -344,8 +344,8 @@ packages:
|
||||
'@dabh/diagnostics@2.0.3':
|
||||
resolution: {integrity: sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==}
|
||||
|
||||
'@design.estate/dees-catalog@1.8.4':
|
||||
resolution: {integrity: sha512-G5N9CUzhWhTt3NuHbix4yyB/Fz1fqO2gTO1OoBffu5DTA1keJlOCvyBaUbgwjmZWnBBMN1O6r8cUhYIHcf4SJg==}
|
||||
'@design.estate/dees-catalog@1.8.8':
|
||||
resolution: {integrity: sha512-so0Jju95vZGsNUKi/ze1bHoK1LOgkCuU+xeiWDMfUpGkJA8OE9wPJmy5hSyIecc352JtlhOkgmTh/XxFTGpkQg==}
|
||||
|
||||
'@design.estate/dees-comms@1.0.27':
|
||||
resolution: {integrity: sha512-GvzTUwkV442LD60T08iqSoqvhA02Mou5lFvvqBPc4yBUiU7cZISqBx+76xvMgMIEI9Dx9JfTl4/2nW8MoVAanw==}
|
||||
@ -356,8 +356,8 @@ packages:
|
||||
'@design.estate/dees-element@2.0.42':
|
||||
resolution: {integrity: sha512-1PzHP6q/PtSiu4P0nCxjSeHtRHn62zoSouMy8JFW2h29FT/CSDVaTUAUqYqnvwE/U98aLNivWTmerZitDF7kBQ==}
|
||||
|
||||
'@design.estate/dees-wcctools@1.0.90':
|
||||
resolution: {integrity: sha512-EHYWHiOe+P261e9fBbOBmkD7lIsOpD+tu4VZQr20oc8vhsFjeUGJqYeBm/Ghwg+Gck/dto+K9zyJNIyQ642cEw==}
|
||||
'@design.estate/dees-wcctools@1.0.98':
|
||||
resolution: {integrity: sha512-6EolTGBiXgF1wgr+KOeSXAIKpXqU95FU4vOJYPPEvb+e3ebFXCuL/B4UTFZYG3e1KuTZgxiaJ04L8ejm5HfTZA==}
|
||||
|
||||
'@esbuild/aix-ppc64@0.24.2':
|
||||
resolution: {integrity: sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==}
|
||||
@ -713,6 +713,14 @@ packages:
|
||||
resolution: {integrity: sha512-mfOoUlIw8VBiJYPrl5RZfMzkXC/z7gbSpi2ecycrj/gRWLq2CMV+Q+0G+JPjeOmuNFgg0skEIzkVFzVYFP6URw==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
|
||||
'@isaacs/balanced-match@4.0.1':
|
||||
resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==}
|
||||
engines: {node: 20 || >=22}
|
||||
|
||||
'@isaacs/brace-expansion@5.0.0':
|
||||
resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==}
|
||||
engines: {node: 20 || >=22}
|
||||
|
||||
'@isaacs/cliui@8.0.2':
|
||||
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
|
||||
engines: {node: '>=12'}
|
||||
@ -1017,8 +1025,8 @@ packages:
|
||||
'@push.rocks/smartmatch@2.0.0':
|
||||
resolution: {integrity: sha512-MBzP++1yNIBeox71X6VxpIgZ8m4bXnJpZJ4nWVH6IWpmO38MXTu4X0QF8tQnyT4LFcwvc9iiWaD15cstHa7Mmw==}
|
||||
|
||||
'@push.rocks/smartmetrics@2.0.9':
|
||||
resolution: {integrity: sha512-3rKHItgIL4Pt/kFH12qCmTxsnB2EcBgO6H0MYe9dPjDI7yl7IDiLzZg2Abp4q9LEPVw009ATJsxklPQSNqI5gQ==}
|
||||
'@push.rocks/smartmetrics@2.0.10':
|
||||
resolution: {integrity: sha512-Fr4ZzJWFqTR67ThmPsj+uUfPoWZ+p87n7wItpXVjlQ2mf4pboWnsfmrrC1gqIXca1Dwa2i7L+GPoJ3hOZ+Qhfw==}
|
||||
|
||||
'@push.rocks/smartmime@1.0.6':
|
||||
resolution: {integrity: sha512-PHd+I4UcsnOATNg8wjDsSAmmJ4CwQFrQCNzd0HSJMs4ZpiK3Ya91almd6GLpDPU370U4HFh4FaPF4eEAI6vkJQ==}
|
||||
@ -1062,8 +1070,8 @@ packages:
|
||||
'@push.rocks/smartpromise@4.2.3':
|
||||
resolution: {integrity: sha512-Ycg/TJR+tMt+S3wSFurOpEoW6nXv12QBtKXgBcjMZ4RsdO28geN46U09osPn9N9WuwQy1PkmTV5J/V4F9U8qEw==}
|
||||
|
||||
'@push.rocks/smartproxy@19.6.2':
|
||||
resolution: {integrity: sha512-k7kmVqJLnCrm435U/NLyWWP0sJ5O61zHRk1RtPZbtrfMvLGO06b0Rjt5xh/UgdceKtvhol0kheibdfOL7vgOuw==}
|
||||
'@push.rocks/smartproxy@19.6.6':
|
||||
resolution: {integrity: sha512-AweTvBYlYubelO+g6Bf/4cg8RXb0fcMgYE1UKAT/m5PNbOuRWzTtXkja4JuFWfIdvmbfZxiWAaw9OhJvHIgIrw==}
|
||||
|
||||
'@push.rocks/smartpuppeteer@2.0.5':
|
||||
resolution: {integrity: sha512-yK/qSeWVHIGWRp3c8S5tfdGP6WCKllZC4DR8d8CQlEjszOSBmHtlTdyyqOMBZ/BA4kd+eU5f3A1r4K2tGYty1g==}
|
||||
@ -3090,8 +3098,8 @@ packages:
|
||||
resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
lucide@0.514.0:
|
||||
resolution: {integrity: sha512-GQ3Rzj1qFANBvTmhe8RM3vR491RGnSjHsivA5wSuEj5taLwH1Sv4N7n6ae3ENGsYRzdrkVXZo4ieUbD1WOXmoA==}
|
||||
lucide@0.515.0:
|
||||
resolution: {integrity: sha512-n7tFK3R1HdsxwM5rMOa6twAi/4RGZCysc7dmk7Cr2GiOUcnHX0+MX9xw3xynpbekXCgS4+o9HeIWhBl3rZHIAA==}
|
||||
|
||||
mailauth@4.8.6:
|
||||
resolution: {integrity: sha512-Ler6XMLCrXyCf3kmNOMA/1aUJN6let/w9HBtjl+2KzXOUxKIl4WPJM1FwqC4IHdVJO8kmHUrvyFIKIiEGj6mvg==}
|
||||
@ -3312,6 +3320,10 @@ packages:
|
||||
resolution: {integrity: sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==}
|
||||
engines: {node: 20 || >=22}
|
||||
|
||||
minimatch@10.0.3:
|
||||
resolution: {integrity: sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==}
|
||||
engines: {node: 20 || >=22}
|
||||
|
||||
minimatch@3.1.2:
|
||||
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
|
||||
|
||||
@ -5075,11 +5087,11 @@ snapshots:
|
||||
enabled: 2.0.0
|
||||
kuler: 2.0.0
|
||||
|
||||
'@design.estate/dees-catalog@1.8.4':
|
||||
'@design.estate/dees-catalog@1.8.8':
|
||||
dependencies:
|
||||
'@design.estate/dees-domtools': 2.3.2
|
||||
'@design.estate/dees-element': 2.0.42
|
||||
'@design.estate/dees-wcctools': 1.0.90
|
||||
'@design.estate/dees-wcctools': 1.0.98
|
||||
'@fortawesome/fontawesome-svg-core': 6.7.2
|
||||
'@fortawesome/free-brands-svg-icons': 6.7.2
|
||||
'@fortawesome/free-regular-svg-icons': 6.7.2
|
||||
@ -5092,7 +5104,7 @@ snapshots:
|
||||
apexcharts: 4.7.0
|
||||
highlight.js: 11.11.1
|
||||
ibantools: 4.5.1
|
||||
lucide: 0.514.0
|
||||
lucide: 0.515.0
|
||||
monaco-editor: 0.52.2
|
||||
pdfjs-dist: 4.10.38
|
||||
xterm: 5.3.0
|
||||
@ -5148,7 +5160,7 @@ snapshots:
|
||||
- supports-color
|
||||
- vue
|
||||
|
||||
'@design.estate/dees-wcctools@1.0.90':
|
||||
'@design.estate/dees-wcctools@1.0.98':
|
||||
dependencies:
|
||||
'@design.estate/dees-domtools': 2.3.2
|
||||
'@design.estate/dees-element': 2.0.42
|
||||
@ -5454,6 +5466,12 @@ snapshots:
|
||||
dependencies:
|
||||
happy-dom: 15.11.7
|
||||
|
||||
'@isaacs/balanced-match@4.0.1': {}
|
||||
|
||||
'@isaacs/brace-expansion@5.0.0':
|
||||
dependencies:
|
||||
'@isaacs/balanced-match': 4.0.1
|
||||
|
||||
'@isaacs/cliui@8.0.2':
|
||||
dependencies:
|
||||
string-width: 5.1.2
|
||||
@ -6092,7 +6110,7 @@ snapshots:
|
||||
dependencies:
|
||||
matcher: 5.0.0
|
||||
|
||||
'@push.rocks/smartmetrics@2.0.9':
|
||||
'@push.rocks/smartmetrics@2.0.10':
|
||||
dependencies:
|
||||
'@push.rocks/smartdelay': 3.0.5
|
||||
'@push.rocks/smartlog': 3.1.8
|
||||
@ -6221,7 +6239,7 @@ snapshots:
|
||||
|
||||
'@push.rocks/smartpromise@4.2.3': {}
|
||||
|
||||
'@push.rocks/smartproxy@19.6.2(@aws-sdk/credential-providers@3.817.0)(socks@2.8.4)':
|
||||
'@push.rocks/smartproxy@19.6.6(@aws-sdk/credential-providers@3.817.0)(socks@2.8.4)':
|
||||
dependencies:
|
||||
'@push.rocks/lik': 6.2.2
|
||||
'@push.rocks/smartacme': 8.0.0(@aws-sdk/credential-providers@3.817.0)(socks@2.8.4)
|
||||
@ -6238,7 +6256,7 @@ snapshots:
|
||||
'@tsclass/tsclass': 9.2.0
|
||||
'@types/minimatch': 5.1.2
|
||||
'@types/ws': 8.18.1
|
||||
minimatch: 10.0.1
|
||||
minimatch: 10.0.3
|
||||
pretty-ms: 9.2.0
|
||||
ws: 8.18.2
|
||||
transitivePeerDependencies:
|
||||
@ -8776,7 +8794,7 @@ snapshots:
|
||||
|
||||
lru-cache@7.18.3: {}
|
||||
|
||||
lucide@0.514.0: {}
|
||||
lucide@0.515.0: {}
|
||||
|
||||
mailauth@4.8.6:
|
||||
dependencies:
|
||||
@ -9189,6 +9207,10 @@ snapshots:
|
||||
dependencies:
|
||||
brace-expansion: 2.0.1
|
||||
|
||||
minimatch@10.0.3:
|
||||
dependencies:
|
||||
'@isaacs/brace-expansion': 5.0.0
|
||||
|
||||
minimatch@3.1.2:
|
||||
dependencies:
|
||||
brace-expansion: 1.1.11
|
||||
|
@ -94,15 +94,19 @@ export class OpsViewEmails extends DeesElement {
|
||||
|
||||
.searchBox {
|
||||
flex: 1;
|
||||
min-width: 200px;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
.emailList {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.emailPreview {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: white;
|
||||
border: 1px solid #e9ecef;
|
||||
border-radius: 8px;
|
||||
@ -110,89 +114,51 @@ export class OpsViewEmails extends DeesElement {
|
||||
}
|
||||
|
||||
.emailHeader {
|
||||
padding: 20px;
|
||||
padding: 24px;
|
||||
border-bottom: 1px solid #e9ecef;
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
.emailSubject {
|
||||
font-size: 20px;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 12px;
|
||||
margin-bottom: 16px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.emailMeta {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.emailMetaRow {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.emailMetaLabel {
|
||||
font-weight: 600;
|
||||
min-width: 60px;
|
||||
}
|
||||
|
||||
.emailBody {
|
||||
padding: 20px;
|
||||
max-height: 500px;
|
||||
flex: 1;
|
||||
padding: 24px;
|
||||
overflow-y: auto;
|
||||
font-size: 15px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.emailActions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
padding: 16px;
|
||||
padding: 16px 24px;
|
||||
border-top: 1px solid #e9ecef;
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
.composeModal {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.composeContent {
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
width: 90%;
|
||||
max-width: 800px;
|
||||
max-height: 90vh;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.composeHeader {
|
||||
padding: 20px;
|
||||
border-bottom: 1px solid #e9ecef;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.composeTitle {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.composeForm {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.composeActions {
|
||||
padding: 20px;
|
||||
border-top: 1px solid #e9ecef;
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.emptyState {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@ -220,63 +186,77 @@ export class OpsViewEmails extends DeesElement {
|
||||
|
||||
<div class="emailContainer">
|
||||
<!-- Sidebar -->
|
||||
<div class="sidebar">
|
||||
<dees-button @click=${() => this.showCompose = true} type="highlighted">
|
||||
<dees-windowbox>
|
||||
<dees-button @click=${() => this.openComposeModal()} type="highlighted" style="width: 100%;">
|
||||
<dees-icon name="penToSquare" slot="iconSlot"></dees-icon>
|
||||
Compose
|
||||
</dees-button>
|
||||
|
||||
<div class="folderList">
|
||||
${this.renderFolderItem('inbox', 'inbox', 'Inbox', this.getEmailCount('inbox'))}
|
||||
${this.renderFolderItem('sent', 'paperPlane', 'Sent', this.getEmailCount('sent'))}
|
||||
${this.renderFolderItem('draft', 'file', 'Drafts', this.getEmailCount('draft'))}
|
||||
${this.renderFolderItem('trash', 'trash', 'Trash', this.getEmailCount('trash'))}
|
||||
</div>
|
||||
</div>
|
||||
<dees-menu style="margin-top: 16px;">
|
||||
<dees-menu-item
|
||||
.active=${this.selectedFolder === 'inbox'}
|
||||
@click=${() => this.selectFolder('inbox')}
|
||||
.iconName=${'inbox'}
|
||||
.label=${'Inbox'}
|
||||
.badgeText=${this.getEmailCount('inbox') > 0 ? String(this.getEmailCount('inbox')) : ''}
|
||||
></dees-menu-item>
|
||||
<dees-menu-item
|
||||
.active=${this.selectedFolder === 'sent'}
|
||||
@click=${() => this.selectFolder('sent')}
|
||||
.iconName=${'paperPlane'}
|
||||
.label=${'Sent'}
|
||||
.badgeText=${this.getEmailCount('sent') > 0 ? String(this.getEmailCount('sent')) : ''}
|
||||
></dees-menu-item>
|
||||
<dees-menu-item
|
||||
.active=${this.selectedFolder === 'draft'}
|
||||
@click=${() => this.selectFolder('draft')}
|
||||
.iconName=${'file'}
|
||||
.label=${'Drafts'}
|
||||
.badgeText=${this.getEmailCount('draft') > 0 ? String(this.getEmailCount('draft')) : ''}
|
||||
></dees-menu-item>
|
||||
<dees-menu-item
|
||||
.active=${this.selectedFolder === 'trash'}
|
||||
@click=${() => this.selectFolder('trash')}
|
||||
.iconName=${'trash'}
|
||||
.label=${'Trash'}
|
||||
.badgeText=${this.getEmailCount('trash') > 0 ? String(this.getEmailCount('trash')) : ''}
|
||||
></dees-menu-item>
|
||||
</dees-menu>
|
||||
</dees-windowbox>
|
||||
|
||||
<!-- Main Content -->
|
||||
<div class="mainContent">
|
||||
<!-- Toolbar -->
|
||||
<div class="emailToolbar">
|
||||
<dees-input-text
|
||||
class="searchBox"
|
||||
placeholder="Search emails..."
|
||||
.value=${this.searchTerm}
|
||||
@input=${(e: Event) => this.searchTerm = (e.target as any).value}
|
||||
>
|
||||
<dees-icon name="magnifyingGlass" slot="iconSlot"></dees-icon>
|
||||
</dees-input-text>
|
||||
|
||||
<dees-button @click=${() => this.refreshEmails()}>
|
||||
${this.isLoading ? html`<dees-spinner size="small"></dees-spinner>` : html`<dees-icon name="arrowsRotate"></dees-icon>`}
|
||||
</dees-button>
|
||||
|
||||
<dees-button @click=${() => this.markAllAsRead()}>
|
||||
<dees-icon name="envelopeOpen"></dees-icon>
|
||||
Mark all read
|
||||
</dees-button>
|
||||
</div>
|
||||
|
||||
<!-- Email List or Preview -->
|
||||
${this.selectedEmail ? this.renderEmailPreview() : this.renderEmailList()}
|
||||
${this.selectedEmail ? this.renderEmailPreview() : this.renderEmailListView()}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Compose Modal -->
|
||||
${this.showCompose ? this.renderComposeModal() : ''}
|
||||
`;
|
||||
}
|
||||
|
||||
private renderFolderItem(folder: string, icon: string, label: string, count: number) {
|
||||
private renderEmailListView() {
|
||||
return html`
|
||||
<div
|
||||
class="folderItem ${this.selectedFolder === folder ? 'selected' : ''}"
|
||||
@click=${() => this.selectFolder(folder as any)}
|
||||
>
|
||||
<dees-icon class="folderIcon" name="${icon}"></dees-icon>
|
||||
<span class="folderLabel">${label}</span>
|
||||
${count > 0 ? html`<span class="folderCount">${count}</span>` : ''}
|
||||
<!-- Toolbar -->
|
||||
<div class="emailToolbar">
|
||||
<dees-input-text
|
||||
class="searchBox"
|
||||
placeholder="Search emails..."
|
||||
.value=${this.searchTerm}
|
||||
@input=${(e: Event) => this.searchTerm = (e.target as any).value}
|
||||
>
|
||||
<dees-icon name="magnifyingGlass" slot="iconSlot"></dees-icon>
|
||||
</dees-input-text>
|
||||
|
||||
<dees-button @click=${() => this.refreshEmails()}>
|
||||
${this.isLoading ? html`<dees-spinner size="small"></dees-spinner>` : html`<dees-icon name="arrowsRotate"></dees-icon>`}
|
||||
</dees-button>
|
||||
|
||||
<dees-button @click=${() => this.markAllAsRead()}>
|
||||
<dees-icon name="envelopeOpen"></dees-icon>
|
||||
Mark all read
|
||||
</dees-button>
|
||||
</div>
|
||||
|
||||
<!-- Email List -->
|
||||
${this.renderEmailList()}
|
||||
`;
|
||||
}
|
||||
|
||||
@ -293,58 +273,58 @@ export class OpsViewEmails extends DeesElement {
|
||||
}
|
||||
|
||||
return html`
|
||||
<div class="emailList">
|
||||
<dees-table
|
||||
.data=${filteredEmails}
|
||||
.displayFunction=${(email: IEmail) => ({
|
||||
'Status': html`<dees-icon name="${email.read ? 'envelopeOpen' : 'envelope'}" style="color: ${email.read ? '#999' : '#1976d2'}"></dees-icon>`,
|
||||
From: email.from,
|
||||
Subject: html`<strong style="${!email.read ? 'font-weight: 600' : ''}">${email.subject}</strong>`,
|
||||
Date: this.formatDate(email.date),
|
||||
'Attach': html`
|
||||
${email.attachments?.length ? html`<dees-icon name="paperclip" style="color: #666"></dees-icon>` : ''}
|
||||
`,
|
||||
})}
|
||||
.dataActions=${[
|
||||
{
|
||||
name: 'Read',
|
||||
iconName: 'eye',
|
||||
type: ['doubleClick', 'inRow'],
|
||||
actionFunc: async (actionData) => {
|
||||
this.selectedEmail = actionData.item;
|
||||
if (!actionData.item.read) {
|
||||
this.markAsRead(actionData.item.id);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Reply',
|
||||
iconName: 'reply',
|
||||
type: ['contextmenu'],
|
||||
actionFunc: async (actionData) => {
|
||||
this.replyToEmail(actionData.item);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Forward',
|
||||
iconName: 'share',
|
||||
type: ['contextmenu'],
|
||||
actionFunc: async (actionData) => {
|
||||
this.forwardEmail(actionData.item);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Delete',
|
||||
iconName: 'trash',
|
||||
type: ['contextmenu'],
|
||||
actionFunc: async (actionData) => {
|
||||
this.deleteEmail(actionData.item.id);
|
||||
<dees-table
|
||||
.data=${filteredEmails}
|
||||
.displayFunction=${(email: IEmail) => ({
|
||||
'Status': html`<dees-icon name="${email.read ? 'envelopeOpen' : 'envelope'}" style="color: ${email.read ? '#999' : '#1976d2'}"></dees-icon>`,
|
||||
From: email.from,
|
||||
Subject: html`<strong style="${!email.read ? 'font-weight: 600' : ''}">${email.subject}</strong>`,
|
||||
Date: this.formatDate(email.date),
|
||||
'Attach': html`
|
||||
${email.attachments?.length ? html`<dees-icon name="paperclip" style="color: #666"></dees-icon>` : ''}
|
||||
`,
|
||||
})}
|
||||
.dataActions=${[
|
||||
{
|
||||
name: 'Read',
|
||||
iconName: 'eye',
|
||||
type: ['doubleClick', 'inRow'],
|
||||
actionFunc: async (actionData) => {
|
||||
this.selectedEmail = actionData.item;
|
||||
if (!actionData.item.read) {
|
||||
this.markAsRead(actionData.item.id);
|
||||
}
|
||||
}
|
||||
]}
|
||||
.selectionMode=${'single'}
|
||||
></dees-table>
|
||||
</div>
|
||||
},
|
||||
{
|
||||
name: 'Reply',
|
||||
iconName: 'reply',
|
||||
type: ['contextmenu'],
|
||||
actionFunc: async (actionData) => {
|
||||
this.replyToEmail(actionData.item);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Forward',
|
||||
iconName: 'share',
|
||||
type: ['contextmenu'],
|
||||
actionFunc: async (actionData) => {
|
||||
this.forwardEmail(actionData.item);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Delete',
|
||||
iconName: 'trash',
|
||||
type: ['contextmenu'],
|
||||
actionFunc: async (actionData) => {
|
||||
this.deleteEmail(actionData.item.id);
|
||||
}
|
||||
}
|
||||
]}
|
||||
.selectionMode=${'single'}
|
||||
heading1=${this.selectedFolder.charAt(0).toUpperCase() + this.selectedFolder.slice(1)}
|
||||
heading2=${`${filteredEmails.length} emails`}
|
||||
></dees-table>
|
||||
`;
|
||||
}
|
||||
|
||||
@ -356,114 +336,136 @@ export class OpsViewEmails extends DeesElement {
|
||||
<div class="emailHeader">
|
||||
<div class="emailSubject">${this.selectedEmail.subject}</div>
|
||||
<div class="emailMeta">
|
||||
<span><strong>From:</strong> ${this.selectedEmail.from}</span>
|
||||
<span><strong>To:</strong> ${this.selectedEmail.to.join(', ')}</span>
|
||||
<span><strong>Date:</strong> ${this.formatDate(this.selectedEmail.date)}</span>
|
||||
<div class="emailMetaRow">
|
||||
<span class="emailMetaLabel">From:</span>
|
||||
<span>${this.selectedEmail.from}</span>
|
||||
</div>
|
||||
<div class="emailMetaRow">
|
||||
<span class="emailMetaLabel">To:</span>
|
||||
<span>${this.selectedEmail.to.join(', ')}</span>
|
||||
</div>
|
||||
${this.selectedEmail.cc?.length ? html`
|
||||
<div class="emailMetaRow">
|
||||
<span class="emailMetaLabel">CC:</span>
|
||||
<span>${this.selectedEmail.cc.join(', ')}</span>
|
||||
</div>
|
||||
` : ''}
|
||||
<div class="emailMetaRow">
|
||||
<span class="emailMetaLabel">Date:</span>
|
||||
<span>${new Date(this.selectedEmail.date).toLocaleString()}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="emailBody">
|
||||
${this.selectedEmail.html ?
|
||||
html`<div .innerHTML=${this.selectedEmail.html}></div>` :
|
||||
html`<pre style="white-space: pre-wrap; font-family: inherit;">${this.selectedEmail.body}</pre>`
|
||||
html`<div style="white-space: pre-wrap;">${this.selectedEmail.body}</div>`
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="emailActions">
|
||||
<dees-button @click=${() => this.selectedEmail = null}>
|
||||
<dees-icon name="arrowLeft"></dees-icon>
|
||||
Back
|
||||
</dees-button>
|
||||
<dees-button @click=${() => this.replyToEmail(this.selectedEmail!)}>
|
||||
<dees-icon name="reply"></dees-icon>
|
||||
Reply
|
||||
</dees-button>
|
||||
<dees-button @click=${() => this.replyAllToEmail(this.selectedEmail!)}>
|
||||
<dees-icon name="replyAll"></dees-icon>
|
||||
Reply All
|
||||
</dees-button>
|
||||
<dees-button @click=${() => this.forwardEmail(this.selectedEmail!)}>
|
||||
<dees-icon name="share"></dees-icon>
|
||||
Forward
|
||||
</dees-button>
|
||||
<dees-button @click=${() => this.deleteEmail(this.selectedEmail!.id)} type="danger">
|
||||
<dees-icon name="trash"></dees-icon>
|
||||
Delete
|
||||
<dees-button @click=${() => this.selectedEmail = null} type="secondary">
|
||||
<dees-icon name="arrowLeft" slot="iconSlot"></dees-icon>
|
||||
Back to List
|
||||
</dees-button>
|
||||
<div style="margin-left: auto; display: flex; gap: 8px;">
|
||||
<dees-button @click=${() => this.replyToEmail(this.selectedEmail!)}>
|
||||
<dees-icon name="reply" slot="iconSlot"></dees-icon>
|
||||
Reply
|
||||
</dees-button>
|
||||
<dees-button @click=${() => this.replyAllToEmail(this.selectedEmail!)}>
|
||||
<dees-icon name="replyAll" slot="iconSlot"></dees-icon>
|
||||
Reply All
|
||||
</dees-button>
|
||||
<dees-button @click=${() => this.forwardEmail(this.selectedEmail!)}>
|
||||
<dees-icon name="share" slot="iconSlot"></dees-icon>
|
||||
Forward
|
||||
</dees-button>
|
||||
<dees-button @click=${() => this.deleteEmail(this.selectedEmail!.id)} type="danger">
|
||||
<dees-icon name="trash" slot="iconSlot"></dees-icon>
|
||||
Delete
|
||||
</dees-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
private renderComposeModal() {
|
||||
return html`
|
||||
<div class="composeModal" @click=${(e: Event) => {
|
||||
if (e.target === e.currentTarget) this.showCompose = false;
|
||||
}}>
|
||||
<div class="composeContent">
|
||||
<div class="composeHeader">
|
||||
<div class="composeTitle">New Email</div>
|
||||
<dees-button @click=${() => this.showCompose = false} type="ghost">
|
||||
<dees-icon name="xmark"></dees-icon>
|
||||
</dees-button>
|
||||
</div>
|
||||
|
||||
<div class="composeForm">
|
||||
<dees-form @formData=${(e: CustomEvent) => this.sendEmail(e.detail)}>
|
||||
<dees-input-tags
|
||||
key="to"
|
||||
label="To"
|
||||
placeholder="Enter recipient email addresses..."
|
||||
required
|
||||
></dees-input-tags>
|
||||
|
||||
<dees-input-tags
|
||||
key="cc"
|
||||
label="CC"
|
||||
placeholder="Enter CC recipients..."
|
||||
></dees-input-tags>
|
||||
|
||||
<dees-input-tags
|
||||
key="bcc"
|
||||
label="BCC"
|
||||
placeholder="Enter BCC recipients..."
|
||||
></dees-input-tags>
|
||||
|
||||
<dees-input-text
|
||||
key="subject"
|
||||
label="Subject"
|
||||
placeholder="Enter email subject..."
|
||||
required
|
||||
></dees-input-text>
|
||||
|
||||
<dees-editor
|
||||
key="body"
|
||||
label="Message"
|
||||
.mode=${'markdown'}
|
||||
.height=${300}
|
||||
required
|
||||
></dees-editor>
|
||||
|
||||
<dees-input-fileupload
|
||||
key="attachments"
|
||||
label="Attachments"
|
||||
multiple
|
||||
></dees-input-fileupload>
|
||||
|
||||
<div class="composeActions">
|
||||
<dees-button @click=${() => this.showCompose = false} type="secondary">
|
||||
Cancel
|
||||
</dees-button>
|
||||
<dees-form-submit>
|
||||
<dees-icon name="paperPlane"></dees-icon>
|
||||
Send Email
|
||||
</dees-form-submit>
|
||||
</div>
|
||||
</dees-form>
|
||||
</div>
|
||||
private async openComposeModal(replyTo?: IEmail, replyAll = false, forward = false) {
|
||||
const { DeesModal } = await import('@design.estate/dees-catalog');
|
||||
|
||||
await DeesModal.createAndShow({
|
||||
heading: forward ? 'Forward Email' : replyTo ? 'Reply to Email' : 'New Email',
|
||||
content: html`
|
||||
<div style="width: 700px; max-width: 90vw;">
|
||||
<dees-form @formData=${async (e: CustomEvent) => {
|
||||
await this.sendEmail(e.detail);
|
||||
// Close modal after sending
|
||||
const modals = document.querySelectorAll('dees-modal');
|
||||
modals.forEach(m => (m as any).destroy?.());
|
||||
}}>
|
||||
<dees-input-tags
|
||||
key="to"
|
||||
label="To"
|
||||
placeholder="Enter recipient email addresses..."
|
||||
.value=${replyTo ? (replyAll ? [replyTo.from, ...replyTo.to].filter((v, i, a) => a.indexOf(v) === i) : [replyTo.from]) : []}
|
||||
required
|
||||
></dees-input-tags>
|
||||
|
||||
<dees-input-tags
|
||||
key="cc"
|
||||
label="CC"
|
||||
placeholder="Enter CC recipients..."
|
||||
.value=${replyAll && replyTo?.cc ? replyTo.cc : []}
|
||||
></dees-input-tags>
|
||||
|
||||
<dees-input-tags
|
||||
key="bcc"
|
||||
label="BCC"
|
||||
placeholder="Enter BCC recipients..."
|
||||
></dees-input-tags>
|
||||
|
||||
<dees-input-text
|
||||
key="subject"
|
||||
label="Subject"
|
||||
placeholder="Enter email subject..."
|
||||
.value=${replyTo ? `${forward ? 'Fwd' : 'Re'}: ${replyTo.subject}` : ''}
|
||||
required
|
||||
></dees-input-text>
|
||||
|
||||
<dees-editor
|
||||
key="body"
|
||||
label="Message"
|
||||
.mode=${'markdown'}
|
||||
.height=${400}
|
||||
.value=${replyTo && !forward ? `\n\n---\nOn ${new Date(replyTo.date).toLocaleString()}, ${replyTo.from} wrote:\n\n${replyTo.body}` : replyTo && forward ? replyTo.body : ''}
|
||||
></dees-editor>
|
||||
|
||||
<dees-input-fileupload
|
||||
key="attachments"
|
||||
label="Attachments"
|
||||
multiple
|
||||
></dees-input-fileupload>
|
||||
</dees-form>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
`,
|
||||
menuOptions: [
|
||||
{
|
||||
name: 'Send',
|
||||
iconName: 'paperPlane',
|
||||
action: async (modalArg) => {
|
||||
const form = modalArg.shadowRoot?.querySelector('dees-form') as any;
|
||||
form?.submit();
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Cancel',
|
||||
iconName: 'xmark',
|
||||
action: async (modalArg) => await modalArg.destroy()
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
private getFilteredEmails(): IEmail[] {
|
||||
@ -518,16 +520,15 @@ export class OpsViewEmails extends DeesElement {
|
||||
}
|
||||
|
||||
private async sendEmail(formData: any) {
|
||||
|
||||
try {
|
||||
// TODO: Implement actual email sending
|
||||
// TODO: Implement actual email sending via API
|
||||
console.log('Sending email:', formData);
|
||||
|
||||
// Add to sent folder
|
||||
// Add to sent folder (mock)
|
||||
const newEmail: IEmail = {
|
||||
id: `email-${Date.now()}`,
|
||||
from: 'me@dcrouter.local',
|
||||
to: formData.to,
|
||||
to: formData.to || [],
|
||||
cc: formData.cc || [],
|
||||
bcc: formData.bcc || [],
|
||||
subject: formData.subject,
|
||||
@ -538,13 +539,13 @@ export class OpsViewEmails extends DeesElement {
|
||||
};
|
||||
|
||||
this.emails = [...this.emails, newEmail];
|
||||
this.showCompose = false;
|
||||
|
||||
// TODO: Implement toast notification when DeesToast.show is available
|
||||
// Show success notification
|
||||
console.log('Email sent successfully');
|
||||
// TODO: Show toast notification when interface is available
|
||||
} catch (error: any) {
|
||||
// TODO: Implement toast notification when DeesToast.show is available
|
||||
console.error('Failed to send email', error);
|
||||
// TODO: Show error toast notification when interface is available
|
||||
}
|
||||
}
|
||||
|
||||
@ -581,18 +582,15 @@ export class OpsViewEmails extends DeesElement {
|
||||
}
|
||||
|
||||
private async replyToEmail(email: IEmail) {
|
||||
// TODO: Open compose with reply context
|
||||
this.showCompose = true;
|
||||
this.openComposeModal(email, false, false);
|
||||
}
|
||||
|
||||
private async replyAllToEmail(email: IEmail) {
|
||||
// TODO: Open compose with reply all context
|
||||
this.showCompose = true;
|
||||
this.openComposeModal(email, true, false);
|
||||
}
|
||||
|
||||
private async forwardEmail(email: IEmail) {
|
||||
// TODO: Open compose with forward context
|
||||
this.showCompose = true;
|
||||
this.openComposeModal(email, false, true);
|
||||
}
|
||||
|
||||
private generateMockEmails() {
|
||||
|
Reference in New Issue
Block a user