@trismegisto/spine 3.3.1 → 3.3.2

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.
@@ -3,7 +3,7 @@ import { inject, ChangeDetectorRef, ChangeDetectionStrategy, Component, Injectio
3
3
  import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
4
4
  import * as i3 from '@angular/router';
5
5
  import { RouterLink, Router, NavigationEnd, NavigationSkipped, RouterOutlet } from '@angular/router';
6
- import { firstValueFrom, Subject, filter, take, debounceTime, distinctUntilChanged } from 'rxjs';
6
+ import { firstValueFrom, filter, Subject, take, debounceTime, distinctUntilChanged } from 'rxjs';
7
7
  import { MenuButtonComponent, HermesThemeService, HERMES_THEME_CONFIG, HermesSidebarService, HermesToastService, IconComponent, ButtonComponent, SkeletonComponent, TextareaComponent, FloatingWindowComponent, IconButtonComponent, HermesShortcutService, HeaderComponent as HeaderComponent$1, AccountAvatarComponent, CommandPaletteComponent, createPersistedWorkspaceStore, HERMES_WORKSPACE_PERSISTENCE_CONFIG, findPanelTabs, SidebarComponent as SidebarComponent$1, SidebarNodeComponent, HermesI18nService, SegmentedControlComponent, ThemePickerComponent, AlertComponent, BreadcrumbComponent, DrawerComponent, ModalComponent, PaginatorComponent, RichTextComponent, SearchFieldComponent, ShortcutListComponent, TagComponent, CodeInputComponent, InputComponent, RadioComponent, CheckboxComponent, CodeViewerComponent, SelectComponent, AvatarGroupComponent, HERMES_SIDEBAR_CONFIG, ComboboxComponent, SettingsDialogComponent, SettingsRowComponent, SettingsSectionComponent, ToggletipComponent, TooltipDirective, EmptyComponent, LoadingSquareComponent, WorkspaceComponent, ToastStackComponent } from '@trismegisto/angular';
8
8
  import { ModalComponent as ModalComponent$1 } from '@trismegisto/spine/modal';
9
9
  import { SidePanelComponent } from '@trismegisto/spine/side-panel';
@@ -724,6 +724,26 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImpo
724
724
  args: [{ providedIn: 'root' }]
725
725
  }] });
726
726
 
727
+ /**
728
+ * Manda uma requisição ao argos-admin com o token da sessão em `x-access-token`. Com token na mão, sai na hora (token
729
+ * vencido é com o interceptor do Orfeu, que troca pelo renovado). Sem token ainda — o cabeçalho, as novidades e a
730
+ * avaliação chamam a API assim que aparecem, às vezes antes de o Orfeu restaurar a sessão —, espera a sessão ser
731
+ * aplicada (`isAuth$`) em vez de sair sem token (o servidor respondia "Access token required"). Orfeu sem `isAuth$`, ou
732
+ * sem `AuthorizationService` (app ou teste sem Orfeu): sai com o que houver.
733
+ */
734
+ function sendWithSession(auth, send) {
735
+ const now = auth?.getToken();
736
+ if (now || !auth)
737
+ return firstValueFrom(send(tokenHeaders(now)));
738
+ const session = auth;
739
+ if (!session.isAuth$ || session.authenticated !== false)
740
+ return firstValueFrom(send(tokenHeaders(now)));
741
+ return firstValueFrom(session.isAuth$.pipe(filter(Boolean))).then(() => firstValueFrom(send(tokenHeaders(auth.getToken()))));
742
+ }
743
+ function tokenHeaders(token) {
744
+ return new HttpHeaders({ 'x-access-token': token ?? '' });
745
+ }
746
+
727
747
  /** Espera depois da entrada (ou do fim da configuração inicial) antes do aviso, para não emendar com ela. */
728
748
  const ANNOUNCE_DELAY_MS = 1200;
729
749
  /** Quantas das mais recentes a entrada lê: decidem o aviso, a contagem do menu e o card do Início. */
@@ -783,9 +803,6 @@ class SpineNewsService {
783
803
  this.announcedKey = `${prefix}_news_announced`;
784
804
  this.favoritesKey = `${prefix}_news_favorites`;
785
805
  }
786
- get headers() {
787
- return new HttpHeaders({ 'x-access-token': this.auth?.getToken() ?? '' });
788
- }
789
806
  /** Relê as mais recentes; qualquer falha deixa a lista vazia (o item some em vez de mostrar um erro sem contexto). */
790
807
  async refresh() {
791
808
  if (!this.available)
@@ -800,14 +817,14 @@ class SpineNewsService {
800
817
  }
801
818
  /** Uma página da lista (`page` a partir de 1). Falha propaga: o painel mostra o erro com "Tentar de novo". */
802
819
  page(page, limit) {
803
- return firstValueFrom(this.http.get(`${this.adminApi}/me/news`, {
804
- headers: this.headers,
820
+ return sendWithSession(this.auth, (headers) => this.http.get(`${this.adminApi}/me/news`, {
821
+ headers,
805
822
  params: { page, limit },
806
823
  }));
807
824
  }
808
825
  /** Uma novidade com o corpo. */
809
826
  detail(id) {
810
- return firstValueFrom(this.http.get(`${this.adminApi}/me/news${urlPath `/${id}`}`, { headers: this.headers }));
827
+ return sendWithSession(this.auth, (headers) => this.http.get(`${this.adminApi}/me/news${urlPath `/${id}`}`, { headers }));
811
828
  }
812
829
  /**
813
830
  * Chamado uma vez pelo layout na entrada: lê as mais recentes, espera a configuração inicial se decidir (e terminar,
@@ -964,9 +981,6 @@ class SpineRatingsService {
964
981
  get url() {
965
982
  return `${this.adminApi}/me/ratings`;
966
983
  }
967
- get headers() {
968
- return new HttpHeaders({ 'x-access-token': this.auth?.getToken() ?? '' });
969
- }
970
984
  /** "Avaliar o {app}": abre a janela (ou troca o conteúdo dela) para a ferramenta. */
971
985
  openApp() {
972
986
  if (this.enabled)
@@ -1001,7 +1015,7 @@ class SpineRatingsService {
1001
1015
  }
1002
1016
  /** Média e total da ferramenta (`GET /me/ratings/summary`); quem mostra trata a falha. */
1003
1017
  async loadAppAverage() {
1004
- const res = await firstValueFrom(this.http.get(`${this.url}/summary`, { headers: this.headers }));
1018
+ const res = await sendWithSession(this.auth, (headers) => this.http.get(`${this.url}/summary`, { headers }));
1005
1019
  const out = { average: res?.average ?? null, total: res?.total ?? 0 };
1006
1020
  this.appAverage.set(out);
1007
1021
  return out;
@@ -1011,7 +1025,7 @@ class SpineRatingsService {
1011
1025
  const params = { scope: target.scope };
1012
1026
  if (target.scope === 'screen')
1013
1027
  params['screen'] = target.screenPath ?? '';
1014
- const res = await firstValueFrom(this.http.get(this.url, { headers: this.headers, params }));
1028
+ const res = await sendWithSession(this.auth, (headers) => this.http.get(this.url, { headers, params }));
1015
1029
  return res?.rating ?? null;
1016
1030
  }
1017
1031
  /** Cria ou atualiza a avaliação (nota 0 a 10); comentário vazio vai como `null`. */
@@ -1021,7 +1035,7 @@ class SpineRatingsService {
1021
1035
  body['screen_path'] = target.screenPath ?? '';
1022
1036
  body['screen_label'] = target.screenLabel ?? null;
1023
1037
  }
1024
- const res = await firstValueFrom(this.http.put(this.url, body, { headers: this.headers }));
1038
+ const res = await sendWithSession(this.auth, (headers) => this.http.put(this.url, body, { headers }));
1025
1039
  this.ratedNow.update((set) => new Set(set).add(keyOf(target)));
1026
1040
  if (target.scope === 'app') {
1027
1041
  this.appRated.set(true);
@@ -6162,21 +6176,18 @@ class SpineSuggestionsService {
6162
6176
  url(strings, ...ids) {
6163
6177
  return `${this.adminApi}/me/suggestions${urlPath(strings, ...ids)}`;
6164
6178
  }
6165
- get headers() {
6166
- return new HttpHeaders({ 'x-access-token': this.auth.getToken() ?? '' });
6167
- }
6168
6179
  create(draft) {
6169
- return firstValueFrom(this.http.post(this.url ``, draft, { headers: this.headers }));
6180
+ return sendWithSession(this.auth, (headers) => this.http.post(this.url ``, draft, { headers }));
6170
6181
  }
6171
6182
  /** As minhas, da mais nova; `status` filtra uma coluna. */
6172
- mine(opts) {
6183
+ async mine(opts) {
6173
6184
  let params = new HttpParams().set('limit', opts.limit).set('offset', opts.offset);
6174
6185
  if (opts.status)
6175
6186
  params = params.set('status', opts.status);
6176
- return firstValueFrom(this.http.get(this.url ``, { headers: this.headers, params }));
6187
+ return sendWithSession(this.auth, (headers) => this.http.get(this.url ``, { headers, params }));
6177
6188
  }
6178
6189
  /** "Sugestões do app": as de todas as pessoas no app (menos recusadas e arquivadas), com filtros e paginação. */
6179
- all(query) {
6190
+ async all(query) {
6180
6191
  let params = new HttpParams().set('limit', query.limit).set('offset', query.offset);
6181
6192
  if (query.status)
6182
6193
  params = params.set('status', query.status);
@@ -6186,24 +6197,24 @@ class SpineSuggestionsService {
6186
6197
  params = params.set('screen', query.screen);
6187
6198
  if (query.sort)
6188
6199
  params = params.set('sort', query.sort);
6189
- return firstValueFrom(this.http.get(this.url `/all`, { headers: this.headers, params }));
6200
+ return sendWithSession(this.auth, (headers) => this.http.get(this.url `/all`, { headers, params }));
6190
6201
  }
6191
6202
  /** Os comentários públicos de uma sugestão (o detalhe só de leitura), do mais novo. */
6192
- comments(id, page) {
6203
+ async comments(id, page) {
6193
6204
  const params = new HttpParams().set('limit', page.limit).set('offset', page.offset);
6194
- return firstValueFrom(this.http.get(this.url `/${id}/comments`, { headers: this.headers, params }));
6205
+ return sendWithSession(this.auth, (headers) => this.http.get(this.url `/${id}/comments`, { headers, params }));
6195
6206
  }
6196
6207
  /** As ainda abertas da tela, de qualquer pessoa: o modal oferece apoiar em vez de repetir. */
6197
6208
  async byScreen(path) {
6198
6209
  const params = new HttpParams().set('path', path);
6199
- const res = await firstValueFrom(this.http.get(this.url `/screen`, { headers: this.headers, params }));
6210
+ const res = await sendWithSession(this.auth, (headers) => this.http.get(this.url `/screen`, { headers, params }));
6200
6211
  return res.suggestions ?? [];
6201
6212
  }
6202
6213
  vote(id) {
6203
- return firstValueFrom(this.http.post(this.url `/${id}/vote`, {}, { headers: this.headers }));
6214
+ return sendWithSession(this.auth, (headers) => this.http.post(this.url `/${id}/vote`, {}, { headers }));
6204
6215
  }
6205
6216
  unvote(id) {
6206
- return firstValueFrom(this.http.delete(this.url `/${id}/vote`, { headers: this.headers }));
6217
+ return sendWithSession(this.auth, (headers) => this.http.delete(this.url `/${id}/vote`, { headers }));
6207
6218
  }
6208
6219
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: SpineSuggestionsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
6209
6220
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: SpineSuggestionsService, providedIn: 'root' }); }