@social-mail/social-mail-client 1.2.64 → 1.2.66
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 +299 -42
- package/dist/admin/AdminAppIndex.pack.js.map +1 -1
- package/dist/admin/AdminAppIndex.pack.min.js +61 -5
- package/dist/admin/AdminAppIndex.pack.min.js.map +1 -1
- package/dist/model/model.d.ts +120 -2
- package/dist/model/model.d.ts.map +1 -1
- package/dist/model/model.js +90 -1
- package/dist/model/model.js.map +1 -1
- package/dist/public/channel/BlogService.d.ts +4 -0
- package/dist/public/channel/BlogService.d.ts.map +1 -1
- package/dist/public/channel/BlogService.js +13 -2
- package/dist/public/channel/BlogService.js.map +1 -1
- package/dist/public/channel/ChannelMessage.d.ts.map +1 -1
- package/dist/public/channel/ChannelMessage.js +28 -4
- package/dist/public/channel/ChannelMessage.js.map +1 -1
- package/dist/public/channel/ChannelMessageList.d.ts.map +1 -1
- package/dist/public/channel/ChannelMessageList.js +8 -5
- package/dist/public/channel/ChannelMessageList.js.map +1 -1
- package/dist/public/channel/ChannelView.pack.js +4116 -3964
- package/dist/public/channel/ChannelView.pack.js.map +1 -1
- package/dist/public/channel/ChannelView.pack.min.js +4 -4
- package/dist/public/channel/ChannelView.pack.min.js.map +1 -1
- package/dist/public/channel/UrlService.d.ts +4 -0
- package/dist/public/channel/UrlService.d.ts.map +1 -0
- package/dist/public/channel/UrlService.js +22 -0
- package/dist/public/channel/UrlService.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/web/AppIndex.pack.js +300 -43
- package/dist/web/AppIndex.pack.js.map +1 -1
- package/dist/web/AppIndex.pack.min.js +62 -6
- package/dist/web/AppIndex.pack.min.js.map +1 -1
- package/dist/web/drawer/AppDrawer.js +1 -1
- package/dist/web/drawer/AppDrawer.js.map +1 -1
- package/dist/web/page/channels/detail/ChannelDetailPage.d.ts +2 -0
- package/dist/web/page/channels/detail/ChannelDetailPage.d.ts.map +1 -1
- package/dist/web/page/channels/detail/ChannelDetailPage.js +128 -2
- package/dist/web/page/channels/detail/ChannelDetailPage.js.map +1 -1
- package/dist/web/page/channels/services/ChannelService.d.ts +8 -0
- package/dist/web/page/channels/services/ChannelService.d.ts.map +1 -1
- package/dist/web/page/channels/services/ChannelService.js +37 -1
- package/dist/web/page/channels/services/ChannelService.js.map +1 -1
- package/dist/web/page/mails/ConversationPage.d.ts.map +1 -1
- package/dist/web/page/mails/ConversationPage.js +6 -3
- package/dist/web/page/mails/ConversationPage.js.map +1 -1
- package/dist/web/page/mails/service/MailService.d.ts.map +1 -1
- package/dist/web/page/mails/service/MailService.js +5 -2
- package/dist/web/page/mails/service/MailService.js.map +1 -1
- package/package.json +1 -1
- package/src/model/model.ts +137 -5
- package/src/public/channel/BlogService.ts +14 -2
- package/src/public/channel/ChannelMessage.tsx +19 -1
- package/src/public/channel/ChannelMessageList.tsx +6 -2
- package/src/public/channel/UrlService.ts +12 -0
- package/src/web/drawer/AppDrawer.tsx +1 -1
- package/src/web/page/channels/detail/ChannelDetailPage.tsx +113 -1
- package/src/web/page/channels/services/ChannelService.ts +32 -1
- package/src/web/page/mails/ConversationPage.tsx +5 -0
- package/src/web/page/mails/service/MailService.ts +3 -2
package/src/model/model.ts
CHANGED
|
@@ -27,9 +27,9 @@ export interface IAppFile extends IClrEntity {
|
|
|
27
27
|
readonly dateCreated?: DateTime;
|
|
28
28
|
dateUpdated?: DateTime | null;
|
|
29
29
|
versions?: number | null;
|
|
30
|
+
sourceUrl?: string;
|
|
30
31
|
url?: string;
|
|
31
32
|
downloadUrl?: string;
|
|
32
|
-
tempKeys?: string[];
|
|
33
33
|
fileContent?: IFileContent;
|
|
34
34
|
creator?: IUser;
|
|
35
35
|
parent?: IAppFile;
|
|
@@ -282,11 +282,12 @@ export interface IEmail extends IClrEntity {
|
|
|
282
282
|
readonly received?: boolean;
|
|
283
283
|
headers?: string | null;
|
|
284
284
|
headerMessageID?: string | null;
|
|
285
|
+
externalEmailID?: string | null;
|
|
285
286
|
mdBody?: string | null;
|
|
286
287
|
dateReceived?: DateTime;
|
|
287
288
|
dateCreated?: DateTime;
|
|
288
289
|
dateSent?: DateTime | null;
|
|
289
|
-
status?: "queued" | "received" | "draft" | "pending-approval" | "scheduled" | "sent" | "sent-failed";
|
|
290
|
+
status?: "queued" | "received" | "draft" | "published" | "pending-approval" | "scheduled" | "sent" | "sent-failed";
|
|
290
291
|
forwardCount?: number;
|
|
291
292
|
replyCount?: number;
|
|
292
293
|
viewCount?: number;
|
|
@@ -316,7 +317,7 @@ export interface IEmail extends IClrEntity {
|
|
|
316
317
|
subscriberActivities?: ICollection<ISubscriberActivity>;
|
|
317
318
|
}
|
|
318
319
|
|
|
319
|
-
export const EmailStatusArray = [{"label":"queued","value":"queued"},{"label":"received","value":"received"},{"label":"draft","value":"draft"},{"label":"pending-approval","value":"pending-approval"},{"label":"scheduled","value":"scheduled"},{"label":"sent","value":"sent"},{"label":"sent-failed","value":"sent-failed"}];
|
|
320
|
+
export const EmailStatusArray = [{"label":"queued","value":"queued"},{"label":"received","value":"received"},{"label":"draft","value":"draft"},{"label":"published","value":"published"},{"label":"pending-approval","value":"pending-approval"},{"label":"scheduled","value":"scheduled"},{"label":"sent","value":"sent"},{"label":"sent-failed","value":"sent-failed"}];
|
|
320
321
|
|
|
321
322
|
export const Email: IModel<IEmail> = new Model<IEmail>("Email", ["emailID"], { senderName: "",received: false,dateReceived: new DefaultFactory(() => new DateTime()),dateCreated: new DefaultFactory(() => new DateTime()),status: "queued",forwardCount: 0,replyCount: 0,viewCount: 0,originalFileSize: 0 });
|
|
322
323
|
|
|
@@ -413,7 +414,10 @@ export interface IMailbox extends IClrEntity {
|
|
|
413
414
|
dateUpdated?: DateTime;
|
|
414
415
|
isChannel?: boolean;
|
|
415
416
|
isPrivateChannel?: boolean;
|
|
417
|
+
requireApproval?: boolean;
|
|
416
418
|
subscriberCount?: number;
|
|
419
|
+
datePublished?: DateTime | null;
|
|
420
|
+
dateEngaged?: DateTime | null;
|
|
417
421
|
username?: string;
|
|
418
422
|
name?: string;
|
|
419
423
|
emailAddress?: IEmailAddress;
|
|
@@ -425,12 +429,13 @@ export interface IMailbox extends IClrEntity {
|
|
|
425
429
|
mailboxContacts?: ICollection<IMailboxContact>;
|
|
426
430
|
threadEmails?: ICollection<IMailboxContactEmail>;
|
|
427
431
|
syncTargets?: ICollection<IMailboxSyncTarget>;
|
|
432
|
+
channelConfig?: IChannelConfig;
|
|
428
433
|
subscriberActivities?: ICollection<ISubscriberActivity>;
|
|
429
434
|
userPins?: ICollection<IUserPin>;
|
|
430
435
|
userMailboxes?: ICollection<IUserMailbox>;
|
|
431
436
|
}
|
|
432
437
|
|
|
433
|
-
export const Mailbox: IModel<IMailbox> = new Model<IMailbox>("Mailbox", ["mailboxID"], { storage: 0,maxStorage: 0,indexAttachments: false,indexImageAttachments: false,dateCreated: new DefaultFactory(() => new DateTime()),dateUpdated: new DefaultFactory(() => new DateTime()),isChannel: false,isPrivateChannel: false,subscriberCount: 0 });
|
|
438
|
+
export const Mailbox: IModel<IMailbox> = new Model<IMailbox>("Mailbox", ["mailboxID"], { storage: 0,maxStorage: 0,indexAttachments: false,indexImageAttachments: false,dateCreated: new DefaultFactory(() => new DateTime()),dateUpdated: new DefaultFactory(() => new DateTime()),isChannel: false,isPrivateChannel: false,requireApproval: false,subscriberCount: 0 });
|
|
434
439
|
|
|
435
440
|
export interface IMailboxEmail extends IClrEntity {
|
|
436
441
|
mailboxID?: number;
|
|
@@ -455,6 +460,7 @@ export interface IMailboxContact extends IClrEntity {
|
|
|
455
460
|
canContribute?: boolean;
|
|
456
461
|
priority?: number;
|
|
457
462
|
blocked?: boolean;
|
|
463
|
+
mute?: boolean;
|
|
458
464
|
status?: "invited" | "added" | "active" | "unsubscribed" | "blocked";
|
|
459
465
|
emailAddressText?: string;
|
|
460
466
|
name?: string;
|
|
@@ -466,7 +472,7 @@ export interface IMailboxContact extends IClrEntity {
|
|
|
466
472
|
|
|
467
473
|
export const MailboxContactStatusArray = [{"label":"invited","value":"invited"},{"label":"added","value":"added"},{"label":"active","value":"active"},{"label":"unsubscribed","value":"unsubscribed"},{"label":"blocked","value":"blocked"}];
|
|
468
474
|
|
|
469
|
-
export const MailboxContact: IModel<IMailboxContact> = new Model<IMailboxContact>("MailboxContact", ["mailboxID","emailAddressID"], { dateCreated: new DefaultFactory(() => new DateTime()),dateUpdated: new DefaultFactory(() => new DateTime()),unread: 0,total: 0,isOwner: false,canContribute: false,priority: 0,blocked: false,status: "invited" });
|
|
475
|
+
export const MailboxContact: IModel<IMailboxContact> = new Model<IMailboxContact>("MailboxContact", ["mailboxID","emailAddressID"], { dateCreated: new DefaultFactory(() => new DateTime()),dateUpdated: new DefaultFactory(() => new DateTime()),unread: 0,total: 0,isOwner: false,canContribute: false,priority: 0,blocked: false,mute: false,status: "invited" });
|
|
470
476
|
|
|
471
477
|
export interface IMailboxContactEmail extends IClrEntity {
|
|
472
478
|
mailboxID?: number;
|
|
@@ -521,6 +527,19 @@ export const MailboxSyncTargetLastSyncStatusArray = [{"label":"none","value":"no
|
|
|
521
527
|
|
|
522
528
|
export const MailboxSyncTarget: IModel<IMailboxSyncTarget> = new Model<IMailboxSyncTarget>("MailboxSyncTarget", ["syncTargetID"], { direction: "in",protocol: "imap",username: "",host: "",port: 0,isSecure: false,syncAllFolders: false,syncJunkMails: false,intervalSeconds: 0,active: false });
|
|
523
529
|
|
|
530
|
+
export interface IChannelConfig extends IClrEntity {
|
|
531
|
+
mailboxID?: number;
|
|
532
|
+
inviteContent?: string | null;
|
|
533
|
+
welcomeContent?: string | null;
|
|
534
|
+
sendInviteOnEngagement?: boolean;
|
|
535
|
+
memberOnlyEngagement?: boolean;
|
|
536
|
+
notSafeForWork?: boolean;
|
|
537
|
+
postFooter?: string | null;
|
|
538
|
+
mailbox?: IMailbox;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
export const ChannelConfig: IModel<IChannelConfig> = new Model<IChannelConfig>("ChannelConfig", ["mailboxID"], { sendInviteOnEngagement: false,memberOnlyEngagement: false,notSafeForWork: false });
|
|
542
|
+
|
|
524
543
|
export interface ISubscriberActivity extends IClrEntity {
|
|
525
544
|
readonly activityID?: number;
|
|
526
545
|
mailboxID?: number;
|
|
@@ -585,6 +604,7 @@ export interface IUser extends IClrEntity {
|
|
|
585
604
|
userMailboxes?: ICollection<IUserMailbox>;
|
|
586
605
|
authFactors?: ICollection<IUserAuthFactor>;
|
|
587
606
|
publishedWebSiteVersions?: ICollection<IWebSiteFolderVersion>;
|
|
607
|
+
licenses?: ICollection<IAppLicense>;
|
|
588
608
|
}
|
|
589
609
|
|
|
590
610
|
export const UserStatusArray = [{"label":"active","value":"active"},{"label":"blocked","value":"blocked"},{"label":"locked","value":"locked"},{"label":"change-password","value":"change-password"},{"label":"external","value":"external"}];
|
|
@@ -718,3 +738,115 @@ export interface ITag extends IClrEntity {
|
|
|
718
738
|
}
|
|
719
739
|
|
|
720
740
|
export const Tag: IModel<ITag> = new Model<ITag>("Tag", ["tagID"], { name: "",isSystemTag: false });
|
|
741
|
+
|
|
742
|
+
export interface IProduct extends IClrEntity {
|
|
743
|
+
productID?: string;
|
|
744
|
+
name?: string;
|
|
745
|
+
description?: string | null;
|
|
746
|
+
prices?: ICollection<IProductPrice>;
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
export const Product: IModel<IProduct> = new Model<IProduct>("Product", ["productID"], { name: "" });
|
|
750
|
+
|
|
751
|
+
export interface IProductPrice extends IClrEntity {
|
|
752
|
+
priceID?: string;
|
|
753
|
+
productID?: string;
|
|
754
|
+
quantity?: number;
|
|
755
|
+
amount?: number;
|
|
756
|
+
isActive?: boolean;
|
|
757
|
+
currency?: string;
|
|
758
|
+
product?: IProduct;
|
|
759
|
+
licenses?: ICollection<IAppLicense>;
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
export const ProductPrice: IModel<IProductPrice> = new Model<IProductPrice>("ProductPrice", ["priceID"], { quantity: 0,amount: 0,isActive: false,currency: "" });
|
|
763
|
+
|
|
764
|
+
export interface IAppLicense extends IClrEntity {
|
|
765
|
+
readonly licenseID?: number;
|
|
766
|
+
customerID?: number;
|
|
767
|
+
priceID?: string;
|
|
768
|
+
dateCreated?: DateTime;
|
|
769
|
+
dateExpiry?: DateTime;
|
|
770
|
+
dateUpdated?: DateTime;
|
|
771
|
+
maxCores?: number;
|
|
772
|
+
licenseCode?: string;
|
|
773
|
+
customer?: IUser;
|
|
774
|
+
price?: IProductPrice;
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
export const AppLicense: IModel<IAppLicense> = new Model<IAppLicense>("AppLicense", ["licenseID","priceID"], { dateCreated: new DefaultFactory(() => new DateTime()),dateExpiry: new DefaultFactory(() => new DateTime()),dateUpdated: new DefaultFactory(() => new DateTime()),maxCores: 0,licenseCode: "" });
|
|
778
|
+
|
|
779
|
+
export interface IVirtualServer extends IClrEntity {
|
|
780
|
+
readonly serverID?: number;
|
|
781
|
+
serverName?: string;
|
|
782
|
+
ownerEmailAddress?: string | null;
|
|
783
|
+
ownerPhoneNumber?: string | null;
|
|
784
|
+
active?: boolean;
|
|
785
|
+
bucketName?: string | null;
|
|
786
|
+
database?: string | null;
|
|
787
|
+
host?: string;
|
|
788
|
+
forwardHost?: string | null;
|
|
789
|
+
forwardPublicKey?: string | null;
|
|
790
|
+
environmentVariables?: string | null;
|
|
791
|
+
maxStorageGB?: number;
|
|
792
|
+
dnsZones?: ICollection<IDnsZone>;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
export const VirtualServer: IModel<IVirtualServer> = new Model<IVirtualServer>("VirtualServer", ["serverID"], { serverName: "",active: false,host: "",maxStorageGB: 0 });
|
|
796
|
+
|
|
797
|
+
export interface IDnsZone extends IClrEntity {
|
|
798
|
+
readonly zoneID?: number;
|
|
799
|
+
serverID?: number;
|
|
800
|
+
zone?: string;
|
|
801
|
+
keySigningKeyID?: number;
|
|
802
|
+
zoneSigningKeyID?: number;
|
|
803
|
+
dateCreated?: DateTime;
|
|
804
|
+
dateUpdated?: DateTime;
|
|
805
|
+
signed?: string | null;
|
|
806
|
+
unsigned?: string | null;
|
|
807
|
+
virtualServer?: IVirtualServer;
|
|
808
|
+
ksk?: IDnsSigningKey;
|
|
809
|
+
zsk?: IDnsSigningKey;
|
|
810
|
+
records?: ICollection<IDnsZoneRecord>;
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
export const DnsZone: IModel<IDnsZone> = new Model<IDnsZone>("DnsZone", ["zoneID"], { zone: "",dateCreated: new DefaultFactory(() => new DateTime()),dateUpdated: new DefaultFactory(() => new DateTime()) });
|
|
814
|
+
|
|
815
|
+
export interface IDnsZoneRecord extends IClrEntity {
|
|
816
|
+
readonly recordID?: number;
|
|
817
|
+
zoneID?: number;
|
|
818
|
+
disabled?: boolean;
|
|
819
|
+
name?: string;
|
|
820
|
+
type?: "A" | "AAAA" | "CNAME" | "MX" | "TXT" | "PTR" | "SRV" | "CAA" | "NS" | "SOA";
|
|
821
|
+
isAlias?: boolean;
|
|
822
|
+
value?: string;
|
|
823
|
+
ttl?: number;
|
|
824
|
+
dateCreated?: DateTime;
|
|
825
|
+
dateUpdated?: DateTime;
|
|
826
|
+
notes?: string | null;
|
|
827
|
+
signature?: string | null;
|
|
828
|
+
expiryDate?: DateTime | null;
|
|
829
|
+
readonly fqdn?: string | null;
|
|
830
|
+
hosted?: boolean;
|
|
831
|
+
zone?: IDnsZone;
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
export const DnsZoneRecordTypeArray = [{"label":"A","value":"A"},{"label":"AAAA","value":"AAAA"},{"label":"CNAME","value":"CNAME"},{"label":"MX","value":"MX"},{"label":"TXT","value":"TXT"},{"label":"PTR","value":"PTR"},{"label":"SRV","value":"SRV"},{"label":"CAA","value":"CAA"},{"label":"NS","value":"NS"},{"label":"SOA","value":"SOA"}];
|
|
835
|
+
|
|
836
|
+
export const DnsZoneRecord: IModel<IDnsZoneRecord> = new Model<IDnsZoneRecord>("DnsZoneRecord", ["recordID"], { disabled: false,name: "",type: "A",isAlias: false,value: "",ttl: 0,dateCreated: new DefaultFactory(() => new DateTime()),dateUpdated: new DefaultFactory(() => new DateTime()),hosted: false });
|
|
837
|
+
|
|
838
|
+
export interface IDnsSigningKey extends IClrEntity {
|
|
839
|
+
readonly keyID?: number;
|
|
840
|
+
publicKey?: string;
|
|
841
|
+
digestAlgorithm?: number;
|
|
842
|
+
signingAlgorithm?: number;
|
|
843
|
+
digest?: string;
|
|
844
|
+
flags?: number;
|
|
845
|
+
dateCreated?: DateTime;
|
|
846
|
+
expiryDate?: DateTime;
|
|
847
|
+
fileName?: string;
|
|
848
|
+
kskZones?: ICollection<IDnsZone>;
|
|
849
|
+
zskZones?: ICollection<IDnsZone>;
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
export const DnsSigningKey: IModel<IDnsSigningKey> = new Model<IDnsSigningKey>("DnsSigningKey", ["keyID"], { publicKey: "",digestAlgorithm: 0,signingAlgorithm: 0,digest: "",flags: 0,dateCreated: new DefaultFactory(() => new DateTime()),expiryDate: new DefaultFactory(() => new DateTime()),fileName: "" });
|
|
@@ -15,6 +15,16 @@ export default class BlogService {
|
|
|
15
15
|
@Inject
|
|
16
16
|
downloader: EmailContentDownloader;
|
|
17
17
|
|
|
18
|
+
async getEmail({
|
|
19
|
+
emailID,
|
|
20
|
+
channelID
|
|
21
|
+
}) {
|
|
22
|
+
const q = this.entityService.query(Email, "channelEmails", channelID)
|
|
23
|
+
.where({ emailID }, (p) => (x) => x.emailID === p.emailID)
|
|
24
|
+
.include((x) => [x.children]);
|
|
25
|
+
return q.firstOrDefault();
|
|
26
|
+
}
|
|
27
|
+
|
|
18
28
|
async getEmails({
|
|
19
29
|
channelID = 0,
|
|
20
30
|
search = "",
|
|
@@ -43,12 +53,14 @@ export default class BlogService {
|
|
|
43
53
|
}
|
|
44
54
|
|
|
45
55
|
async getChannel(channelID?, emailAddress?: any) {
|
|
46
|
-
let q = this.entityService.query(Mailbox, "channels", emailAddress)
|
|
56
|
+
let q = this.entityService.query(Mailbox, "channels", emailAddress)
|
|
57
|
+
.where((x) => x.datePublished !== null);
|
|
47
58
|
if (channelID) {
|
|
48
59
|
q = q.where({ channelID}, (p) => (x) => x.mailboxID === p.channelID);
|
|
49
60
|
}
|
|
50
|
-
const c = await
|
|
61
|
+
const c = await q
|
|
51
62
|
.include((x) => x.emailAddress)
|
|
63
|
+
.orderByDescending((x) => x.datePublished)
|
|
52
64
|
.firstOrDefault();
|
|
53
65
|
return c;
|
|
54
66
|
}
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import InjectProperty from "@web-atoms/core/dist/core/InjectProperty";
|
|
2
2
|
import { AtomControl } from "@web-atoms/core/dist/web/controls/AtomControl";
|
|
3
3
|
import BlogService from "./BlogService";
|
|
4
|
+
import XNode from "@web-atoms/core/dist/core/XNode";
|
|
5
|
+
import { DateFormats } from "../../common/date/DateFormats";
|
|
6
|
+
import { renderMail } from "../../web/page/mails/service/ConversationService";
|
|
4
7
|
|
|
5
8
|
const url = (window as any).pageUrl as URL;
|
|
6
9
|
|
|
7
|
-
|
|
10
|
+
let {1: channelID = 1, 2: emailID = 82 } = /^\/channels\/([^\/]+)\/([^\/]+)\//.exec(url.pathname) ?? {} as any;
|
|
11
|
+
|
|
12
|
+
channelID = parseInt(channelID, 36);
|
|
13
|
+
emailID = parseInt(emailID, 36);
|
|
8
14
|
|
|
9
15
|
export default class ChannelMessage extends AtomControl {
|
|
10
16
|
|
|
@@ -13,6 +19,18 @@ export default class ChannelMessage extends AtomControl {
|
|
|
13
19
|
|
|
14
20
|
async init() {
|
|
15
21
|
const { items: [ email ]} = await this.blogService.getEmails({ channelID, start: 0, size: 1, cancelToken: null});
|
|
22
|
+
|
|
23
|
+
this.renderer = <section data-element="blog-item">
|
|
24
|
+
<h4 data-element="title">
|
|
25
|
+
<label text={email.subject}/>
|
|
26
|
+
</h4>
|
|
27
|
+
<h6 data-element="date" text={DateFormats.relative.short(email.dateSent)}/>
|
|
28
|
+
<h6 text={email.senderName}/>
|
|
29
|
+
<section
|
|
30
|
+
data-element="content">
|
|
31
|
+
<section { ... renderMail({ email })}/>
|
|
32
|
+
</section>
|
|
33
|
+
</section>;
|
|
16
34
|
}
|
|
17
35
|
|
|
18
36
|
}
|
|
@@ -10,6 +10,7 @@ import { IMailbox, IEmail } from "../../model/model";
|
|
|
10
10
|
import { renderMail } from "../../web/page/mails/service/ConversationService";
|
|
11
11
|
import BlogService from "./BlogService";
|
|
12
12
|
import { channelViewStyle } from "./channelViewStyle";
|
|
13
|
+
import { UrlService } from "./UrlService";
|
|
13
14
|
|
|
14
15
|
export default class ChannelView extends AtomControl {
|
|
15
16
|
|
|
@@ -29,12 +30,15 @@ export default class ChannelView extends AtomControl {
|
|
|
29
30
|
|
|
30
31
|
async init() {
|
|
31
32
|
|
|
32
|
-
|
|
33
|
+
let { channelID, emailAddress } = (window as any).socialMail ?? {};
|
|
33
34
|
|
|
34
35
|
this.element.setAttribute("data-blog-list", "blog-list");
|
|
35
36
|
|
|
36
37
|
this.channel = await this.blogService.getChannel(emailAddress, channelID);
|
|
37
38
|
|
|
39
|
+
channelID = this.channel.mailboxID;
|
|
40
|
+
emailAddress = this.channel.emailAddress.emailAddress;
|
|
41
|
+
|
|
38
42
|
this.renderer = <div data-layout="flex-center">
|
|
39
43
|
<span text="..."/>
|
|
40
44
|
</div>;
|
|
@@ -68,7 +72,7 @@ export default class ChannelView extends AtomControl {
|
|
|
68
72
|
itemRenderer={(email: IEmail) => {
|
|
69
73
|
return <section data-element="blog-item">
|
|
70
74
|
<h4 data-element="title">
|
|
71
|
-
<a href={
|
|
75
|
+
<a href={UrlService.toBlogUrl(channelID, email.emailID, email.subject)} text={email.subject}></a>
|
|
72
76
|
</h4>
|
|
73
77
|
<h6 data-element="date" text={DateFormats.relative.short(email.dateSent)}/>
|
|
74
78
|
<h6 text={email.senderName}/>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export const UrlService = {
|
|
2
|
+
|
|
3
|
+
toBlogUrl: (channelID: number, emailID: number, subject: string ) => {
|
|
4
|
+
subject ||= "";
|
|
5
|
+
if(subject.length > 400) {
|
|
6
|
+
subject = subject.substring(0, 400);
|
|
7
|
+
}
|
|
8
|
+
subject = subject.replace(/[^\p{L}\p{N}]+/ug, "-");
|
|
9
|
+
subject = encodeURIComponent(subject).replace(/\%20/g, "-");
|
|
10
|
+
return `/channels/${Number(channelID).toString(36)}/${Number(emailID).toString(36)}/${subject}`;
|
|
11
|
+
}
|
|
12
|
+
};
|
|
@@ -89,7 +89,7 @@ export default class AppDrawer extends Drawer {
|
|
|
89
89
|
commandLink={null}
|
|
90
90
|
/>
|
|
91
91
|
{ ... channels.map((mb) => <MenuItem
|
|
92
|
-
commandLink={AppCommands.
|
|
92
|
+
commandLink={AppCommands.openChannel.displayRoute({ id: mb.mailboxID })}
|
|
93
93
|
label={mb.emailAddress.name}
|
|
94
94
|
description={mb.emailAddress.emailAddress}
|
|
95
95
|
title={mb.emailAddress.emailAddress}
|
|
@@ -1,7 +1,76 @@
|
|
|
1
1
|
import { ContentPage } from "@web-atoms/web-controls/dist/mobile-app/MobileApp";
|
|
2
|
-
import { IMailbox } from "../../../../model/model";
|
|
2
|
+
import { IEmail, IMailbox } from "../../../../model/model";
|
|
3
3
|
import InjectProperty from "@web-atoms/core/dist/core/InjectProperty";
|
|
4
4
|
import MailboxService from "../../../../common/pages/mailboxes/services/MailboxService";
|
|
5
|
+
import XNode from "@web-atoms/core/dist/core/XNode";
|
|
6
|
+
import AppCommands from "../../../commands/AppCommands";
|
|
7
|
+
import AtomRepeater from "@web-atoms/web-controls/dist/basic/AtomRepeater";
|
|
8
|
+
import ChannelService from "../services/ChannelService";
|
|
9
|
+
import InfiniteRepeater from "../../../../common/controls/repeater/InfiniteRepeater";
|
|
10
|
+
import Bind from "@web-atoms/core/dist/core/Bind";
|
|
11
|
+
import LimitedText from "@web-atoms/web-controls/dist/basic/LimitedText";
|
|
12
|
+
import { renderMail } from "../../mails/service/ConversationService";
|
|
13
|
+
import { DateFormats } from "../../../../common/date/DateFormats";
|
|
14
|
+
import styled from "@web-atoms/core/dist/style/styled";
|
|
15
|
+
|
|
16
|
+
const css = styled.css `
|
|
17
|
+
|
|
18
|
+
& [data-blog-list=blog-list] {
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
display: flex;
|
|
22
|
+
flex-direction: column;
|
|
23
|
+
gap: 10px;
|
|
24
|
+
|
|
25
|
+
& > * {
|
|
26
|
+
border: solid 1px lightgray;
|
|
27
|
+
border-radius: 5px;
|
|
28
|
+
display: inline-grid;
|
|
29
|
+
grid-template-columns: 5px 1fr auto auto 5px;
|
|
30
|
+
grid-template-rows: 5px auto auto 1fr auto 5px;
|
|
31
|
+
|
|
32
|
+
& > [data-element=bg] {
|
|
33
|
+
grid-row: 1 / span 3;
|
|
34
|
+
grid-column: 1/ span 5;
|
|
35
|
+
background-color: lightgrey;
|
|
36
|
+
z-index: -1;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
& > h4, & > h6 {
|
|
40
|
+
margin-block-start: 0;
|
|
41
|
+
margin-block-end: 0;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
& > [data-element=actions] {
|
|
45
|
+
grid-row: 2;
|
|
46
|
+
grid-column: 4;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
& > [data-element=title] {
|
|
50
|
+
grid-row: 3;
|
|
51
|
+
grid-column: 2 / span 2;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
& > [data-element=date] {
|
|
55
|
+
grid-row: 2;
|
|
56
|
+
grid-column: 3;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
& > [data-element=author] {
|
|
60
|
+
grid-row: 2;
|
|
61
|
+
grid-column: 2;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
& > [data-element=content] {
|
|
65
|
+
grid-row: 4;
|
|
66
|
+
grid-column: 2 / span 4;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
`.installLocal();
|
|
73
|
+
|
|
5
74
|
|
|
6
75
|
export default class ChannelDetailPage extends ContentPage {
|
|
7
76
|
|
|
@@ -9,12 +78,55 @@ export default class ChannelDetailPage extends ContentPage {
|
|
|
9
78
|
|
|
10
79
|
public mailbox: IMailbox;
|
|
11
80
|
|
|
81
|
+
public search = "";
|
|
82
|
+
|
|
12
83
|
@InjectProperty
|
|
13
84
|
private mailboxService: MailboxService;
|
|
14
85
|
|
|
86
|
+
@InjectProperty
|
|
87
|
+
private channelService: ChannelService;
|
|
88
|
+
|
|
15
89
|
async init() {
|
|
90
|
+
|
|
16
91
|
this.mailbox = await this.mailboxService.get(this.parameters.id);
|
|
17
92
|
this.title = `${this.mailbox.emailAddress.name || this.mailbox.name} (${this.mailbox.emailAddress.emailAddress})`;
|
|
93
|
+
|
|
94
|
+
this.headerRenderer = () => <div data-layout="header-row">
|
|
95
|
+
<input type="search" value={Bind.twoWaysImmediate(() => this.search)}/>
|
|
96
|
+
<a
|
|
97
|
+
data-click-event="route"
|
|
98
|
+
href={AppCommands.openSubscribers.displayRoute({ id: this.parameters.id})}>Subscribers</a>
|
|
99
|
+
</div>;
|
|
100
|
+
|
|
101
|
+
this.renderer = <section class={css}>
|
|
102
|
+
<AtomRepeater
|
|
103
|
+
data-blog-list="blog-list"
|
|
104
|
+
{ ... InfiniteRepeater.pagedItems((start) =>
|
|
105
|
+
(c, e, cancelToken) =>
|
|
106
|
+
this.channelService.getMails({
|
|
107
|
+
channelID: this.parameters.id,
|
|
108
|
+
search: this.search,
|
|
109
|
+
cancelToken
|
|
110
|
+
})
|
|
111
|
+
)}
|
|
112
|
+
itemRenderer={(email: IEmail) => <section data-element="blog-item">
|
|
113
|
+
<div data-element="bg"/>
|
|
114
|
+
<h4 data-element="title"
|
|
115
|
+
text={email.subject}/>
|
|
116
|
+
<h6 data-element="date" text={DateFormats.relative.short(email.dateSent)}/>
|
|
117
|
+
<h6 data-element="author" text={email.senderName}/>
|
|
118
|
+
<i
|
|
119
|
+
data-element="actions"
|
|
120
|
+
class="fa-light fa-square-ellipsis-vertical"/>
|
|
121
|
+
<section
|
|
122
|
+
data-element="content">
|
|
123
|
+
<LimitedText height={200}>
|
|
124
|
+
<section { ... renderMail({ email })}/>
|
|
125
|
+
</LimitedText>
|
|
126
|
+
</section>
|
|
127
|
+
</section>}
|
|
128
|
+
/>
|
|
129
|
+
</section>;
|
|
18
130
|
}
|
|
19
131
|
|
|
20
132
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import DITransient from "@web-atoms/core/dist/di/DITransient";
|
|
2
2
|
import { Inject } from "@web-atoms/core/dist/di/Inject";
|
|
3
3
|
import EntityService from "../../../../services/EntityService";
|
|
4
|
-
import { IMailboxContact, Mailbox, MailboxContact } from "../../../../model/model";
|
|
4
|
+
import { Email, IMailboxContact, Mailbox, MailboxContact } from "../../../../model/model";
|
|
5
5
|
import { Sql } from "../../../../common/Sql";
|
|
6
6
|
|
|
7
7
|
@DITransient({})
|
|
@@ -10,6 +10,37 @@ export default class ChannelService {
|
|
|
10
10
|
@Inject
|
|
11
11
|
private entityService: EntityService;
|
|
12
12
|
|
|
13
|
+
public async getMails({
|
|
14
|
+
channelID,
|
|
15
|
+
published = true,
|
|
16
|
+
start = 0,
|
|
17
|
+
size = 100,
|
|
18
|
+
search = "",
|
|
19
|
+
cancelToken
|
|
20
|
+
}) {
|
|
21
|
+
let q = this.entityService.query(Email);
|
|
22
|
+
|
|
23
|
+
if (channelID) {
|
|
24
|
+
q = q.where({ channelID}, (p) => (x) => x.mailboxes.some((m) => m.mailboxID === p.channelID));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (published) {
|
|
28
|
+
q = q.where((x) => x.status === "published");
|
|
29
|
+
} else {
|
|
30
|
+
q = q.where((x) => x.status !== "published");
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (search) {
|
|
34
|
+
if (!/\%/.test(search)) {
|
|
35
|
+
search = search + "%";
|
|
36
|
+
}
|
|
37
|
+
q = q.where({ search }, (p) => (x) => Sql.text.like(x.subject, p.search));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return q.orderByDescending((x) => x.emailID)
|
|
41
|
+
.toPagedList({ start, size, cancelToken });
|
|
42
|
+
}
|
|
43
|
+
|
|
13
44
|
public async getMailbox(id: number) {
|
|
14
45
|
return this.entityService.query(Mailbox)
|
|
15
46
|
.include((x) => x.emailAddress)
|
|
@@ -288,6 +288,11 @@ export default class ConversationPage extends ContentPage {
|
|
|
288
288
|
void InlinePopupControl.showPopup(ce.target as HTMLElement, <div
|
|
289
289
|
data-click-event="none"
|
|
290
290
|
data-click-animate="none">
|
|
291
|
+
{ thread.email?.status === "published" &&
|
|
292
|
+
<MenuItem
|
|
293
|
+
icon="fas fa-delete"
|
|
294
|
+
data-click-event="un-publish-mail"/>
|
|
295
|
+
}
|
|
291
296
|
<MenuItem
|
|
292
297
|
eventClick={() => PageNavigator.pushPage(MailDetailPage, thread.email)}
|
|
293
298
|
icon="fas fa-eye"
|
|
@@ -52,8 +52,9 @@ export default class MailService {
|
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
async send(email: IEmail) {
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
const { textBody } = email;
|
|
56
|
+
if (textBody) {
|
|
57
|
+
email.subject ||= textBody.split("\n")[0].substring(0, 80);
|
|
57
58
|
}
|
|
58
59
|
for (const iterator of email.recipients) {
|
|
59
60
|
if (iterator.emailAddressText) {
|