@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
JavaScript
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