@social-mail/social-mail-client 1.2.4 → 1.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin/AdminAppIndex.pack.js +53 -9
- package/dist/admin/AdminAppIndex.pack.js.map +1 -1
- package/dist/admin/AdminAppIndex.pack.min.js +10 -6
- package/dist/admin/AdminAppIndex.pack.min.js.map +1 -1
- package/dist/services/files/LocalFileService.d.ts +2 -0
- package/dist/services/files/LocalFileService.d.ts.map +1 -1
- package/dist/services/files/LocalFileService.js +32 -8
- package/dist/services/files/LocalFileService.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/web/AppIndex.pack.js +53 -9
- package/dist/web/AppIndex.pack.js.map +1 -1
- package/dist/web/AppIndex.pack.min.js +10 -6
- package/dist/web/AppIndex.pack.min.js.map +1 -1
- package/dist/web/page/mails/ConversationPage.d.ts +1 -0
- package/dist/web/page/mails/ConversationPage.d.ts.map +1 -1
- package/dist/web/page/mails/ConversationPage.js +12 -1
- package/dist/web/page/mails/ConversationPage.js.map +1 -1
- package/dist/web/page/mails/service/ConversationService.d.ts +1 -0
- package/dist/web/page/mails/service/ConversationService.d.ts.map +1 -1
- package/dist/web/page/mails/service/ConversationService.js +9 -0
- package/dist/web/page/mails/service/ConversationService.js.map +1 -1
- package/index.js +0 -1
- package/node_modules/@web-atoms/web-controls/dist/dev/DevHost.d.ts +35 -0
- package/node_modules/@web-atoms/web-controls/dist/dev/DevHost.d.ts.map +1 -0
- package/node_modules/@web-atoms/web-controls/dist/dev/DevHost.js +203 -0
- package/node_modules/@web-atoms/web-controls/dist/dev/DevHost.js.map +1 -0
- package/node_modules/@web-atoms/web-controls/dist/tsconfig.tsbuildinfo +1 -1
- package/node_modules/@web-atoms/web-controls/index.js +89 -0
- package/node_modules/@web-atoms/web-controls/package.json +1 -1
- package/node_modules/@web-atoms/web-controls/src/dev/DevHost.tsx +222 -0
- package/package.json +2 -2
- package/src/services/files/LocalFileService.tsx +35 -11
- package/src/web/page/mails/ConversationPage.tsx +11 -1
- package/src/web/page/mails/service/ConversationService.tsx +6 -0
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import Bind from "@web-atoms/core/dist/core/Bind"
|
|
2
|
+
import XNode from "@web-atoms/core/dist/core/XNode"
|
|
3
|
+
import { BaseService, Get, Query } from "@web-atoms/core/dist/services/http/RestService";
|
|
4
|
+
import { AtomControl } from "@web-atoms/core/dist/web/controls/AtomControl";
|
|
5
|
+
import styled from "@web-atoms/core/dist/style/styled";
|
|
6
|
+
import InjectProperty from "@web-atoms/core/dist/core/InjectProperty";
|
|
7
|
+
|
|
8
|
+
import "@web-atoms/data-styles/data-styles";
|
|
9
|
+
import { CancelToken } from "@web-atoms/core/dist/core/types";
|
|
10
|
+
import Action from "@web-atoms/core/dist/view-model/Action";
|
|
11
|
+
import DISingleton from "@web-atoms/core/dist/di/DISingleton";
|
|
12
|
+
import AtomRepeater from "../basic/AtomRepeater";
|
|
13
|
+
import ToggleButtonBar from "../basic/ToggleButtonBar";
|
|
14
|
+
|
|
15
|
+
styled.css `
|
|
16
|
+
:root {
|
|
17
|
+
--accent-color: orangered;
|
|
18
|
+
--accent-text-color: white;
|
|
19
|
+
}
|
|
20
|
+
html, body {
|
|
21
|
+
margin: 0;
|
|
22
|
+
padding: 0;
|
|
23
|
+
font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif;
|
|
24
|
+
}
|
|
25
|
+
`.installGlobal();
|
|
26
|
+
|
|
27
|
+
const css = styled.css `
|
|
28
|
+
position: absolute;
|
|
29
|
+
left: 0;
|
|
30
|
+
top: 0;
|
|
31
|
+
right: 0;
|
|
32
|
+
bottom: 0;
|
|
33
|
+
display: grid;
|
|
34
|
+
grid-template-rows: auto 1fr;
|
|
35
|
+
gap: 5px;
|
|
36
|
+
|
|
37
|
+
& > header {
|
|
38
|
+
grid-row: 1;
|
|
39
|
+
}
|
|
40
|
+
& > div {
|
|
41
|
+
grid-row: 2;
|
|
42
|
+
align-items: stretch;
|
|
43
|
+
justify-self: stretch;
|
|
44
|
+
overflow: auto;
|
|
45
|
+
|
|
46
|
+
& [data-item-index]:hover {
|
|
47
|
+
background-color: lightgreen;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
`.installLocal();
|
|
51
|
+
|
|
52
|
+
const fileTypes = () => [
|
|
53
|
+
{ label: "Packed", value: "packed"},
|
|
54
|
+
{ label: "All", value: "all"}
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
const designModes = () => [
|
|
58
|
+
{ label: "Design", value: true },
|
|
59
|
+
{ label: "Live", value: false }
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
const replaceSrc = (src: string): string => {
|
|
63
|
+
src = src.split("\\").join("/");
|
|
64
|
+
const tokens = src.split("/");
|
|
65
|
+
if (tokens[0] === "src") {
|
|
66
|
+
tokens[0] = "dist";
|
|
67
|
+
}
|
|
68
|
+
return tokens.join("/");
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const toAbsoluteUrl = (file: IFilePath, designMode?: boolean) => {
|
|
72
|
+
let url = `/_view/${replaceSrc(file.dir)}/${file.name}`;
|
|
73
|
+
if (designMode) {
|
|
74
|
+
if (url.indexOf("?") === -1) {
|
|
75
|
+
url += "?";
|
|
76
|
+
}
|
|
77
|
+
url += "&designMode=true";
|
|
78
|
+
}
|
|
79
|
+
return `${location.protocol}//${location.host}${url}`;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
@DISingleton({})
|
|
83
|
+
export class FileService extends BaseService {
|
|
84
|
+
|
|
85
|
+
public async getModules(search: string, packed: boolean, cancelToken: CancelToken) {
|
|
86
|
+
const result = await this.getRemoteModules(search, packed, cancelToken);
|
|
87
|
+
return result.files;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
@Get("/flat-modules")
|
|
91
|
+
private getRemoteModules(
|
|
92
|
+
@Query("search") search: string,
|
|
93
|
+
@Query("packed") packed: boolean,
|
|
94
|
+
ct?: CancelToken): Promise<IFilePathResult> {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export default class AppHost extends AtomControl {
|
|
101
|
+
|
|
102
|
+
public search: string = "";
|
|
103
|
+
|
|
104
|
+
public designMode = false;
|
|
105
|
+
|
|
106
|
+
public fileType = "packed";
|
|
107
|
+
|
|
108
|
+
@InjectProperty
|
|
109
|
+
private fileService: FileService;
|
|
110
|
+
|
|
111
|
+
public async init() {
|
|
112
|
+
|
|
113
|
+
this.render(
|
|
114
|
+
<div
|
|
115
|
+
class={css}>
|
|
116
|
+
<header
|
|
117
|
+
data-layout="row"
|
|
118
|
+
data-padding="auto"
|
|
119
|
+
class="header">
|
|
120
|
+
<input
|
|
121
|
+
type="search"
|
|
122
|
+
value={Bind.twoWaysImmediate(() => this.search)}
|
|
123
|
+
placeholder="Search...">
|
|
124
|
+
</input>
|
|
125
|
+
|
|
126
|
+
<span>Mode</span>
|
|
127
|
+
<ToggleButtonBar
|
|
128
|
+
items={designModes()}
|
|
129
|
+
value={Bind.twoWays(() => this.designMode)}
|
|
130
|
+
/>
|
|
131
|
+
|
|
132
|
+
<ToggleButtonBar
|
|
133
|
+
items={fileTypes()}
|
|
134
|
+
value={Bind.twoWays(() => this.fileType)}
|
|
135
|
+
/>
|
|
136
|
+
</header>
|
|
137
|
+
<div>
|
|
138
|
+
<AtomRepeater
|
|
139
|
+
class="grid"
|
|
140
|
+
items={Bind.oneWayAsync((x, e, cancelToken) =>
|
|
141
|
+
this.getModules(this.search, this.fileType === "packed", cancelToken))}
|
|
142
|
+
for="table"
|
|
143
|
+
itemRenderer={(item: IFilePath) => <tr
|
|
144
|
+
template="itemTemplate">
|
|
145
|
+
<td>
|
|
146
|
+
<div
|
|
147
|
+
text={item.name}
|
|
148
|
+
title={item.dir}
|
|
149
|
+
style="font-weight: 500;">
|
|
150
|
+
</div>
|
|
151
|
+
<div
|
|
152
|
+
style="font-size: small;"
|
|
153
|
+
text={item.dir}>
|
|
154
|
+
</div>
|
|
155
|
+
</td>
|
|
156
|
+
<td>
|
|
157
|
+
<a
|
|
158
|
+
data-layout="accent-button"
|
|
159
|
+
data-text-decoration="none"
|
|
160
|
+
href={Bind.source(item, (x) => toAbsoluteUrl(x.source, this.designMode))}
|
|
161
|
+
target="_blank"
|
|
162
|
+
text="Open">
|
|
163
|
+
</a>
|
|
164
|
+
<i
|
|
165
|
+
class="fas fa-copy"
|
|
166
|
+
title="Copy Url"
|
|
167
|
+
style="margin: 5px; cursor: pointer;"
|
|
168
|
+
data-click-event="copy-url"
|
|
169
|
+
eventClick={() => this.copyUrl(toAbsoluteUrl(item, this.designMode))}>
|
|
170
|
+
</i>
|
|
171
|
+
</td>
|
|
172
|
+
</tr> } />
|
|
173
|
+
</div>
|
|
174
|
+
</div>
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
async getModules(search: string, packed: boolean, cancelToken: CancelToken) {
|
|
179
|
+
const result = await this.fileService.getModules(search, packed, cancelToken);
|
|
180
|
+
if (!result.length && packed) {
|
|
181
|
+
this.fileType = "all";
|
|
182
|
+
}
|
|
183
|
+
return result;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
protected preCreate(): void {
|
|
187
|
+
super.preCreate();
|
|
188
|
+
(this.app).installStyleSheet({
|
|
189
|
+
href: "https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.4.0/css/all.min.css",
|
|
190
|
+
integrity: "sha256-HtsXJanqjKTc8vVQjO4YMhiqFoXkfBsjBWcX91T1jr8=",
|
|
191
|
+
crossOrigin: "anonymous"
|
|
192
|
+
});
|
|
193
|
+
this.runAfterInit(() => this.app.runAsync(() => this.init()));
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
@Action({ success: "Copied successfully"})
|
|
197
|
+
protected async copyUrl(url: string) {
|
|
198
|
+
await navigator.clipboard.writeText(url);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
export interface IFilePath {
|
|
202
|
+
|
|
203
|
+
name: string;
|
|
204
|
+
base: string;
|
|
205
|
+
dir: string;
|
|
206
|
+
ext: string;
|
|
207
|
+
root: string;
|
|
208
|
+
url: string;
|
|
209
|
+
hostUrl?: string;
|
|
210
|
+
package?: string;
|
|
211
|
+
visible: boolean;
|
|
212
|
+
packed?: boolean;
|
|
213
|
+
module?: string;
|
|
214
|
+
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
export interface IFilePathResult {
|
|
218
|
+
|
|
219
|
+
files: IFilePath[];
|
|
220
|
+
|
|
221
|
+
}
|
|
222
|
+
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@social-mail/social-mail-client",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.6",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"@web-atoms/font-awesome": "^1.0.37",
|
|
20
20
|
"@web-atoms/hybrid-clr": "^1.0.21",
|
|
21
21
|
"@web-atoms/module-loader": "^2.1.34",
|
|
22
|
-
"@web-atoms/web-controls": "^2.4.
|
|
22
|
+
"@web-atoms/web-controls": "^2.4.15",
|
|
23
23
|
"reflect-metadata": "^0.1.13",
|
|
24
24
|
"tinycolor2": "^1.6.0"
|
|
25
25
|
},
|
|
@@ -31,7 +31,7 @@ export type UploadedFiles = CustomEvent<{ files: IUploadedFile[], extra: any}>;
|
|
|
31
31
|
|
|
32
32
|
styled.css `
|
|
33
33
|
display: inline-grid;
|
|
34
|
-
grid-template-rows: auto auto;
|
|
34
|
+
grid-template-rows: auto auto auto;
|
|
35
35
|
|
|
36
36
|
& > [data-element=file-name] {
|
|
37
37
|
grid-row: 1;
|
|
@@ -40,15 +40,20 @@ export type UploadedFiles = CustomEvent<{ files: IUploadedFile[], extra: any}>;
|
|
|
40
40
|
text-overflow: ellipsis;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
& >
|
|
43
|
+
& > progress {
|
|
44
44
|
grid-row: 2;
|
|
45
45
|
width: 100%;
|
|
46
46
|
}
|
|
47
|
+
& > [data-element=error] {
|
|
48
|
+
grid-row: 3;
|
|
49
|
+
width: 100%;
|
|
50
|
+
}
|
|
47
51
|
|
|
48
52
|
`.installGlobal("[data-attachment-file]");
|
|
49
53
|
|
|
50
54
|
export interface IFileUpload {
|
|
51
55
|
name: string;
|
|
56
|
+
error?: string;
|
|
52
57
|
progress?: number;
|
|
53
58
|
promise?: Promise<{ appFileID }>
|
|
54
59
|
}
|
|
@@ -164,23 +169,38 @@ export default class LocalFileService extends TaskManager {
|
|
|
164
169
|
const upload = {
|
|
165
170
|
total: 0,
|
|
166
171
|
tasks,
|
|
167
|
-
progress:0
|
|
172
|
+
progress:0,
|
|
173
|
+
error: "",
|
|
168
174
|
};
|
|
169
175
|
for (const file of files) {
|
|
170
176
|
upload.total += file.size;
|
|
171
177
|
const uploadFile: IFileUpload = {
|
|
172
178
|
name: file.name,
|
|
179
|
+
error: "",
|
|
173
180
|
progress: 0
|
|
174
181
|
};
|
|
175
182
|
uploadFile.promise = this.run(async () => {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
183
|
+
let lastError: string;
|
|
184
|
+
for(let i=0; i<3; i++) {
|
|
185
|
+
try {
|
|
186
|
+
uploadFile.progress = 0.01;
|
|
187
|
+
|
|
188
|
+
// we will check if file exists and has same sha256?
|
|
189
|
+
|
|
190
|
+
const r = await this.uploadFile(file, extra, ct, (n) => uploadFile.progress = n);
|
|
191
|
+
upload.progress += r.file.size;
|
|
192
|
+
setTimeout(() => tasks.remove(uploadFile), 500);
|
|
193
|
+
upload.error = "";
|
|
194
|
+
lastError = null;
|
|
195
|
+
return r;
|
|
196
|
+
} catch (error) {
|
|
197
|
+
lastError = `${file.webkitRelativePath ?? ""}/${file.name} failed to upload.\n${error.stack ?? error}`;
|
|
198
|
+
uploadFile.error = lastError;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
if (lastError) {
|
|
202
|
+
upload.error += "\n" + lastError;
|
|
203
|
+
}
|
|
184
204
|
});
|
|
185
205
|
tasks.push(uploadFile);
|
|
186
206
|
}
|
|
@@ -231,6 +251,10 @@ class FileUploadWindow extends PopupWindow {
|
|
|
231
251
|
min={0}
|
|
232
252
|
max={1}
|
|
233
253
|
value={Bind.source(file, (x) => x.source.progress)}/>
|
|
254
|
+
<div
|
|
255
|
+
data-element="error"
|
|
256
|
+
data-color="red"
|
|
257
|
+
text={Bind.source(file, (x) => x.source.error)}/>
|
|
234
258
|
</div>}
|
|
235
259
|
/>
|
|
236
260
|
</div>);
|
|
@@ -31,7 +31,7 @@ const itemCss = styled.css `
|
|
|
31
31
|
border-radius: 10px;
|
|
32
32
|
padding: 10px;
|
|
33
33
|
margin-right: 20%;
|
|
34
|
-
|
|
34
|
+
contain: content;
|
|
35
35
|
position: relative;
|
|
36
36
|
background-color: canvas;
|
|
37
37
|
&[data-sent=true] {
|
|
@@ -334,4 +334,14 @@ export default class ConversationPage extends ContentPage {
|
|
|
334
334
|
async unblockSender() {
|
|
335
335
|
await this.conversationService.block(this.parameters);
|
|
336
336
|
}
|
|
337
|
+
|
|
338
|
+
@Action({
|
|
339
|
+
onEvent: "delete-draft",
|
|
340
|
+
confirm: "Are you sure you want to delete this draft?"
|
|
341
|
+
})
|
|
342
|
+
async deleteDraft(mce: IMailboxContactEmail) {
|
|
343
|
+
await this.conversationService.delete(mce.email);
|
|
344
|
+
this.mails.remove(mce);
|
|
345
|
+
this.draft = null;
|
|
346
|
+
}
|
|
337
347
|
}
|