UNPKG

@rxap/ngx-changelog

Version:

This package provides Angular components and services to display changelogs within an application. It fetches changelog data from a remote source and presents it in a user-friendly dialog or component, allowing users to view updates and changes. The packa

253 lines (242 loc) 20.7 kB
import { __decorate } from 'tslib'; import * as i0 from '@angular/core'; import { Injectable, signal, computed, inject, Component, EventEmitter, ViewChild, Output, ApplicationRef, createComponent, provideAppInitializer } from '@angular/core'; import { OpenApiRemoteMethod, RxapOpenApiRemoteMethod } from '@rxap/open-api/remote-method'; import { NgForOf, NgIf, NgClass, CommonModule } from '@angular/common'; import * as i1$1 from '@angular/forms'; import { FormsModule } from '@angular/forms'; import { MethodTemplateDirective } from '@rxap/directives'; import { RXAP_ENVIRONMENT } from '@rxap/environment'; import * as i1 from 'ngx-markdown'; import { MarkdownModule } from 'ngx-markdown'; import { take } from 'rxjs'; import { tap } from 'rxjs/operators'; let ChangelogControllerGetLatestRemoteMethod = class ChangelogControllerGetLatestRemoteMethod extends OpenApiRemoteMethod { call(parameters) { return super.call(parameters); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: ChangelogControllerGetLatestRemoteMethod, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: ChangelogControllerGetLatestRemoteMethod, providedIn: 'root' }); } }; ChangelogControllerGetLatestRemoteMethod = __decorate([ RxapOpenApiRemoteMethod({ serverId: 'service-changelog', operationId: 'ChangelogController_getLatest', operation: '{"operationId":"ChangelogController_getLatest","parameters":[{"name":"application","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"general":{"type":"array","items":{"type":"string"}},"application":{"type":"array","items":{"type":"string"}}},"required":["general","application"]}}}}},"method":"get","path":"/latest/{application}"}', }) ], ChangelogControllerGetLatestRemoteMethod); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: ChangelogControllerGetLatestRemoteMethod, decorators: [{ type: Injectable, args: [{ providedIn: 'root', }] }] }); let ChangelogControllerGetVersionRemoteMethod = class ChangelogControllerGetVersionRemoteMethod extends OpenApiRemoteMethod { call(parameters) { return super.call(parameters); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: ChangelogControllerGetVersionRemoteMethod, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: ChangelogControllerGetVersionRemoteMethod, providedIn: 'root' }); } }; ChangelogControllerGetVersionRemoteMethod = __decorate([ RxapOpenApiRemoteMethod({ serverId: 'service-changelog', operationId: 'ChangelogController_getVersion', operation: '{"operationId":"ChangelogController_getVersion","parameters":[{"name":"version","required":true,"in":"path","schema":{"type":"string"}},{"name":"application","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"general":{"type":"array","items":{"type":"string"}},"application":{"type":"array","items":{"type":"string"}}},"required":["general","application"]}}}}},"method":"get","path":"/{version}/{application}"}', }) ], ChangelogControllerGetVersionRemoteMethod); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: ChangelogControllerGetVersionRemoteMethod, decorators: [{ type: Injectable, args: [{ providedIn: 'root', }] }] }); let ChangelogControllerListRemoteMethod = class ChangelogControllerListRemoteMethod extends OpenApiRemoteMethod { call() { return super.call(); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: ChangelogControllerListRemoteMethod, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: ChangelogControllerListRemoteMethod, providedIn: 'root' }); } }; ChangelogControllerListRemoteMethod = __decorate([ RxapOpenApiRemoteMethod({ serverId: 'service-changelog', operationId: 'ChangelogController_list', operation: '{"operationId":"ChangelogController_list","parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"array","items":{"type":"string"}}}}}},"method":"get","path":"/available-versions"}', }) ], ChangelogControllerListRemoteMethod); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: ChangelogControllerListRemoteMethod, decorators: [{ type: Injectable, args: [{ providedIn: 'root', }] }] }); class ChangelogComponent { constructor() { this.availableVersions = signal([]); this.error = signal(null); this.activeIndex = signal(-1); this.selectedVersion = computed(() => { const activeIndex = this.activeIndex(); const availableVersions = this.availableVersions(); if (activeIndex > -1) { return availableVersions[activeIndex] ?? 'latest'; } return availableVersions[availableVersions.length - 1] ?? 'latest'; }); this.displayedButtons = computed(() => { let activeIndex = this.activeIndex(); if (activeIndex === -1) { activeIndex = this.availableVersions().length - 1; } let start = Math.max(0, activeIndex - 2); let end = Math.min(this.availableVersions().length, activeIndex + 3); if (end - start < 5) { if (start === 0) { end += 5 - (end - start); } else { start -= 5 - (end - start); } } end = Math.min(this.availableVersions().length, end); start = Math.max(0, start); return Array.from({ length: end - start }, (_, i) => ({ index: start + i, version: this.availableVersions()[start + i], })); }); this.application = inject(RXAP_ENVIRONMENT).app; this.getChangelogMethod = inject(ChangelogControllerGetVersionRemoteMethod); this.getChangelogMethodParameters = computed(() => ({ parameters: { version: this.selectedVersion(), application: this.application, }, })); this.getAvailableVersionsMethod = inject(ChangelogControllerListRemoteMethod); } ngOnInit() { this.loadAvailableVersions(); } async loadAvailableVersions() { try { const availableVersions = await this.getAvailableVersionsMethod.call(); this.availableVersions.set(availableVersions); this.activeIndex.set(availableVersions.length - 1); } catch (e) { this.error.set(e.message); } } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: ChangelogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.3", type: ChangelogComponent, isStandalone: true, selector: "rxap-changelog", ngImport: i0, template: "<ng-container *ngIf=\"error(); else noError\">\n <h2 class=\"text-2xl pb-2\" i18n>Something has gone wrong!</h2>\n <p i18n>Unable to load the application changelog</p>\n</ng-container>\n<ng-template #noError>\n<div class=\"flex flex-col gap-3\">\n <ng-container *ngIf=\"availableVersions().length\">\n <div class=\"controls flex justify-center space-x-2 my-4\">\n <button\n (click)=\"activeIndex.set(activeIndex() - 1)\"\n [disabled]=\"activeIndex() <= 0\"\n [ngClass]=\"{\n 'bg-gray-100 dark:bg-gray-900': activeIndex() <= 0,\n 'hover:bg-gray-300': activeIndex() > 0,\n }\"\n class=\"px-4 py-2 bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-900 transition-colors duration-150 rounded\">Previous\n </button>\n <button (click)=\"activeIndex.set(item.index)\"\n *ngFor=\"let item of displayedButtons()\"\n [ngClass]=\"{\n 'bg-primary-500': item.index === activeIndex(),\n 'bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-900 hover:bg-gray-300 transition-colors duration-150': item.index !== activeIndex()\n }\"\n class=\"px-4 py-2 rounded\">\n {{ item.version }}\n </button>\n <button\n (click)=\"activeIndex.set(activeIndex() + 1)\"\n [disabled]=\"activeIndex() >= availableVersions().length - 1\"\n [ngClass]=\"{\n 'bg-gray-100 dark:bg-gray-900': activeIndex() >= availableVersions().length - 1,\n 'hover:bg-gray-300': activeIndex() < availableVersions().length - 1,\n }\"\n class=\"px-4 py-2 bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-900 hover:bg-gray-300 transition-colors duration-150 rounded\">Next\n </button>\n </div>\n <hr>\n </ng-container>\n <div class=\"flex flex-col gap-6 p-8 overflow-auto\" style=\"max-height: 60vh\">\n <ng-container *rxapMethod=\"let changelog call getChangelogMethod; parameters: getChangelogMethodParameters()\">\n <markdown *ngFor=\"let general of changelog.general\" [data]=\"general\" class=\"prose dark:prose-invert\">\n </markdown>\n <markdown *ngFor=\"let application of changelog.application\" [data]=\"application\" class=\"prose dark:prose-invert\">\n </markdown>\n </ng-container>\n </div>\n</div>\n</ng-template>\n", styles: [""], dependencies: [{ kind: "directive", type: MethodTemplateDirective, selector: "[rxapMethod]", inputs: ["rxapMethodCall", "rxapMethodParameters", "rxapMethodError", "rxapMethodLoading", "rxapMethodWithoutParameters", "immediately"], outputs: ["executed", "failure", "successful", "executing", "embedded"], exportAs: ["rxapMethod"] }, { kind: "ngmodule", type: MarkdownModule }, { kind: "component", type: i1.MarkdownComponent, selector: "markdown, [markdown]", inputs: ["data", "src", "disableSanitizer", "inline", "srcRelativeLink", "clipboard", "clipboardButtonComponent", "clipboardButtonTemplate", "emoji", "katex", "katexOptions", "mermaid", "mermaidOptions", "lineHighlight", "line", "lineOffset", "lineNumbers", "start", "commandLine", "filterOutput", "host", "prompt", "output", "user"], outputs: ["error", "load", "ready"] }, { kind: "directive", type: NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: ChangelogComponent, decorators: [{ type: Component, args: [{ selector: 'rxap-changelog', imports: [ MethodTemplateDirective, MarkdownModule, NgForOf, NgIf, NgClass, ], template: "<ng-container *ngIf=\"error(); else noError\">\n <h2 class=\"text-2xl pb-2\" i18n>Something has gone wrong!</h2>\n <p i18n>Unable to load the application changelog</p>\n</ng-container>\n<ng-template #noError>\n<div class=\"flex flex-col gap-3\">\n <ng-container *ngIf=\"availableVersions().length\">\n <div class=\"controls flex justify-center space-x-2 my-4\">\n <button\n (click)=\"activeIndex.set(activeIndex() - 1)\"\n [disabled]=\"activeIndex() <= 0\"\n [ngClass]=\"{\n 'bg-gray-100 dark:bg-gray-900': activeIndex() <= 0,\n 'hover:bg-gray-300': activeIndex() > 0,\n }\"\n class=\"px-4 py-2 bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-900 transition-colors duration-150 rounded\">Previous\n </button>\n <button (click)=\"activeIndex.set(item.index)\"\n *ngFor=\"let item of displayedButtons()\"\n [ngClass]=\"{\n 'bg-primary-500': item.index === activeIndex(),\n 'bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-900 hover:bg-gray-300 transition-colors duration-150': item.index !== activeIndex()\n }\"\n class=\"px-4 py-2 rounded\">\n {{ item.version }}\n </button>\n <button\n (click)=\"activeIndex.set(activeIndex() + 1)\"\n [disabled]=\"activeIndex() >= availableVersions().length - 1\"\n [ngClass]=\"{\n 'bg-gray-100 dark:bg-gray-900': activeIndex() >= availableVersions().length - 1,\n 'hover:bg-gray-300': activeIndex() < availableVersions().length - 1,\n }\"\n class=\"px-4 py-2 bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-900 hover:bg-gray-300 transition-colors duration-150 rounded\">Next\n </button>\n </div>\n <hr>\n </ng-container>\n <div class=\"flex flex-col gap-6 p-8 overflow-auto\" style=\"max-height: 60vh\">\n <ng-container *rxapMethod=\"let changelog call getChangelogMethod; parameters: getChangelogMethodParameters()\">\n <markdown *ngFor=\"let general of changelog.general\" [data]=\"general\" class=\"prose dark:prose-invert\">\n </markdown>\n <markdown *ngFor=\"let application of changelog.application\" [data]=\"application\" class=\"prose dark:prose-invert\">\n </markdown>\n </ng-container>\n </div>\n</div>\n</ng-template>\n" }] }] }); class ChangelogDialogComponent { constructor() { this.closeDialog = new EventEmitter(); this.remember = true; } ngAfterViewInit() { this.dialog.nativeElement.showModal(); } close(remember = this.remember) { this.dialog.nativeElement.close(); this.closeDialog.emit(remember); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: ChangelogDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.3", type: ChangelogDialogComponent, isStandalone: true, selector: "rxap-changelog-dialog", outputs: { closeDialog: "closeDialog" }, viewQueries: [{ propertyName: "dialog", first: true, predicate: ["dialog"], descendants: true, static: true }], ngImport: i0, template: "<dialog #dialog\n class=\"max-w-6xl rounded overflow-auto drop-shadow-2xl bg-white text-black dark:bg-black dark:text-white flex flex-col gap-3 p-6\">\n <rxap-changelog></rxap-changelog>\n <div class=\"flex flex-row justify-end gap-6\">\n <div class=\"flex flex-row gap-3 items-center\">\n <input [(ngModel)]=\"remember\" id=\"rxap-changelog-remember\" type=\"checkbox\">\n <label for=\"rxap-changelog-remember\" i18n>Don't show again until next new version</label>\n </div>\n <button (click)=\"close()\" class=\"px-4 py-2 rounded bg-primary-500\" i18n>close</button>\n </div>\n</dialog>\n", styles: ["dialog::backdrop{background:#000000b3}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: ChangelogComponent, selector: "rxap-changelog" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: ChangelogDialogComponent, decorators: [{ type: Component, args: [{ selector: 'rxap-changelog-dialog', imports: [CommonModule, ChangelogComponent, FormsModule], template: "<dialog #dialog\n class=\"max-w-6xl rounded overflow-auto drop-shadow-2xl bg-white text-black dark:bg-black dark:text-white flex flex-col gap-3 p-6\">\n <rxap-changelog></rxap-changelog>\n <div class=\"flex flex-row justify-end gap-6\">\n <div class=\"flex flex-row gap-3 items-center\">\n <input [(ngModel)]=\"remember\" id=\"rxap-changelog-remember\" type=\"checkbox\">\n <label for=\"rxap-changelog-remember\" i18n>Don't show again until next new version</label>\n </div>\n <button (click)=\"close()\" class=\"px-4 py-2 rounded bg-primary-500\" i18n>close</button>\n </div>\n</dialog>\n", styles: ["dialog::backdrop{background:#000000b3}\n"] }] }], propDecorators: { dialog: [{ type: ViewChild, args: ['dialog', { static: true }] }], closeDialog: [{ type: Output }] } }); const RXAP_CHANGELOG_LAST_VERSION = 'RXAP_CHANGELOG_LAST_VERSION'; const RXAP_CHANGELOG_DISABLED = 'RXAP_CHANGELOG_DISABLED'; class ChangelogService { constructor() { this.version = inject(RXAP_ENVIRONMENT).name; this.applicationRef = inject(ApplicationRef); } showChangelogDialog() { const body = document.getElementsByTagName('body')[0]; const div = document.createElement('div'); body.appendChild(div); const componentRef = createComponent(ChangelogDialogComponent, { hostElement: div, environmentInjector: this.applicationRef.injector, }); this.applicationRef.attachView(componentRef.hostView); componentRef.instance.closeDialog.pipe(take(1), tap(remember => { componentRef.destroy(); body.removeChild(div); div.remove(); if (remember && this.version) { this.lastVersion = this.version; } })).subscribe(); } get isDisabled() { return localStorage.getItem(RXAP_CHANGELOG_DISABLED) === 'true'; } get lastVersion() { return localStorage.getItem(RXAP_CHANGELOG_LAST_VERSION); } set lastVersion(version) { if (version) { localStorage.setItem(RXAP_CHANGELOG_LAST_VERSION, version); } else { localStorage.removeItem(RXAP_CHANGELOG_LAST_VERSION); } } showChangelogDialogIfNewVersion() { if (this.isDisabled) { return; } const lastVersion = this.lastVersion; if (this.version && lastVersion && this.version !== lastVersion) { this.lastVersion = null; } if (this.lastVersion === this.version) { return; } this.showChangelogDialog(); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: ChangelogService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: ChangelogService, providedIn: 'root' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: ChangelogService, decorators: [{ type: Injectable, args: [{ providedIn: 'root', }] }] }); function ProvideChangelog() { return provideAppInitializer(() => { const initializerFn = ((changelogService) => () => changelogService.showChangelogDialogIfNewVersion())(inject(ChangelogService)); return initializerFn(); }); } // region openapi responses // endregion /** * Generated bundle index. Do not edit. */ export { ChangelogComponent, ChangelogControllerGetLatestRemoteMethod, ChangelogControllerGetVersionRemoteMethod, ChangelogControllerListRemoteMethod, ChangelogDialogComponent, ChangelogService, ProvideChangelog, RXAP_CHANGELOG_DISABLED, RXAP_CHANGELOG_LAST_VERSION }; //# sourceMappingURL=rxap-ngx-changelog.mjs.map