@roastcodes/ttdash 6.1.4 → 6.1.6
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/README.md +14 -4
- package/dist/assets/AutoImportModal-Dqbl8H04.js +2 -0
- package/dist/assets/CustomTooltip-DBPq6A_5.js +1 -0
- package/dist/assets/DrillDownModal-BKuxN4GY.js +1 -0
- package/dist/assets/index-D8uaHhGW.js +4 -0
- package/dist/assets/index-TppJ6Iqj.css +2 -0
- package/dist/index.html +4 -4
- package/package.json +18 -5
- package/server/model-normalization.json +28 -0
- package/server/report/charts.js +151 -64
- package/server/report/index.js +149 -109
- package/server/report/utils.js +482 -85
- package/server.js +305 -191
- package/src/locales/de/common.json +78 -1
- package/src/locales/en/common.json +78 -1
- package/usage-normalizer.js +44 -36
- package/dist/assets/AutoImportModal-Dig6ASar.js +0 -2
- package/dist/assets/CustomTooltip-YeXs5zcp.js +0 -1
- package/dist/assets/DrillDownModal-Ct7hxDzy.js +0 -1
- package/dist/assets/index-9cPAel40.js +0 -4
- package/dist/assets/index-DWoj-vpZ.css +0 -2
|
@@ -72,6 +72,8 @@
|
|
|
72
72
|
"hidden": "Versteckt",
|
|
73
73
|
"open": "Öffnen",
|
|
74
74
|
"close": "Schliessen",
|
|
75
|
+
"previousMonth": "Vorheriger Monat",
|
|
76
|
+
"nextMonth": "Nächster Monat",
|
|
75
77
|
"startDate": "Startdatum",
|
|
76
78
|
"endDate": "Enddatum",
|
|
77
79
|
"selectedProviders": "Ausgewählte Provider",
|
|
@@ -165,6 +167,9 @@
|
|
|
165
167
|
"cacheRoi": "Cache ROI"
|
|
166
168
|
},
|
|
167
169
|
"stats": {
|
|
170
|
+
"min": "Min",
|
|
171
|
+
"max": "Max",
|
|
172
|
+
"avg": "Ø",
|
|
168
173
|
"cacheHitRate": "Cache-Hit-Rate",
|
|
169
174
|
"totalTokens": "Gesamt-Tokens",
|
|
170
175
|
"cacheRead": "Cache Read",
|
|
@@ -206,6 +211,7 @@
|
|
|
206
211
|
"spread": "Spanne: {{value}}",
|
|
207
212
|
"medianPerUnit": "Median/{{unit}}",
|
|
208
213
|
"vsAverage": "{{direction}}{{value}}% vs. Ø",
|
|
214
|
+
"vsAverageWithVolatility": "{{direction}}{{value}}% vs. Ø · σ Req {{volatility}}",
|
|
209
215
|
"medianInfo": "Der Median zeigt den typischen Wert und ist weniger anfällig für Ausreisser als der Durchschnitt.",
|
|
210
216
|
"requestLeader": "{{model}} · {{requests}} Req",
|
|
211
217
|
"dominantProviderSubtitle": "{{share}} Anteil · {{cost}}{{requestLeader}}"
|
|
@@ -250,6 +256,7 @@
|
|
|
250
256
|
"ioRatio": "I/O Ratio: {{value}}:1",
|
|
251
257
|
"topModel": "Top: {{value}}",
|
|
252
258
|
"cacheMix": "In: {{input}} / Out: {{output}}",
|
|
259
|
+
"costPerRequest": "{{value}} / Req",
|
|
253
260
|
"requestsSubtitle": "Ø {{value}}/Tag · {{cost}}/Req",
|
|
254
261
|
"requestCountersMissing": "Keine Request-Zähler",
|
|
255
262
|
"thinkingSubtitle": "{{value}} Anteil"
|
|
@@ -919,6 +926,11 @@
|
|
|
919
926
|
"subscriptionPaysOff": "Subscription zahlt sich aus",
|
|
920
927
|
"belowSubscription": "Noch unter Subscription"
|
|
921
928
|
},
|
|
929
|
+
"badge": {
|
|
930
|
+
"limit": "{{value}}% Limit",
|
|
931
|
+
"subscription": "{{value}}% Abo",
|
|
932
|
+
"open": "Offen"
|
|
933
|
+
},
|
|
922
934
|
"tracks": {
|
|
923
935
|
"budgetTitle": "Budget-Status je Anbieter",
|
|
924
936
|
"budgetSubtitle": "Jeder Track zeigt pro Anbieter direkt den Abstand bis zum Limit oder den bereits eingetretenen Überzug",
|
|
@@ -930,7 +942,9 @@
|
|
|
930
942
|
"portfolioSubtitle": "Monatlicher Verlauf von Usage, konfigurierten Limits und Subscription-Wirkung",
|
|
931
943
|
"usage": "Usage",
|
|
932
944
|
"limit": "Limit",
|
|
945
|
+
"limits": "Limits",
|
|
933
946
|
"subscription": "Subscription",
|
|
947
|
+
"subscriptions": "Subscriptions",
|
|
934
948
|
"breakEven": "Break-even",
|
|
935
949
|
"currentlyUsed": "Aktuell verbraucht",
|
|
936
950
|
"remainingToLimit": "Bis Limit offen",
|
|
@@ -969,7 +983,70 @@
|
|
|
969
983
|
}
|
|
970
984
|
},
|
|
971
985
|
"report": {
|
|
972
|
-
"title": "TTDash Report"
|
|
986
|
+
"title": "TTDash Report",
|
|
987
|
+
"common": {
|
|
988
|
+
"notAvailable": "n/v"
|
|
989
|
+
},
|
|
990
|
+
"header": {
|
|
991
|
+
"eyebrow": "TTDash PDF-Bericht"
|
|
992
|
+
},
|
|
993
|
+
"summary": {
|
|
994
|
+
"peakPeriod": "Spitzenzeitraum"
|
|
995
|
+
},
|
|
996
|
+
"sections": {
|
|
997
|
+
"overview": "Überblick",
|
|
998
|
+
"insights": "Wichtigste Erkenntnisse",
|
|
999
|
+
"filters": "Filter",
|
|
1000
|
+
"modelsProviders": "Modelle & Provider",
|
|
1001
|
+
"recentPeriods": "Letzte Zeiträume",
|
|
1002
|
+
"interpretation": "Interpretation"
|
|
1003
|
+
},
|
|
1004
|
+
"fields": {
|
|
1005
|
+
"dateRange": "Zeitraum",
|
|
1006
|
+
"view": "Ansicht",
|
|
1007
|
+
"generated": "Generiert",
|
|
1008
|
+
"month": "Monat",
|
|
1009
|
+
"selectedProviders": "Ausgewählte Provider",
|
|
1010
|
+
"selectedModels": "Ausgewählte Modelle",
|
|
1011
|
+
"startDate": "Startdatum",
|
|
1012
|
+
"endDate": "Enddatum"
|
|
1013
|
+
},
|
|
1014
|
+
"filters": {
|
|
1015
|
+
"all": "Alle",
|
|
1016
|
+
"noFilter": "Kein Filter",
|
|
1017
|
+
"andMore": "+{{count}} weitere"
|
|
1018
|
+
},
|
|
1019
|
+
"tables": {
|
|
1020
|
+
"topModels": "Top-Modelle",
|
|
1021
|
+
"providers": "Provider",
|
|
1022
|
+
"columns": {
|
|
1023
|
+
"model": "Modell",
|
|
1024
|
+
"provider": "Provider",
|
|
1025
|
+
"cost": "Kosten",
|
|
1026
|
+
"tokens": "Tokens",
|
|
1027
|
+
"requests": "Requests",
|
|
1028
|
+
"period": "Zeitraum"
|
|
1029
|
+
}
|
|
1030
|
+
},
|
|
1031
|
+
"charts": {
|
|
1032
|
+
"costTrend": "Kostenverlauf",
|
|
1033
|
+
"topModels": "Top-Modelle nach Kosten",
|
|
1034
|
+
"tokenTrend": "Token-Mix pro Zeitraum"
|
|
1035
|
+
},
|
|
1036
|
+
"interpretation": {
|
|
1037
|
+
"summary": "Dieser Report umfasst {{days}} Rohdaten-Tage und {{periods}} aggregierte Zeiträume. Spitzenzeitraum: {{peak}}. Top-Modell: {{topModel}}. Führender Provider: {{topProvider}}.",
|
|
1038
|
+
"footer": "Erstellt mit TTDash v{{version}} und serverseitiger Typst-Kompilierung."
|
|
1039
|
+
},
|
|
1040
|
+
"insights": {
|
|
1041
|
+
"coverageTitle": "Datenbasis",
|
|
1042
|
+
"coverageBody": "Dieser Report basiert auf einer schmalen Datenbasis mit {{days}} Rohdaten-Tagen und {{periods}} aggregierten Zeiträumen. Trend-Aussagen sollten vorsichtig gelesen werden.",
|
|
1043
|
+
"providerTitle": "Provider-Konzentration",
|
|
1044
|
+
"providerBody": "{{provider}} steht für {{share}} der gesamten Report-Kosten.",
|
|
1045
|
+
"cacheTitle": "Cache-Beitrag",
|
|
1046
|
+
"cacheBody": "Cache-Reads machen im gewählten Zeitraum {{share}} der Token-Aktivität aus.",
|
|
1047
|
+
"peakWindowTitle": "Stärkstes 7-Tage-Fenster",
|
|
1048
|
+
"peakWindowBody": "Das stärkste rollierende 7-Tage-Fenster lag zwischen {{start}} und {{end}} mit insgesamt {{cost}} Kosten."
|
|
1049
|
+
}
|
|
973
1050
|
},
|
|
974
1051
|
"api": {
|
|
975
1052
|
"fetchUsageFailed": "Fehler beim Laden der Daten",
|
|
@@ -72,6 +72,8 @@
|
|
|
72
72
|
"hidden": "Hidden",
|
|
73
73
|
"open": "Open",
|
|
74
74
|
"close": "Close",
|
|
75
|
+
"previousMonth": "Previous month",
|
|
76
|
+
"nextMonth": "Next month",
|
|
75
77
|
"startDate": "Start date",
|
|
76
78
|
"endDate": "End date",
|
|
77
79
|
"selectedProviders": "Selected providers",
|
|
@@ -165,6 +167,9 @@
|
|
|
165
167
|
"cacheRoi": "Cache ROI"
|
|
166
168
|
},
|
|
167
169
|
"stats": {
|
|
170
|
+
"min": "Min",
|
|
171
|
+
"max": "Max",
|
|
172
|
+
"avg": "Avg",
|
|
168
173
|
"cacheHitRate": "Cache hit rate",
|
|
169
174
|
"totalTokens": "Total tokens",
|
|
170
175
|
"cacheRead": "Cache read",
|
|
@@ -206,6 +211,7 @@
|
|
|
206
211
|
"spread": "Spread: {{value}}",
|
|
207
212
|
"medianPerUnit": "Median/{{unit}}",
|
|
208
213
|
"vsAverage": "{{direction}}{{value}}% vs avg",
|
|
214
|
+
"vsAverageWithVolatility": "{{direction}}{{value}}% vs avg · σ Req {{volatility}}",
|
|
209
215
|
"medianInfo": "The median shows the typical value and is less sensitive to outliers than the average.",
|
|
210
216
|
"requestLeader": "{{model}} · {{requests}} req",
|
|
211
217
|
"dominantProviderSubtitle": "{{share}} share · {{cost}}{{requestLeader}}"
|
|
@@ -250,6 +256,7 @@
|
|
|
250
256
|
"ioRatio": "I/O ratio: {{value}}:1",
|
|
251
257
|
"topModel": "Top: {{value}}",
|
|
252
258
|
"cacheMix": "In: {{input}} / Out: {{output}}",
|
|
259
|
+
"costPerRequest": "{{value}} / req",
|
|
253
260
|
"requestsSubtitle": "Avg {{value}}/day · {{cost}}/req",
|
|
254
261
|
"requestCountersMissing": "No request counters",
|
|
255
262
|
"thinkingSubtitle": "{{value}} share"
|
|
@@ -919,6 +926,11 @@
|
|
|
919
926
|
"subscriptionPaysOff": "Subscription pays off",
|
|
920
927
|
"belowSubscription": "Still below subscription"
|
|
921
928
|
},
|
|
929
|
+
"badge": {
|
|
930
|
+
"limit": "{{value}}% Limit",
|
|
931
|
+
"subscription": "{{value}}% Sub",
|
|
932
|
+
"open": "Open"
|
|
933
|
+
},
|
|
922
934
|
"tracks": {
|
|
923
935
|
"budgetTitle": "Budget status by provider",
|
|
924
936
|
"budgetSubtitle": "Each track shows the remaining distance to the limit or the already incurred overrun for each provider",
|
|
@@ -930,7 +942,9 @@
|
|
|
930
942
|
"portfolioSubtitle": "Monthly trend of usage, configured limits, and subscription impact",
|
|
931
943
|
"usage": "Usage",
|
|
932
944
|
"limit": "Limit",
|
|
945
|
+
"limits": "Limits",
|
|
933
946
|
"subscription": "Subscription",
|
|
947
|
+
"subscriptions": "Subscriptions",
|
|
934
948
|
"breakEven": "Break-even",
|
|
935
949
|
"currentlyUsed": "Currently used",
|
|
936
950
|
"remainingToLimit": "Remaining to limit",
|
|
@@ -969,7 +983,70 @@
|
|
|
969
983
|
}
|
|
970
984
|
},
|
|
971
985
|
"report": {
|
|
972
|
-
"title": "TTDash Report"
|
|
986
|
+
"title": "TTDash Report",
|
|
987
|
+
"common": {
|
|
988
|
+
"notAvailable": "n/a"
|
|
989
|
+
},
|
|
990
|
+
"header": {
|
|
991
|
+
"eyebrow": "TTDash PDF Report"
|
|
992
|
+
},
|
|
993
|
+
"summary": {
|
|
994
|
+
"peakPeriod": "Peak period"
|
|
995
|
+
},
|
|
996
|
+
"sections": {
|
|
997
|
+
"overview": "Overview",
|
|
998
|
+
"insights": "Key insights",
|
|
999
|
+
"filters": "Filters",
|
|
1000
|
+
"modelsProviders": "Models & Providers",
|
|
1001
|
+
"recentPeriods": "Recent periods",
|
|
1002
|
+
"interpretation": "Interpretation"
|
|
1003
|
+
},
|
|
1004
|
+
"fields": {
|
|
1005
|
+
"dateRange": "Date range",
|
|
1006
|
+
"view": "View",
|
|
1007
|
+
"generated": "Generated",
|
|
1008
|
+
"month": "Month",
|
|
1009
|
+
"selectedProviders": "Selected providers",
|
|
1010
|
+
"selectedModels": "Selected models",
|
|
1011
|
+
"startDate": "Start date",
|
|
1012
|
+
"endDate": "End date"
|
|
1013
|
+
},
|
|
1014
|
+
"filters": {
|
|
1015
|
+
"all": "All",
|
|
1016
|
+
"noFilter": "No filter",
|
|
1017
|
+
"andMore": "+{{count}} more"
|
|
1018
|
+
},
|
|
1019
|
+
"tables": {
|
|
1020
|
+
"topModels": "Top models",
|
|
1021
|
+
"providers": "Providers",
|
|
1022
|
+
"columns": {
|
|
1023
|
+
"model": "Model",
|
|
1024
|
+
"provider": "Provider",
|
|
1025
|
+
"cost": "Cost",
|
|
1026
|
+
"tokens": "Tokens",
|
|
1027
|
+
"requests": "Requests",
|
|
1028
|
+
"period": "Period"
|
|
1029
|
+
}
|
|
1030
|
+
},
|
|
1031
|
+
"charts": {
|
|
1032
|
+
"costTrend": "Cost trend",
|
|
1033
|
+
"topModels": "Top models by cost",
|
|
1034
|
+
"tokenTrend": "Token mix by period"
|
|
1035
|
+
},
|
|
1036
|
+
"interpretation": {
|
|
1037
|
+
"summary": "This report covers {{days}} raw days and {{periods}} aggregated periods. Peak period: {{peak}}. Top model: {{topModel}}. Leading provider: {{topProvider}}.",
|
|
1038
|
+
"footer": "Created with TTDash v{{version}} and server-side Typst compilation."
|
|
1039
|
+
},
|
|
1040
|
+
"insights": {
|
|
1041
|
+
"coverageTitle": "Data coverage",
|
|
1042
|
+
"coverageBody": "This report is based on a narrow slice of data with {{days}} raw days and {{periods}} aggregated periods. Treat trend statements cautiously.",
|
|
1043
|
+
"providerTitle": "Provider concentration",
|
|
1044
|
+
"providerBody": "{{provider}} accounts for {{share}} of total report cost.",
|
|
1045
|
+
"cacheTitle": "Cache contribution",
|
|
1046
|
+
"cacheBody": "Cache reads contribute {{share}} of token activity in the selected period.",
|
|
1047
|
+
"peakWindowTitle": "Peak 7-day window",
|
|
1048
|
+
"peakWindowBody": "The strongest rolling 7-day window ran from {{start}} to {{end}} with {{cost}} total cost."
|
|
1049
|
+
}
|
|
973
1050
|
},
|
|
974
1051
|
"api": {
|
|
975
1052
|
"fetchUsageFailed": "Failed to load data",
|
package/usage-normalizer.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
function toNumber(value) {
|
|
2
|
-
return Number.isFinite(value) ? value : Number(value) || 0
|
|
2
|
+
return Number.isFinite(value) ? value : Number(value) || 0;
|
|
3
3
|
}
|
|
4
4
|
|
|
5
5
|
function toStringValue(value) {
|
|
6
|
-
return typeof value === 'string' ? value : ''
|
|
6
|
+
return typeof value === 'string' ? value : '';
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
function normalizeLegacyModelBreakdown(entry) {
|
|
@@ -20,13 +20,13 @@ function normalizeLegacyModelBreakdown(entry) {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
function withDailyTotals(day) {
|
|
23
|
-
const totalTokens =
|
|
23
|
+
const totalTokens =
|
|
24
|
+
toNumber(day.totalTokens) ||
|
|
24
25
|
toNumber(day.inputTokens) +
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
);
|
|
26
|
+
toNumber(day.outputTokens) +
|
|
27
|
+
toNumber(day.cacheCreationTokens) +
|
|
28
|
+
toNumber(day.cacheReadTokens) +
|
|
29
|
+
toNumber(day.thinkingTokens);
|
|
30
30
|
|
|
31
31
|
return {
|
|
32
32
|
date: toStringValue(day.date),
|
|
@@ -38,8 +38,12 @@ function withDailyTotals(day) {
|
|
|
38
38
|
totalTokens,
|
|
39
39
|
totalCost: toNumber(day.totalCost),
|
|
40
40
|
requestCount: toNumber(day.requestCount),
|
|
41
|
-
modelsUsed: Array.isArray(day.modelsUsed)
|
|
42
|
-
|
|
41
|
+
modelsUsed: Array.isArray(day.modelsUsed)
|
|
42
|
+
? day.modelsUsed.filter((value) => typeof value === 'string')
|
|
43
|
+
: [],
|
|
44
|
+
modelBreakdowns: Array.isArray(day.modelBreakdowns)
|
|
45
|
+
? day.modelBreakdowns.map(normalizeLegacyModelBreakdown)
|
|
46
|
+
: [],
|
|
43
47
|
};
|
|
44
48
|
}
|
|
45
49
|
|
|
@@ -66,9 +70,10 @@ function normalizeLegacyDay(entry) {
|
|
|
66
70
|
}
|
|
67
71
|
|
|
68
72
|
function normalizeToktrackDay(entry) {
|
|
69
|
-
const models =
|
|
70
|
-
|
|
71
|
-
|
|
73
|
+
const models =
|
|
74
|
+
entry?.models && typeof entry.models === 'object' && !Array.isArray(entry.models)
|
|
75
|
+
? entry.models
|
|
76
|
+
: {};
|
|
72
77
|
|
|
73
78
|
const modelBreakdowns = Object.entries(models).map(([modelName, modelData]) => ({
|
|
74
79
|
modelName,
|
|
@@ -98,25 +103,28 @@ function normalizeToktrackDay(entry) {
|
|
|
98
103
|
}
|
|
99
104
|
|
|
100
105
|
function computeTotals(daily) {
|
|
101
|
-
return daily.reduce(
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
106
|
+
return daily.reduce(
|
|
107
|
+
(totals, day) => ({
|
|
108
|
+
inputTokens: totals.inputTokens + day.inputTokens,
|
|
109
|
+
outputTokens: totals.outputTokens + day.outputTokens,
|
|
110
|
+
cacheCreationTokens: totals.cacheCreationTokens + day.cacheCreationTokens,
|
|
111
|
+
cacheReadTokens: totals.cacheReadTokens + day.cacheReadTokens,
|
|
112
|
+
thinkingTokens: totals.thinkingTokens + day.thinkingTokens,
|
|
113
|
+
totalCost: totals.totalCost + day.totalCost,
|
|
114
|
+
totalTokens: totals.totalTokens + day.totalTokens,
|
|
115
|
+
requestCount: totals.requestCount + day.requestCount,
|
|
116
|
+
}),
|
|
117
|
+
{
|
|
118
|
+
inputTokens: 0,
|
|
119
|
+
outputTokens: 0,
|
|
120
|
+
cacheCreationTokens: 0,
|
|
121
|
+
cacheReadTokens: 0,
|
|
122
|
+
thinkingTokens: 0,
|
|
123
|
+
totalCost: 0,
|
|
124
|
+
totalTokens: 0,
|
|
125
|
+
requestCount: 0,
|
|
126
|
+
},
|
|
127
|
+
);
|
|
120
128
|
}
|
|
121
129
|
|
|
122
130
|
function normalizeIncomingData(payload) {
|
|
@@ -125,7 +133,9 @@ function normalizeIncomingData(payload) {
|
|
|
125
133
|
if (Array.isArray(payload)) {
|
|
126
134
|
daily = payload.map(normalizeToktrackDay);
|
|
127
135
|
} else if (payload && typeof payload === 'object' && Array.isArray(payload.daily)) {
|
|
128
|
-
const looksLikeToktrack = payload.daily.some(
|
|
136
|
+
const looksLikeToktrack = payload.daily.some(
|
|
137
|
+
(item) => item && typeof item === 'object' && 'total_input_tokens' in item,
|
|
138
|
+
);
|
|
129
139
|
daily = looksLikeToktrack
|
|
130
140
|
? payload.daily.map(normalizeToktrackDay)
|
|
131
141
|
: payload.daily.map(normalizeLegacyDay);
|
|
@@ -133,9 +143,7 @@ function normalizeIncomingData(payload) {
|
|
|
133
143
|
throw new Error('Die JSON-Datei muss ein gültiges tägliches Nutzungsformat enthalten.');
|
|
134
144
|
}
|
|
135
145
|
|
|
136
|
-
const filtered = daily
|
|
137
|
-
.filter((item) => item.date)
|
|
138
|
-
.sort((a, b) => a.date.localeCompare(b.date));
|
|
146
|
+
const filtered = daily.filter((item) => item.date).sort((a, b) => a.date.localeCompare(b.date));
|
|
139
147
|
|
|
140
148
|
if (filtered.length === 0) {
|
|
141
149
|
throw new Error('Keine Nutzungsdaten gefunden.');
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{a as e}from"./rolldown-runtime-COnpUsM8.js";import{w as t}from"./charts-vendor-CiBqdKXh.js";import{r as n}from"./motion-vendor-BXI2L__C.js";import{a as r,i,n as a,r as o,t as s}from"./dialog-Cn1m7WhC.js";import{n as c,t as l}from"./button-D7Ib8H7t.js";import{V as u,b as d,c as f,z as p}from"./icons-vendor-DFoaijFJ.js";var m=e(t());function h(e,t){if(e===`Starte lokalen toktrack-Import...`)return t(`autoImportModal.startingLocalImport`);if(e.startsWith(`Lade Nutzungsdaten via `))return t(`autoImportModal.loadingUsageData`,{command:e.replace(`Lade Nutzungsdaten via `,``).replace(/\.\.\.$/,``)});let n=e.match(/^Verarbeite Nutzungsdaten\.\.\. \((\d+)s\)$/);return n?t(`autoImportModal.processingUsageData`,{seconds:n[1]}):e===`Verbindung zum Server verloren.`?t(`autoImportModal.serverConnectionLost`):e===`Ein Auto-Import läuft bereits. Bitte warten.`?t(`autoImportModal.autoImportRunning`):e===`Kein lokales toktrack, Bun oder npm exec gefunden.`?t(`autoImportModal.noRunnerFound`):e.startsWith(`Fehler: `)?t(`autoImportModal.errorPrefix`,{message:e.replace(/^Fehler: /,``)}):e}function g(e,t=(e,t)=>e){let n=new EventSource(`/api/auto-import/stream`);return n.addEventListener(`check`,t=>{e.onCheck(JSON.parse(t.data))}),n.addEventListener(`progress`,n=>{let r=JSON.parse(n.data);e.onProgress({...r,message:h(r.message,t)})}),n.addEventListener(`stderr`,n=>{let r=JSON.parse(n.data);e.onStderr({...r,line:h(r.line,t)})}),n.addEventListener(`success`,t=>{e.onSuccess(JSON.parse(t.data))}),n.addEventListener(`error`,r=>{if(r instanceof MessageEvent&&r.data){let n=JSON.parse(r.data);e.onError({...n,message:h(n.message,t)})}else e.onError({message:t(`autoImportModal.serverConnectionLost`)}),n.close(),e.onDone()}),n.addEventListener(`done`,()=>{n.close(),e.onDone()}),{close:()=>{n.close()}}}var _=n(),v={check:`text-primary`,progress:`text-muted-foreground`,stderr:`text-foreground`,success:`text-green-500`,error:`text-destructive`};function y({open:e,onOpenChange:t,onSuccess:n}){let{t:h}=c(),[y,b]=(0,m.useState)(`idle`),[x,S]=(0,m.useState)([]),[C,w]=(0,m.useState)(null),T=(0,m.useRef)(null),E=(0,m.useRef)(null),D=(0,m.useCallback)((e,t)=>{S(n=>[...n,{type:e,text:t}])},[]);(0,m.useEffect)(()=>{if(!e)return;b(`checking`),S([]),w(null);let t=g({onCheck:e=>{e.status===`checking`?D(`check`,h(`autoImportModal.checkingTool`,{tool:e.tool})):e.status===`found`?(D(`check`,h(`autoImportModal.toolFound`,{tool:e.tool,method:e.method,version:e.version})),b(`running`)):e.status===`not_found`&&D(`check`,h(`autoImportModal.toolNotFound`,{tool:e.tool}))},onProgress:e=>{D(`progress`,e.message)},onStderr:e=>{D(`stderr`,e.line)},onSuccess:e=>{D(`success`,h(`autoImportModal.importedDays`,{days:e.days,cost:e.totalCost.toFixed(2)})),w(e),b(`success`),n()},onError:e=>{D(`error`,e.message),b(`error`)},onDone:()=>{E.current=null}},h);return E.current=t,()=>{t.close(),E.current=null}},[e,D,n,h]),(0,m.useEffect)(()=>{T.current&&(T.current.scrollTop=T.current.scrollHeight)},[x]);let O=y===`checking`||y===`running`;return(0,_.jsx)(s,{open:e,onOpenChange:e=>{O||t(e)},children:(0,_.jsxs)(a,{className:`max-w-lg`,onPointerDownOutside:e=>{O&&e.preventDefault()},children:[(0,_.jsxs)(i,{children:[(0,_.jsxs)(r,{className:`flex items-center gap-2`,children:[(0,_.jsx)(f,{className:`h-5 w-5`}),h(`autoImportModal.title`)]}),(0,_.jsx)(o,{children:h(`autoImportModal.description`)})]}),(0,_.jsxs)(`div`,{ref:T,className:`bg-muted/30 rounded-lg p-3 font-mono text-xs max-h-[300px] min-h-[120px] overflow-y-auto border border-border`,children:[x.length===0&&(0,_.jsx)(`span`,{className:`text-muted-foreground`,children:h(`autoImportModal.connecting`)}),x.map((e,t)=>(0,_.jsx)(`div`,{className:v[e.type],children:e.text.split(`
|
|
2
|
-
`).map((e,t)=>(0,_.jsx)(`div`,{children:e},t))},t))]}),(0,_.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,_.jsxs)(`div`,{className:`flex items-center gap-2 text-sm`,children:[O&&(0,_.jsxs)(_.Fragment,{children:[(0,_.jsx)(d,{className:`h-4 w-4 animate-spin text-primary`}),(0,_.jsx)(`span`,{className:`text-muted-foreground`,children:h(y===`checking`?`autoImportModal.checkingPrerequisites`:`autoImportModal.importingData`)})]}),y===`success`&&C&&(0,_.jsxs)(_.Fragment,{children:[(0,_.jsx)(u,{className:`h-4 w-4 text-green-500`}),(0,_.jsx)(`span`,{className:`text-green-500`,children:h(`autoImportModal.loadedDays`,{days:C.days,cost:C.totalCost.toFixed(2)})})]}),y===`error`&&(0,_.jsxs)(_.Fragment,{children:[(0,_.jsx)(p,{className:`h-4 w-4 text-destructive`}),(0,_.jsx)(`span`,{className:`text-destructive`,children:h(`autoImportModal.errorOccurred`)})]})]}),!O&&(0,_.jsx)(l,{variant:`outline`,size:`sm`,onClick:()=>t(!1),children:h(`autoImportModal.close`)})]})]})})}export{y as AutoImportModal};
|