<link rel="stylesheet" href="/assets/fonts/inter/inter.css" />
All posts

Angular me Looker Embedded: si ta eliminosh boilerplate-in dhe ndërfaqet TypeScript për tabelat e të dhënave

Në çdo aplikacion menaxhimi vjen momenti i tabelës numër njëzet: një tjetër ndërfaqe TypeScript, një tjetër DTO, një tjetër komponent me paginim, renditje, filtra dhe eksport. Është kod i dobishëm, por gjithmonë i njëjtë, dhe rritet me çdo kërkesë. Në këtë artikull tregoj si, për të dhënat e konsultimit dhe analizës, Angular me Looker Embedded lejon të eliminohet pothuajse plotësisht ai boilerplate.

Problemi i boilerplate-it tradicional

Qasja klasike për të shfaqur një dataset në Angular kërkon gjithmonë të njëjtat pjesë:

  • Ndërfaqe dhe DTO që dyfishojnë në frontend formën e të dhënave të backend-it, për t'u përditësuar në çdo ndryshim.
  • Një komponent tabele i dedikuar, me Angular Material ose PrimeNG, kolona të përcaktuara me dorë dhe template për çdo fushë.
  • Paginim, renditje dhe filtra për t'u lidhur dhe testuar, shpesh edhe në anën e serverit.
  • Formatim i valutave, datave dhe statuseve, i përsëritur në çdo tabelë.
  • Eksport në CSV ose Excel, i shkruar me dorë ose i besuar një librarie tjetër.

Ja si duket, në formë të reduktuar, një tabelë e vetme porosish:

// 1. The API contract, duplicated on the frontend
export interface OrderDto {
  id: number; customer_name: string; region: string;
  total_cents: number; status: 'OPEN' | 'PAID' | 'CANCELLED'; created_at: string;
}
// 2. The view model, because the API shape is not the table shape
export interface OrderRow {
  id: number; customer: string; region: string;
  total: number; status: string; createdAt: Date;
}

@Component({ /* ... MatTableModule, MatPaginatorModule, MatSortModule ... */ })
export class OrdersTableComponent implements AfterViewInit {
  readonly columns = ['id', 'customer', 'region', 'total', 'status', 'createdAt'];
  readonly dataSource = new MatTableDataSource<OrderRow>([]);
  @ViewChild(MatPaginator) paginator!: MatPaginator;
  @ViewChild(MatSort) sort!: MatSort;

  constructor(private api: OrdersApi) {
    this.api.list().subscribe(dtos => (this.dataSource.data = dtos.map(toRow)));
  }
  ngAfterViewInit(): void {
    this.dataSource.paginator = this.paginator;
    this.dataSource.sort = this.sort;
  }
  applyFilter(value: string): void { this.dataSource.filter = value.trim().toLowerCase(); }
  exportCsv(): void { /* build the CSV by hand, escape quotes, trigger the download... */ }
}

// 3. Mapping and formatting, also by hand
const toRow = (d: OrderDto): OrderRow => ({
  id: d.id, customer: d.customer_name, region: d.region,
  total: d.total_cents / 100, status: d.status, createdAt: new Date(d.created_at),
});
// ...plus the HTML template with one <ng-container matColumnDef> per column

Dhe ky është vetëm frontend-i: për çdo kolonë të re duhet ndryshuar DTO-ja, mapping-u, template-i, testet, dhe duhen publikuar bashkë backend-i dhe frontend-i.

Kthesa: Angular me Looker Embedded

Me Looker kontrata e të dhënave dhe prezantimi jetojnë në modelin LookML: dimensionet, masat, formatet, etiketat dhe marrëdhëniet përcaktohen një herë të vetme, në anën e analitikës. Frontend-i nuk ka më nevojë të njohë formën e të dhënave: duhet vetëm të shfaqë një përmbajtje të gatshme, që Looker e integron në një iframe të sigurt.

SDK-ja inicializohet një herë për aplikacionin, duke treguar endpoint-in e backend-it tonë që nënshkruan URL-të e embed-it:

// app.config.ts — once for the whole application
import { LookerEmbedSDK } from '@looker/embed-sdk';

export const appConfig: ApplicationConfig = {
  providers: [
    // The SDK asks our backend for a signed embed URL for each content item
    provideAppInitializer(() => LookerEmbedSDK.init('analytics.example.com', '/api/looker/embed-auth')),
  ],
};

Pastaj mjafton një komponent gjenerik, <app-looker-table>, që merr vetëm ID-në e përmbajtjes dhe nuk di asgjë për kolonat apo tipet:

@Component({
  selector: 'app-looker-table',
  template: `<div #host class="looker-host"></div>`,
  styles: `.looker-host, .looker-host iframe { width: 100%; height: 100%; border: 0; }`,
})
export class LookerTableComponent {
  /** Look ID defined in Looker: the component knows nothing about the data. */
  readonly lookId = input.required<string>();
  private readonly host = viewChild.required<ElementRef<HTMLDivElement>>('host');

  constructor() {
    afterNextRender(() => {
      LookerEmbedSDK.createLookWithId(this.lookId())
        .appendTo(this.host().nativeElement)
        .build()
        .connect()
        .catch(err => console.error('Looker embed failed', err));
    });
  }
}

// Usage: the same component for any dataset
// <app-looker-table lookId="42" />   orders
// <app-looker-table lookId="57" />   invoices

Vini re çfarë mungon: asnjë interface, asnjë DTO, asnjë përkufizim kolone, asnjë funksion eksporti. I njëjti komponent shfaq porositë, faturat ose çdo dataset tjetër.

Përfitimet për ekipin

Kolona të reja pa deploy të frontend-it

Shtimi i një kolone, ndryshimi i një formati ose i një etikete është një ndryshim në modelin LookML ose në Look: sapo ruhet, është i dukshëm në aplikacion. Frontend-i nuk duhet as rikompiluar, as publikuar.

Eksport, drill-down dhe paginim të përfshira

Shkarkimi në CSV, Excel dhe PDF, renditja, paginimi dhe drill-down-i mbi vlerat janë funksione të Looker-it, tashmë të testuara dhe koherente në çdo tabelë, dhe aktivizohen me lejet e përdoruesit.

Siguria në nivel rreshti

Me signed embed, backend-i ynë gjeneron URL-në e nënshkruar me atributet e përdoruesit të identifikuar. Në modelin LookML një access_filter i përdor ato atribute për të filtruar çdo query: një përdorues nuk mund të shohë rreshtat e një rajoni tjetër, as duke manipuluar URL-në.

// NestJS: signs the embed URL with the logged-in user's attributes
@Get('looker/embed-auth')
async embedAuth(@Query('src') src: string, @CurrentUser() user: User) {
  const embed = await this.looker.ok(this.looker.create_sso_embed_url({
    target_url: `https://analytics.example.com${src}`,
    session_length: 3600,
    external_user_id: String(user.id),
    first_name: user.firstName,
    last_name: user.lastName,
    permissions: ['access_data', 'see_looks', 'download_without_limit'],
    models: ['sales'],
    user_attributes: { region: user.region },   // drives row-level security
  }));
  return { url: embed.url };
}
# LookML: every query on this explore is filtered by the user's region
explore: orders {
  access_filter: {
    field: customers.region
    user_attribute: region
  }
}

Krahasimi

AspektiTabelë tradicionale në AngularAngular me Looker Embedded
Kodi frontend për një dataset të riDhjetëra ose qindra rreshta: service, mapping, komponent, templateNjë rresht template, me një komponent të përbashkët
Ndërfaqe TypeScript për datasetTë paktën dy: DTO dhe modeli i pamjesAsnjë
Shtimi i një koloneZhvillim, rishikim dhe deploy i backend-it dhe frontend-itNdryshim në modelin LookML, pa deploy frontend
Paginim, renditje, filtra, eksportPër t'u implementuar dhe testuarTë përfshira
Siguria e të dhënave për përdoruesLogjikë e dedikuar në backendAtribute përdoruesi dhe access filter në LookML
MirëmbajtjaRritet me numrin e tabelaveE përqendruar në modelin e të dhënave

Kur të mos e përdorësh

  • Tabela të modifikueshme: futja, modifikimi në rresht dhe veprimet mbi rreshtat mbeten detyrë e aplikacionit.
  • Ndërfaqe shumë të personalizuara: përmbajtja jeton në një iframe, ndaj stili përshtatet me temat e Looker-it, jo me CSS-në e aplikacionit.
  • Kostoja dhe infrastruktura: Looker është një platformë me licencë dhe një model të dhënash për t'u mirëmbajtur; ia vlen kur dataset-et janë shumë dhe ndryshojnë shpesh.
  • Logjika e aplikacionit ka ende nevojë për tipet e saj: ndërfaqet zhduken për tabelat e konsultimit, jo për formularët dhe rregullat e biznesit.

Përfundime

  • Time-to-market: një raport i ri bëhet një rresht template, jo një sprint.
  • Mirëmbajtja: codebase-i Angular ndalon së rrituri me çdo dataset; kompleksiteti mbetet në modelin e të dhënave, aty ku duhet të jetë.
  • Siguria: rregullat e dukshmërisë së të dhënave janë të centralizuara dhe zbatohen në çdo query.
  • Ndarja e roleve: zhvilluesit frontend përqendrohen te përvoja e aplikacionit, ata që punojnë me të dhënat te modeli.

Për të dhënat e konsultimit dhe analizës, Angular me Looker Embedded e zhvendos punën nga kodi i përsëritur te modeli i të dhënave. Nëse doni të thelloheni se si të organizoni pjesën tjetër të aplikacionit, kam shkruar për arkitekturën Angular dhe për design system me komponentë të ripërdorshëm; nëse po vlerësoni një integrim të ngjashëm, më shkruani.

💬 Shënime nga lexuesit

0 shënime

Shkruaj një shënim

Ndaj mendimin tënd, një sugjerim ose një kompliment

Shënimet e fundit

Ende asnjë shënim. Bëhu i pari që komenton!