valtech-components 4.0.247 → 4.0.248
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.
- package/esm2022/lib/components/molecules/chat-composer/chat-composer.component.mjs +4 -2
- package/esm2022/lib/version.mjs +2 -2
- package/esm2022/public-api.mjs +1 -4
- package/fesm2022/valtech-components.mjs +5 -209
- package/fesm2022/valtech-components.mjs.map +1 -1
- package/lib/components/molecules/load-more/load-more.component.d.ts +1 -1
- package/lib/components/organisms/article/article.component.d.ts +2 -2
- package/lib/components/organisms/chat-window/chat-window.component.d.ts +1 -1
- package/lib/components/organisms/member-import-modal/member-import-modal.component.d.ts +1 -1
- package/lib/version.d.ts +1 -1
- package/package.json +1 -1
- package/public-api.d.ts +0 -3
- package/esm2022/lib/components/molecules/usage-meters/types.mjs +0 -5
- package/esm2022/lib/components/molecules/usage-meters/usage-meters.component.mjs +0 -124
- package/esm2022/lib/services/usage/usage.service.mjs +0 -87
- package/lib/components/molecules/usage-meters/types.d.ts +0 -24
- package/lib/components/molecules/usage-meters/usage-meters.component.d.ts +0 -26
- package/lib/services/usage/usage.service.d.ts +0 -25
|
@@ -26,7 +26,7 @@ export declare class LoadMoreComponent {
|
|
|
26
26
|
readonly color: import("@angular/core").Signal<string>;
|
|
27
27
|
readonly fill: import("@angular/core").Signal<string>;
|
|
28
28
|
readonly shape: import("@angular/core").Signal<string>;
|
|
29
|
-
readonly size: import("@angular/core").Signal<"
|
|
29
|
+
readonly size: import("@angular/core").Signal<"default" | "small" | "large">;
|
|
30
30
|
readonly threshold: import("@angular/core").Signal<string>;
|
|
31
31
|
readonly label: import("@angular/core").Signal<string>;
|
|
32
32
|
private readonly _pendingComplete;
|
|
@@ -93,9 +93,9 @@ export declare class ArticleComponent implements OnInit {
|
|
|
93
93
|
contentInterpolation?: Record<string, string | number>;
|
|
94
94
|
icon?: import("valtech-components").IconMetada;
|
|
95
95
|
shape?: "round";
|
|
96
|
-
size?: "
|
|
96
|
+
size?: "default" | "small" | "large";
|
|
97
97
|
fill?: "default" | "clear" | "outline" | "solid";
|
|
98
|
-
type: "
|
|
98
|
+
type: "reset" | "submit" | "button";
|
|
99
99
|
token?: string;
|
|
100
100
|
ref?: any;
|
|
101
101
|
handler?: (value: any) => any;
|
|
@@ -53,7 +53,7 @@ export declare class ChatWindowComponent {
|
|
|
53
53
|
protected readonly replyingTo: import("@angular/core").WritableSignal<MessageReplyTo>;
|
|
54
54
|
protected readonly atBottom: import("@angular/core").WritableSignal<boolean>;
|
|
55
55
|
protected readonly hasNew: import("@angular/core").WritableSignal<boolean>;
|
|
56
|
-
protected readonly locale: import("@angular/core").Signal<"
|
|
56
|
+
protected readonly locale: import("@angular/core").Signal<"es-CL" | "en-US">;
|
|
57
57
|
constructor();
|
|
58
58
|
protected readonly rows: import("@angular/core").Signal<ChatRow[]>;
|
|
59
59
|
protected onScroll(): void;
|
|
@@ -28,7 +28,7 @@ export declare class MemberImportModalComponent implements OnInit {
|
|
|
28
28
|
/** Namespace i18n. */
|
|
29
29
|
i18nNamespace: string;
|
|
30
30
|
csv: string;
|
|
31
|
-
readonly importMode: import("@angular/core").WritableSignal<"
|
|
31
|
+
readonly importMode: import("@angular/core").WritableSignal<"paste" | "file">;
|
|
32
32
|
readonly onConflictControl: FormControl<string>;
|
|
33
33
|
readonly sendActivationControl: FormControl<boolean>;
|
|
34
34
|
readonly conflictSelectProps: import("@angular/core").Signal<Partial<InputMetadata>>;
|
package/lib/version.d.ts
CHANGED
package/package.json
CHANGED
package/public-api.d.ts
CHANGED
|
@@ -182,9 +182,6 @@ export * from './lib/components/molecules/media-object/media-object.component';
|
|
|
182
182
|
export * from './lib/components/molecules/media-object/types';
|
|
183
183
|
export * from './lib/components/molecules/stats-bar/stats-bar.component';
|
|
184
184
|
export * from './lib/components/molecules/stats-bar/types';
|
|
185
|
-
export * from './lib/components/molecules/usage-meters/usage-meters.component';
|
|
186
|
-
export * from './lib/components/molecules/usage-meters/types';
|
|
187
|
-
export * from './lib/services/usage/usage.service';
|
|
188
185
|
export * from './lib/components/molecules/article-card/article-card.component';
|
|
189
186
|
export * from './lib/components/molecules/article-card/types';
|
|
190
187
|
export * from './lib/components/molecules/cta-card/cta-card.component';
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
// val-usage-meters — tipos. Componente presentacional del dashboard de consumo
|
|
2
|
-
// (ADR-046 D3). Object-first; el consumer pasa los datos ya resueltos
|
|
3
|
-
// (típicamente desde UsageService, que lee Firestore en vivo).
|
|
4
|
-
export {};
|
|
5
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvbGliL2NvbXBvbmVudHMvbW9sZWN1bGVzL3VzYWdlLW1ldGVycy90eXBlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwrRUFBK0U7QUFDL0Usc0VBQXNFO0FBQ3RFLCtEQUErRCIsInNvdXJjZXNDb250ZW50IjpbIi8vIHZhbC11c2FnZS1tZXRlcnMg4oCUIHRpcG9zLiBDb21wb25lbnRlIHByZXNlbnRhY2lvbmFsIGRlbCBkYXNoYm9hcmQgZGUgY29uc3Vtb1xuLy8gKEFEUi0wNDYgRDMpLiBPYmplY3QtZmlyc3Q7IGVsIGNvbnN1bWVyIHBhc2EgbG9zIGRhdG9zIHlhIHJlc3VlbHRvc1xuLy8gKHTDrXBpY2FtZW50ZSBkZXNkZSBVc2FnZVNlcnZpY2UsIHF1ZSBsZWUgRmlyZXN0b3JlIGVuIHZpdm8pLlxuXG5leHBvcnQgaW50ZXJmYWNlIFVzYWdlTWV0cmljIHtcbiAgLyoqIENsYXZlIGRlIGxhIG3DqXRyaWNhIChlai4gXCJlbWFpbHNfbW9udGhcIikuICovXG4gIGtleTogc3RyaW5nO1xuICAvKiogRXRpcXVldGEgdmlzaWJsZSB5YSByZXN1ZWx0YSBwb3IgZWwgY29uc3VtZXIgKGVqLiBcIkVtYWlscyAvIG1lc1wiKS4gKi9cbiAgbGFiZWw6IHN0cmluZztcbiAgLyoqIENvbnN1bW8gZGVsIHBlcsOtb2RvLiAqL1xuICB1c2VkOiBudW1iZXI7XG4gIC8qKiBUb3BlOyAtMSA9IGlsaW1pdGFkby4gKi9cbiAgbGltaXQ6IG51bWJlcjtcbiAgLyoqIHRydWUgc2kgZWwgdG9wZSBlcyBpbGltaXRhZG8gKC0xKS4gKi9cbiAgdW5saW1pdGVkOiBib29sZWFuO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFVzYWdlTWV0ZXJzTWV0YWRhdGEge1xuICAvKiogVMOtdHVsbyBkZSBsYSBzZWNjacOzbiAob3BjaW9uYWwpLiAqL1xuICB0aXRsZT86IHN0cmluZztcbiAgLyoqIE5vbWJyZSBkZSBsYSBhcHAgYSBsYSBxdWUgcGVydGVuZWNlIGVzdGUgYmxvcXVlIChwYXJhIHZpc3RhIG11bHRpLWFwcCkuICovXG4gIGFwcE5hbWU/OiBzdHJpbmc7XG4gIC8qKiBUaWVyIGRlbCBwbGFuLCBwYXJhIG1vc3RyYXIgY29tbyBiYWRnZSAoZWouIFwiUHJvXCIpLiAqL1xuICBwbGFuPzogc3RyaW5nO1xuICAvKiogUGVyw61vZG8gKGVqLiBcIjIwMjYtMDZcIikuICovXG4gIHBlcmlvZD86IHN0cmluZztcbiAgLyoqIE3DqXRyaWNhcyBhIG1vc3RyYXIuICovXG4gIG1ldHJpY3M6IFVzYWdlTWV0cmljW107XG59XG4iXX0=
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
import { Component, computed, inject, input } from '@angular/core';
|
|
2
|
-
import { CommonModule } from '@angular/common';
|
|
3
|
-
import { I18nService } from '../../../services/i18n/i18n.service';
|
|
4
|
-
import * as i0 from "@angular/core";
|
|
5
|
-
const USAGE_METERS_I18N = {
|
|
6
|
-
es: { unlimited: 'Ilimitado', of: 'de', empty: 'Sin datos de consumo aún.' },
|
|
7
|
-
en: { unlimited: 'Unlimited', of: 'of', empty: 'No usage data yet.' },
|
|
8
|
-
};
|
|
9
|
-
/**
|
|
10
|
-
* val-usage-meters — bloque de consumo (uso vs tope por métrica) para el
|
|
11
|
-
* dashboard de monetización (ADR-046 D3). Presentacional: recibe los datos ya
|
|
12
|
-
* resueltos (UsageService los arma desde Firestore). Reutilizable single-app o
|
|
13
|
-
* por sección en multi-app (myvaltech account).
|
|
14
|
-
*/
|
|
15
|
-
export class UsageMetersComponent {
|
|
16
|
-
constructor() {
|
|
17
|
-
this.i18n = inject(I18nService);
|
|
18
|
-
this.props = input.required();
|
|
19
|
-
this.rows = computed(() => {
|
|
20
|
-
this.i18n.lang();
|
|
21
|
-
const unlimitedLabel = this.t('unlimited');
|
|
22
|
-
const ofLabel = this.t('of');
|
|
23
|
-
return (this.props().metrics ?? []).map((m) => {
|
|
24
|
-
const unlimited = m.unlimited || m.limit < 0;
|
|
25
|
-
const over = !unlimited && m.limit > 0 && m.used >= m.limit;
|
|
26
|
-
const pct = unlimited || m.limit <= 0
|
|
27
|
-
? 0
|
|
28
|
-
: Math.min(100, Math.round((m.used / m.limit) * 100));
|
|
29
|
-
const usedLabel = unlimited
|
|
30
|
-
? `${m.used} · ${unlimitedLabel}`
|
|
31
|
-
: `${m.used} ${ofLabel} ${m.limit}`;
|
|
32
|
-
return { key: m.key, label: m.label, usedLabel, pct, unlimited, over };
|
|
33
|
-
});
|
|
34
|
-
});
|
|
35
|
-
if (!this.i18n.hasNamespace('UsageMeters')) {
|
|
36
|
-
this.i18n.registerContent('UsageMeters', USAGE_METERS_I18N);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
t(key) {
|
|
40
|
-
this.i18n.lang();
|
|
41
|
-
return this.i18n.t(key, 'UsageMeters');
|
|
42
|
-
}
|
|
43
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: UsageMetersComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
44
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: UsageMetersComponent, isStandalone: true, selector: "val-usage-meters", inputs: { props: { classPropertyName: "props", publicName: "props", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: `
|
|
45
|
-
<div class="usage">
|
|
46
|
-
@if (props().appName || props().title) {
|
|
47
|
-
<div class="usage__head">
|
|
48
|
-
<span class="usage__title">{{ props().appName || props().title }}</span>
|
|
49
|
-
@if (props().plan) {
|
|
50
|
-
<span class="usage__plan">{{ props().plan }}</span>
|
|
51
|
-
}
|
|
52
|
-
</div>
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
@if (rows().length === 0) {
|
|
56
|
-
<p class="usage__empty">{{ t('empty') }}</p>
|
|
57
|
-
} @else {
|
|
58
|
-
<ul class="usage__list">
|
|
59
|
-
@for (row of rows(); track row.key) {
|
|
60
|
-
<li class="meter">
|
|
61
|
-
<div class="meter__top">
|
|
62
|
-
<span class="meter__label">{{ row.label }}</span>
|
|
63
|
-
<span class="meter__value" [class.meter__value--over]="row.over">
|
|
64
|
-
{{ row.usedLabel }}
|
|
65
|
-
</span>
|
|
66
|
-
</div>
|
|
67
|
-
@if (!row.unlimited) {
|
|
68
|
-
<div class="meter__track">
|
|
69
|
-
<div
|
|
70
|
-
class="meter__fill"
|
|
71
|
-
[class.meter__fill--over]="row.over"
|
|
72
|
-
[style.width.%]="row.pct"
|
|
73
|
-
></div>
|
|
74
|
-
</div>
|
|
75
|
-
}
|
|
76
|
-
</li>
|
|
77
|
-
}
|
|
78
|
-
</ul>
|
|
79
|
-
}
|
|
80
|
-
</div>
|
|
81
|
-
`, isInline: true, styles: [":host{display:block}.usage__head{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px}.usage__title{font-size:1.125rem;font-weight:700;color:var(--ion-text-color, #000)}.usage__plan{font-size:.75rem;font-weight:600;padding:2px 10px;border-radius:999px;background:var(--ion-color-primary, #3880ff);color:var(--ion-color-primary-contrast, #fff)}.usage__empty{font-size:.875rem;color:var(--ion-color-medium, #92949c)}.usage__list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:14px}.meter__top{display:flex;justify-content:space-between;align-items:baseline;margin-bottom:6px}.meter__label{font-size:.875rem;color:var(--ion-text-color, #000)}.meter__value{font-size:.8125rem;font-weight:600;color:var(--ion-color-medium, #92949c)}.meter__value--over{color:var(--ion-color-danger, #eb445a)}.meter__track{height:8px;border-radius:999px;background:var(--ion-color-light, rgba(0, 0, 0, .08));overflow:hidden}.meter__fill{height:100%;border-radius:999px;background:var(--ion-color-primary, #3880ff);transition:width .3s ease}.meter__fill--over{background:var(--ion-color-danger, #eb445a)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }] }); }
|
|
82
|
-
}
|
|
83
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: UsageMetersComponent, decorators: [{
|
|
84
|
-
type: Component,
|
|
85
|
-
args: [{ selector: 'val-usage-meters', standalone: true, imports: [CommonModule], template: `
|
|
86
|
-
<div class="usage">
|
|
87
|
-
@if (props().appName || props().title) {
|
|
88
|
-
<div class="usage__head">
|
|
89
|
-
<span class="usage__title">{{ props().appName || props().title }}</span>
|
|
90
|
-
@if (props().plan) {
|
|
91
|
-
<span class="usage__plan">{{ props().plan }}</span>
|
|
92
|
-
}
|
|
93
|
-
</div>
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
@if (rows().length === 0) {
|
|
97
|
-
<p class="usage__empty">{{ t('empty') }}</p>
|
|
98
|
-
} @else {
|
|
99
|
-
<ul class="usage__list">
|
|
100
|
-
@for (row of rows(); track row.key) {
|
|
101
|
-
<li class="meter">
|
|
102
|
-
<div class="meter__top">
|
|
103
|
-
<span class="meter__label">{{ row.label }}</span>
|
|
104
|
-
<span class="meter__value" [class.meter__value--over]="row.over">
|
|
105
|
-
{{ row.usedLabel }}
|
|
106
|
-
</span>
|
|
107
|
-
</div>
|
|
108
|
-
@if (!row.unlimited) {
|
|
109
|
-
<div class="meter__track">
|
|
110
|
-
<div
|
|
111
|
-
class="meter__fill"
|
|
112
|
-
[class.meter__fill--over]="row.over"
|
|
113
|
-
[style.width.%]="row.pct"
|
|
114
|
-
></div>
|
|
115
|
-
</div>
|
|
116
|
-
}
|
|
117
|
-
</li>
|
|
118
|
-
}
|
|
119
|
-
</ul>
|
|
120
|
-
}
|
|
121
|
-
</div>
|
|
122
|
-
`, styles: [":host{display:block}.usage__head{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px}.usage__title{font-size:1.125rem;font-weight:700;color:var(--ion-text-color, #000)}.usage__plan{font-size:.75rem;font-weight:600;padding:2px 10px;border-radius:999px;background:var(--ion-color-primary, #3880ff);color:var(--ion-color-primary-contrast, #fff)}.usage__empty{font-size:.875rem;color:var(--ion-color-medium, #92949c)}.usage__list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:14px}.meter__top{display:flex;justify-content:space-between;align-items:baseline;margin-bottom:6px}.meter__label{font-size:.875rem;color:var(--ion-text-color, #000)}.meter__value{font-size:.8125rem;font-weight:600;color:var(--ion-color-medium, #92949c)}.meter__value--over{color:var(--ion-color-danger, #eb445a)}.meter__track{height:8px;border-radius:999px;background:var(--ion-color-light, rgba(0, 0, 0, .08));overflow:hidden}.meter__fill{height:100%;border-radius:999px;background:var(--ion-color-primary, #3880ff);transition:width .3s ease}.meter__fill--over{background:var(--ion-color-danger, #eb445a)}\n"] }]
|
|
123
|
-
}], ctorParameters: () => [] });
|
|
124
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXNhZ2UtbWV0ZXJzLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3NyYy9saWIvY29tcG9uZW50cy9tb2xlY3VsZXMvdXNhZ2UtbWV0ZXJzL3VzYWdlLW1ldGVycy5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxRQUFRLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUNuRSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDL0MsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLHFDQUFxQyxDQUFDOztBQUdsRSxNQUFNLGlCQUFpQixHQUFHO0lBQ3hCLEVBQUUsRUFBRSxFQUFFLFNBQVMsRUFBRSxXQUFXLEVBQUUsRUFBRSxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsMkJBQTJCLEVBQUU7SUFDNUUsRUFBRSxFQUFFLEVBQUUsU0FBUyxFQUFFLFdBQVcsRUFBRSxFQUFFLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBRSxvQkFBb0IsRUFBRTtDQUN0RSxDQUFDO0FBV0Y7Ozs7O0dBS0c7QUFtSEgsTUFBTSxPQUFPLG9CQUFvQjtJQUsvQjtRQUpRLFNBQUksR0FBRyxNQUFNLENBQUMsV0FBVyxDQUFDLENBQUM7UUFFMUIsVUFBSyxHQUFHLEtBQUssQ0FBQyxRQUFRLEVBQXVCLENBQUM7UUFROUMsU0FBSSxHQUFHLFFBQVEsQ0FBYSxHQUFHLEVBQUU7WUFDeEMsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUNqQixNQUFNLGNBQWMsR0FBRyxJQUFJLENBQUMsQ0FBQyxDQUFDLFdBQVcsQ0FBQyxDQUFDO1lBQzNDLE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDN0IsT0FBTyxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQyxPQUFPLElBQUksRUFBRSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUU7Z0JBQzVDLE1BQU0sU0FBUyxHQUFHLENBQUMsQ0FBQyxTQUFTLElBQUksQ0FBQyxDQUFDLEtBQUssR0FBRyxDQUFDLENBQUM7Z0JBQzdDLE1BQU0sSUFBSSxHQUFHLENBQUMsU0FBUyxJQUFJLENBQUMsQ0FBQyxLQUFLLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQyxJQUFJLElBQUksQ0FBQyxDQUFDLEtBQUssQ0FBQztnQkFDNUQsTUFBTSxHQUFHLEdBQ1AsU0FBUyxJQUFJLENBQUMsQ0FBQyxLQUFLLElBQUksQ0FBQztvQkFDdkIsQ0FBQyxDQUFDLENBQUM7b0JBQ0gsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxHQUFHLENBQUMsQ0FBQyxLQUFLLENBQUMsR0FBRyxHQUFHLENBQUMsQ0FBQyxDQUFDO2dCQUMxRCxNQUFNLFNBQVMsR0FBRyxTQUFTO29CQUN6QixDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxNQUFNLGNBQWMsRUFBRTtvQkFDakMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksSUFBSSxPQUFPLElBQUksQ0FBQyxDQUFDLEtBQUssRUFBRSxDQUFDO2dCQUN0QyxPQUFPLEVBQUUsR0FBRyxFQUFFLENBQUMsQ0FBQyxHQUFHLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQyxLQUFLLEVBQUUsU0FBUyxFQUFFLEdBQUcsRUFBRSxTQUFTLEVBQUUsSUFBSSxFQUFFLENBQUM7WUFDekUsQ0FBQyxDQUFDLENBQUM7UUFDTCxDQUFDLENBQUMsQ0FBQztRQXJCRCxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsYUFBYSxDQUFDLEVBQUUsQ0FBQztZQUMzQyxJQUFJLENBQUMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxhQUFhLEVBQUUsaUJBQWlCLENBQUMsQ0FBQztRQUM5RCxDQUFDO0lBQ0gsQ0FBQztJQW9CRCxDQUFDLENBQUMsR0FBVztRQUNYLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDakIsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUUsYUFBYSxDQUFDLENBQUM7SUFDekMsQ0FBQzsrR0FoQ1Usb0JBQW9CO21HQUFwQixvQkFBb0IsK01BOUdyQjs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXFDVCwwckNBdENTLFlBQVk7OzRGQStHWCxvQkFBb0I7a0JBbEhoQyxTQUFTOytCQUNFLGtCQUFrQixjQUNoQixJQUFJLFdBQ1AsQ0FBQyxZQUFZLENBQUMsWUFDYjs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXFDVCIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgY29tcHV0ZWQsIGluamVjdCwgaW5wdXQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IENvbW1vbk1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5pbXBvcnQgeyBJMThuU2VydmljZSB9IGZyb20gJy4uLy4uLy4uL3NlcnZpY2VzL2kxOG4vaTE4bi5zZXJ2aWNlJztcbmltcG9ydCB7IFVzYWdlTWV0ZXJzTWV0YWRhdGEgfSBmcm9tICcuL3R5cGVzJztcblxuY29uc3QgVVNBR0VfTUVURVJTX0kxOE4gPSB7XG4gIGVzOiB7IHVubGltaXRlZDogJ0lsaW1pdGFkbycsIG9mOiAnZGUnLCBlbXB0eTogJ1NpbiBkYXRvcyBkZSBjb25zdW1vIGHDum4uJyB9LFxuICBlbjogeyB1bmxpbWl0ZWQ6ICdVbmxpbWl0ZWQnLCBvZjogJ29mJywgZW1wdHk6ICdObyB1c2FnZSBkYXRhIHlldC4nIH0sXG59O1xuXG5pbnRlcmZhY2UgTWV0ZXJSb3cge1xuICBrZXk6IHN0cmluZztcbiAgbGFiZWw6IHN0cmluZztcbiAgdXNlZExhYmVsOiBzdHJpbmc7XG4gIHBjdDogbnVtYmVyOyAvLyAwLi4xMDAgKDAgc2kgaWxpbWl0YWRvKVxuICB1bmxpbWl0ZWQ6IGJvb2xlYW47XG4gIG92ZXI6IGJvb2xlYW47XG59XG5cbi8qKlxuICogdmFsLXVzYWdlLW1ldGVycyDigJQgYmxvcXVlIGRlIGNvbnN1bW8gKHVzbyB2cyB0b3BlIHBvciBtw6l0cmljYSkgcGFyYSBlbFxuICogZGFzaGJvYXJkIGRlIG1vbmV0aXphY2nDs24gKEFEUi0wNDYgRDMpLiBQcmVzZW50YWNpb25hbDogcmVjaWJlIGxvcyBkYXRvcyB5YVxuICogcmVzdWVsdG9zIChVc2FnZVNlcnZpY2UgbG9zIGFybWEgZGVzZGUgRmlyZXN0b3JlKS4gUmV1dGlsaXphYmxlIHNpbmdsZS1hcHAgb1xuICogcG9yIHNlY2Npw7NuIGVuIG11bHRpLWFwcCAobXl2YWx0ZWNoIGFjY291bnQpLlxuICovXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICd2YWwtdXNhZ2UtbWV0ZXJzJyxcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcbiAgaW1wb3J0czogW0NvbW1vbk1vZHVsZV0sXG4gIHRlbXBsYXRlOiBgXG4gICAgPGRpdiBjbGFzcz1cInVzYWdlXCI+XG4gICAgICBAaWYgKHByb3BzKCkuYXBwTmFtZSB8fCBwcm9wcygpLnRpdGxlKSB7XG4gICAgICAgIDxkaXYgY2xhc3M9XCJ1c2FnZV9faGVhZFwiPlxuICAgICAgICAgIDxzcGFuIGNsYXNzPVwidXNhZ2VfX3RpdGxlXCI+e3sgcHJvcHMoKS5hcHBOYW1lIHx8IHByb3BzKCkudGl0bGUgfX08L3NwYW4+XG4gICAgICAgICAgQGlmIChwcm9wcygpLnBsYW4pIHtcbiAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwidXNhZ2VfX3BsYW5cIj57eyBwcm9wcygpLnBsYW4gfX08L3NwYW4+XG4gICAgICAgICAgfVxuICAgICAgICA8L2Rpdj5cbiAgICAgIH1cblxuICAgICAgQGlmIChyb3dzKCkubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIDxwIGNsYXNzPVwidXNhZ2VfX2VtcHR5XCI+e3sgdCgnZW1wdHknKSB9fTwvcD5cbiAgICAgIH0gQGVsc2Uge1xuICAgICAgICA8dWwgY2xhc3M9XCJ1c2FnZV9fbGlzdFwiPlxuICAgICAgICAgIEBmb3IgKHJvdyBvZiByb3dzKCk7IHRyYWNrIHJvdy5rZXkpIHtcbiAgICAgICAgICAgIDxsaSBjbGFzcz1cIm1ldGVyXCI+XG4gICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJtZXRlcl9fdG9wXCI+XG4gICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJtZXRlcl9fbGFiZWxcIj57eyByb3cubGFiZWwgfX08L3NwYW4+XG4gICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJtZXRlcl9fdmFsdWVcIiBbY2xhc3MubWV0ZXJfX3ZhbHVlLS1vdmVyXT1cInJvdy5vdmVyXCI+XG4gICAgICAgICAgICAgICAgICB7eyByb3cudXNlZExhYmVsIH19XG4gICAgICAgICAgICAgICAgPC9zcGFuPlxuICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgQGlmICghcm93LnVubGltaXRlZCkge1xuICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJtZXRlcl9fdHJhY2tcIj5cbiAgICAgICAgICAgICAgICAgIDxkaXZcbiAgICAgICAgICAgICAgICAgICAgY2xhc3M9XCJtZXRlcl9fZmlsbFwiXG4gICAgICAgICAgICAgICAgICAgIFtjbGFzcy5tZXRlcl9fZmlsbC0tb3Zlcl09XCJyb3cub3ZlclwiXG4gICAgICAgICAgICAgICAgICAgIFtzdHlsZS53aWR0aC4lXT1cInJvdy5wY3RcIlxuICAgICAgICAgICAgICAgICAgPjwvZGl2PlxuICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICA8L2xpPlxuICAgICAgICAgIH1cbiAgICAgICAgPC91bD5cbiAgICAgIH1cbiAgICA8L2Rpdj5cbiAgYCxcbiAgc3R5bGVzOiBbXG4gICAgYFxuICAgICAgOmhvc3Qge1xuICAgICAgICBkaXNwbGF5OiBibG9jaztcbiAgICAgIH1cbiAgICAgIC51c2FnZV9faGVhZCB7XG4gICAgICAgIGRpc3BsYXk6IGZsZXg7XG4gICAgICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gICAgICAgIGp1c3RpZnktY29udGVudDogc3BhY2UtYmV0d2VlbjtcbiAgICAgICAgbWFyZ2luLWJvdHRvbTogMTJweDtcbiAgICAgIH1cbiAgICAgIC51c2FnZV9fdGl0bGUge1xuICAgICAgICBmb250LXNpemU6IDEuMTI1cmVtO1xuICAgICAgICBmb250LXdlaWdodDogNzAwO1xuICAgICAgICBjb2xvcjogdmFyKC0taW9uLXRleHQtY29sb3IsICMwMDApO1xuICAgICAgfVxuICAgICAgLnVzYWdlX19wbGFuIHtcbiAgICAgICAgZm9udC1zaXplOiAwLjc1cmVtO1xuICAgICAgICBmb250LXdlaWdodDogNjAwO1xuICAgICAgICBwYWRkaW5nOiAycHggMTBweDtcbiAgICAgICAgYm9yZGVyLXJhZGl1czogOTk5cHg7XG4gICAgICAgIGJhY2tncm91bmQ6IHZhcigtLWlvbi1jb2xvci1wcmltYXJ5LCAjMzg4MGZmKTtcbiAgICAgICAgY29sb3I6IHZhcigtLWlvbi1jb2xvci1wcmltYXJ5LWNvbnRyYXN0LCAjZmZmKTtcbiAgICAgIH1cbiAgICAgIC51c2FnZV9fZW1wdHkge1xuICAgICAgICBmb250LXNpemU6IDAuODc1cmVtO1xuICAgICAgICBjb2xvcjogdmFyKC0taW9uLWNvbG9yLW1lZGl1bSwgIzkyOTQ5Yyk7XG4gICAgICB9XG4gICAgICAudXNhZ2VfX2xpc3Qge1xuICAgICAgICBsaXN0LXN0eWxlOiBub25lO1xuICAgICAgICBtYXJnaW46IDA7XG4gICAgICAgIHBhZGRpbmc6IDA7XG4gICAgICAgIGRpc3BsYXk6IGZsZXg7XG4gICAgICAgIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47XG4gICAgICAgIGdhcDogMTRweDtcbiAgICAgIH1cbiAgICAgIC5tZXRlcl9fdG9wIHtcbiAgICAgICAgZGlzcGxheTogZmxleDtcbiAgICAgICAganVzdGlmeS1jb250ZW50OiBzcGFjZS1iZXR3ZWVuO1xuICAgICAgICBhbGlnbi1pdGVtczogYmFzZWxpbmU7XG4gICAgICAgIG1hcmdpbi1ib3R0b206IDZweDtcbiAgICAgIH1cbiAgICAgIC5tZXRlcl9fbGFiZWwge1xuICAgICAgICBmb250LXNpemU6IDAuODc1cmVtO1xuICAgICAgICBjb2xvcjogdmFyKC0taW9uLXRleHQtY29sb3IsICMwMDApO1xuICAgICAgfVxuICAgICAgLm1ldGVyX192YWx1ZSB7XG4gICAgICAgIGZvbnQtc2l6ZTogMC44MTI1cmVtO1xuICAgICAgICBmb250LXdlaWdodDogNjAwO1xuICAgICAgICBjb2xvcjogdmFyKC0taW9uLWNvbG9yLW1lZGl1bSwgIzkyOTQ5Yyk7XG4gICAgICB9XG4gICAgICAubWV0ZXJfX3ZhbHVlLS1vdmVyIHtcbiAgICAgICAgY29sb3I6IHZhcigtLWlvbi1jb2xvci1kYW5nZXIsICNlYjQ0NWEpO1xuICAgICAgfVxuICAgICAgLm1ldGVyX190cmFjayB7XG4gICAgICAgIGhlaWdodDogOHB4O1xuICAgICAgICBib3JkZXItcmFkaXVzOiA5OTlweDtcbiAgICAgICAgYmFja2dyb3VuZDogdmFyKC0taW9uLWNvbG9yLWxpZ2h0LCByZ2JhKDAsIDAsIDAsIDAuMDgpKTtcbiAgICAgICAgb3ZlcmZsb3c6IGhpZGRlbjtcbiAgICAgIH1cbiAgICAgIC5tZXRlcl9fZmlsbCB7XG4gICAgICAgIGhlaWdodDogMTAwJTtcbiAgICAgICAgYm9yZGVyLXJhZGl1czogOTk5cHg7XG4gICAgICAgIGJhY2tncm91bmQ6IHZhcigtLWlvbi1jb2xvci1wcmltYXJ5LCAjMzg4MGZmKTtcbiAgICAgICAgdHJhbnNpdGlvbjogd2lkdGggMC4zcyBlYXNlO1xuICAgICAgfVxuICAgICAgLm1ldGVyX19maWxsLS1vdmVyIHtcbiAgICAgICAgYmFja2dyb3VuZDogdmFyKC0taW9uLWNvbG9yLWRhbmdlciwgI2ViNDQ1YSk7XG4gICAgICB9XG4gICAgYCxcbiAgXSxcbn0pXG5leHBvcnQgY2xhc3MgVXNhZ2VNZXRlcnNDb21wb25lbnQge1xuICBwcml2YXRlIGkxOG4gPSBpbmplY3QoSTE4blNlcnZpY2UpO1xuXG4gIHJlYWRvbmx5IHByb3BzID0gaW5wdXQucmVxdWlyZWQ8VXNhZ2VNZXRlcnNNZXRhZGF0YT4oKTtcblxuICBjb25zdHJ1Y3RvcigpIHtcbiAgICBpZiAoIXRoaXMuaTE4bi5oYXNOYW1lc3BhY2UoJ1VzYWdlTWV0ZXJzJykpIHtcbiAgICAgIHRoaXMuaTE4bi5yZWdpc3RlckNvbnRlbnQoJ1VzYWdlTWV0ZXJzJywgVVNBR0VfTUVURVJTX0kxOE4pO1xuICAgIH1cbiAgfVxuXG4gIHJlYWRvbmx5IHJvd3MgPSBjb21wdXRlZDxNZXRlclJvd1tdPigoKSA9PiB7XG4gICAgdGhpcy5pMThuLmxhbmcoKTtcbiAgICBjb25zdCB1bmxpbWl0ZWRMYWJlbCA9IHRoaXMudCgndW5saW1pdGVkJyk7XG4gICAgY29uc3Qgb2ZMYWJlbCA9IHRoaXMudCgnb2YnKTtcbiAgICByZXR1cm4gKHRoaXMucHJvcHMoKS5tZXRyaWNzID8/IFtdKS5tYXAoKG0pID0+IHtcbiAgICAgIGNvbnN0IHVubGltaXRlZCA9IG0udW5saW1pdGVkIHx8IG0ubGltaXQgPCAwO1xuICAgICAgY29uc3Qgb3ZlciA9ICF1bmxpbWl0ZWQgJiYgbS5saW1pdCA+IDAgJiYgbS51c2VkID49IG0ubGltaXQ7XG4gICAgICBjb25zdCBwY3QgPVxuICAgICAgICB1bmxpbWl0ZWQgfHwgbS5saW1pdCA8PSAwXG4gICAgICAgICAgPyAwXG4gICAgICAgICAgOiBNYXRoLm1pbigxMDAsIE1hdGgucm91bmQoKG0udXNlZCAvIG0ubGltaXQpICogMTAwKSk7XG4gICAgICBjb25zdCB1c2VkTGFiZWwgPSB1bmxpbWl0ZWRcbiAgICAgICAgPyBgJHttLnVzZWR9IMK3ICR7dW5saW1pdGVkTGFiZWx9YFxuICAgICAgICA6IGAke20udXNlZH0gJHtvZkxhYmVsfSAke20ubGltaXR9YDtcbiAgICAgIHJldHVybiB7IGtleTogbS5rZXksIGxhYmVsOiBtLmxhYmVsLCB1c2VkTGFiZWwsIHBjdCwgdW5saW1pdGVkLCBvdmVyIH07XG4gICAgfSk7XG4gIH0pO1xuXG4gIHQoa2V5OiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIHRoaXMuaTE4bi5sYW5nKCk7XG4gICAgcmV0dXJuIHRoaXMuaTE4bi50KGtleSwgJ1VzYWdlTWV0ZXJzJyk7XG4gIH1cbn1cbiJdfQ==
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { Injectable, inject } from '@angular/core';
|
|
2
|
-
import { map } from 'rxjs/operators';
|
|
3
|
-
import { ABS_PATH_SENTINEL, FirestoreService } from '../firebase/firestore.service';
|
|
4
|
-
import { I18nService } from '../i18n/i18n.service';
|
|
5
|
-
import * as i0 from "@angular/core";
|
|
6
|
-
// Orden de display de las métricas conocidas.
|
|
7
|
-
const METRIC_ORDER = [
|
|
8
|
-
'members',
|
|
9
|
-
'emails_month',
|
|
10
|
-
'sms_month',
|
|
11
|
-
'push_month',
|
|
12
|
-
'api_calls_month',
|
|
13
|
-
'storage_mb',
|
|
14
|
-
];
|
|
15
|
-
const USAGE_METRICS_I18N = {
|
|
16
|
-
es: {
|
|
17
|
-
members: 'Miembros',
|
|
18
|
-
emails_month: 'Emails / mes',
|
|
19
|
-
sms_month: 'SMS / mes',
|
|
20
|
-
push_month: 'Push / mes',
|
|
21
|
-
api_calls_month: 'Llamadas API / mes',
|
|
22
|
-
storage_mb: 'Almacenamiento (MB)',
|
|
23
|
-
},
|
|
24
|
-
en: {
|
|
25
|
-
members: 'Members',
|
|
26
|
-
emails_month: 'Emails / mo',
|
|
27
|
-
sms_month: 'SMS / mo',
|
|
28
|
-
push_month: 'Push / mo',
|
|
29
|
-
api_calls_month: 'API calls / mo',
|
|
30
|
-
storage_mb: 'Storage (MB)',
|
|
31
|
-
},
|
|
32
|
-
};
|
|
33
|
-
/**
|
|
34
|
-
* UsageService — lee el resumen de consumo (uso + límites + plan) en vivo desde
|
|
35
|
-
* Firestore y lo mapea a `UsageMetersMetadata` para `<val-usage-meters>`.
|
|
36
|
-
* (ADR-046 D3). Firestore es la fuente única (el backend proyecta usage+limits).
|
|
37
|
-
* Granular por app: `watch(appId, orgId)`. Multi-app: una suscripción por app.
|
|
38
|
-
*/
|
|
39
|
-
export class UsageService {
|
|
40
|
-
constructor() {
|
|
41
|
-
this.firestore = inject(FirestoreService);
|
|
42
|
-
this.i18n = inject(I18nService);
|
|
43
|
-
if (!this.i18n.hasNamespace('UsageMetrics')) {
|
|
44
|
-
this.i18n.registerContent('UsageMetrics', USAGE_METRICS_I18N);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
/** Período actual `YYYY-MM` (UTC), igual que el backend. */
|
|
48
|
-
currentPeriod() {
|
|
49
|
-
return new Date().toISOString().slice(0, 7);
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Observa el consumo de (org, app) en vivo. Lee el path absoluto
|
|
53
|
-
* `apps/{appId}/orgs/{orgId}/usage/{period}` (sin auto-prefix de la app actual,
|
|
54
|
-
* para soportar la vista multi-app desde account).
|
|
55
|
-
*/
|
|
56
|
-
watch(appId, orgId, appName, period) {
|
|
57
|
-
const p = period || this.currentPeriod();
|
|
58
|
-
const collectionPath = `${ABS_PATH_SENTINEL}apps/${appId}/orgs/${orgId}/usage`;
|
|
59
|
-
return this.firestore
|
|
60
|
-
.docChanges(collectionPath, p)
|
|
61
|
-
.pipe(map((doc) => this.toMetadata(doc, appName, p)));
|
|
62
|
-
}
|
|
63
|
-
toMetadata(doc, appName, period) {
|
|
64
|
-
this.i18n.lang();
|
|
65
|
-
const limits = doc?.limits ?? {};
|
|
66
|
-
const usage = doc?.usage ?? {};
|
|
67
|
-
const keys = METRIC_ORDER.filter((k) => k in limits || k in usage);
|
|
68
|
-
const metrics = keys.map((k) => {
|
|
69
|
-
const limit = k in limits ? Number(limits[k]) : -1;
|
|
70
|
-
return {
|
|
71
|
-
key: k,
|
|
72
|
-
label: this.i18n.t(k, 'UsageMetrics') || k,
|
|
73
|
-
used: Number(usage[k] ?? 0),
|
|
74
|
-
limit,
|
|
75
|
-
unlimited: limit < 0,
|
|
76
|
-
};
|
|
77
|
-
});
|
|
78
|
-
return { appName, plan: doc?.plan, period, metrics };
|
|
79
|
-
}
|
|
80
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: UsageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
81
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: UsageService, providedIn: 'root' }); }
|
|
82
|
-
}
|
|
83
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: UsageService, decorators: [{
|
|
84
|
-
type: Injectable,
|
|
85
|
-
args: [{ providedIn: 'root' }]
|
|
86
|
-
}], ctorParameters: () => [] });
|
|
87
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXNhZ2Uuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9saWIvc2VydmljZXMvdXNhZ2UvdXNhZ2Uuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUVuRCxPQUFPLEVBQUUsR0FBRyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDckMsT0FBTyxFQUFFLGlCQUFpQixFQUFFLGdCQUFnQixFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFFcEYsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLHNCQUFzQixDQUFDOztBQWNuRCw4Q0FBOEM7QUFDOUMsTUFBTSxZQUFZLEdBQUc7SUFDbkIsU0FBUztJQUNULGNBQWM7SUFDZCxXQUFXO0lBQ1gsWUFBWTtJQUNaLGlCQUFpQjtJQUNqQixZQUFZO0NBQ2IsQ0FBQztBQUVGLE1BQU0sa0JBQWtCLEdBQUc7SUFDekIsRUFBRSxFQUFFO1FBQ0YsT0FBTyxFQUFFLFVBQVU7UUFDbkIsWUFBWSxFQUFFLGNBQWM7UUFDNUIsU0FBUyxFQUFFLFdBQVc7UUFDdEIsVUFBVSxFQUFFLFlBQVk7UUFDeEIsZUFBZSxFQUFFLG9CQUFvQjtRQUNyQyxVQUFVLEVBQUUscUJBQXFCO0tBQ2xDO0lBQ0QsRUFBRSxFQUFFO1FBQ0YsT0FBTyxFQUFFLFNBQVM7UUFDbEIsWUFBWSxFQUFFLGFBQWE7UUFDM0IsU0FBUyxFQUFFLFVBQVU7UUFDckIsVUFBVSxFQUFFLFdBQVc7UUFDdkIsZUFBZSxFQUFFLGdCQUFnQjtRQUNqQyxVQUFVLEVBQUUsY0FBYztLQUMzQjtDQUNGLENBQUM7QUFFRjs7Ozs7R0FLRztBQUVILE1BQU0sT0FBTyxZQUFZO0lBSXZCO1FBSFEsY0FBUyxHQUFHLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO1FBQ3JDLFNBQUksR0FBRyxNQUFNLENBQUMsV0FBVyxDQUFDLENBQUM7UUFHakMsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLGNBQWMsQ0FBQyxFQUFFLENBQUM7WUFDNUMsSUFBSSxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsY0FBYyxFQUFFLGtCQUFrQixDQUFDLENBQUM7UUFDaEUsQ0FBQztJQUNILENBQUM7SUFFRCw0REFBNEQ7SUFDNUQsYUFBYTtRQUNYLE9BQU8sSUFBSSxJQUFJLEVBQUUsQ0FBQyxXQUFXLEVBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBQzlDLENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsS0FBSyxDQUNILEtBQWEsRUFDYixLQUFhLEVBQ2IsT0FBZ0IsRUFDaEIsTUFBZTtRQUVmLE1BQU0sQ0FBQyxHQUFHLE1BQU0sSUFBSSxJQUFJLENBQUMsYUFBYSxFQUFFLENBQUM7UUFDekMsTUFBTSxjQUFjLEdBQUcsR0FBRyxpQkFBaUIsUUFBUSxLQUFLLFNBQVMsS0FBSyxRQUFRLENBQUM7UUFDL0UsT0FBTyxJQUFJLENBQUMsU0FBUzthQUNsQixVQUFVLENBQVcsY0FBYyxFQUFFLENBQUMsQ0FBQzthQUN2QyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLEdBQUcsRUFBRSxPQUFPLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQzFELENBQUM7SUFFTyxVQUFVLENBQ2hCLEdBQW9CLEVBQ3BCLE9BQTJCLEVBQzNCLE1BQWM7UUFFZCxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ2pCLE1BQU0sTUFBTSxHQUFHLEdBQUcsRUFBRSxNQUFNLElBQUksRUFBRSxDQUFDO1FBQ2pDLE1BQU0sS0FBSyxHQUFHLEdBQUcsRUFBRSxLQUFLLElBQUksRUFBRSxDQUFDO1FBQy9CLE1BQU0sSUFBSSxHQUFHLFlBQVksQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsSUFBSSxNQUFNLElBQUksQ0FBQyxJQUFJLEtBQUssQ0FBQyxDQUFDO1FBQ25FLE1BQU0sT0FBTyxHQUFrQixJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUU7WUFDNUMsTUFBTSxLQUFLLEdBQUcsQ0FBQyxJQUFJLE1BQU0sQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUNuRCxPQUFPO2dCQUNMLEdBQUcsRUFBRSxDQUFDO2dCQUNOLEtBQUssRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsY0FBYyxDQUFDLElBQUksQ0FBQztnQkFDMUMsSUFBSSxFQUFFLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDO2dCQUMzQixLQUFLO2dCQUNMLFNBQVMsRUFBRSxLQUFLLEdBQUcsQ0FBQzthQUNyQixDQUFDO1FBQ0osQ0FBQyxDQUFDLENBQUM7UUFDSCxPQUFPLEVBQUUsT0FBTyxFQUFFLElBQUksRUFBRSxHQUFHLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRSxPQUFPLEVBQUUsQ0FBQztJQUN2RCxDQUFDOytHQXJEVSxZQUFZO21IQUFaLFlBQVksY0FEQyxNQUFNOzs0RkFDbkIsWUFBWTtrQkFEeEIsVUFBVTttQkFBQyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlLCBpbmplY3QgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IE9ic2VydmFibGUgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IG1hcCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcbmltcG9ydCB7IEFCU19QQVRIX1NFTlRJTkVMLCBGaXJlc3RvcmVTZXJ2aWNlIH0gZnJvbSAnLi4vZmlyZWJhc2UvZmlyZXN0b3JlLnNlcnZpY2UnO1xuaW1wb3J0IHsgRmlyZXN0b3JlRG9jdW1lbnQgfSBmcm9tICcuLi9maXJlYmFzZS90eXBlcyc7XG5pbXBvcnQgeyBJMThuU2VydmljZSB9IGZyb20gJy4uL2kxOG4vaTE4bi5zZXJ2aWNlJztcbmltcG9ydCB7XG4gIFVzYWdlTWV0ZXJzTWV0YWRhdGEsXG4gIFVzYWdlTWV0cmljLFxufSBmcm9tICcuLi8uLi9jb21wb25lbnRzL21vbGVjdWxlcy91c2FnZS1tZXRlcnMvdHlwZXMnO1xuXG4vKiogRG9jIHByb3llY3RhZG8gcG9yIGVsIGJhY2tlbmQgKEFEUi0wNDYgQzUvRDMpLiAqL1xuaW50ZXJmYWNlIFVzYWdlRG9jIGV4dGVuZHMgRmlyZXN0b3JlRG9jdW1lbnQge1xuICBwbGFuPzogc3RyaW5nO1xuICBwZXJpb2Q/OiBzdHJpbmc7XG4gIGxpbWl0cz86IFJlY29yZDxzdHJpbmcsIG51bWJlcj47XG4gIHVzYWdlPzogUmVjb3JkPHN0cmluZywgbnVtYmVyPjtcbn1cblxuLy8gT3JkZW4gZGUgZGlzcGxheSBkZSBsYXMgbcOpdHJpY2FzIGNvbm9jaWRhcy5cbmNvbnN0IE1FVFJJQ19PUkRFUiA9IFtcbiAgJ21lbWJlcnMnLFxuICAnZW1haWxzX21vbnRoJyxcbiAgJ3Ntc19tb250aCcsXG4gICdwdXNoX21vbnRoJyxcbiAgJ2FwaV9jYWxsc19tb250aCcsXG4gICdzdG9yYWdlX21iJyxcbl07XG5cbmNvbnN0IFVTQUdFX01FVFJJQ1NfSTE4TiA9IHtcbiAgZXM6IHtcbiAgICBtZW1iZXJzOiAnTWllbWJyb3MnLFxuICAgIGVtYWlsc19tb250aDogJ0VtYWlscyAvIG1lcycsXG4gICAgc21zX21vbnRoOiAnU01TIC8gbWVzJyxcbiAgICBwdXNoX21vbnRoOiAnUHVzaCAvIG1lcycsXG4gICAgYXBpX2NhbGxzX21vbnRoOiAnTGxhbWFkYXMgQVBJIC8gbWVzJyxcbiAgICBzdG9yYWdlX21iOiAnQWxtYWNlbmFtaWVudG8gKE1CKScsXG4gIH0sXG4gIGVuOiB7XG4gICAgbWVtYmVyczogJ01lbWJlcnMnLFxuICAgIGVtYWlsc19tb250aDogJ0VtYWlscyAvIG1vJyxcbiAgICBzbXNfbW9udGg6ICdTTVMgLyBtbycsXG4gICAgcHVzaF9tb250aDogJ1B1c2ggLyBtbycsXG4gICAgYXBpX2NhbGxzX21vbnRoOiAnQVBJIGNhbGxzIC8gbW8nLFxuICAgIHN0b3JhZ2VfbWI6ICdTdG9yYWdlIChNQiknLFxuICB9LFxufTtcblxuLyoqXG4gKiBVc2FnZVNlcnZpY2Ug4oCUIGxlZSBlbCByZXN1bWVuIGRlIGNvbnN1bW8gKHVzbyArIGzDrW1pdGVzICsgcGxhbikgZW4gdml2byBkZXNkZVxuICogRmlyZXN0b3JlIHkgbG8gbWFwZWEgYSBgVXNhZ2VNZXRlcnNNZXRhZGF0YWAgcGFyYSBgPHZhbC11c2FnZS1tZXRlcnM+YC5cbiAqIChBRFItMDQ2IEQzKS4gRmlyZXN0b3JlIGVzIGxhIGZ1ZW50ZSDDum5pY2EgKGVsIGJhY2tlbmQgcHJveWVjdGEgdXNhZ2UrbGltaXRzKS5cbiAqIEdyYW51bGFyIHBvciBhcHA6IGB3YXRjaChhcHBJZCwgb3JnSWQpYC4gTXVsdGktYXBwOiB1bmEgc3VzY3JpcGNpw7NuIHBvciBhcHAuXG4gKi9cbkBJbmplY3RhYmxlKHsgcHJvdmlkZWRJbjogJ3Jvb3QnIH0pXG5leHBvcnQgY2xhc3MgVXNhZ2VTZXJ2aWNlIHtcbiAgcHJpdmF0ZSBmaXJlc3RvcmUgPSBpbmplY3QoRmlyZXN0b3JlU2VydmljZSk7XG4gIHByaXZhdGUgaTE4biA9IGluamVjdChJMThuU2VydmljZSk7XG5cbiAgY29uc3RydWN0b3IoKSB7XG4gICAgaWYgKCF0aGlzLmkxOG4uaGFzTmFtZXNwYWNlKCdVc2FnZU1ldHJpY3MnKSkge1xuICAgICAgdGhpcy5pMThuLnJlZ2lzdGVyQ29udGVudCgnVXNhZ2VNZXRyaWNzJywgVVNBR0VfTUVUUklDU19JMThOKTtcbiAgICB9XG4gIH1cblxuICAvKiogUGVyw61vZG8gYWN0dWFsIGBZWVlZLU1NYCAoVVRDKSwgaWd1YWwgcXVlIGVsIGJhY2tlbmQuICovXG4gIGN1cnJlbnRQZXJpb2QoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gbmV3IERhdGUoKS50b0lTT1N0cmluZygpLnNsaWNlKDAsIDcpO1xuICB9XG5cbiAgLyoqXG4gICAqIE9ic2VydmEgZWwgY29uc3VtbyBkZSAob3JnLCBhcHApIGVuIHZpdm8uIExlZSBlbCBwYXRoIGFic29sdXRvXG4gICAqIGBhcHBzL3thcHBJZH0vb3Jncy97b3JnSWR9L3VzYWdlL3twZXJpb2R9YCAoc2luIGF1dG8tcHJlZml4IGRlIGxhIGFwcCBhY3R1YWwsXG4gICAqIHBhcmEgc29wb3J0YXIgbGEgdmlzdGEgbXVsdGktYXBwIGRlc2RlIGFjY291bnQpLlxuICAgKi9cbiAgd2F0Y2goXG4gICAgYXBwSWQ6IHN0cmluZyxcbiAgICBvcmdJZDogc3RyaW5nLFxuICAgIGFwcE5hbWU/OiBzdHJpbmcsXG4gICAgcGVyaW9kPzogc3RyaW5nLFxuICApOiBPYnNlcnZhYmxlPFVzYWdlTWV0ZXJzTWV0YWRhdGE+IHtcbiAgICBjb25zdCBwID0gcGVyaW9kIHx8IHRoaXMuY3VycmVudFBlcmlvZCgpO1xuICAgIGNvbnN0IGNvbGxlY3Rpb25QYXRoID0gYCR7QUJTX1BBVEhfU0VOVElORUx9YXBwcy8ke2FwcElkfS9vcmdzLyR7b3JnSWR9L3VzYWdlYDtcbiAgICByZXR1cm4gdGhpcy5maXJlc3RvcmVcbiAgICAgIC5kb2NDaGFuZ2VzPFVzYWdlRG9jPihjb2xsZWN0aW9uUGF0aCwgcClcbiAgICAgIC5waXBlKG1hcCgoZG9jKSA9PiB0aGlzLnRvTWV0YWRhdGEoZG9jLCBhcHBOYW1lLCBwKSkpO1xuICB9XG5cbiAgcHJpdmF0ZSB0b01ldGFkYXRhKFxuICAgIGRvYzogVXNhZ2VEb2MgfCBudWxsLFxuICAgIGFwcE5hbWU6IHN0cmluZyB8IHVuZGVmaW5lZCxcbiAgICBwZXJpb2Q6IHN0cmluZyxcbiAgKTogVXNhZ2VNZXRlcnNNZXRhZGF0YSB7XG4gICAgdGhpcy5pMThuLmxhbmcoKTtcbiAgICBjb25zdCBsaW1pdHMgPSBkb2M/LmxpbWl0cyA/PyB7fTtcbiAgICBjb25zdCB1c2FnZSA9IGRvYz8udXNhZ2UgPz8ge307XG4gICAgY29uc3Qga2V5cyA9IE1FVFJJQ19PUkRFUi5maWx0ZXIoKGspID0+IGsgaW4gbGltaXRzIHx8IGsgaW4gdXNhZ2UpO1xuICAgIGNvbnN0IG1ldHJpY3M6IFVzYWdlTWV0cmljW10gPSBrZXlzLm1hcCgoaykgPT4ge1xuICAgICAgY29uc3QgbGltaXQgPSBrIGluIGxpbWl0cyA/IE51bWJlcihsaW1pdHNba10pIDogLTE7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBrZXk6IGssXG4gICAgICAgIGxhYmVsOiB0aGlzLmkxOG4udChrLCAnVXNhZ2VNZXRyaWNzJykgfHwgayxcbiAgICAgICAgdXNlZDogTnVtYmVyKHVzYWdlW2tdID8/IDApLFxuICAgICAgICBsaW1pdCxcbiAgICAgICAgdW5saW1pdGVkOiBsaW1pdCA8IDAsXG4gICAgICB9O1xuICAgIH0pO1xuICAgIHJldHVybiB7IGFwcE5hbWUsIHBsYW46IGRvYz8ucGxhbiwgcGVyaW9kLCBtZXRyaWNzIH07XG4gIH1cbn1cbiJdfQ==
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
export interface UsageMetric {
|
|
2
|
-
/** Clave de la métrica (ej. "emails_month"). */
|
|
3
|
-
key: string;
|
|
4
|
-
/** Etiqueta visible ya resuelta por el consumer (ej. "Emails / mes"). */
|
|
5
|
-
label: string;
|
|
6
|
-
/** Consumo del período. */
|
|
7
|
-
used: number;
|
|
8
|
-
/** Tope; -1 = ilimitado. */
|
|
9
|
-
limit: number;
|
|
10
|
-
/** true si el tope es ilimitado (-1). */
|
|
11
|
-
unlimited: boolean;
|
|
12
|
-
}
|
|
13
|
-
export interface UsageMetersMetadata {
|
|
14
|
-
/** Título de la sección (opcional). */
|
|
15
|
-
title?: string;
|
|
16
|
-
/** Nombre de la app a la que pertenece este bloque (para vista multi-app). */
|
|
17
|
-
appName?: string;
|
|
18
|
-
/** Tier del plan, para mostrar como badge (ej. "Pro"). */
|
|
19
|
-
plan?: string;
|
|
20
|
-
/** Período (ej. "2026-06"). */
|
|
21
|
-
period?: string;
|
|
22
|
-
/** Métricas a mostrar. */
|
|
23
|
-
metrics: UsageMetric[];
|
|
24
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { UsageMetersMetadata } from './types';
|
|
2
|
-
import * as i0 from "@angular/core";
|
|
3
|
-
interface MeterRow {
|
|
4
|
-
key: string;
|
|
5
|
-
label: string;
|
|
6
|
-
usedLabel: string;
|
|
7
|
-
pct: number;
|
|
8
|
-
unlimited: boolean;
|
|
9
|
-
over: boolean;
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* val-usage-meters — bloque de consumo (uso vs tope por métrica) para el
|
|
13
|
-
* dashboard de monetización (ADR-046 D3). Presentacional: recibe los datos ya
|
|
14
|
-
* resueltos (UsageService los arma desde Firestore). Reutilizable single-app o
|
|
15
|
-
* por sección en multi-app (myvaltech account).
|
|
16
|
-
*/
|
|
17
|
-
export declare class UsageMetersComponent {
|
|
18
|
-
private i18n;
|
|
19
|
-
readonly props: import("@angular/core").InputSignal<UsageMetersMetadata>;
|
|
20
|
-
constructor();
|
|
21
|
-
readonly rows: import("@angular/core").Signal<MeterRow[]>;
|
|
22
|
-
t(key: string): string;
|
|
23
|
-
static ɵfac: i0.ɵɵFactoryDeclaration<UsageMetersComponent, never>;
|
|
24
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<UsageMetersComponent, "val-usage-meters", never, { "props": { "alias": "props"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
25
|
-
}
|
|
26
|
-
export {};
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { Observable } from 'rxjs';
|
|
2
|
-
import { UsageMetersMetadata } from '../../components/molecules/usage-meters/types';
|
|
3
|
-
import * as i0 from "@angular/core";
|
|
4
|
-
/**
|
|
5
|
-
* UsageService — lee el resumen de consumo (uso + límites + plan) en vivo desde
|
|
6
|
-
* Firestore y lo mapea a `UsageMetersMetadata` para `<val-usage-meters>`.
|
|
7
|
-
* (ADR-046 D3). Firestore es la fuente única (el backend proyecta usage+limits).
|
|
8
|
-
* Granular por app: `watch(appId, orgId)`. Multi-app: una suscripción por app.
|
|
9
|
-
*/
|
|
10
|
-
export declare class UsageService {
|
|
11
|
-
private firestore;
|
|
12
|
-
private i18n;
|
|
13
|
-
constructor();
|
|
14
|
-
/** Período actual `YYYY-MM` (UTC), igual que el backend. */
|
|
15
|
-
currentPeriod(): string;
|
|
16
|
-
/**
|
|
17
|
-
* Observa el consumo de (org, app) en vivo. Lee el path absoluto
|
|
18
|
-
* `apps/{appId}/orgs/{orgId}/usage/{period}` (sin auto-prefix de la app actual,
|
|
19
|
-
* para soportar la vista multi-app desde account).
|
|
20
|
-
*/
|
|
21
|
-
watch(appId: string, orgId: string, appName?: string, period?: string): Observable<UsageMetersMetadata>;
|
|
22
|
-
private toMetadata;
|
|
23
|
-
static ɵfac: i0.ɵɵFactoryDeclaration<UsageService, never>;
|
|
24
|
-
static ɵprov: i0.ɵɵInjectableDeclaration<UsageService>;
|
|
25
|
-
}
|