@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.
Files changed (111) hide show
  1. package/README.md +1 -91
  2. package/dist/admin/Admin.js +50 -2
  3. package/dist/admin/Admin.js.map +1 -1
  4. package/dist/admin/commands/AdminCommands.js +37 -0
  5. package/dist/admin/commands/AdminCommands.js.map +1 -1
  6. package/dist/admin/drawer/AdminDrawer.js +40 -2
  7. package/dist/admin/drawer/AdminDrawer.js.map +1 -1
  8. package/dist/admin/pages/config/ConfigPage.js +18 -0
  9. package/dist/admin/pages/config/ConfigPage.js.map +1 -0
  10. package/dist/admin/pages/domains/ChooseDomainPage.js +86 -0
  11. package/dist/admin/pages/domains/ChooseDomainPage.js.map +1 -0
  12. package/dist/admin/pages/domains/DomainListPage.js +67 -0
  13. package/dist/admin/pages/domains/DomainListPage.js.map +1 -0
  14. package/dist/admin/pages/domains/EditDomainPage.js +79 -0
  15. package/dist/admin/pages/domains/EditDomainPage.js.map +1 -0
  16. package/dist/admin/pages/domains/services/AdminDomainService.js +50 -0
  17. package/dist/admin/pages/domains/services/AdminDomainService.js.map +1 -0
  18. package/dist/admin/pages/home/AdminHome.js +18 -0
  19. package/dist/admin/pages/home/AdminHome.js.map +1 -0
  20. package/dist/admin/pages/users/EditUserPage.js +105 -0
  21. package/dist/admin/pages/users/EditUserPage.js.map +1 -0
  22. package/dist/admin/pages/users/UserListPage.js +82 -0
  23. package/dist/admin/pages/users/UserListPage.js.map +1 -0
  24. package/dist/admin/pages/users/services/AdminUserService.js +57 -0
  25. package/dist/admin/pages/users/services/AdminUserService.js.map +1 -0
  26. package/dist/common/SocialMailApp.js +14 -0
  27. package/dist/common/SocialMailApp.js.map +1 -0
  28. package/dist/common/Sql.js +12 -0
  29. package/dist/common/Sql.js.map +1 -0
  30. package/dist/common/controls/form/RequiredFormField.js +57 -0
  31. package/dist/common/controls/form/RequiredFormField.js.map +1 -0
  32. package/dist/common/controls/repeater/InfiniteRepeater.js +100 -0
  33. package/dist/common/controls/repeater/InfiniteRepeater.js.map +1 -0
  34. package/dist/common/pages/LoginPage.js +79 -0
  35. package/dist/common/pages/LoginPage.js.map +1 -0
  36. package/dist/common/pages/mailboxes/MailboxEditorPage.js +79 -0
  37. package/dist/common/pages/mailboxes/MailboxEditorPage.js.map +1 -0
  38. package/dist/common/pages/mailboxes/MailboxListPage.js +80 -0
  39. package/dist/common/pages/mailboxes/MailboxListPage.js.map +1 -0
  40. package/dist/common/pages/mailboxes/services/MailboxService.js +60 -0
  41. package/dist/common/pages/mailboxes/services/MailboxService.js.map +1 -0
  42. package/dist/common/pages/user/LoginPage.js +79 -0
  43. package/dist/common/pages/user/LoginPage.js.map +1 -0
  44. package/dist/model/model.js +36 -0
  45. package/dist/model/model.js.map +1 -1
  46. package/dist/services/ConfigService.js +45 -0
  47. package/dist/services/ConfigService.js.map +1 -0
  48. package/dist/services/EntityService.js +4 -0
  49. package/dist/services/EntityService.js.map +1 -1
  50. package/dist/services/UserService.js +54 -0
  51. package/dist/services/UserService.js.map +1 -0
  52. package/dist/style/GlobalStyle.js +11 -3
  53. package/dist/style/GlobalStyle.js.map +1 -1
  54. package/dist/style/OverrideAppStyle.js +22 -0
  55. package/dist/style/OverrideAppStyle.js.map +1 -0
  56. package/dist/tsconfig.tsbuildinfo +1 -1
  57. package/dist/web/AppIndex.js +38 -2
  58. package/dist/web/AppIndex.js.map +1 -1
  59. package/node_modules/@web-atoms/entity/dist/services/BaseEntityService.d.ts +5 -2
  60. package/node_modules/@web-atoms/entity/dist/services/BaseEntityService.d.ts.map +1 -1
  61. package/node_modules/@web-atoms/entity/dist/services/BaseEntityService.js +18 -1
  62. package/node_modules/@web-atoms/entity/dist/services/BaseEntityService.js.map +1 -1
  63. package/node_modules/@web-atoms/entity/dist/services/MockBaseEntityService.d.ts +2 -0
  64. package/node_modules/@web-atoms/entity/dist/services/MockBaseEntityService.d.ts.map +1 -1
  65. package/node_modules/@web-atoms/entity/dist/services/MockBaseEntityService.js +1 -0
  66. package/node_modules/@web-atoms/entity/dist/services/MockBaseEntityService.js.map +1 -1
  67. package/node_modules/@web-atoms/entity/dist/services/Query.d.ts +2 -0
  68. package/node_modules/@web-atoms/entity/dist/services/Query.d.ts.map +1 -1
  69. package/node_modules/@web-atoms/entity/dist/services/Query.js +9 -6
  70. package/node_modules/@web-atoms/entity/dist/services/Query.js.map +1 -1
  71. package/node_modules/@web-atoms/entity/dist/services/QueryProcessor.d.ts +2 -0
  72. package/node_modules/@web-atoms/entity/dist/services/QueryProcessor.d.ts.map +1 -0
  73. package/node_modules/@web-atoms/entity/dist/services/QueryProcessor.js +9 -0
  74. package/node_modules/@web-atoms/entity/dist/services/QueryProcessor.js.map +1 -0
  75. package/node_modules/@web-atoms/entity/dist/tsconfig.tsbuildinfo +1 -1
  76. package/node_modules/@web-atoms/entity/package.json +1 -1
  77. package/node_modules/@web-atoms/entity/src/services/BaseEntityService.ts +23 -3
  78. package/node_modules/@web-atoms/entity/src/services/MockBaseEntityService.ts +3 -0
  79. package/node_modules/@web-atoms/entity/src/services/Query.ts +12 -7
  80. package/node_modules/@web-atoms/entity/src/services/QueryProcessor.ts +1 -0
  81. package/package.json +2 -2
  82. package/src/admin/Admin.tsx +40 -1
  83. package/src/admin/commands/AdminCommands.ts +33 -0
  84. package/src/admin/drawer/AdminDrawer.tsx +70 -0
  85. package/src/admin/pages/config/ConfigPage.tsx +5 -0
  86. package/src/admin/pages/domains/DomainListPage.tsx +43 -0
  87. package/src/admin/pages/domains/choose/ChooseDomainPage.tsx +57 -0
  88. package/src/admin/pages/domains/edit/EditDomainPage.tsx +102 -0
  89. package/src/admin/pages/domains/services/AdminDomainService.ts +34 -0
  90. package/src/admin/pages/home/AdminHome.tsx +6 -0
  91. package/src/admin/pages/users/EditUserPage.tsx +85 -0
  92. package/src/admin/pages/users/UserListPage.tsx +53 -0
  93. package/src/admin/pages/users/services/AdminUserService.ts +34 -0
  94. package/src/common/SocialMailApp.ts +7 -0
  95. package/src/common/Sql.ts +74 -0
  96. package/src/common/commands/CommonCommands.ts +6 -0
  97. package/src/common/controls/buttons/IconButton.tsx +60 -0
  98. package/src/common/controls/form/RequiredFormField.tsx +53 -0
  99. package/src/common/controls/repeater/InfiniteRepeater.tsx +93 -0
  100. package/src/common/pages/mailboxes/MailboxEditorPage.tsx +66 -0
  101. package/src/common/pages/mailboxes/MailboxListPage.tsx +48 -0
  102. package/src/common/pages/mailboxes/services/MailboxService.ts +34 -0
  103. package/src/common/pages/user/LoginPage.tsx +51 -0
  104. package/src/model/model.ts +234 -0
  105. package/src/services/BusyProgress.ts +2 -2
  106. package/src/services/ConfigService.ts +19 -0
  107. package/src/services/EntityService.ts +3 -0
  108. package/src/services/UserService.ts +26 -0
  109. package/src/style/GlobalStyle.ts +11 -2
  110. package/src/style/OverrideAppStyle.ts +9 -0
  111. 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
- constructor(public name: string) {
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.1",
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.19",
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",
@@ -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,5 @@
1
+ import { ContentPage } from "@web-atoms/web-controls/dist/mobile-app/MobileApp";
2
+
3
+ export default class ConfigPage extends ContentPage {
4
+
5
+ }
@@ -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,6 @@
1
+ import Command from "@web-atoms/core/dist/core/Command";
2
+ import { ContentPage } from "@web-atoms/web-controls/dist/mobile-app/MobileApp";
3
+
4
+ export default class AdminHome extends ContentPage {
5
+
6
+ }
@@ -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
+ }