@social-mail/social-mail-client 1.0.1 → 1.0.3
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/README.md +1 -91
- package/dist/admin/Admin.js +50 -2
- package/dist/admin/Admin.js.map +1 -1
- package/dist/admin/commands/AdminCommands.js +37 -0
- package/dist/admin/commands/AdminCommands.js.map +1 -1
- package/dist/admin/drawer/AdminDrawer.js +40 -2
- package/dist/admin/drawer/AdminDrawer.js.map +1 -1
- package/dist/admin/pages/config/ConfigPage.js +18 -0
- package/dist/admin/pages/config/ConfigPage.js.map +1 -0
- package/dist/admin/pages/domains/ChooseDomainPage.js +86 -0
- package/dist/admin/pages/domains/ChooseDomainPage.js.map +1 -0
- package/dist/admin/pages/domains/DomainListPage.js +67 -0
- package/dist/admin/pages/domains/DomainListPage.js.map +1 -0
- package/dist/admin/pages/domains/EditDomainPage.js +79 -0
- package/dist/admin/pages/domains/EditDomainPage.js.map +1 -0
- package/dist/admin/pages/domains/services/AdminDomainService.js +50 -0
- package/dist/admin/pages/domains/services/AdminDomainService.js.map +1 -0
- package/dist/admin/pages/home/AdminHome.js +18 -0
- package/dist/admin/pages/home/AdminHome.js.map +1 -0
- package/dist/admin/pages/users/EditUserPage.js +105 -0
- package/dist/admin/pages/users/EditUserPage.js.map +1 -0
- package/dist/admin/pages/users/UserListPage.js +82 -0
- package/dist/admin/pages/users/UserListPage.js.map +1 -0
- package/dist/admin/pages/users/services/AdminUserService.js +57 -0
- package/dist/admin/pages/users/services/AdminUserService.js.map +1 -0
- package/dist/common/SocialMailApp.js +14 -0
- package/dist/common/SocialMailApp.js.map +1 -0
- package/dist/common/Sql.js +12 -0
- package/dist/common/Sql.js.map +1 -0
- package/dist/common/controls/form/RequiredFormField.js +57 -0
- package/dist/common/controls/form/RequiredFormField.js.map +1 -0
- package/dist/common/controls/repeater/InfiniteRepeater.js +100 -0
- package/dist/common/controls/repeater/InfiniteRepeater.js.map +1 -0
- package/dist/common/pages/LoginPage.js +79 -0
- package/dist/common/pages/LoginPage.js.map +1 -0
- package/dist/common/pages/mailboxes/MailboxEditorPage.js +79 -0
- package/dist/common/pages/mailboxes/MailboxEditorPage.js.map +1 -0
- package/dist/common/pages/mailboxes/MailboxListPage.js +80 -0
- package/dist/common/pages/mailboxes/MailboxListPage.js.map +1 -0
- package/dist/common/pages/mailboxes/services/MailboxService.js +60 -0
- package/dist/common/pages/mailboxes/services/MailboxService.js.map +1 -0
- package/dist/common/pages/user/LoginPage.js +79 -0
- package/dist/common/pages/user/LoginPage.js.map +1 -0
- package/dist/model/model.js +36 -0
- package/dist/model/model.js.map +1 -1
- package/dist/services/ConfigService.js +45 -0
- package/dist/services/ConfigService.js.map +1 -0
- package/dist/services/EntityService.js +4 -0
- package/dist/services/EntityService.js.map +1 -1
- package/dist/services/UserService.js +54 -0
- package/dist/services/UserService.js.map +1 -0
- package/dist/style/GlobalStyle.js +11 -3
- package/dist/style/GlobalStyle.js.map +1 -1
- package/dist/style/OverrideAppStyle.js +22 -0
- package/dist/style/OverrideAppStyle.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/web/AppIndex.js +38 -2
- package/dist/web/AppIndex.js.map +1 -1
- package/node_modules/@web-atoms/entity/dist/services/BaseEntityService.d.ts +5 -2
- package/node_modules/@web-atoms/entity/dist/services/BaseEntityService.d.ts.map +1 -1
- package/node_modules/@web-atoms/entity/dist/services/BaseEntityService.js +18 -1
- package/node_modules/@web-atoms/entity/dist/services/BaseEntityService.js.map +1 -1
- package/node_modules/@web-atoms/entity/dist/services/MockBaseEntityService.d.ts +2 -0
- package/node_modules/@web-atoms/entity/dist/services/MockBaseEntityService.d.ts.map +1 -1
- package/node_modules/@web-atoms/entity/dist/services/MockBaseEntityService.js +1 -0
- package/node_modules/@web-atoms/entity/dist/services/MockBaseEntityService.js.map +1 -1
- package/node_modules/@web-atoms/entity/dist/services/Query.d.ts +2 -0
- package/node_modules/@web-atoms/entity/dist/services/Query.d.ts.map +1 -1
- package/node_modules/@web-atoms/entity/dist/services/Query.js +9 -6
- package/node_modules/@web-atoms/entity/dist/services/Query.js.map +1 -1
- package/node_modules/@web-atoms/entity/dist/services/QueryProcessor.d.ts +2 -0
- package/node_modules/@web-atoms/entity/dist/services/QueryProcessor.d.ts.map +1 -0
- package/node_modules/@web-atoms/entity/dist/services/QueryProcessor.js +9 -0
- package/node_modules/@web-atoms/entity/dist/services/QueryProcessor.js.map +1 -0
- package/node_modules/@web-atoms/entity/dist/tsconfig.tsbuildinfo +1 -1
- package/node_modules/@web-atoms/entity/package.json +1 -1
- package/node_modules/@web-atoms/entity/src/services/BaseEntityService.ts +23 -3
- package/node_modules/@web-atoms/entity/src/services/MockBaseEntityService.ts +3 -0
- package/node_modules/@web-atoms/entity/src/services/Query.ts +12 -7
- package/node_modules/@web-atoms/entity/src/services/QueryProcessor.ts +1 -0
- package/package.json +2 -2
- package/src/admin/Admin.tsx +40 -1
- package/src/admin/commands/AdminCommands.ts +33 -0
- package/src/admin/drawer/AdminDrawer.tsx +70 -0
- package/src/admin/pages/config/ConfigPage.tsx +5 -0
- package/src/admin/pages/domains/DomainListPage.tsx +43 -0
- package/src/admin/pages/domains/choose/ChooseDomainPage.tsx +57 -0
- package/src/admin/pages/domains/edit/EditDomainPage.tsx +102 -0
- package/src/admin/pages/domains/services/AdminDomainService.ts +34 -0
- package/src/admin/pages/home/AdminHome.tsx +6 -0
- package/src/admin/pages/users/EditUserPage.tsx +85 -0
- package/src/admin/pages/users/UserListPage.tsx +53 -0
- package/src/admin/pages/users/services/AdminUserService.ts +34 -0
- package/src/common/SocialMailApp.ts +7 -0
- package/src/common/Sql.ts +74 -0
- package/src/common/commands/CommonCommands.ts +6 -0
- package/src/common/controls/buttons/IconButton.tsx +60 -0
- package/src/common/controls/form/RequiredFormField.tsx +53 -0
- package/src/common/controls/repeater/InfiniteRepeater.tsx +93 -0
- package/src/common/pages/mailboxes/MailboxEditorPage.tsx +66 -0
- package/src/common/pages/mailboxes/MailboxListPage.tsx +48 -0
- package/src/common/pages/mailboxes/services/MailboxService.ts +34 -0
- package/src/common/pages/user/LoginPage.tsx +51 -0
- package/src/model/model.ts +234 -0
- package/src/services/BusyProgress.ts +2 -2
- package/src/services/ConfigService.ts +19 -0
- package/src/services/EntityService.ts +3 -0
- package/src/services/UserService.ts +26 -0
- package/src/style/GlobalStyle.ts +11 -2
- package/src/style/OverrideAppStyle.ts +9 -0
- package/src/web/AppIndex.tsx +26 -1
|
@@ -7,6 +7,7 @@ import HttpSession, { IHttpRequest } from "./HttpSession";
|
|
|
7
7
|
import mergeProperties from "./mergeProperties";
|
|
8
8
|
import Query, { IDateRange, IEntityWithDateRange, stepTypes } from "./Query";
|
|
9
9
|
import resolve from "./resolve";
|
|
10
|
+
import { QueryProcessor } from "./QueryProcessor";
|
|
10
11
|
|
|
11
12
|
export interface IGeometry {
|
|
12
13
|
latitude: number;
|
|
@@ -223,19 +224,37 @@ export interface IModel<T> {
|
|
|
223
224
|
}
|
|
224
225
|
|
|
225
226
|
export class Model<T> implements IModel<T> {
|
|
226
|
-
|
|
227
|
-
|
|
227
|
+
private defaults: [string, any][];
|
|
228
|
+
constructor(public name: string, defaults: any = null) {
|
|
229
|
+
if (defaults) {
|
|
230
|
+
this.defaults = [];
|
|
231
|
+
for (const key in defaults) {
|
|
232
|
+
if (Object.prototype.hasOwnProperty.call(defaults, key)) {
|
|
233
|
+
const element = defaults[key];
|
|
234
|
+
this.defaults.push([key, element]);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
228
238
|
}
|
|
229
239
|
public create(properties: Omit<T, "$type"> = {} as any): T {
|
|
230
240
|
(properties as any).$type = this.name;
|
|
241
|
+
if (this.defaults) {
|
|
242
|
+
for (const [key, value] of this.defaults) {
|
|
243
|
+
if (properties[key] === void 0) {
|
|
244
|
+
properties[key] = value;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
231
248
|
return properties as T;
|
|
232
249
|
}
|
|
233
250
|
}
|
|
234
251
|
|
|
235
|
-
export default class BaseEntityService extends HttpSession {
|
|
252
|
+
export default abstract class BaseEntityService extends HttpSession {
|
|
236
253
|
|
|
237
254
|
public url: string = "/api/entity/";
|
|
238
255
|
|
|
256
|
+
public abstract queryProcessor: QueryProcessor;
|
|
257
|
+
|
|
239
258
|
protected resultConverter = resolve;
|
|
240
259
|
|
|
241
260
|
private entityModel: EntityContext;
|
|
@@ -266,6 +285,7 @@ export default class BaseEntityService extends HttpSession {
|
|
|
266
285
|
return new Query({
|
|
267
286
|
service: this,
|
|
268
287
|
name: m.name,
|
|
288
|
+
queryProcessor: this.queryProcessor,
|
|
269
289
|
queryFunction,
|
|
270
290
|
args
|
|
271
291
|
});
|
|
@@ -4,6 +4,7 @@ import { EntityContext } from "../models/IEntityModel";
|
|
|
4
4
|
import IPagedList from "../models/IPagedList";
|
|
5
5
|
import BaseEntityService, { IBulkDeleteModel, IBulkUpdateModel, IModel, IQueryMethod } from "./BaseEntityService";
|
|
6
6
|
import Query from "./Query";
|
|
7
|
+
import { QueryProcessor } from "./QueryProcessor";
|
|
7
8
|
|
|
8
9
|
const replacer = /(\.[a-z0-9\_])|([a-z0-9\_]\())/ig;
|
|
9
10
|
|
|
@@ -190,6 +191,8 @@ class MockEntityRestService {
|
|
|
190
191
|
|
|
191
192
|
export default class MockBaseEntityService extends BaseEntityService {
|
|
192
193
|
|
|
194
|
+
public queryProcessor: QueryProcessor = "DotNet";
|
|
195
|
+
|
|
193
196
|
public entityContext: EntityContext;
|
|
194
197
|
|
|
195
198
|
private local: { [key: string]: any } = {};
|
|
@@ -122,11 +122,12 @@ export class QueryComposer<Q> {
|
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
interface IQueryContext {
|
|
125
|
-
service: BaseEntityService;
|
|
125
|
+
service: BaseEntityService;
|
|
126
126
|
name: string;
|
|
127
127
|
traceQuery?: boolean;
|
|
128
128
|
queryFunction?: string;
|
|
129
129
|
args?: any[];
|
|
130
|
+
queryProcessor?: "DotNet" | "JavaScript"
|
|
130
131
|
}
|
|
131
132
|
|
|
132
133
|
export default class Query<T> {
|
|
@@ -218,12 +219,12 @@ export default class Query<T> {
|
|
|
218
219
|
|
|
219
220
|
public join<TInner, TKey>(model: IModel<TInner>, left: (x: T) => TKey, right: (x: TInner) => TKey)
|
|
220
221
|
: Query<{ entity: T, inner: TInner }> {
|
|
221
|
-
return this.append(["join" as any, model.name, convertToLinq(left.toString()), convertToLinq(right.toString())] ) as any;
|
|
222
|
+
return this.append(["join" as any, model.name, this.convertToLinq(left.toString()), this.convertToLinq(right.toString())] ) as any;
|
|
222
223
|
}
|
|
223
224
|
|
|
224
225
|
public leftJoin<TInner, TKey>(model: IModel<TInner>, left: (x: T) => TKey, right: (x: TInner) => TKey)
|
|
225
226
|
: Query<{ entity: T, inner: TInner }> {
|
|
226
|
-
return this.append(["leftJoin" as any, model.name, convertToLinq(left.toString()), convertToLinq(right.toString())] ) as any;
|
|
227
|
+
return this.append(["leftJoin" as any, model.name, this.convertToLinq(left.toString()), this.convertToLinq(right.toString())] ) as any;
|
|
227
228
|
}
|
|
228
229
|
|
|
229
230
|
public include<TR>(q: (x: T) => TR[]): IIncludedArrayQuery<T, TR, TR[]>;
|
|
@@ -235,7 +236,7 @@ export default class Query<T> {
|
|
|
235
236
|
["include", tOrP],
|
|
236
237
|
... q.map((s) => ["include", s] as IQueryMethod)) as any;
|
|
237
238
|
}
|
|
238
|
-
const select = convertToLinq(tOrP.toString());
|
|
239
|
+
const select = this.convertToLinq(tOrP.toString());
|
|
239
240
|
return this.append(["include", select] ) as any;
|
|
240
241
|
}
|
|
241
242
|
|
|
@@ -377,7 +378,7 @@ export default class Query<T> {
|
|
|
377
378
|
}
|
|
378
379
|
|
|
379
380
|
protected thenInclude(a): any {
|
|
380
|
-
const select = convertToLinq(a.toString());
|
|
381
|
+
const select = this.convertToLinq(a.toString());
|
|
381
382
|
return this.append(["thenInclude", select]);
|
|
382
383
|
}
|
|
383
384
|
|
|
@@ -388,7 +389,7 @@ export default class Query<T> {
|
|
|
388
389
|
private process<TP, TR>(name: any, tOrP: TP | T, q?: (p: TP) => (x: T) => TR): Query<T> {
|
|
389
390
|
|
|
390
391
|
if (!q) {
|
|
391
|
-
const select = convertToLinq(tOrP.toString());
|
|
392
|
+
const select = this.convertToLinq(tOrP.toString());
|
|
392
393
|
return this.append<T>([name , select]);
|
|
393
394
|
}
|
|
394
395
|
|
|
@@ -405,8 +406,12 @@ export default class Query<T> {
|
|
|
405
406
|
pl.push(element);
|
|
406
407
|
}
|
|
407
408
|
}
|
|
408
|
-
text = convertToLinq(text);
|
|
409
|
+
text = this.convertToLinq(text);
|
|
409
410
|
return this.append([name , text, ...pl]);
|
|
410
411
|
}
|
|
411
412
|
|
|
413
|
+
private convertToLinq(text: string) {
|
|
414
|
+
return this.context.queryProcessor === "DotNet" ? convertToLinq(text) : text;
|
|
415
|
+
}
|
|
416
|
+
|
|
412
417
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type QueryProcessor = "DotNet" | "JavaScript";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@social-mail/social-mail-client",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"@web-atoms/data-styles": "^1.0.101",
|
|
16
16
|
"@web-atoms/date-time": "^1.1.0",
|
|
17
17
|
"@web-atoms/email-dom": "^1.0.29",
|
|
18
|
-
"@web-atoms/entity": "^2.4.
|
|
18
|
+
"@web-atoms/entity": "^2.4.26",
|
|
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.32",
|
package/src/admin/Admin.tsx
CHANGED
|
@@ -2,9 +2,48 @@ import Pack from "@web-atoms/core/dist/Pack";
|
|
|
2
2
|
import MobileDesktopApp from "@web-atoms/web-controls/dist/desktop-app/MobileDesktopApp";
|
|
3
3
|
|
|
4
4
|
import "../style/GlobalStyle";
|
|
5
|
+
import UserService from "../services/UserService";
|
|
6
|
+
import InjectProperty from "@web-atoms/core/dist/core/InjectProperty";
|
|
7
|
+
import AdminCommands from "./commands/AdminCommands";
|
|
8
|
+
import PageNavigator from "@web-atoms/web-controls/dist/PageNavigator";
|
|
9
|
+
import LoginPage from "../common/pages/user/LoginPage";
|
|
10
|
+
import AdminDrawer from "./drawer/AdminDrawer";
|
|
11
|
+
import Command from "@web-atoms/core/dist/core/Command";
|
|
12
|
+
import Route from "@web-atoms/core/dist/core/Route";
|
|
5
13
|
|
|
6
14
|
@Pack
|
|
7
15
|
export default class AppIndex extends MobileDesktopApp {
|
|
16
|
+
|
|
17
|
+
@InjectProperty
|
|
18
|
+
private userService: UserService;
|
|
19
|
+
|
|
8
20
|
async init() {
|
|
21
|
+
AdminCommands.install(this);
|
|
22
|
+
|
|
23
|
+
// check if we are logged in...
|
|
24
|
+
const user = await this.userService.getUser();
|
|
25
|
+
if (!user || !user.roles?.some((r) => r.roleName === "Administrator")) {
|
|
26
|
+
PageNavigator.openPage(LoginPage);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
this.drawerMenu = AdminDrawer;
|
|
31
|
+
|
|
32
|
+
if(!Command.invokeRoute()) {
|
|
33
|
+
|
|
34
|
+
// check if we are configured...
|
|
35
|
+
|
|
36
|
+
AdminCommands.openHome.dispatch();
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
Route.encodeUrl = (url) => {
|
|
42
|
+
if (url.startsWith("#")) {
|
|
43
|
+
return url;
|
|
44
|
+
}
|
|
45
|
+
if (/\d+\./.test(location.hostname)) {
|
|
46
|
+
return "#!" + url;
|
|
9
47
|
}
|
|
10
|
-
|
|
48
|
+
return url;
|
|
49
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import Command, { Commands } from "@web-atoms/core/dist/core/Command";
|
|
2
|
+
|
|
3
|
+
export default class AdminCommands extends Commands {
|
|
4
|
+
|
|
5
|
+
static openHome = Command.create({
|
|
6
|
+
route: "/admin",
|
|
7
|
+
routeOrder: 1000,
|
|
8
|
+
openPage: () => import("../pages/home/AdminHome")
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
static openDomainList = Command.create({
|
|
12
|
+
route: "/admin/domains",
|
|
13
|
+
routeOrder: 100,
|
|
14
|
+
openPage: () => import("../pages/domains/DomainListPage")
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
static openDomain = Command.create({
|
|
18
|
+
route: "/admin/domains/{domainID}",
|
|
19
|
+
openPage: () => import("../pages/domains/edit/EditDomainPage")
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
static openUserList = Command.create({
|
|
23
|
+
route: "/admin/users",
|
|
24
|
+
routeOrder: 100,
|
|
25
|
+
openPage: () => import("../pages/users/UserListPage")
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
static openMailboxList = Command.create({
|
|
29
|
+
route: "/admin/mailboxes",
|
|
30
|
+
routeOrder: 100,
|
|
31
|
+
openPage: () => import("../../common/pages/mailboxes/MailboxListPage")
|
|
32
|
+
});
|
|
33
|
+
}
|
|
@@ -1,5 +1,75 @@
|
|
|
1
|
+
import XNode from "@web-atoms/core/dist/core/XNode";
|
|
2
|
+
import styled from "@web-atoms/core/dist/style/styled";
|
|
1
3
|
import { Drawer } from "@web-atoms/web-controls/dist/mobile-app/MobileApp";
|
|
4
|
+
import { IUser } from "../../model/model";
|
|
5
|
+
import SocialMailApp from "../../common/SocialMailApp";
|
|
6
|
+
import AdminCommands from "../commands/AdminCommands";
|
|
7
|
+
|
|
8
|
+
const css = styled.css `
|
|
9
|
+
min-width: 200px;
|
|
10
|
+
`.installLocal();
|
|
11
|
+
|
|
12
|
+
const MenuItem = ({
|
|
13
|
+
label,
|
|
14
|
+
icon,
|
|
15
|
+
click = undefined,
|
|
16
|
+
href = "",
|
|
17
|
+
commandLink = "",
|
|
18
|
+
target = undefined as string
|
|
19
|
+
}) => href || commandLink
|
|
20
|
+
? <a data-layout="menu-item"
|
|
21
|
+
data-click-event={ commandLink ? "route" : void 0}
|
|
22
|
+
href={href || commandLink}
|
|
23
|
+
target={target}
|
|
24
|
+
event-click={click}>
|
|
25
|
+
<i class={icon}/>
|
|
26
|
+
<span text={label}/></a>
|
|
27
|
+
: <div
|
|
28
|
+
data-layout="menu-item"
|
|
29
|
+
event-click={click}>
|
|
30
|
+
<i class={icon}/>
|
|
31
|
+
<span text={label}/>
|
|
32
|
+
</div>;
|
|
2
33
|
|
|
3
34
|
export default class AdminDrawer extends Drawer {
|
|
4
35
|
|
|
36
|
+
user: IUser;
|
|
37
|
+
|
|
38
|
+
protected async init() {
|
|
39
|
+
this.element.className = css;
|
|
40
|
+
|
|
41
|
+
this.user = SocialMailApp.user;
|
|
42
|
+
|
|
43
|
+
this.renderer = <div>
|
|
44
|
+
<div data-background-color="accent">
|
|
45
|
+
<div
|
|
46
|
+
data-padding="large"
|
|
47
|
+
data-font-size="large"
|
|
48
|
+
data-color="white"
|
|
49
|
+
text="Social Mail Admin"/>
|
|
50
|
+
</div>
|
|
51
|
+
<MenuItem
|
|
52
|
+
icon="fas fa-home"
|
|
53
|
+
label="Home"
|
|
54
|
+
commandLink={AdminCommands.openHome.displayRoute({})}
|
|
55
|
+
/>
|
|
56
|
+
<MenuItem
|
|
57
|
+
icon="fas fa-home"
|
|
58
|
+
label="Domains"
|
|
59
|
+
commandLink={AdminCommands.openDomainList.displayRoute({})}
|
|
60
|
+
/>
|
|
61
|
+
<MenuItem
|
|
62
|
+
icon="fas fa-home"
|
|
63
|
+
label="Users"
|
|
64
|
+
commandLink={AdminCommands.openUserList.displayRoute({})}
|
|
65
|
+
/>
|
|
66
|
+
<MenuItem
|
|
67
|
+
icon="fas fa-home"
|
|
68
|
+
label="Mailboxes"
|
|
69
|
+
commandLink={AdminCommands.openMailboxList.displayRoute({})}
|
|
70
|
+
/>
|
|
71
|
+
</div>;
|
|
72
|
+
|
|
73
|
+
}
|
|
74
|
+
|
|
5
75
|
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import XNode from "@web-atoms/core/dist/core/XNode";
|
|
2
|
+
import { ContentPage } from "@web-atoms/web-controls/dist/mobile-app/MobileApp";
|
|
3
|
+
import AtomRepeater from "@web-atoms/web-controls/dist/basic/AtomRepeater";
|
|
4
|
+
import InjectProperty from "@web-atoms/core/dist/core/InjectProperty";
|
|
5
|
+
import AdminDomainService from "./services/AdminDomainService";
|
|
6
|
+
import Action from "@web-atoms/core/dist/view-model/Action";
|
|
7
|
+
import PageNavigator from "@web-atoms/web-controls/dist/PageNavigator";
|
|
8
|
+
import EditDomainPage from "./edit/EditDomainPage";
|
|
9
|
+
import { IDomain, IHostedDomain } from "../../../model/model";
|
|
10
|
+
import AdminCommands from "../../commands/AdminCommands";
|
|
11
|
+
|
|
12
|
+
export default class DomainListPage extends ContentPage {
|
|
13
|
+
|
|
14
|
+
@InjectProperty
|
|
15
|
+
private adminDomainService: AdminDomainService;
|
|
16
|
+
|
|
17
|
+
private domains: IHostedDomain[];
|
|
18
|
+
|
|
19
|
+
async init() {
|
|
20
|
+
|
|
21
|
+
this.title = "Domains";
|
|
22
|
+
this.domains = await this.adminDomainService.list();
|
|
23
|
+
|
|
24
|
+
this.actionRenderer = () => <i data-click-event="add-domain" class="fas fa-plus"/>;
|
|
25
|
+
|
|
26
|
+
this.renderer = <div>
|
|
27
|
+
<AtomRepeater
|
|
28
|
+
items={this.domains}
|
|
29
|
+
itemRenderer={(domain) => <div>
|
|
30
|
+
<a
|
|
31
|
+
data-click-event="route"
|
|
32
|
+
href={AdminCommands.openDomain.displayRoute(domain)}>{domain.domain.name}</a>
|
|
33
|
+
</div> }
|
|
34
|
+
/>
|
|
35
|
+
</div>;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
@Action({ onEvent: "add-domain"})
|
|
39
|
+
async addDomain() {
|
|
40
|
+
const domain = await PageNavigator.pushPageForResult(EditDomainPage, {});
|
|
41
|
+
this.domains.add(domain);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import InjectProperty from "@web-atoms/core/dist/core/InjectProperty";
|
|
2
|
+
import XNode from "@web-atoms/core/dist/core/XNode";
|
|
3
|
+
import Action from "@web-atoms/core/dist/view-model/Action";
|
|
4
|
+
import PageNavigator from "@web-atoms/web-controls/dist/PageNavigator";
|
|
5
|
+
import AtomRepeater from "@web-atoms/web-controls/dist/basic/AtomRepeater";
|
|
6
|
+
import { PopupWindowPage } from "@web-atoms/web-controls/dist/mobile-app/MobileApp";
|
|
7
|
+
import { IHostedDomain } from "../../../../model/model";
|
|
8
|
+
import EditDomainPage from "../edit/EditDomainPage";
|
|
9
|
+
import AdminDomainService from "../services/AdminDomainService";
|
|
10
|
+
import Bind from "@web-atoms/core/dist/core/Bind";
|
|
11
|
+
|
|
12
|
+
export default class ChooseDomainPage extends PopupWindowPage<any, IHostedDomain> {
|
|
13
|
+
|
|
14
|
+
@InjectProperty
|
|
15
|
+
private adminDomainService: AdminDomainService;
|
|
16
|
+
|
|
17
|
+
private domains: IHostedDomain[];
|
|
18
|
+
|
|
19
|
+
private domain: IHostedDomain = null;
|
|
20
|
+
|
|
21
|
+
async init() {
|
|
22
|
+
|
|
23
|
+
this.title = "Domains";
|
|
24
|
+
this.domains = await this.adminDomainService.list();
|
|
25
|
+
|
|
26
|
+
this.actionRenderer = () => <i data-click-event="add-domain" class="fas fa-plus"/>;
|
|
27
|
+
|
|
28
|
+
this.renderer = <div>
|
|
29
|
+
<AtomRepeater
|
|
30
|
+
data-list-selection="default"
|
|
31
|
+
for="table"
|
|
32
|
+
items={this.domains}
|
|
33
|
+
data-selection-updated-event="domain-selected"
|
|
34
|
+
selectedItem={Bind.twoWaysImmediate(() => this.domain)}
|
|
35
|
+
itemRenderer={(domain) => <tr data-click-event="item-select">
|
|
36
|
+
<td>
|
|
37
|
+
{domain.domain.name}
|
|
38
|
+
</td>
|
|
39
|
+
</tr> }
|
|
40
|
+
/>
|
|
41
|
+
</div>;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
@Action({ onEvent: "add-domain"})
|
|
45
|
+
async addDomain() {
|
|
46
|
+
const domain = await PageNavigator.pushPageForResult(EditDomainPage, {});
|
|
47
|
+
this.domains.add(domain);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
@Action({ onEvent: "domain-selected"})
|
|
51
|
+
domainSelected() {
|
|
52
|
+
if(this.domain) {
|
|
53
|
+
this.close(this.domain);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { ContentPage, PopupWindowPage } from "@web-atoms/web-controls/dist/mobile-app/MobileApp";
|
|
2
|
+
import { Domain, HostedDomain, IDomain, IHostedDomain } from "../../../../model/model";
|
|
3
|
+
import XNode from "@web-atoms/core/dist/core/XNode";
|
|
4
|
+
import Form from "@web-atoms/web-controls/dist/basic/Form";
|
|
5
|
+
import FormField from "@web-atoms/web-controls/dist/basic/FormField";
|
|
6
|
+
import RequiredFormField, { TextFormField } from "../../../../common/controls/form/RequiredFormField";
|
|
7
|
+
import Bind from "@web-atoms/core/dist/core/Bind";
|
|
8
|
+
import Action from "@web-atoms/core/dist/view-model/Action";
|
|
9
|
+
import InjectProperty from "@web-atoms/core/dist/core/InjectProperty";
|
|
10
|
+
import AdminDomainService from "../services/AdminDomainService";
|
|
11
|
+
import Checkbox from "@web-atoms/web-controls/dist/basic/Checkbox";
|
|
12
|
+
import AtomRepeater from "@web-atoms/web-controls/dist/basic/AtomRepeater";
|
|
13
|
+
import Expander from "@web-atoms/web-controls/dist/basic/Expander";
|
|
14
|
+
import { AddIconTextButton } from "../../../../common/controls/buttons/IconButton";
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
export default class EditDomainPage extends ContentPage {
|
|
18
|
+
|
|
19
|
+
public parameters: { model?: IHostedDomain, domainID?: number };
|
|
20
|
+
|
|
21
|
+
public model: IHostedDomain;
|
|
22
|
+
|
|
23
|
+
@InjectProperty
|
|
24
|
+
private domainService: AdminDomainService;
|
|
25
|
+
|
|
26
|
+
async init() {
|
|
27
|
+
|
|
28
|
+
this.model = this.parameters.model
|
|
29
|
+
?? ( this.parameters.domainID
|
|
30
|
+
? await this.domainService.get(this.parameters.domainID)
|
|
31
|
+
: HostedDomain.create({
|
|
32
|
+
enableReceive: true,
|
|
33
|
+
enableSend: true,
|
|
34
|
+
useRelay: true,
|
|
35
|
+
domain: Domain.create({ name: ""})
|
|
36
|
+
}));
|
|
37
|
+
|
|
38
|
+
this.renderer = <div data-layout="center-page-900px">
|
|
39
|
+
<Form>
|
|
40
|
+
{ this.model.domainID
|
|
41
|
+
? <span text={this.model.domain.name}/>
|
|
42
|
+
: <TextFormField
|
|
43
|
+
required={true}
|
|
44
|
+
label="Domain"
|
|
45
|
+
value={() => this.model.domain.name}/>}
|
|
46
|
+
<Checkbox
|
|
47
|
+
checked={Bind.twoWaysImmediate(() => this.model.enableReceive)}
|
|
48
|
+
text="Receive Mails"
|
|
49
|
+
/>
|
|
50
|
+
<Checkbox
|
|
51
|
+
checked={Bind.twoWaysImmediate(() => this.model.enableSend)}
|
|
52
|
+
text="Send Mails"
|
|
53
|
+
/>
|
|
54
|
+
<Checkbox
|
|
55
|
+
checked={Bind.twoWaysImmediate(() => this.model.useRelay)}
|
|
56
|
+
text="Use Domain Relay"
|
|
57
|
+
/>
|
|
58
|
+
|
|
59
|
+
<Expander isExpanded={false}>
|
|
60
|
+
<label text="Relays"/>
|
|
61
|
+
<AtomRepeater
|
|
62
|
+
items={this.model.relays}
|
|
63
|
+
footer={true}
|
|
64
|
+
footerRenderer={() => <div data-layout="row">
|
|
65
|
+
<AddIconTextButton
|
|
66
|
+
text="New Relay"
|
|
67
|
+
/>
|
|
68
|
+
</div>}
|
|
69
|
+
/>
|
|
70
|
+
</Expander>
|
|
71
|
+
|
|
72
|
+
<Expander isExpanded={false}>
|
|
73
|
+
<label text="Domain Keys"/>
|
|
74
|
+
<AtomRepeater
|
|
75
|
+
items={this.model.domainKeys}
|
|
76
|
+
footer={true}
|
|
77
|
+
footerRenderer={() => <div data-layout="row">
|
|
78
|
+
<AddIconTextButton
|
|
79
|
+
text="New Domain Key"
|
|
80
|
+
/>
|
|
81
|
+
</div>}
|
|
82
|
+
/>
|
|
83
|
+
</Expander>
|
|
84
|
+
|
|
85
|
+
<div data-layout="command-row">
|
|
86
|
+
<button
|
|
87
|
+
data-layout="accent-button"
|
|
88
|
+
data-submit-event="save-domain"
|
|
89
|
+
text="Save"
|
|
90
|
+
/>
|
|
91
|
+
</div>
|
|
92
|
+
</Form>
|
|
93
|
+
</div>;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
@Action({ onEvent: "save-domain", close: true})
|
|
97
|
+
async saveDomain() {
|
|
98
|
+
await this.domainService.save(this.model);
|
|
99
|
+
return this.model;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import DITransient from "@web-atoms/core/dist/di/DITransient";
|
|
2
|
+
import { Inject } from "@web-atoms/core/dist/di/Inject";
|
|
3
|
+
import EntityService from "../../../../services/EntityService";
|
|
4
|
+
import { Domain, HostedDomain, IDomain, IHostedDomain } from "../../../../model/model";
|
|
5
|
+
|
|
6
|
+
@DITransient()
|
|
7
|
+
export default class AdminDomainService {
|
|
8
|
+
|
|
9
|
+
@Inject
|
|
10
|
+
private entityService: EntityService;
|
|
11
|
+
|
|
12
|
+
public list() {
|
|
13
|
+
return this.entityService
|
|
14
|
+
.query(HostedDomain)
|
|
15
|
+
.include((x) => x.domain)
|
|
16
|
+
.toArray();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
public save(domain: IHostedDomain) {
|
|
20
|
+
const clone = this.entityService.cloner(domain)
|
|
21
|
+
.include((x) => x.domainUsers)
|
|
22
|
+
.include((x) => x.domain);
|
|
23
|
+
return this.entityService.save(clone.copy);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
public get(domainID: number) {
|
|
27
|
+
return this.entityService.query(HostedDomain)
|
|
28
|
+
.where({ domainID }, (p) => (x) => x.domainID === p.domainID)
|
|
29
|
+
.include((x) => x.domain)
|
|
30
|
+
.include((x) => x.relays)
|
|
31
|
+
.include((x) => x.domainKeys).firstOrDefault();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { ContentPage } from "@web-atoms/web-controls/dist/mobile-app/MobileApp";
|
|
2
|
+
import { DomainUser, IUser, User } from "../../../model/model";
|
|
3
|
+
import XNode from "@web-atoms/core/dist/core/XNode";
|
|
4
|
+
import Form from "@web-atoms/web-controls/dist/basic/Form";
|
|
5
|
+
import FormField from "@web-atoms/web-controls/dist/basic/FormField";
|
|
6
|
+
import Bind from "@web-atoms/core/dist/core/Bind";
|
|
7
|
+
import RequiredFormField, { PasswordFormField, TextFormField } from "../../../common/controls/form/RequiredFormField";
|
|
8
|
+
import Action from "@web-atoms/core/dist/view-model/Action";
|
|
9
|
+
import AtomRepeater from "@web-atoms/web-controls/dist/basic/AtomRepeater";
|
|
10
|
+
import PageNavigator from "@web-atoms/web-controls/dist/PageNavigator";
|
|
11
|
+
import ChooseDomainPage from "../domains/choose/ChooseDomainPage";
|
|
12
|
+
import AdminUserService from "./services/AdminUserService";
|
|
13
|
+
import InjectProperty from "@web-atoms/core/dist/core/InjectProperty";
|
|
14
|
+
|
|
15
|
+
export default class EditUserPage extends ContentPage {
|
|
16
|
+
|
|
17
|
+
public parameters: { model?: IUser};
|
|
18
|
+
|
|
19
|
+
public model: IUser & { password?: string };
|
|
20
|
+
|
|
21
|
+
@InjectProperty
|
|
22
|
+
private adminUserService: AdminUserService;
|
|
23
|
+
|
|
24
|
+
async init() {
|
|
25
|
+
|
|
26
|
+
this.model = this.parameters.model ?? {
|
|
27
|
+
... User.create({
|
|
28
|
+
domainUsers: []
|
|
29
|
+
}),
|
|
30
|
+
password: ""
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
this.renderer = <div data-layout="center-page-900px">
|
|
34
|
+
<Form>
|
|
35
|
+
<TextFormField label="Display Name" autofocus={true} required={true} value={() => this.model.displayName}/>
|
|
36
|
+
<TextFormField label="Username" required={true} value={() => this.model.userName}/>
|
|
37
|
+
{ this.model.userID
|
|
38
|
+
? <PasswordFormField
|
|
39
|
+
label="Password"
|
|
40
|
+
required={true}
|
|
41
|
+
value={() => this.model.password}/>
|
|
42
|
+
: <PasswordFormField
|
|
43
|
+
label="Password"
|
|
44
|
+
placeholder="Leave empty..."
|
|
45
|
+
value={() => this.model.password}/>
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
<div>
|
|
49
|
+
<h5>Domains <i data-click-event="add-domain" class="fas fa-plus"/></h5>
|
|
50
|
+
<AtomRepeater
|
|
51
|
+
for="table"
|
|
52
|
+
items={this.model.domainUsers}
|
|
53
|
+
itemRenderer={(item) => <tr>
|
|
54
|
+
<td>{item.hostedDomain.domain.name}</td>
|
|
55
|
+
</tr>}
|
|
56
|
+
/>
|
|
57
|
+
</div>
|
|
58
|
+
|
|
59
|
+
<div data-layout="command-row">
|
|
60
|
+
<button
|
|
61
|
+
data-submit-event="save-user"
|
|
62
|
+
data-layout="accept-button"
|
|
63
|
+
text="Save"
|
|
64
|
+
/>
|
|
65
|
+
</div>
|
|
66
|
+
</Form>
|
|
67
|
+
</div>;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
@Action({ onEvent: "add-domain"})
|
|
71
|
+
async addDomain() {
|
|
72
|
+
const hostedDomain = await PageNavigator.pushPageForResult(ChooseDomainPage);
|
|
73
|
+
this.model.domainUsers.add(DomainUser.create({
|
|
74
|
+
domainID: hostedDomain.domainID,
|
|
75
|
+
hostedDomain
|
|
76
|
+
}));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
@Action({ onEvent: "save-user", close: true })
|
|
80
|
+
async saveUser() {
|
|
81
|
+
await this.adminUserService.save(this.model);
|
|
82
|
+
return this.model;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
}
|