@things-factory/announcement 10.1.256 → 10.1.257

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.
@@ -2,16 +2,18 @@ import '@operato/list-state/ox-page-state.js'
2
2
  import '../components/announcement-sheet.js'
3
3
  import '../components/announcement-receipts.js'
4
4
 
5
+ import gql from 'graphql-tag'
5
6
  import { css, html, nothing } from 'lit'
6
7
  import { customElement, state } from 'lit/decorators.js'
7
8
 
9
+ import { MutationController, QueryController } from '@operato/graphql'
8
10
  import { i18next, localize } from '@operato/i18n'
9
11
  import { notify, openPopup } from '@operato/layout'
10
12
  import { navigate, PageView } from '@operato/shell'
11
13
  import { DocumentPageStyles } from '@operato/styles'
12
14
 
13
- import { announcementApi, type AnnouncementItem } from '../utils/announcement-api.js'
14
- import { reasonOf, statusWord, t, when } from '../utils/announcement-words.js'
15
+ import { announcementApi, FULL_FIELDS, type AnnouncementItem } from '../utils/announcement-api.js'
16
+ import { statusWord, t, when } from '../utils/announcement-words.js'
15
17
 
16
18
  /**
17
19
  * 공지 보기 — one announcement. Opening it reads it for its audience (ADR-0163 decision 5). Its writers also see whom it
@@ -49,9 +51,34 @@ export class AnnouncementView extends localize(i18next)(PageView) {
49
51
  `
50
52
  ]
51
53
 
52
- @state() announcement: AnnouncementItem | null = null
53
- @state() loading = false
54
- @state() error: unknown = null
54
+ @state() private announcementId = ''
55
+
56
+ /* The announcement the address names, with its writers' counts (ADR-0190). */
57
+ private read = new QueryController(this, gql`query ($id: String!) { announcement(id: $id) { ${FULL_FIELDS} readCount acknowledgedCount } }`, {
58
+ variables: () => (this.announcementId ? { id: this.announcementId } : undefined)
59
+ })
60
+
61
+ private reminder = new MutationController(this, gql`mutation ($id: String!) { remindAnnouncement(id: $id) }`)
62
+
63
+ get announcement(): AnnouncementItem | null {
64
+ return this.read.data?.announcement ?? null
65
+ }
66
+
67
+ private get error(): unknown {
68
+ if (this.read.error) return this.read.error
69
+ return this.read.data && !this.announcement ? new Error(t('announcement.refusal.unknown-announcement')) : null
70
+ }
71
+
72
+ /* Opening it reads it - asked again after, so its writer's counts include this reading. */
73
+ private readFor?: unknown
74
+
75
+ async updated() {
76
+ const one = this.announcement
77
+ if (!one?.addressed || one.mine?.readAt || this.readFor === this.read.data) return
78
+ this.readFor = this.read.data
79
+ await announcementApi.read(one.id).catch(() => {})
80
+ await this.read.refetch()
81
+ }
55
82
 
56
83
  get context() {
57
84
  const one = this.announcement
@@ -78,19 +105,19 @@ export class AnnouncementView extends localize(i18next)(PageView) {
78
105
  async pageUpdated(changes: any, lifecycle: any) {
79
106
  if (!this.active || !(changes.active || changes.params)) return
80
107
  const id = lifecycle?.params?.id
81
- if (id) await this.load(id)
108
+ if (id) this.announcementId = id
82
109
  }
83
110
 
84
111
  render() {
85
112
  const one = this.announcement
86
- return html`<ox-page-state .loading=${this.loading} .error=${this.error} @retry=${() => one && this.load(one.id)}>
113
+ return html`<ox-page-state .loading=${this.read.loading} .error=${this.error} @retry=${() => this.read.refetch()}>
87
114
  ${one
88
115
  ? html`<div class="page">
89
116
  <section class="page-section">
90
117
  <h2>${one.title}</h2>
91
118
  ${one.status === 'WITHDRAWN' ? html`<p class="notice">${t('announcement.text.withdrawn', { when: when(one.withdrawnAt), reason: one.withdrawReason ?? '' })}</p>` : nothing}
92
119
  ${one.status === 'SCHEDULED' ? html`<p class="notice">${t('announcement.text.scheduled', { when: when(one.startsAt) })}</p>` : nothing}
93
- <announcement-sheet .announcement=${one} @announcement-acknowledged=${() => this.load(one.id)}></announcement-sheet>
120
+ <announcement-sheet .announcement=${one} @announcement-acknowledged=${() => this.read.refetch()}></announcement-sheet>
94
121
  </section>
95
122
  ${one.editable && one.audiences
96
123
  ? html`<section class="page-section">
@@ -123,27 +150,6 @@ export class AnnouncementView extends localize(i18next)(PageView) {
123
150
  </ox-page-state>`
124
151
  }
125
152
 
126
- private async load(id: string) {
127
- this.loading = true
128
- this.error = null
129
- try {
130
- let one = await announcementApi.one(id)
131
- if (!one) throw new Error(t('announcement.refusal.unknown-announcement'))
132
- /* Opening it reads it - asked again after, so its writer's counts include this reading. */
133
- if (one.addressed && !one.mine?.readAt) {
134
- await announcementApi.read(id)
135
- one = (await announcementApi.one(id)) ?? one
136
- }
137
- this.announcement = one
138
- } catch (error) {
139
- this.announcement = null
140
- this.error = error
141
- } finally {
142
- this.loading = false
143
- this.updateContext()
144
- }
145
- }
146
-
147
153
  private openReceipts() {
148
154
  const one = this.announcement!
149
155
  const popup: any = openPopup(html`<announcement-receipts .announcement=${one} @done=${() => popup.close()}></announcement-receipts>`, {
@@ -154,18 +160,14 @@ export class AnnouncementView extends localize(i18next)(PageView) {
154
160
  }
155
161
 
156
162
  private async remind() {
157
- try {
158
- const told = await announcementApi.remind(this.announcement!.id)
159
- notify({ message: t('announcement.text.reminded', { count: told }) })
160
- } catch (error) {
161
- notify({ level: 'error', message: reasonOf(error) })
162
- }
163
+ const done = await this.reminder.run({ id: this.announcement!.id })
164
+ if (done) notify({ message: t('announcement.text.reminded', { count: done.remindAnnouncement }) })
163
165
  }
164
166
 
165
167
  private withdraw() {
166
168
  const one = this.announcement!
167
169
  const popup: any = openPopup(
168
- html`<announcement-withdraw-form .announcement=${one} @announcement-withdrawn=${() => this.load(one.id)} @done=${() => popup.close()}></announcement-withdraw-form>`,
170
+ html`<announcement-withdraw-form .announcement=${one} @announcement-withdrawn=${() => this.read.refetch()} @done=${() => popup.close()}></announcement-withdraw-form>`,
169
171
  { backdrop: true, size: 'small', title: `${t('announcement.button.withdraw')} · ${one.title}` }
170
172
  )
171
173
  }
@@ -1,5 +1,6 @@
1
1
  /*
2
- * The announcement doors as the screens call them (ADR-0163). Every call throws the server's words when it is refused.
2
+ * The announcement doors the editor, the badge and the popups call (ADR-0163). Every call throws the server's words when
3
+ * it is refused. The other screens declare their own reads and saves (ADR-0190).
3
4
  */
4
5
  import gql from 'graphql-tag'
5
6
 
@@ -84,59 +85,11 @@ async function change<T>(mutation: string, variables: Record<string, unknown>, f
84
85
  export const announcementsChanged = () => window.dispatchEvent(new CustomEvent('announcements-changed'))
85
86
 
86
87
  export const announcementApi = {
87
- one: (id: string) => ask<AnnouncementItem | null>(`query ($id: String!) { announcement(id: $id) { ${FULL_FIELDS} readCount acknowledgedCount } }`, { id }, 'announcement'),
88
88
  summary: () => ask<{ unread: number; toAcknowledge: number; pending: number }>(`query { announcementSummary { unread toAcknowledge pending } }`, {}, 'announcementSummary'),
89
89
  popups: () => ask<AnnouncementItem[]>(`query { announcementPopups { ${FULL_FIELDS} } }`, {}, 'announcementPopups'),
90
90
  read: async (id: string) => {
91
91
  const one = await change<AnnouncementItem>(`mutation ($id: String!) { readAnnouncement(id: $id) { id readerState mine { readAt acknowledgedAt } } }`, { id }, 'readAnnouncement')
92
92
  announcementsChanged()
93
93
  return one
94
- },
95
- acknowledge: async (id: string) => {
96
- const one = await change<AnnouncementItem>(`mutation ($id: String!) { acknowledgeAnnouncement(id: $id) { id readerState mine { readAt acknowledgedAt } } }`, { id }, 'acknowledgeAnnouncement')
97
- announcementsChanged()
98
- return one
99
- },
100
- receipts: (id: string) =>
101
- ask<{ userId: string; name?: string; email?: string; listed: boolean; notifiedAt?: string; readAt?: string; acknowledgedAt?: string }[]>(
102
- `query ($id: String!) { announcementReceipts(id: $id) { userId name email listed notifiedAt readAt acknowledgedAt } }`,
103
- { id },
104
- 'announcementReceipts'
105
- ),
106
- revisions: (id: string) =>
107
- ask<{ version: number; title: string; body?: string; rest?: any; createdAt: string; creator?: { name?: string } }[]>(
108
- `query ($id: String!) { announcementRevisions(id: $id) { version title body rest createdAt creator { name } } }`,
109
- { id },
110
- 'announcementRevisions'
111
- ),
112
- choices: () =>
113
- ask<{ domainId: string; domainName: string; departments: { id: string; name: string; note?: string }[]; roles: { id: string; name: string; note?: string }[] }>(
114
- `query { announcementAudienceChoices { domainId domainName departments { id name note } roles { id name note } } }`,
115
- {},
116
- 'announcementAudienceChoices'
117
- ),
118
- people: (text: string) => ask<{ id: string; name: string; note?: string }[]>(`query ($text: String!) { announcementPeople(text: $text) { id name note } }`, { text }, 'announcementPeople'),
119
- audienceSize: (audiences: Audience[]) =>
120
- ask<number>(`query ($audiences: [AnnouncementAudienceInput!]!) { announcementAudienceSize(audiences: $audiences) }`, { audiences }, 'announcementAudienceSize'),
121
- create: (input: AnnouncementInput, attach: File[], uploading?: (fraction: number) => void) =>
122
- change<AnnouncementItem>(
123
- `mutation ($input: AnnouncementInput!, $attach: [Upload!]) { createAnnouncement(input: $input, attach: $attach) { id } }`,
124
- { input, attach },
125
- 'createAnnouncement',
126
- attach.length ? uploading ?? (() => {}) : undefined
127
- ),
128
- update: (id: string, input: AnnouncementInput, attach: File[], remove: string[], notifyAgain: boolean, uploading?: (fraction: number) => void) =>
129
- change<AnnouncementItem>(
130
- `mutation ($id: String!, $input: AnnouncementInput!, $attach: [Upload!], $remove: [String!], $notifyAgain: Boolean) {
131
- updateAnnouncement(id: $id, input: $input, attach: $attach, remove: $remove, notifyAgain: $notifyAgain) { id status }
132
- }`,
133
- { id, input, attach, remove, notifyAgain },
134
- 'updateAnnouncement',
135
- attach.length ? uploading ?? (() => {}) : undefined
136
- ),
137
- publish: (id: string) => change<AnnouncementItem>(`mutation ($id: String!) { publishAnnouncement(id: $id) { id status startsAt } }`, { id }, 'publishAnnouncement'),
138
- withdraw: (id: string, reason: string) =>
139
- change<AnnouncementItem>(`mutation ($id: String!, $reason: String!) { withdrawAnnouncement(id: $id, reason: $reason) { id status } }`, { id, reason }, 'withdrawAnnouncement'),
140
- remove: (id: string) => change<boolean>(`mutation ($id: String!) { deleteAnnouncement(id: $id) }`, { id }, 'deleteAnnouncement'),
141
- remind: (id: string) => change<number>(`mutation ($id: String!) { remindAnnouncement(id: $id) }`, { id }, 'remindAnnouncement')
94
+ }
142
95
  }
@@ -7,11 +7,11 @@ declare const AnnouncementReceipts_base: (new (...args: any[]) => LitElement) &
7
7
  export declare class AnnouncementReceipts extends AnnouncementReceipts_base {
8
8
  static styles: import("lit").CSSResult[];
9
9
  announcement: AnnouncementItem;
10
- private rows;
11
10
  private which;
12
- private busy;
13
- connectedCallback(): void;
14
- private load;
11
+ private receipts;
12
+ private reminder;
13
+ private get rows();
14
+ private get busy();
15
15
  render(): import("lit-html").TemplateResult<1>;
16
16
  private remind;
17
17
  private close;
@@ -22,7 +22,8 @@ export declare class AnnouncementWithdrawForm extends AnnouncementWithdrawForm_b
22
22
  static styles: import("lit").CSSResult[];
23
23
  announcement: AnnouncementItem;
24
24
  private reason;
25
- private busy;
25
+ private withdrawal;
26
+ private get busy();
26
27
  render(): import("lit-html").TemplateResult<1>;
27
28
  private withdraw;
28
29
  private close;
@@ -6,13 +6,14 @@ import { __decorate, __metadata } from "tslib";
6
6
  import '@material/web/button/filled-button.js';
7
7
  import '@material/web/button/text-button.js';
8
8
  import '@operato/popup/ox-popup-actions.js';
9
+ import gql from 'graphql-tag';
9
10
  import { css, html, LitElement, nothing } from 'lit';
10
11
  import { customElement, property, state } from 'lit/decorators.js';
12
+ import { MutationController, QueryController } from '@operato/graphql';
11
13
  import { i18next, localize } from '@operato/i18n';
12
14
  import { notify } from '@operato/layout';
13
15
  import { CommonPopupStyles, PopupBodyStyles } from '@operato/styles';
14
- import { announcementApi } from '../utils/announcement-api.js';
15
- import { reasonOf, t, when } from '../utils/announcement-words.js';
16
+ import { t, when } from '../utils/announcement-words.js';
16
17
  const FormStyles = css `
17
18
  :host {
18
19
  height: 100%;
@@ -67,22 +68,19 @@ const FormStyles = css `
67
68
  let AnnouncementReceipts = class AnnouncementReceipts extends localize(i18next)(LitElement) {
68
69
  constructor() {
69
70
  super(...arguments);
70
- this.rows = [];
71
71
  this.which = 'all';
72
- this.busy = false;
72
+ /* Whom it reached and what each did with it, read for the announcement shown (ADR-0190). */
73
+ this.receipts = new QueryController(this, gql `query ($id: String!) { announcementReceipts(id: $id) { userId name email listed notifiedAt readAt acknowledgedAt } }`, { variables: () => (this.announcement?.id ? { id: this.announcement.id } : undefined) });
74
+ this.reminder = new MutationController(this, gql `mutation ($id: String!) { remindAnnouncement(id: $id) }`, {
75
+ refetch: () => [this.receipts]
76
+ });
73
77
  }
74
78
  static { this.styles = [CommonPopupStyles, PopupBodyStyles, FormStyles]; }
75
- connectedCallback() {
76
- super.connectedCallback();
77
- this.load();
79
+ get rows() {
80
+ return this.receipts.data?.announcementReceipts ?? [];
78
81
  }
79
- async load() {
80
- try {
81
- this.rows = await announcementApi.receipts(this.announcement.id);
82
- }
83
- catch (error) {
84
- notify({ level: 'error', message: reasonOf(error) });
85
- }
82
+ get busy() {
83
+ return this.reminder.pending;
86
84
  }
87
85
  render() {
88
86
  const one = this.announcement;
@@ -127,18 +125,9 @@ let AnnouncementReceipts = class AnnouncementReceipts extends localize(i18next)(
127
125
  </ox-popup-actions>`;
128
126
  }
129
127
  async remind() {
130
- this.busy = true;
131
- try {
132
- const told = await announcementApi.remind(this.announcement.id);
133
- notify({ message: t('announcement.text.reminded', { count: told }) });
134
- await this.load();
135
- }
136
- catch (error) {
137
- notify({ level: 'error', message: reasonOf(error) });
138
- }
139
- finally {
140
- this.busy = false;
141
- }
128
+ const done = await this.reminder.run({ id: this.announcement.id });
129
+ if (done)
130
+ notify({ message: t('announcement.text.reminded', { count: done.remindAnnouncement }) });
142
131
  }
143
132
  close() {
144
133
  this.dispatchEvent(new CustomEvent('done', { bubbles: true, composed: true }));
@@ -148,18 +137,10 @@ __decorate([
148
137
  property({ attribute: false }),
149
138
  __metadata("design:type", Object)
150
139
  ], AnnouncementReceipts.prototype, "announcement", void 0);
151
- __decorate([
152
- state(),
153
- __metadata("design:type", Array)
154
- ], AnnouncementReceipts.prototype, "rows", void 0);
155
140
  __decorate([
156
141
  state(),
157
142
  __metadata("design:type", String)
158
143
  ], AnnouncementReceipts.prototype, "which", void 0);
159
- __decorate([
160
- state(),
161
- __metadata("design:type", Object)
162
- ], AnnouncementReceipts.prototype, "busy", void 0);
163
144
  AnnouncementReceipts = __decorate([
164
145
  customElement('announcement-receipts')
165
146
  ], AnnouncementReceipts);
@@ -169,9 +150,12 @@ let AnnouncementWithdrawForm = class AnnouncementWithdrawForm extends localize(i
169
150
  constructor() {
170
151
  super(...arguments);
171
152
  this.reason = '';
172
- this.busy = false;
153
+ this.withdrawal = new MutationController(this, gql `mutation ($id: String!, $reason: String!) { withdrawAnnouncement(id: $id, reason: $reason) { id status } }`);
173
154
  }
174
155
  static { this.styles = [CommonPopupStyles, PopupBodyStyles, FormStyles]; }
156
+ get busy() {
157
+ return this.withdrawal.pending;
158
+ }
175
159
  render() {
176
160
  return html `<div class="body">
177
161
  <p>${t('announcement.text.withdraw-lead')}</p>
@@ -183,19 +167,11 @@ let AnnouncementWithdrawForm = class AnnouncementWithdrawForm extends localize(i
183
167
  </ox-popup-actions>`;
184
168
  }
185
169
  async withdraw() {
186
- this.busy = true;
187
- try {
188
- await announcementApi.withdraw(this.announcement.id, this.reason);
189
- notify({ message: t('announcement.text.withdrawn-done') });
190
- this.dispatchEvent(new CustomEvent('announcement-withdrawn', { bubbles: true, composed: true }));
191
- this.close();
192
- }
193
- catch (error) {
194
- notify({ level: 'error', message: reasonOf(error) });
195
- }
196
- finally {
197
- this.busy = false;
198
- }
170
+ if (!(await this.withdrawal.run({ id: this.announcement.id, reason: this.reason })))
171
+ return;
172
+ notify({ message: t('announcement.text.withdrawn-done') });
173
+ this.dispatchEvent(new CustomEvent('announcement-withdrawn', { bubbles: true, composed: true }));
174
+ this.close();
199
175
  }
200
176
  close() {
201
177
  this.dispatchEvent(new CustomEvent('done', { bubbles: true, composed: true }));
@@ -209,10 +185,6 @@ __decorate([
209
185
  state(),
210
186
  __metadata("design:type", Object)
211
187
  ], AnnouncementWithdrawForm.prototype, "reason", void 0);
212
- __decorate([
213
- state(),
214
- __metadata("design:type", Object)
215
- ], AnnouncementWithdrawForm.prototype, "busy", void 0);
216
188
  AnnouncementWithdrawForm = __decorate([
217
189
  customElement('announcement-withdraw-form')
218
190
  ], AnnouncementWithdrawForm);
@@ -1 +1 @@
1
- {"version":3,"file":"announcement-receipts.js","sourceRoot":"","sources":["../../client/components/announcement-receipts.ts"],"names":[],"mappings":";AAAA;;;GAGG;AACH,OAAO,uCAAuC,CAAA;AAC9C,OAAO,qCAAqC,CAAA;AAC5C,OAAO,oCAAoC,CAAA;AAE3C,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,KAAK,CAAA;AACpD,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAElE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AACxC,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAEpE,OAAO,EAAE,eAAe,EAAyB,MAAM,8BAA8B,CAAA;AACrF,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,gCAAgC,CAAA;AAIlE,MAAM,UAAU,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkDrB,CAAA;AAGM,IAAM,oBAAoB,GAA1B,MAAM,oBAAqB,SAAQ,QAAQ,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC;IAAhE;;QAGY,SAAI,GAAU,EAAE,CAAA;QAChB,UAAK,GAAkD,KAAK,CAAA;QAC5D,SAAI,GAAG,KAAK,CAAA;IA+E/B,CAAC;aAnFQ,WAAM,GAAG,CAAC,iBAAiB,EAAE,eAAe,EAAE,UAAU,CAAC,AAAnD,CAAmD;IAMhE,iBAAiB;QACf,KAAK,CAAC,iBAAiB,EAAE,CAAA;QACzB,IAAI,CAAC,IAAI,EAAE,CAAA;IACb,CAAC;IAEO,KAAK,CAAC,IAAI;QAChB,IAAI,CAAC;YACH,IAAI,CAAC,IAAI,GAAG,MAAM,eAAe,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,CAAA;QAClE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QACtD,CAAC;IACH,CAAC;IAED,MAAM;QACJ,MAAM,GAAG,GAAG,IAAI,CAAC,YAAY,CAAA;QAC7B,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;QAClD,MAAM,MAAM,GAAG;YACb,GAAG,EAAE,MAAM,CAAC,MAAM;YAClB,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,MAAM;YAChD,cAAc,EAAE,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,MAAM;YAChE,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,MAAM;SACnD,CAAA;QACD,MAAM,IAAI,GAAI,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAA6B,CAAC,GAAG,CAC7J,GAAG,CAAC,EAAE,CAAC,IAAI,CAAA,wBAAwB,MAAM,CAAC,IAAI,CAAC,KAAK,KAAK,GAAG,CAAC,WAAW,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,yBAAyB,GAAG,EAAE,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,WAAW,CAChK,CAAA;QACD,MAAM,KAAK,GACT,IAAI,CAAC,KAAK,KAAK,OAAO;YACpB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;YACtC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,KAAK,gBAAgB,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAA;QAClI,MAAM,IAAI,GAAG,GAAG,CAAC,uBAAuB,CAAC,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAA;QAChF,OAAO,IAAI,CAAA;4BACa,IAAI;;;;oBAIZ,CAAC,CAAC,4BAA4B,CAAC;oBAC/B,CAAC,CAAC,+BAA+B,CAAC;gBACtC,GAAG,CAAC,uBAAuB,CAAC,CAAC,CAAC,IAAI,CAAA,OAAO,CAAC,CAAC,uCAAuC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO;oBAChG,CAAC,CAAC,mCAAmC,CAAC;;;;cAI5C,KAAK,CAAC,GAAG,CACT,GAAG,CAAC,EAAE,CAAC,IAAI,CAAA;sBACH,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,MAAM;4BAC7B,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,kCAAkC,CAAC;kBAC5G,GAAG,CAAC,uBAAuB,CAAC,CAAC,CAAC,IAAI,CAAA,aAAa,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,IAAI,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,OAAO;oCACtI,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC;oBACpC,CACP;;;;;+CAKkC,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,2BAA2B,CAAC;qDAC9C,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,MAAM,KAAK,WAAW,WAAW,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE;aACtH,CAAC,CAAC,kCAAkC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;;0BAEzC,CAAA;IACxB,CAAC;IAEO,KAAK,CAAC,MAAM;QAClB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,CAAA;YAC/D,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,4BAA4B,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAA;YACrE,MAAM,IAAI,CAAC,IAAI,EAAE,CAAA;QACnB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QACtD,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,IAAI,GAAG,KAAK,CAAA;QACnB,CAAC;IACH,CAAC;IAEO,KAAK;QACX,IAAI,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;IAChF,CAAC;;AAjF+B;IAA/B,QAAQ,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;;0DAAgC;AAC9C;IAAhB,KAAK,EAAE;;kDAAyB;AAChB;IAAhB,KAAK,EAAE;;mDAAqE;AAC5D;IAAhB,KAAK,EAAE;;kDAAqB;AALlB,oBAAoB;IADhC,aAAa,CAAC,uBAAuB,CAAC;GAC1B,oBAAoB,CAoFhC;;AAED,sFAAsF;AAE/E,IAAM,wBAAwB,GAA9B,MAAM,wBAAyB,SAAQ,QAAQ,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC;IAApE;;QAGY,WAAM,GAAG,EAAE,CAAA;QACX,SAAI,GAAG,KAAK,CAAA;IA8B/B,CAAC;aAjCQ,WAAM,GAAG,CAAC,iBAAiB,EAAE,eAAe,EAAE,UAAU,CAAC,AAAnD,CAAmD;IAKhE,MAAM;QACJ,OAAO,IAAI,CAAA;aACF,CAAC,CAAC,iCAAiC,CAAC;2BACtB,IAAI,CAAC,MAAM,gCAAgC,CAAC,CAAC,mCAAmC,CAAC,WAAW,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;;;+CAGlH,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,4BAA4B,CAAC;qDAC/C,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,WAAW,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,8BAA8B,CAAC;0BAChI,CAAA;IACxB,CAAC;IAEO,KAAK,CAAC,QAAQ;QACpB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,IAAI,CAAC;YACH,MAAM,eAAe,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC,CAAA;YACjE,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,kCAAkC,CAAC,EAAE,CAAC,CAAA;YAC1D,IAAI,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,wBAAwB,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;YAChG,IAAI,CAAC,KAAK,EAAE,CAAA;QACd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QACtD,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,IAAI,GAAG,KAAK,CAAA;QACnB,CAAC;IACH,CAAC;IAEO,KAAK;QACX,IAAI,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;IAChF,CAAC;;AA/B+B;IAA/B,QAAQ,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;;8DAAgC;AAC9C;IAAhB,KAAK,EAAE;;wDAAoB;AACX;IAAhB,KAAK,EAAE;;sDAAqB;AAJlB,wBAAwB;IADpC,aAAa,CAAC,4BAA4B,CAAC;GAC/B,wBAAwB,CAkCpC","sourcesContent":["/*\n * The small forms a writer opens from an announcement (ADR-0163 decision 4): who read it and who acknowledged it, with\n * a reminder to those who have not; and the reason it is withdrawn.\n */\nimport '@material/web/button/filled-button.js'\nimport '@material/web/button/text-button.js'\nimport '@operato/popup/ox-popup-actions.js'\n\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { notify } from '@operato/layout'\nimport { CommonPopupStyles, PopupBodyStyles } from '@operato/styles'\n\nimport { announcementApi, type AnnouncementItem } from '../utils/announcement-api.js'\nimport { reasonOf, t, when } from '../utils/announcement-words.js'\n\ntype Row = Awaited<ReturnType<typeof announcementApi.receipts>>[number]\n\nconst FormStyles = css`\n :host {\n height: 100%;\n line-height: 1.5;\n }\n .tabs {\n display: flex;\n gap: var(--spacing-small, 4px);\n margin-bottom: var(--spacing-medium, 8px);\n }\n .tabs button {\n border: 1px solid var(--ui-line-soft, var(--md-sys-color-outline-variant));\n background: none;\n border-radius: 999px;\n padding: 2px var(--spacing-medium, 8px);\n font: inherit;\n font-size: var(--ui-t-small, 12px);\n cursor: pointer;\n color: inherit;\n }\n .tabs button[aria-pressed='true'] {\n background: var(--md-sys-color-secondary-container);\n border-color: transparent;\n }\n table {\n width: 100%;\n border-collapse: collapse;\n font-size: var(--ui-t-body, 14px);\n font-variant-numeric: tabular-nums;\n }\n th,\n td {\n text-align: left;\n padding: var(--spacing-small, 4px) var(--spacing-medium, 8px);\n border-bottom: 1px solid var(--ui-line-soft, var(--md-sys-color-outline-variant));\n }\n th {\n font-weight: 600;\n font-size: var(--ui-t-small, 12px);\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n }\n .muted {\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n }\n textarea {\n width: 100%;\n min-height: 96px;\n box-sizing: border-box;\n font: inherit;\n }\n`\n\n@customElement('announcement-receipts')\nexport class AnnouncementReceipts extends localize(i18next)(LitElement) {\n static styles = [CommonPopupStyles, PopupBodyStyles, FormStyles]\n @property({ attribute: false }) announcement!: AnnouncementItem\n @state() private rows: Row[] = []\n @state() private which: 'all' | 'unread' | 'unacknowledged' | 'later' = 'all'\n @state() private busy = false\n\n connectedCallback() {\n super.connectedCallback()\n this.load()\n }\n\n private async load() {\n try {\n this.rows = await announcementApi.receipts(this.announcement.id)\n } catch (error) {\n notify({ level: 'error', message: reasonOf(error) })\n }\n }\n\n render() {\n const one = this.announcement\n const listed = this.rows.filter(row => row.listed)\n const counts = {\n all: listed.length,\n unread: listed.filter(row => !row.readAt).length,\n unacknowledged: listed.filter(row => !row.acknowledgedAt).length,\n later: this.rows.filter(row => !row.listed).length\n }\n const tabs = (['all', 'unread', ...(one.requiresAcknowledgement ? ['unacknowledged'] : []), ...(counts.later ? ['later'] : [])] as (keyof typeof counts)[]).map(\n key => html`<button aria-pressed=${String(this.which === key)} @click=${() => (this.which = key)}>${t(`announcement.receipts.${key}`)} ${counts[key]}</button>`\n )\n const shown =\n this.which === 'later'\n ? this.rows.filter(row => !row.listed)\n : listed.filter(row => (this.which === 'unread' ? !row.readAt : this.which === 'unacknowledged' ? !row.acknowledgedAt : true))\n const owed = one.requiresAcknowledgement ? counts.unacknowledged : counts.unread\n return html`<div class=\"body\">\n <div class=\"tabs\">${tabs}</div>\n <table>\n <thead>\n <tr>\n <th>${t('announcement.receipts.name')}</th>\n <th>${t('announcement.receipts.read-at')}</th>\n ${one.requiresAcknowledgement ? html`<th>${t('announcement.receipts.acknowledged-at')}</th>` : nothing}\n <th>${t('announcement.receipts.notified-at')}</th>\n </tr>\n </thead>\n <tbody>\n ${shown.map(\n row => html`<tr>\n <td>${row.name ?? row.email ?? row.userId}</td>\n <td class=${row.readAt ? '' : 'muted'}>${row.readAt ? when(row.readAt) : t('announcement.reader-state.unread')}</td>\n ${one.requiresAcknowledgement ? html`<td class=${row.acknowledgedAt ? '' : 'muted'}>${row.acknowledgedAt ? when(row.acknowledgedAt) : '—'}</td>` : nothing}\n <td class=\"muted\">${when(row.notifiedAt)}</td>\n </tr>`\n )}\n </tbody>\n </table>\n </div>\n <ox-popup-actions>\n <md-text-button slot=\"cancel\" @click=${() => this.close()}>${t('announcement.button.close')}</md-text-button>\n <md-filled-button slot=\"confirm\" ?disabled=${this.busy || !owed || one.status !== 'PUBLISHED'} @click=${() => this.remind()}\n >${t('announcement.button.remind-count', { count: owed })}</md-filled-button\n >\n </ox-popup-actions>`\n }\n\n private async remind() {\n this.busy = true\n try {\n const told = await announcementApi.remind(this.announcement.id)\n notify({ message: t('announcement.text.reminded', { count: told }) })\n await this.load()\n } catch (error) {\n notify({ level: 'error', message: reasonOf(error) })\n } finally {\n this.busy = false\n }\n }\n\n private close() {\n this.dispatchEvent(new CustomEvent('done', { bubbles: true, composed: true }))\n }\n}\n\n/** Why it is withdrawn - the readers' copy goes, the reason stays with its record. */\n@customElement('announcement-withdraw-form')\nexport class AnnouncementWithdrawForm extends localize(i18next)(LitElement) {\n static styles = [CommonPopupStyles, PopupBodyStyles, FormStyles]\n @property({ attribute: false }) announcement!: AnnouncementItem\n @state() private reason = ''\n @state() private busy = false\n\n render() {\n return html`<div class=\"body\">\n <p>${t('announcement.text.withdraw-lead')}</p>\n <textarea .value=${this.reason} maxlength=\"500\" placeholder=${t('announcement.text.withdraw-reason')} @input=${(e: any) => (this.reason = e.target.value)}></textarea>\n </div>\n <ox-popup-actions>\n <md-text-button slot=\"cancel\" @click=${() => this.close()}>${t('announcement.button.cancel')}</md-text-button>\n <md-filled-button slot=\"confirm\" ?disabled=${this.busy || !this.reason.trim()} @click=${() => this.withdraw()}>${t('announcement.button.withdraw')}</md-filled-button>\n </ox-popup-actions>`\n }\n\n private async withdraw() {\n this.busy = true\n try {\n await announcementApi.withdraw(this.announcement.id, this.reason)\n notify({ message: t('announcement.text.withdrawn-done') })\n this.dispatchEvent(new CustomEvent('announcement-withdrawn', { bubbles: true, composed: true }))\n this.close()\n } catch (error) {\n notify({ level: 'error', message: reasonOf(error) })\n } finally {\n this.busy = false\n }\n }\n\n private close() {\n this.dispatchEvent(new CustomEvent('done', { bubbles: true, composed: true }))\n }\n}\n"]}
1
+ {"version":3,"file":"announcement-receipts.js","sourceRoot":"","sources":["../../client/components/announcement-receipts.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * The small forms a writer opens from an announcement (ADR-0163 decision 4): who read it and who acknowledged it, with\n * a reminder to those who have not; and the reason it is withdrawn.\n */\nimport '@material/web/button/filled-button.js'\nimport '@material/web/button/text-button.js'\nimport '@operato/popup/ox-popup-actions.js'\n\nimport gql from 'graphql-tag'\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { MutationController, QueryController } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { notify } from '@operato/layout'\nimport { CommonPopupStyles, PopupBodyStyles } from '@operato/styles'\n\nimport { type AnnouncementItem } from '../utils/announcement-api.js'\nimport { t, when } from '../utils/announcement-words.js'\n\ntype Row = { userId: string; name?: string; email?: string; listed: boolean; notifiedAt?: string; readAt?: string; acknowledgedAt?: string }\n\nconst FormStyles = css`\n :host {\n height: 100%;\n line-height: 1.5;\n }\n .tabs {\n display: flex;\n gap: var(--spacing-small, 4px);\n margin-bottom: var(--spacing-medium, 8px);\n }\n .tabs button {\n border: 1px solid var(--ui-line-soft, var(--md-sys-color-outline-variant));\n background: none;\n border-radius: 999px;\n padding: 2px var(--spacing-medium, 8px);\n font: inherit;\n font-size: var(--ui-t-small, 12px);\n cursor: pointer;\n color: inherit;\n }\n .tabs button[aria-pressed='true'] {\n background: var(--md-sys-color-secondary-container);\n border-color: transparent;\n }\n table {\n width: 100%;\n border-collapse: collapse;\n font-size: var(--ui-t-body, 14px);\n font-variant-numeric: tabular-nums;\n }\n th,\n td {\n text-align: left;\n padding: var(--spacing-small, 4px) var(--spacing-medium, 8px);\n border-bottom: 1px solid var(--ui-line-soft, var(--md-sys-color-outline-variant));\n }\n th {\n font-weight: 600;\n font-size: var(--ui-t-small, 12px);\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n }\n .muted {\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n }\n textarea {\n width: 100%;\n min-height: 96px;\n box-sizing: border-box;\n font: inherit;\n }\n`\n\n@customElement('announcement-receipts')\nexport class AnnouncementReceipts extends localize(i18next)(LitElement) {\n static styles = [CommonPopupStyles, PopupBodyStyles, FormStyles]\n @property({ attribute: false }) announcement!: AnnouncementItem\n @state() private which: 'all' | 'unread' | 'unacknowledged' | 'later' = 'all'\n\n /* Whom it reached and what each did with it, read for the announcement shown (ADR-0190). */\n private receipts = new QueryController(\n this,\n gql`query ($id: String!) { announcementReceipts(id: $id) { userId name email listed notifiedAt readAt acknowledgedAt } }`,\n { variables: () => (this.announcement?.id ? { id: this.announcement.id } : undefined) }\n )\n\n private reminder = new MutationController(this, gql`mutation ($id: String!) { remindAnnouncement(id: $id) }`, {\n refetch: () => [this.receipts]\n })\n\n private get rows(): Row[] {\n return this.receipts.data?.announcementReceipts ?? []\n }\n\n private get busy() {\n return this.reminder.pending\n }\n\n render() {\n const one = this.announcement\n const listed = this.rows.filter(row => row.listed)\n const counts = {\n all: listed.length,\n unread: listed.filter(row => !row.readAt).length,\n unacknowledged: listed.filter(row => !row.acknowledgedAt).length,\n later: this.rows.filter(row => !row.listed).length\n }\n const tabs = (['all', 'unread', ...(one.requiresAcknowledgement ? ['unacknowledged'] : []), ...(counts.later ? ['later'] : [])] as (keyof typeof counts)[]).map(\n key => html`<button aria-pressed=${String(this.which === key)} @click=${() => (this.which = key)}>${t(`announcement.receipts.${key}`)} ${counts[key]}</button>`\n )\n const shown =\n this.which === 'later'\n ? this.rows.filter(row => !row.listed)\n : listed.filter(row => (this.which === 'unread' ? !row.readAt : this.which === 'unacknowledged' ? !row.acknowledgedAt : true))\n const owed = one.requiresAcknowledgement ? counts.unacknowledged : counts.unread\n return html`<div class=\"body\">\n <div class=\"tabs\">${tabs}</div>\n <table>\n <thead>\n <tr>\n <th>${t('announcement.receipts.name')}</th>\n <th>${t('announcement.receipts.read-at')}</th>\n ${one.requiresAcknowledgement ? html`<th>${t('announcement.receipts.acknowledged-at')}</th>` : nothing}\n <th>${t('announcement.receipts.notified-at')}</th>\n </tr>\n </thead>\n <tbody>\n ${shown.map(\n row => html`<tr>\n <td>${row.name ?? row.email ?? row.userId}</td>\n <td class=${row.readAt ? '' : 'muted'}>${row.readAt ? when(row.readAt) : t('announcement.reader-state.unread')}</td>\n ${one.requiresAcknowledgement ? html`<td class=${row.acknowledgedAt ? '' : 'muted'}>${row.acknowledgedAt ? when(row.acknowledgedAt) : '—'}</td>` : nothing}\n <td class=\"muted\">${when(row.notifiedAt)}</td>\n </tr>`\n )}\n </tbody>\n </table>\n </div>\n <ox-popup-actions>\n <md-text-button slot=\"cancel\" @click=${() => this.close()}>${t('announcement.button.close')}</md-text-button>\n <md-filled-button slot=\"confirm\" ?disabled=${this.busy || !owed || one.status !== 'PUBLISHED'} @click=${() => this.remind()}\n >${t('announcement.button.remind-count', { count: owed })}</md-filled-button\n >\n </ox-popup-actions>`\n }\n\n private async remind() {\n const done = await this.reminder.run({ id: this.announcement.id })\n if (done) notify({ message: t('announcement.text.reminded', { count: done.remindAnnouncement }) })\n }\n\n private close() {\n this.dispatchEvent(new CustomEvent('done', { bubbles: true, composed: true }))\n }\n}\n\n/** Why it is withdrawn - the readers' copy goes, the reason stays with its record. */\n@customElement('announcement-withdraw-form')\nexport class AnnouncementWithdrawForm extends localize(i18next)(LitElement) {\n static styles = [CommonPopupStyles, PopupBodyStyles, FormStyles]\n @property({ attribute: false }) announcement!: AnnouncementItem\n @state() private reason = ''\n private withdrawal = new MutationController(this, gql`mutation ($id: String!, $reason: String!) { withdrawAnnouncement(id: $id, reason: $reason) { id status } }`)\n\n private get busy() {\n return this.withdrawal.pending\n }\n\n render() {\n return html`<div class=\"body\">\n <p>${t('announcement.text.withdraw-lead')}</p>\n <textarea .value=${this.reason} maxlength=\"500\" placeholder=${t('announcement.text.withdraw-reason')} @input=${(e: any) => (this.reason = e.target.value)}></textarea>\n </div>\n <ox-popup-actions>\n <md-text-button slot=\"cancel\" @click=${() => this.close()}>${t('announcement.button.cancel')}</md-text-button>\n <md-filled-button slot=\"confirm\" ?disabled=${this.busy || !this.reason.trim()} @click=${() => this.withdraw()}>${t('announcement.button.withdraw')}</md-filled-button>\n </ox-popup-actions>`\n }\n\n private async withdraw() {\n if (!(await this.withdrawal.run({ id: this.announcement.id, reason: this.reason }))) return\n notify({ message: t('announcement.text.withdrawn-done') })\n this.dispatchEvent(new CustomEvent('announcement-withdrawn', { bubbles: true, composed: true }))\n this.close()\n }\n\n private close() {\n this.dispatchEvent(new CustomEvent('done', { bubbles: true, composed: true }))\n }\n}\n"]}
@@ -8,7 +8,8 @@ declare const AnnouncementSheet_base: (new (...args: any[]) => LitElement) & typ
8
8
  export declare class AnnouncementSheet extends AnnouncementSheet_base {
9
9
  static styles: import("lit").CSSResult;
10
10
  announcement: AnnouncementItem;
11
- private busy;
11
+ private acknowledgement;
12
+ private get busy();
12
13
  render(): typeof nothing | import("lit-html").TemplateResult<1>;
13
14
  private renderAcknowledge;
14
15
  private follow;
@@ -5,15 +5,16 @@ import { __decorate, __metadata } from "tslib";
5
5
  */
6
6
  import '@material/web/icon/icon.js';
7
7
  import '@material/web/button/filled-button.js';
8
+ import gql from 'graphql-tag';
8
9
  import { css, html, LitElement, nothing } from 'lit';
9
- import { customElement, property, state } from 'lit/decorators.js';
10
+ import { customElement, property } from 'lit/decorators.js';
10
11
  import { unsafeHTML } from 'lit/directives/unsafe-html.js';
12
+ import { MutationController } from '@operato/graphql';
11
13
  import { i18next, localize } from '@operato/i18n';
12
- import { notify } from '@operato/layout';
13
14
  import { navigate } from '@operato/shell';
14
15
  import { renderMarkdown } from '@things-factory/ai-assistant/dist-client/index.js';
15
- import { announcementApi } from '../utils/announcement-api.js';
16
- import { categoryWord, importanceWord, reasonOf, t, when } from '../utils/announcement-words.js';
16
+ import { announcementsChanged } from '../utils/announcement-api.js';
17
+ import { categoryWord, importanceWord, t, when } from '../utils/announcement-words.js';
17
18
  /** A screen of the application opens in place; an https page opens apart. */
18
19
  export function followLink(url) {
19
20
  if (/^https:\/\//i.test(url))
@@ -24,7 +25,7 @@ export function followLink(url) {
24
25
  let AnnouncementSheet = class AnnouncementSheet extends localize(i18next)(LitElement) {
25
26
  constructor() {
26
27
  super(...arguments);
27
- this.busy = false;
28
+ this.acknowledgement = new MutationController(this, gql `mutation ($id: String!) { acknowledgeAnnouncement(id: $id) { id readerState mine { readAt acknowledgedAt } } }`);
28
29
  }
29
30
  static { this.styles = css `
30
31
  :host {
@@ -142,6 +143,9 @@ let AnnouncementSheet = class AnnouncementSheet extends localize(i18next)(LitEle
142
143
  color: var(--ui-muted, var(--md-sys-color-on-surface-variant));
143
144
  }
144
145
  `; }
146
+ get busy() {
147
+ return this.acknowledgement.pending;
148
+ }
145
149
  render() {
146
150
  const one = this.announcement;
147
151
  if (!one)
@@ -195,28 +199,18 @@ let AnnouncementSheet = class AnnouncementSheet extends localize(i18next)(LitEle
195
199
  followLink(url);
196
200
  }
197
201
  async acknowledge() {
198
- this.busy = true;
199
- try {
200
- const done = await announcementApi.acknowledge(this.announcement.id);
201
- this.announcement = { ...this.announcement, ...done };
202
- this.dispatchEvent(new CustomEvent('announcement-acknowledged', { bubbles: true, composed: true, detail: this.announcement }));
203
- }
204
- catch (error) {
205
- notify({ level: 'error', message: reasonOf(error) });
206
- }
207
- finally {
208
- this.busy = false;
209
- }
202
+ const done = await this.acknowledgement.run({ id: this.announcement.id });
203
+ if (!done)
204
+ return;
205
+ announcementsChanged();
206
+ this.announcement = { ...this.announcement, ...done.acknowledgeAnnouncement };
207
+ this.dispatchEvent(new CustomEvent('announcement-acknowledged', { bubbles: true, composed: true, detail: this.announcement }));
210
208
  }
211
209
  };
212
210
  __decorate([
213
211
  property({ attribute: false }),
214
212
  __metadata("design:type", Object)
215
213
  ], AnnouncementSheet.prototype, "announcement", void 0);
216
- __decorate([
217
- state(),
218
- __metadata("design:type", Object)
219
- ], AnnouncementSheet.prototype, "busy", void 0);
220
214
  AnnouncementSheet = __decorate([
221
215
  customElement('announcement-sheet')
222
216
  ], AnnouncementSheet);
@@ -1 +1 @@
1
- {"version":3,"file":"announcement-sheet.js","sourceRoot":"","sources":["../../client/components/announcement-sheet.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * One announcement as its reader sees it - what kind it is and from whom, its body, its files, the screens it points to,\n * and the acknowledgement it asks for (ADR-0163 decisions 3, 5). The screen and the popup both draw it.\n */\nimport '@material/web/icon/icon.js'\nimport '@material/web/button/filled-button.js'\n\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { unsafeHTML } from 'lit/directives/unsafe-html.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { notify } from '@operato/layout'\nimport { navigate } from '@operato/shell'\nimport { renderMarkdown } from '@things-factory/ai-assistant/dist-client/index.js'\n\nimport { announcementApi, type AnnouncementItem } from '../utils/announcement-api.js'\nimport { categoryWord, importanceWord, reasonOf, t, when } from '../utils/announcement-words.js'\n\n/** A screen of the application opens in place; an https page opens apart. */\nexport function followLink(url: string) {\n if (/^https:\\/\\//i.test(url)) window.open(url, '_blank', 'noopener')\n else navigate(url)\n}\n\n@customElement('announcement-sheet')\nexport class AnnouncementSheet extends localize(i18next)(LitElement) {\n static styles = css`\n :host {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-medium, 8px);\n color: var(--md-sys-color-on-surface);\n }\n .meta {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--spacing-small, 4px) var(--spacing-medium, 8px);\n font-size: var(--ui-t-small, 12px);\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n }\n .chip {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n padding: 0 var(--spacing-small, 4px);\n border-radius: var(--border-radius, 4px);\n border: 1px solid var(--ui-line-soft, var(--md-sys-color-outline-variant));\n line-height: 1.6;\n }\n .chip.URGENT {\n color: var(--md-sys-color-error);\n border-color: currentColor;\n }\n .chip.IMPORTANT {\n color: var(--md-sys-color-primary);\n border-color: currentColor;\n }\n .chip md-icon {\n --md-icon-size: 14px;\n }\n .markdown {\n font-size: var(--ui-t-body, 14px);\n line-height: 1.6;\n overflow-wrap: anywhere;\n }\n .markdown :is(h1, h2, h3, h4) {\n margin: var(--spacing-medium, 8px) 0 var(--spacing-small, 4px);\n font-size: var(--ui-t-title, 16px);\n }\n .markdown :is(p, ul, ol, blockquote, pre, table) {\n margin: 0 0 var(--spacing-medium, 8px);\n }\n .markdown :is(ul, ol) {\n padding-inline-start: 1.4em;\n list-style: revert;\n display: block;\n }\n .markdown a {\n color: var(--md-sys-color-primary);\n }\n .markdown table {\n border-collapse: collapse;\n }\n .markdown :is(th, td) {\n border: 1px solid var(--ui-line-soft, var(--md-sys-color-outline-variant));\n padding: 2px var(--spacing-small, 4px);\n }\n h4 {\n margin: var(--spacing-medium, 8px) 0 var(--spacing-small, 4px);\n font-size: var(--ui-t-small, 12px);\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n font-weight: 600;\n }\n ul.files {\n margin: 0;\n padding: 0;\n list-style: none;\n display: flex;\n flex-direction: column;\n gap: 2px;\n }\n a,\n .link {\n display: inline-flex;\n align-items: center;\n gap: var(--spacing-small, 4px);\n color: var(--md-sys-color-primary);\n text-decoration: none;\n cursor: pointer;\n background: none;\n border: 0;\n padding: 0;\n font: inherit;\n }\n a:hover,\n .link:hover {\n text-decoration: underline;\n }\n a md-icon,\n .link md-icon {\n --md-icon-size: 16px;\n }\n .size {\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n font-size: var(--ui-t-small, 12px);\n }\n .acknowledge {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: space-between;\n gap: var(--spacing-medium, 8px);\n padding: var(--spacing-medium, 8px) var(--spacing-large, 12px);\n border-radius: var(--border-radius, 4px);\n background: var(--md-sys-color-surface-container, rgba(0, 0, 0, 0.04));\n font-size: var(--ui-t-body, 14px);\n }\n .acknowledge.done {\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n }\n `\n\n @property({ attribute: false }) announcement!: AnnouncementItem\n @state() private busy = false\n\n render() {\n const one = this.announcement\n if (!one) return nothing\n const files = one.attachments ?? []\n const links = one.links ?? []\n return html`<div class=\"meta\">\n ${one.pinned ? html`<span class=\"chip\"><md-icon>push_pin</md-icon>${t('announcement.field.pinned')}</span>` : nothing}\n ${one.importance !== 'NORMAL' ? html`<span class=\"chip ${one.importance}\">${importanceWord(one.importance)}</span>` : nothing}\n <span class=\"chip\">${categoryWord(one.category)}</span>\n <span>${one.publisher?.name ?? one.creator?.name ?? ''}</span>\n <span>${when(one.publishedAt ?? one.startsAt)}</span>\n ${one.endsAt ? html`<span>${t('announcement.text.until', { when: when(one.endsAt) })}</span>` : nothing}\n ${one.version > 1 ? html`<span>${t('announcement.text.version', { version: one.version })}</span>` : nothing}\n </div>\n ${one.body ? html`<div class=\"markdown\">${unsafeHTML(renderMarkdown(one.body))}</div>` : nothing}\n ${files.length\n ? html`<h4>${t('announcement.field.attachments')}</h4>\n <ul class=\"files\">\n ${files.map(\n file =>\n html`<li>\n <a href=${file.fullpath} target=\"_blank\" rel=\"noopener\" download=${file.name}><md-icon>attach_file</md-icon>${file.name}</a>\n ${file.size ? html`<span class=\"size\">${Math.max(1, Math.round(file.size / 1024))} KB</span>` : nothing}\n </li>`\n )}\n </ul>`\n : nothing}\n ${links.length\n ? html`<h4>${t('announcement.field.links')}</h4>\n <ul class=\"files\">\n ${links.map(link => html`<li><button class=\"link\" @click=${() => this.follow(link.url)}><md-icon>open_in_new</md-icon>${link.label}</button></li>`)}\n </ul>`\n : nothing}\n ${this.renderAcknowledge()}`\n }\n\n private renderAcknowledge() {\n const one = this.announcement\n if (!one.requiresAcknowledgement || one.status !== 'PUBLISHED') return nothing\n const by = one.acknowledgeBy ? t('announcement.text.acknowledge-by', { when: when(one.acknowledgeBy, false) }) : ''\n if (one.mine?.acknowledgedAt) return html`<div class=\"acknowledge done\">${t('announcement.text.acknowledged-at', { when: when(one.mine.acknowledgedAt) })}</div>`\n /* Only its audience acknowledges; a writer looking at one addressed to others sees what is asked. */\n if (!one.addressed) return html`<div class=\"acknowledge\">${t('announcement.text.acknowledge-asked')} ${by}</div>`\n return html`<div class=\"acknowledge\">\n <span>${t('announcement.text.acknowledge-asked')} ${by}</span>\n <md-filled-button ?disabled=${this.busy} @click=${() => this.acknowledge()}>${t('announcement.button.acknowledge')}</md-filled-button>\n </div>`\n }\n\n private follow(url: string) {\n this.dispatchEvent(new CustomEvent('announcement-follow', { bubbles: true, composed: true }))\n followLink(url)\n }\n\n private async acknowledge() {\n this.busy = true\n try {\n const done = await announcementApi.acknowledge(this.announcement.id)\n this.announcement = { ...this.announcement, ...done }\n this.dispatchEvent(new CustomEvent('announcement-acknowledged', { bubbles: true, composed: true, detail: this.announcement }))\n } catch (error) {\n notify({ level: 'error', message: reasonOf(error) })\n } finally {\n this.busy = false\n }\n }\n}\n"]}
1
+ {"version":3,"file":"announcement-sheet.js","sourceRoot":"","sources":["../../client/components/announcement-sheet.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * One announcement as its reader sees it - what kind it is and from whom, its body, its files, the screens it points to,\n * and the acknowledgement it asks for (ADR-0163 decisions 3, 5). The screen and the popup both draw it.\n */\nimport '@material/web/icon/icon.js'\nimport '@material/web/button/filled-button.js'\n\nimport gql from 'graphql-tag'\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\nimport { unsafeHTML } from 'lit/directives/unsafe-html.js'\n\nimport { MutationController } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { navigate } from '@operato/shell'\nimport { renderMarkdown } from '@things-factory/ai-assistant/dist-client/index.js'\n\nimport { announcementsChanged, type AnnouncementItem } from '../utils/announcement-api.js'\nimport { categoryWord, importanceWord, t, when } from '../utils/announcement-words.js'\n\n/** A screen of the application opens in place; an https page opens apart. */\nexport function followLink(url: string) {\n if (/^https:\\/\\//i.test(url)) window.open(url, '_blank', 'noopener')\n else navigate(url)\n}\n\n@customElement('announcement-sheet')\nexport class AnnouncementSheet extends localize(i18next)(LitElement) {\n static styles = css`\n :host {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-medium, 8px);\n color: var(--md-sys-color-on-surface);\n }\n .meta {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--spacing-small, 4px) var(--spacing-medium, 8px);\n font-size: var(--ui-t-small, 12px);\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n }\n .chip {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n padding: 0 var(--spacing-small, 4px);\n border-radius: var(--border-radius, 4px);\n border: 1px solid var(--ui-line-soft, var(--md-sys-color-outline-variant));\n line-height: 1.6;\n }\n .chip.URGENT {\n color: var(--md-sys-color-error);\n border-color: currentColor;\n }\n .chip.IMPORTANT {\n color: var(--md-sys-color-primary);\n border-color: currentColor;\n }\n .chip md-icon {\n --md-icon-size: 14px;\n }\n .markdown {\n font-size: var(--ui-t-body, 14px);\n line-height: 1.6;\n overflow-wrap: anywhere;\n }\n .markdown :is(h1, h2, h3, h4) {\n margin: var(--spacing-medium, 8px) 0 var(--spacing-small, 4px);\n font-size: var(--ui-t-title, 16px);\n }\n .markdown :is(p, ul, ol, blockquote, pre, table) {\n margin: 0 0 var(--spacing-medium, 8px);\n }\n .markdown :is(ul, ol) {\n padding-inline-start: 1.4em;\n list-style: revert;\n display: block;\n }\n .markdown a {\n color: var(--md-sys-color-primary);\n }\n .markdown table {\n border-collapse: collapse;\n }\n .markdown :is(th, td) {\n border: 1px solid var(--ui-line-soft, var(--md-sys-color-outline-variant));\n padding: 2px var(--spacing-small, 4px);\n }\n h4 {\n margin: var(--spacing-medium, 8px) 0 var(--spacing-small, 4px);\n font-size: var(--ui-t-small, 12px);\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n font-weight: 600;\n }\n ul.files {\n margin: 0;\n padding: 0;\n list-style: none;\n display: flex;\n flex-direction: column;\n gap: 2px;\n }\n a,\n .link {\n display: inline-flex;\n align-items: center;\n gap: var(--spacing-small, 4px);\n color: var(--md-sys-color-primary);\n text-decoration: none;\n cursor: pointer;\n background: none;\n border: 0;\n padding: 0;\n font: inherit;\n }\n a:hover,\n .link:hover {\n text-decoration: underline;\n }\n a md-icon,\n .link md-icon {\n --md-icon-size: 16px;\n }\n .size {\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n font-size: var(--ui-t-small, 12px);\n }\n .acknowledge {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: space-between;\n gap: var(--spacing-medium, 8px);\n padding: var(--spacing-medium, 8px) var(--spacing-large, 12px);\n border-radius: var(--border-radius, 4px);\n background: var(--md-sys-color-surface-container, rgba(0, 0, 0, 0.04));\n font-size: var(--ui-t-body, 14px);\n }\n .acknowledge.done {\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n }\n `\n\n @property({ attribute: false }) announcement!: AnnouncementItem\n private acknowledgement = new MutationController(\n this,\n gql`mutation ($id: String!) { acknowledgeAnnouncement(id: $id) { id readerState mine { readAt acknowledgedAt } } }`\n )\n\n private get busy() {\n return this.acknowledgement.pending\n }\n\n render() {\n const one = this.announcement\n if (!one) return nothing\n const files = one.attachments ?? []\n const links = one.links ?? []\n return html`<div class=\"meta\">\n ${one.pinned ? html`<span class=\"chip\"><md-icon>push_pin</md-icon>${t('announcement.field.pinned')}</span>` : nothing}\n ${one.importance !== 'NORMAL' ? html`<span class=\"chip ${one.importance}\">${importanceWord(one.importance)}</span>` : nothing}\n <span class=\"chip\">${categoryWord(one.category)}</span>\n <span>${one.publisher?.name ?? one.creator?.name ?? ''}</span>\n <span>${when(one.publishedAt ?? one.startsAt)}</span>\n ${one.endsAt ? html`<span>${t('announcement.text.until', { when: when(one.endsAt) })}</span>` : nothing}\n ${one.version > 1 ? html`<span>${t('announcement.text.version', { version: one.version })}</span>` : nothing}\n </div>\n ${one.body ? html`<div class=\"markdown\">${unsafeHTML(renderMarkdown(one.body))}</div>` : nothing}\n ${files.length\n ? html`<h4>${t('announcement.field.attachments')}</h4>\n <ul class=\"files\">\n ${files.map(\n file =>\n html`<li>\n <a href=${file.fullpath} target=\"_blank\" rel=\"noopener\" download=${file.name}><md-icon>attach_file</md-icon>${file.name}</a>\n ${file.size ? html`<span class=\"size\">${Math.max(1, Math.round(file.size / 1024))} KB</span>` : nothing}\n </li>`\n )}\n </ul>`\n : nothing}\n ${links.length\n ? html`<h4>${t('announcement.field.links')}</h4>\n <ul class=\"files\">\n ${links.map(link => html`<li><button class=\"link\" @click=${() => this.follow(link.url)}><md-icon>open_in_new</md-icon>${link.label}</button></li>`)}\n </ul>`\n : nothing}\n ${this.renderAcknowledge()}`\n }\n\n private renderAcknowledge() {\n const one = this.announcement\n if (!one.requiresAcknowledgement || one.status !== 'PUBLISHED') return nothing\n const by = one.acknowledgeBy ? t('announcement.text.acknowledge-by', { when: when(one.acknowledgeBy, false) }) : ''\n if (one.mine?.acknowledgedAt) return html`<div class=\"acknowledge done\">${t('announcement.text.acknowledged-at', { when: when(one.mine.acknowledgedAt) })}</div>`\n /* Only its audience acknowledges; a writer looking at one addressed to others sees what is asked. */\n if (!one.addressed) return html`<div class=\"acknowledge\">${t('announcement.text.acknowledge-asked')} ${by}</div>`\n return html`<div class=\"acknowledge\">\n <span>${t('announcement.text.acknowledge-asked')} ${by}</span>\n <md-filled-button ?disabled=${this.busy} @click=${() => this.acknowledge()}>${t('announcement.button.acknowledge')}</md-filled-button>\n </div>`\n }\n\n private follow(url: string) {\n this.dispatchEvent(new CustomEvent('announcement-follow', { bubbles: true, composed: true }))\n followLink(url)\n }\n\n private async acknowledge() {\n const done = await this.acknowledgement.run({ id: this.announcement.id })\n if (!done) return\n announcementsChanged()\n this.announcement = { ...this.announcement, ...done.acknowledgeAnnouncement }\n this.dispatchEvent(new CustomEvent('announcement-acknowledged', { bubbles: true, composed: true, detail: this.announcement }))\n }\n}\n"]}
@@ -13,13 +13,17 @@ export declare class AudiencePicker extends AudiencePicker_base {
13
13
  static styles: import("lit").CSSResult;
14
14
  value: Audience[];
15
15
  disabled: boolean;
16
- private choices?;
17
16
  private text;
18
- private found;
19
- private size?;
17
+ private searched;
18
+ private counted;
20
19
  private searching?;
21
20
  private counting?;
22
- connectedCallback(): Promise<void>;
21
+ private choicesRead;
22
+ private people;
23
+ private sizeRead;
24
+ private get choices();
25
+ private get found();
26
+ private get size();
23
27
  updated(changes: Map<string, unknown>): void;
24
28
  render(): import("lit-html").TemplateResult<1>;
25
29
  private give;