@64mb/freelens-power 1.0.3 → 1.1.0
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 +5 -1
- package/out/main/common/monitoring-history.js +52 -0
- package/out/main/common/monitoring-history.js.map +1 -0
- package/out/main/common/store/monitoring-preferences-store.js +25 -2
- package/out/main/common/store/monitoring-preferences-store.js.map +1 -1
- package/out/main/dashboard-views.js +132 -28
- package/out/main/dashboard-views.js.map +1 -1
- package/out/main/index.js +2 -0
- package/out/main/index.js.map +1 -1
- package/out/main/monitoring-history-database.js +103 -0
- package/out/main/monitoring-history-database.js.map +1 -0
- package/out/main/monitoring-history-worker.js +61 -0
- package/out/main/monitoring-history-worker.js.map +1 -0
- package/out/main/monitoring-history.js +100 -0
- package/out/main/monitoring-history.js.map +1 -0
- package/out/renderer/_virtual/_global-external_mobx.js +2 -1
- package/out/renderer/diagnostics.js +647 -0
- package/out/renderer/diagnostics.js.map +1 -0
- package/out/renderer/index.js +28 -1
- package/out/renderer/index.js.map +1 -1
- package/out/renderer/monitoring-collector.js +202 -0
- package/out/renderer/monitoring-collector.js.map +1 -0
- package/out/renderer/monitoring-history-collection.js +184 -0
- package/out/renderer/monitoring-history-collection.js.map +1 -0
- package/out/renderer/monitoring-history-view.js +150 -0
- package/out/renderer/monitoring-history-view.js.map +1 -0
- package/out/renderer/monitoring-history.js +19 -0
- package/out/renderer/monitoring-history.js.map +1 -0
- package/out/renderer/monitoring.js +98 -125
- package/out/renderer/monitoring.js.map +1 -1
- package/out/renderer/node-monitoring.js +116 -0
- package/out/renderer/node-monitoring.js.map +1 -0
- package/out/renderer/pod-monitoring.js +39 -8
- package/out/renderer/pod-monitoring.js.map +1 -1
- package/out/renderer/preferences/monitoring-preferences.js +55 -10
- package/out/renderer/preferences/monitoring-preferences.js.map +1 -1
- package/out/renderer/src/common/monitoring-history.js +15 -0
- package/out/renderer/src/common/monitoring-history.js.map +1 -0
- package/out/renderer/src/common/monitoring-math.js +98 -0
- package/out/renderer/src/common/monitoring-math.js.map +1 -0
- package/out/renderer/src/common/resource-diagnostics.js +227 -0
- package/out/renderer/src/common/resource-diagnostics.js.map +1 -0
- package/out/renderer/src/common/store/monitoring-preferences-store.js +25 -2
- package/out/renderer/src/common/store/monitoring-preferences-store.js.map +1 -1
- package/out/renderer/welcome.js +3 -1
- package/out/renderer/welcome.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
const require_monitoring_math = require("./monitoring-math.js");
|
|
2
|
+
//#region src/common/resource-diagnostics.ts
|
|
3
|
+
function effectivePodResource(pod, metric, kind = "requests") {
|
|
4
|
+
return require_monitoring_math.effectivePodResource(pod, metric, kind);
|
|
5
|
+
}
|
|
6
|
+
function buildConsumerGroups(pods, owners, usage = []) {
|
|
7
|
+
const objects = new Map(owners.filter((o) => o.metadata.uid).map((o) => [o.metadata.uid, o]));
|
|
8
|
+
const metrics = new Map(usage.map((u) => [u.uid, u]));
|
|
9
|
+
const groups = /* @__PURE__ */ new Map();
|
|
10
|
+
for (const [index, pod] of pods.entries()) {
|
|
11
|
+
if (pod.status?.phase === "Succeeded" || pod.status?.phase === "Failed") continue;
|
|
12
|
+
let owner = pod;
|
|
13
|
+
let resolved = true;
|
|
14
|
+
const visited = /* @__PURE__ */ new Set();
|
|
15
|
+
let unresolved;
|
|
16
|
+
while (true) {
|
|
17
|
+
const references = owner.metadata.ownerReferences ?? [];
|
|
18
|
+
const reference = references.find((r) => r.controller) ?? (references.length === 1 ? references[0] : void 0);
|
|
19
|
+
if (!reference) break;
|
|
20
|
+
if (visited.has(reference.uid)) {
|
|
21
|
+
resolved = false;
|
|
22
|
+
break;
|
|
23
|
+
}
|
|
24
|
+
visited.add(reference.uid);
|
|
25
|
+
const next = objects.get(reference.uid);
|
|
26
|
+
if (!next || next.metadata.namespace !== pod.metadata.namespace) {
|
|
27
|
+
unresolved = reference;
|
|
28
|
+
resolved = false;
|
|
29
|
+
break;
|
|
30
|
+
}
|
|
31
|
+
owner = next;
|
|
32
|
+
}
|
|
33
|
+
const namespace = pod.metadata.namespace ?? "default";
|
|
34
|
+
const identity = unresolved?.uid ?? owner.metadata.uid ?? `unidentified-pod-${index}`;
|
|
35
|
+
const key = `${namespace}/${identity}`;
|
|
36
|
+
let group = groups.get(key);
|
|
37
|
+
if (!group) {
|
|
38
|
+
const summary = () => ({
|
|
39
|
+
requests: 0,
|
|
40
|
+
scheduledRequests: 0,
|
|
41
|
+
unscheduledRequests: 0,
|
|
42
|
+
coveredPods: 0,
|
|
43
|
+
totalPods: 0,
|
|
44
|
+
unknownRequestPods: 0
|
|
45
|
+
});
|
|
46
|
+
group = {
|
|
47
|
+
namespace,
|
|
48
|
+
identity,
|
|
49
|
+
kind: unresolved?.kind ?? owner.kind ?? "Pod",
|
|
50
|
+
name: unresolved?.name ?? owner.metadata.name ?? "Unknown",
|
|
51
|
+
ownerResolved: resolved,
|
|
52
|
+
pods: [],
|
|
53
|
+
cpu: summary(),
|
|
54
|
+
memory: summary()
|
|
55
|
+
};
|
|
56
|
+
groups.set(key, group);
|
|
57
|
+
}
|
|
58
|
+
group.pods.push(pod);
|
|
59
|
+
for (const metric of ["cpu", "memory"]) {
|
|
60
|
+
const summary = group[metric];
|
|
61
|
+
summary.totalPods++;
|
|
62
|
+
try {
|
|
63
|
+
const request = effectivePodResource(pod, metric);
|
|
64
|
+
summary.requests += request;
|
|
65
|
+
summary[pod.spec?.nodeName ? "scheduledRequests" : "unscheduledRequests"] += request;
|
|
66
|
+
} catch {
|
|
67
|
+
summary.unknownRequestPods++;
|
|
68
|
+
}
|
|
69
|
+
const value = pod.metadata.uid ? metrics.get(pod.metadata.uid)?.[metric] : void 0;
|
|
70
|
+
if (value !== void 0 && Number.isFinite(value) && value >= 0) {
|
|
71
|
+
summary.coveredPods++;
|
|
72
|
+
summary.usage = (summary.usage ?? 0) + value;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return [...groups.values()];
|
|
77
|
+
}
|
|
78
|
+
var validTime = (value) => value && Number.isFinite(Date.parse(value)) ? value : void 0;
|
|
79
|
+
function normalizeEvents(events) {
|
|
80
|
+
return events.map((event, index) => ({
|
|
81
|
+
id: event.metadata?.uid ?? `event-${index}`,
|
|
82
|
+
reason: event.reason ?? "Event",
|
|
83
|
+
message: event.message ?? event.note ?? "",
|
|
84
|
+
time: validTime(event.series?.lastObservedTime) ?? validTime(event.lastTimestamp) ?? validTime(event.eventTime) ?? validTime(event.metadata?.creationTimestamp),
|
|
85
|
+
firstTime: validTime(event.firstTimestamp) ?? validTime(event.eventTime),
|
|
86
|
+
count: event.series?.count ?? event.count ?? 1,
|
|
87
|
+
certainty: "reported",
|
|
88
|
+
objectUid: event.involvedObject?.uid ?? event.regarding?.uid
|
|
89
|
+
})).map((entry) => ({
|
|
90
|
+
...entry,
|
|
91
|
+
certainty: entry.time ? entry.certainty : "unknown"
|
|
92
|
+
}));
|
|
93
|
+
}
|
|
94
|
+
function diagnosePendingPod(pod, nodes, events = [], pvcs) {
|
|
95
|
+
const state = pod.status?.phase !== "Pending" ? "not-pending" : pod.spec?.nodeName ? "assigned-waiting" : "unscheduled";
|
|
96
|
+
const evidence = events.filter((event) => !!pod.metadata.uid && (event.involvedObject?.uid ?? event.regarding?.uid) === pod.metadata.uid).map((event) => ({
|
|
97
|
+
source: "event",
|
|
98
|
+
message: `${event.reason ?? "Event"}: ${event.message ?? event.note ?? ""}`
|
|
99
|
+
}));
|
|
100
|
+
const limitations = ["Local checks do not establish exact schedulability or available node capacity"];
|
|
101
|
+
if (state !== "unscheduled") return {
|
|
102
|
+
state,
|
|
103
|
+
evidence,
|
|
104
|
+
limitations
|
|
105
|
+
};
|
|
106
|
+
const spec = pod.spec;
|
|
107
|
+
if (!nodes.length) limitations.push("Node data unavailable");
|
|
108
|
+
if (spec?.schedulerName && spec.schedulerName !== "default-scheduler") limitations.push("Custom scheduler profile is unknown");
|
|
109
|
+
if (spec?.affinity?.podAffinity || spec?.affinity?.podAntiAffinity || spec?.topologySpreadConstraints?.length) limitations.push("Pod affinity and topology constraints are not evaluated");
|
|
110
|
+
for (const node of nodes) {
|
|
111
|
+
const reject = (message) => evidence.push({
|
|
112
|
+
source: "constraint",
|
|
113
|
+
node: node.metadata.name,
|
|
114
|
+
message
|
|
115
|
+
});
|
|
116
|
+
if (node.spec?.unschedulable) reject("Node is cordoned");
|
|
117
|
+
if (Object.entries(spec?.nodeSelector ?? {}).some(([key, value]) => node.metadata.labels?.[key] !== value)) reject("Node selector does not match");
|
|
118
|
+
for (const taint of node.spec?.taints ?? []) {
|
|
119
|
+
if (!["NoSchedule", "NoExecute"].includes(taint.effect)) continue;
|
|
120
|
+
if (!(spec?.tolerations ?? []).some((t) => (!t.effect || t.effect === taint.effect) && (t.operator === "Exists" ? !t.key || t.key === taint.key : t.key === taint.key && (t.value ?? "") === (taint.value ?? "")))) reject(`Untolerated taint ${taint.key} (${taint.effect})`);
|
|
121
|
+
}
|
|
122
|
+
const required = spec?.affinity?.nodeAffinity?.requiredDuringSchedulingIgnoredDuringExecution;
|
|
123
|
+
const terms = required && typeof required === "object" && "nodeSelectorTerms" in required && Array.isArray(required.nodeSelectorTerms) ? required.nodeSelectorTerms : void 0;
|
|
124
|
+
if (required && !terms) limitations.push("Required node affinity data is unsupported");
|
|
125
|
+
if (terms) {
|
|
126
|
+
if (terms.some((term) => term.matchFields?.length || term.matchExpressions?.some((e) => ![
|
|
127
|
+
"In",
|
|
128
|
+
"NotIn",
|
|
129
|
+
"Exists",
|
|
130
|
+
"DoesNotExist",
|
|
131
|
+
"Gt",
|
|
132
|
+
"Lt"
|
|
133
|
+
].includes(e.operator)))) {
|
|
134
|
+
if (!limitations.includes("Required node affinity contains unsupported expressions")) limitations.push("Required node affinity contains unsupported expressions");
|
|
135
|
+
} else if (!terms.some((term) => !!term.matchExpressions?.length && term.matchExpressions.every((e) => {
|
|
136
|
+
const value = node.metadata.labels?.[e.key];
|
|
137
|
+
if (e.operator === "Exists") return value !== void 0;
|
|
138
|
+
if (e.operator === "DoesNotExist") return value === void 0;
|
|
139
|
+
if (e.operator === "In") return value !== void 0 && !!e.values?.includes(value);
|
|
140
|
+
if (e.operator === "NotIn") return value === void 0 || !e.values?.includes(value);
|
|
141
|
+
return value !== void 0 && !!e.values?.length && Number.isFinite(Number(value)) && (e.operator === "Gt" ? Number(value) > Number(e.values[0]) : Number(value) < Number(e.values[0]));
|
|
142
|
+
}))) reject("Required node affinity does not match");
|
|
143
|
+
}
|
|
144
|
+
for (const metric of ["cpu", "memory"]) try {
|
|
145
|
+
if (node.status?.allocatable?.[metric] !== void 0 && effectivePodResource(pod, metric) > require_monitoring_math.parseQuantity(node.status.allocatable[metric], metric === "memory")) reject(`Pod ${metric} request exceeds node allocatable`);
|
|
146
|
+
} catch {
|
|
147
|
+
limitations.push(`Invalid or unavailable ${metric} resource data`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
for (const volume of spec?.volumes ?? []) {
|
|
151
|
+
const claim = volume.persistentVolumeClaim?.claimName;
|
|
152
|
+
if (!claim) continue;
|
|
153
|
+
const pvc = pvcs?.find((item) => item.metadata.name === claim && item.metadata.namespace === pod.metadata.namespace);
|
|
154
|
+
if (!pvc) limitations.push(`PVC ${claim} data unavailable`);
|
|
155
|
+
else if (pvc.status?.phase !== "Bound") limitations.push(`PVC ${claim} is not bound; delayed binding and storage topology require scheduler evidence`);
|
|
156
|
+
}
|
|
157
|
+
return {
|
|
158
|
+
state,
|
|
159
|
+
evidence,
|
|
160
|
+
limitations: [...new Set(limitations)]
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
function observePodChanges(previous, current, observedAt) {
|
|
164
|
+
const entries = [];
|
|
165
|
+
const prior = new Map(previous.filter((pod) => pod.metadata.uid).map((pod) => [pod.metadata.uid, pod]));
|
|
166
|
+
for (const pod of current) {
|
|
167
|
+
const old = pod.metadata.uid ? prior.get(pod.metadata.uid) : void 0;
|
|
168
|
+
const add = (reason, message) => entries.push({
|
|
169
|
+
id: `${pod.metadata.uid ?? pod.metadata.name}/${reason}/${observedAt}`,
|
|
170
|
+
reason,
|
|
171
|
+
message,
|
|
172
|
+
time: validTime(observedAt),
|
|
173
|
+
count: 1,
|
|
174
|
+
certainty: validTime(observedAt) ? "observed" : "unknown",
|
|
175
|
+
objectUid: pod.metadata.uid,
|
|
176
|
+
gap: "Change occurred between snapshots; exact transition time is unknown"
|
|
177
|
+
});
|
|
178
|
+
if (!old) {
|
|
179
|
+
add("FirstObserved", `${pod.metadata.name ?? "Pod"} first observed; creation or rollout time is unknown`);
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
if (old.status?.phase !== pod.status?.phase) add("PhaseChanged", `${old.status?.phase ?? "Unknown"} → ${pod.status?.phase ?? "Unknown"}`);
|
|
183
|
+
for (const status of pod.status?.containerStatuses ?? []) {
|
|
184
|
+
const before = old.status?.containerStatuses?.find((item) => item.name === status.name);
|
|
185
|
+
if (before && status.restartCount !== before.restartCount) add(`Restarts/${status.name}`, `${status.name}: restart count ${before.restartCount} → ${status.restartCount}`);
|
|
186
|
+
if (before && status.ready !== before.ready) add(`Readiness/${status.name}`, `${status.name}: ready ${String(before.ready)} → ${String(status.ready)}`);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return entries;
|
|
190
|
+
}
|
|
191
|
+
function observeResourceChanges(previous, current, observedAt) {
|
|
192
|
+
const entries = observePodChanges(previous, current.filter((object) => object.kind === "Pod" || !!object.spec?.containers), observedAt);
|
|
193
|
+
const prior = new Map(previous.filter((object) => object.metadata.uid).map((object) => [object.metadata.uid, object]));
|
|
194
|
+
for (const object of current) {
|
|
195
|
+
if (object.kind === "Pod" || object.spec?.containers) continue;
|
|
196
|
+
const old = object.metadata.uid ? prior.get(object.metadata.uid) : void 0;
|
|
197
|
+
if (!old) continue;
|
|
198
|
+
const changes = [
|
|
199
|
+
"readyReplicas",
|
|
200
|
+
"updatedReplicas",
|
|
201
|
+
"observedGeneration"
|
|
202
|
+
].filter((key) => old.status?.[key] !== object.status?.[key]).map((key) => `${key}: ${old.status?.[key] ?? "unknown"} → ${object.status?.[key] ?? "unknown"}`);
|
|
203
|
+
if (old.metadata.generation !== object.metadata.generation) changes.push(`generation: ${old.metadata.generation ?? "unknown"} → ${object.metadata.generation ?? "unknown"}`);
|
|
204
|
+
const revisionKey = "deployment.kubernetes.io/revision";
|
|
205
|
+
if (old.metadata.annotations?.[revisionKey] !== object.metadata.annotations?.[revisionKey]) changes.push(`revision: ${old.metadata.annotations?.[revisionKey] ?? "unknown"} → ${object.metadata.annotations?.[revisionKey] ?? "unknown"}`);
|
|
206
|
+
if (changes.length) entries.push({
|
|
207
|
+
id: `${object.metadata.uid}/rollout/${observedAt}`,
|
|
208
|
+
reason: "RolloutObserved",
|
|
209
|
+
message: `${object.metadata.name ?? "Workload"}: ${changes.join(", ")}`,
|
|
210
|
+
time: validTime(observedAt),
|
|
211
|
+
count: 1,
|
|
212
|
+
certainty: validTime(observedAt) ? "observed" : "unknown",
|
|
213
|
+
objectUid: object.metadata.uid,
|
|
214
|
+
gap: "Change occurred between snapshots; exact transition time is unknown"
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
return entries;
|
|
218
|
+
}
|
|
219
|
+
//#endregion
|
|
220
|
+
exports.buildConsumerGroups = buildConsumerGroups;
|
|
221
|
+
exports.diagnosePendingPod = diagnosePendingPod;
|
|
222
|
+
exports.effectivePodResource = effectivePodResource;
|
|
223
|
+
exports.normalizeEvents = normalizeEvents;
|
|
224
|
+
exports.observePodChanges = observePodChanges;
|
|
225
|
+
exports.observeResourceChanges = observeResourceChanges;
|
|
226
|
+
|
|
227
|
+
//# sourceMappingURL=resource-diagnostics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resource-diagnostics.js","names":[],"sources":["../../../../src/common/resource-diagnostics.ts"],"sourcesContent":["import { effectivePodResource as effectiveResource, parseQuantity } from \"./monitoring-math\";\n\nexport interface ResourceValues {\n requests?: Partial<Record<string, string>>;\n limits?: Partial<Record<string, string>>;\n}\nexport interface DiagnosticsObject {\n kind?: string;\n metadata: {\n uid?: string;\n name?: string;\n namespace?: string;\n labels?: Partial<Record<string, string>>;\n generation?: number;\n annotations?: Partial<Record<string, string>>;\n ownerReferences?: { uid: string; name?: string; kind?: string; controller?: boolean }[];\n };\n spec?: {\n nodeName?: string;\n schedulerName?: string;\n containers?: { resources?: ResourceValues }[];\n initContainers?: { resources?: ResourceValues; restartPolicy?: string }[];\n resources?: ResourceValues;\n overhead?: Partial<Record<string, string>>;\n nodeSelector?: Partial<Record<string, string>>;\n tolerations?: { key?: string; operator?: string; value?: string; effect?: string; tolerationSeconds?: number }[];\n taints?: { key: string; value?: string; effect: string }[];\n unschedulable?: boolean;\n affinity?: {\n nodeAffinity?: {\n requiredDuringSchedulingIgnoredDuringExecution?: unknown;\n };\n podAffinity?: unknown;\n podAntiAffinity?: unknown;\n };\n topologySpreadConstraints?: unknown[];\n volumes?: { persistentVolumeClaim?: { claimName: string } }[];\n };\n status?: {\n phase?: string;\n readyReplicas?: number;\n updatedReplicas?: number;\n observedGeneration?: number;\n conditions?: { type: string; status: string; reason?: string; message?: string; lastTransitionTime?: string }[];\n containerStatuses?: { name: string; restartCount: number; ready?: boolean }[];\n allocatable?: Partial<Record<string, string>>;\n };\n}\nexport interface PodUsage {\n uid: string;\n cpu?: number;\n memory?: number;\n}\nexport interface ResourceSummary {\n requests: number;\n scheduledRequests: number;\n unscheduledRequests: number;\n usage?: number;\n coveredPods: number;\n totalPods: number;\n unknownRequestPods: number;\n}\nexport interface ConsumerGroup {\n namespace: string;\n identity: string;\n kind: string;\n name: string;\n ownerResolved: boolean;\n pods: DiagnosticsObject[];\n cpu: ResourceSummary;\n memory: ResourceSummary;\n}\nexport { parseQuantity } from \"./monitoring-math\";\nexport function effectivePodResource(\n pod: DiagnosticsObject,\n metric: \"cpu\" | \"memory\",\n kind: \"requests\" | \"limits\" = \"requests\",\n): number {\n return effectiveResource(pod, metric, kind);\n}\nexport function buildConsumerGroups(\n pods: DiagnosticsObject[],\n owners: DiagnosticsObject[],\n usage: PodUsage[] = [],\n): ConsumerGroup[] {\n const objects = new Map(owners.filter((o) => o.metadata.uid).map((o) => [o.metadata.uid, o]));\n const metrics = new Map(usage.map((u) => [u.uid, u]));\n const groups = new Map<string, ConsumerGroup>();\n for (const [index, pod] of pods.entries()) {\n if (pod.status?.phase === \"Succeeded\" || pod.status?.phase === \"Failed\") continue;\n let owner = pod;\n let resolved = true;\n const visited = new Set<string>();\n let unresolved: { uid: string; name?: string; kind?: string } | undefined;\n while (true) {\n const references = owner.metadata.ownerReferences ?? [];\n const reference = references.find((r) => r.controller) ?? (references.length === 1 ? references[0] : undefined);\n if (!reference) break;\n if (visited.has(reference.uid)) {\n resolved = false;\n break;\n }\n visited.add(reference.uid);\n const next = objects.get(reference.uid);\n if (!next || next.metadata.namespace !== pod.metadata.namespace) {\n unresolved = reference;\n resolved = false;\n break;\n }\n owner = next;\n }\n const namespace = pod.metadata.namespace ?? \"default\";\n const identity = unresolved?.uid ?? owner.metadata.uid ?? `unidentified-pod-${index}`;\n const key = `${namespace}/${identity}`;\n let group = groups.get(key);\n if (!group) {\n const summary = (): ResourceSummary => ({\n requests: 0,\n scheduledRequests: 0,\n unscheduledRequests: 0,\n coveredPods: 0,\n totalPods: 0,\n unknownRequestPods: 0,\n });\n group = {\n namespace,\n identity,\n kind: unresolved?.kind ?? owner.kind ?? \"Pod\",\n name: unresolved?.name ?? owner.metadata.name ?? \"Unknown\",\n ownerResolved: resolved,\n pods: [],\n cpu: summary(),\n memory: summary(),\n };\n groups.set(key, group);\n }\n group.pods.push(pod);\n for (const metric of [\"cpu\", \"memory\"] as const) {\n const summary = group[metric];\n summary.totalPods++;\n try {\n const request = effectivePodResource(pod, metric);\n summary.requests += request;\n summary[pod.spec?.nodeName ? \"scheduledRequests\" : \"unscheduledRequests\"] += request;\n } catch {\n summary.unknownRequestPods++;\n }\n const value = pod.metadata.uid ? metrics.get(pod.metadata.uid)?.[metric] : undefined;\n if (value !== undefined && Number.isFinite(value) && value >= 0) {\n summary.coveredPods++;\n summary.usage = (summary.usage ?? 0) + value;\n }\n }\n }\n return [...groups.values()];\n}\nexport interface DiagnosticsEvent {\n metadata?: { uid?: string; creationTimestamp?: string };\n involvedObject?: { uid?: string; name?: string; namespace?: string };\n regarding?: { uid?: string; name?: string; namespace?: string };\n reason?: string;\n message?: string;\n note?: string;\n type?: string;\n count?: number;\n firstTimestamp?: string;\n lastTimestamp?: string;\n eventTime?: string;\n series?: { count?: number; lastObservedTime?: string };\n}\nexport interface TimelineEntry {\n id: string;\n reason: string;\n message: string;\n time?: string;\n firstTime?: string;\n count: number;\n certainty: \"reported\" | \"observed\" | \"unknown\";\n objectUid?: string;\n gap?: string;\n}\nconst validTime = (value?: string) => (value && Number.isFinite(Date.parse(value)) ? value : undefined);\nexport function normalizeEvents(events: DiagnosticsEvent[]): TimelineEntry[] {\n return events\n .map((event, index) => ({\n id: event.metadata?.uid ?? `event-${index}`,\n reason: event.reason ?? \"Event\",\n message: event.message ?? event.note ?? \"\",\n time:\n validTime(event.series?.lastObservedTime) ??\n validTime(event.lastTimestamp) ??\n validTime(event.eventTime) ??\n validTime(event.metadata?.creationTimestamp),\n firstTime: validTime(event.firstTimestamp) ?? validTime(event.eventTime),\n count: event.series?.count ?? event.count ?? 1,\n certainty: \"reported\" as const,\n objectUid: event.involvedObject?.uid ?? event.regarding?.uid,\n }))\n .map((entry) => ({ ...entry, certainty: entry.time ? entry.certainty : (\"unknown\" as const) }));\n}\nexport interface PendingEvidence {\n source: \"event\" | \"constraint\";\n message: string;\n node?: string;\n}\nexport function diagnosePendingPod(\n pod: DiagnosticsObject,\n nodes: DiagnosticsObject[],\n events: DiagnosticsEvent[] = [],\n pvcs?: DiagnosticsObject[],\n): { state: \"assigned-waiting\" | \"unscheduled\" | \"not-pending\"; evidence: PendingEvidence[]; limitations: string[] } {\n const state =\n pod.status?.phase !== \"Pending\" ? \"not-pending\" : pod.spec?.nodeName ? \"assigned-waiting\" : \"unscheduled\";\n const evidence: PendingEvidence[] = events\n .filter((event) => !!pod.metadata.uid && (event.involvedObject?.uid ?? event.regarding?.uid) === pod.metadata.uid)\n .map((event) => ({ source: \"event\", message: `${event.reason ?? \"Event\"}: ${event.message ?? event.note ?? \"\"}` }));\n const limitations = [\"Local checks do not establish exact schedulability or available node capacity\"];\n if (state !== \"unscheduled\") return { state, evidence, limitations };\n const spec = pod.spec;\n if (!nodes.length) limitations.push(\"Node data unavailable\");\n if (spec?.schedulerName && spec.schedulerName !== \"default-scheduler\")\n limitations.push(\"Custom scheduler profile is unknown\");\n if (spec?.affinity?.podAffinity || spec?.affinity?.podAntiAffinity || spec?.topologySpreadConstraints?.length)\n limitations.push(\"Pod affinity and topology constraints are not evaluated\");\n for (const node of nodes) {\n const reject = (message: string) => evidence.push({ source: \"constraint\", node: node.metadata.name, message });\n if (node.spec?.unschedulable) reject(\"Node is cordoned\");\n if (Object.entries(spec?.nodeSelector ?? {}).some(([key, value]) => node.metadata.labels?.[key] !== value))\n reject(\"Node selector does not match\");\n for (const taint of node.spec?.taints ?? []) {\n if (![\"NoSchedule\", \"NoExecute\"].includes(taint.effect)) continue;\n if (\n !(spec?.tolerations ?? []).some(\n (t) =>\n (!t.effect || t.effect === taint.effect) &&\n (t.operator === \"Exists\"\n ? !t.key || t.key === taint.key\n : t.key === taint.key && (t.value ?? \"\") === (taint.value ?? \"\")),\n )\n )\n reject(`Untolerated taint ${taint.key} (${taint.effect})`);\n }\n const required = spec?.affinity?.nodeAffinity?.requiredDuringSchedulingIgnoredDuringExecution;\n const terms =\n required &&\n typeof required === \"object\" &&\n \"nodeSelectorTerms\" in required &&\n Array.isArray(required.nodeSelectorTerms)\n ? (required.nodeSelectorTerms as {\n matchExpressions?: { key: string; operator: string; values?: string[] }[];\n matchFields?: unknown[];\n }[])\n : undefined;\n if (required && !terms) limitations.push(\"Required node affinity data is unsupported\");\n if (terms) {\n const unsupported = terms.some(\n (term) =>\n term.matchFields?.length ||\n term.matchExpressions?.some(\n (e) => ![\"In\", \"NotIn\", \"Exists\", \"DoesNotExist\", \"Gt\", \"Lt\"].includes(e.operator),\n ),\n );\n if (unsupported) {\n if (!limitations.includes(\"Required node affinity contains unsupported expressions\"))\n limitations.push(\"Required node affinity contains unsupported expressions\");\n } else if (\n !terms.some(\n (term) =>\n !!term.matchExpressions?.length &&\n term.matchExpressions.every((e) => {\n const value = node.metadata.labels?.[e.key];\n if (e.operator === \"Exists\") return value !== undefined;\n if (e.operator === \"DoesNotExist\") return value === undefined;\n if (e.operator === \"In\") return value !== undefined && !!e.values?.includes(value);\n if (e.operator === \"NotIn\") return value === undefined || !e.values?.includes(value);\n return (\n value !== undefined &&\n !!e.values?.length &&\n Number.isFinite(Number(value)) &&\n (e.operator === \"Gt\" ? Number(value) > Number(e.values[0]) : Number(value) < Number(e.values[0]))\n );\n }),\n )\n )\n reject(\"Required node affinity does not match\");\n }\n for (const metric of [\"cpu\", \"memory\"] as const) {\n try {\n if (\n node.status?.allocatable?.[metric] !== undefined &&\n effectivePodResource(pod, metric) > parseQuantity(node.status.allocatable[metric], metric === \"memory\")\n )\n reject(`Pod ${metric} request exceeds node allocatable`);\n } catch {\n limitations.push(`Invalid or unavailable ${metric} resource data`);\n }\n }\n }\n for (const volume of spec?.volumes ?? []) {\n const claim = volume.persistentVolumeClaim?.claimName;\n if (!claim) continue;\n const pvc = pvcs?.find(\n (item) => item.metadata.name === claim && item.metadata.namespace === pod.metadata.namespace,\n );\n if (!pvc) limitations.push(`PVC ${claim} data unavailable`);\n else if (pvc.status?.phase !== \"Bound\")\n limitations.push(`PVC ${claim} is not bound; delayed binding and storage topology require scheduler evidence`);\n }\n return { state, evidence, limitations: [...new Set(limitations)] };\n}\nexport function observePodChanges(\n previous: DiagnosticsObject[],\n current: DiagnosticsObject[],\n observedAt: string,\n): TimelineEntry[] {\n const entries: TimelineEntry[] = [];\n const prior = new Map(previous.filter((pod) => pod.metadata.uid).map((pod) => [pod.metadata.uid, pod]));\n for (const pod of current) {\n const old = pod.metadata.uid ? prior.get(pod.metadata.uid) : undefined;\n const add = (reason: string, message: string) =>\n entries.push({\n id: `${pod.metadata.uid ?? pod.metadata.name}/${reason}/${observedAt}`,\n reason,\n message,\n time: validTime(observedAt),\n count: 1,\n certainty: validTime(observedAt) ? \"observed\" : \"unknown\",\n objectUid: pod.metadata.uid,\n gap: \"Change occurred between snapshots; exact transition time is unknown\",\n });\n if (!old) {\n add(\"FirstObserved\", `${pod.metadata.name ?? \"Pod\"} first observed; creation or rollout time is unknown`);\n continue;\n }\n if (old.status?.phase !== pod.status?.phase)\n add(\"PhaseChanged\", `${old.status?.phase ?? \"Unknown\"} → ${pod.status?.phase ?? \"Unknown\"}`);\n for (const status of pod.status?.containerStatuses ?? []) {\n const before = old.status?.containerStatuses?.find((item) => item.name === status.name);\n if (before && status.restartCount !== before.restartCount)\n add(`Restarts/${status.name}`, `${status.name}: restart count ${before.restartCount} → ${status.restartCount}`);\n if (before && status.ready !== before.ready)\n add(`Readiness/${status.name}`, `${status.name}: ready ${String(before.ready)} → ${String(status.ready)}`);\n }\n }\n return entries;\n}\n\nexport function observeResourceChanges(\n previous: DiagnosticsObject[],\n current: DiagnosticsObject[],\n observedAt: string,\n): TimelineEntry[] {\n const entries = observePodChanges(\n previous,\n current.filter((object) => object.kind === \"Pod\" || !!object.spec?.containers),\n observedAt,\n );\n const prior = new Map(\n previous.filter((object) => object.metadata.uid).map((object) => [object.metadata.uid, object]),\n );\n for (const object of current) {\n if (object.kind === \"Pod\" || object.spec?.containers) continue;\n const old = object.metadata.uid ? prior.get(object.metadata.uid) : undefined;\n if (!old) continue;\n const changes = ([\"readyReplicas\", \"updatedReplicas\", \"observedGeneration\"] as const)\n .filter((key) => old.status?.[key] !== object.status?.[key])\n .map((key) => `${key}: ${old.status?.[key] ?? \"unknown\"} → ${object.status?.[key] ?? \"unknown\"}`);\n if (old.metadata.generation !== object.metadata.generation)\n changes.push(`generation: ${old.metadata.generation ?? \"unknown\"} → ${object.metadata.generation ?? \"unknown\"}`);\n const revisionKey = \"deployment.kubernetes.io/revision\";\n if (old.metadata.annotations?.[revisionKey] !== object.metadata.annotations?.[revisionKey])\n changes.push(\n `revision: ${old.metadata.annotations?.[revisionKey] ?? \"unknown\"} → ${object.metadata.annotations?.[revisionKey] ?? \"unknown\"}`,\n );\n if (changes.length)\n entries.push({\n id: `${object.metadata.uid}/rollout/${observedAt}`,\n reason: \"RolloutObserved\",\n message: `${object.metadata.name ?? \"Workload\"}: ${changes.join(\", \")}`,\n time: validTime(observedAt),\n count: 1,\n certainty: validTime(observedAt) ? \"observed\" : \"unknown\",\n objectUid: object.metadata.uid,\n gap: \"Change occurred between snapshots; exact transition time is unknown\",\n });\n }\n return entries;\n}\n"],"mappings":"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"}
|
|
@@ -1,23 +1,46 @@
|
|
|
1
1
|
const require_extensions = require("../../../_virtual/_global-external_@freelensapp/extensions.js");
|
|
2
2
|
const require__global_external_mobx = require("../../../_virtual/_global-external_mobx.js");
|
|
3
|
+
const require_monitoring_history = require("../monitoring-history.js");
|
|
3
4
|
//#region src/common/store/monitoring-preferences-store.ts
|
|
4
5
|
var MonitoringPreferencesStore = class extends require_extensions.Common.Store.ExtensionStore {
|
|
5
6
|
enabled = false;
|
|
7
|
+
historyEnabled = false;
|
|
8
|
+
trackedHistory = [];
|
|
6
9
|
constructor() {
|
|
7
10
|
super({
|
|
8
11
|
configName: "monitoring-preferences",
|
|
9
|
-
defaults: {
|
|
12
|
+
defaults: {
|
|
13
|
+
enabled: false,
|
|
14
|
+
historyEnabled: false,
|
|
15
|
+
trackedHistory: []
|
|
16
|
+
}
|
|
10
17
|
});
|
|
11
18
|
require__global_external_mobx.makeObservable(this, {
|
|
12
19
|
enabled: require__global_external_mobx.observable,
|
|
20
|
+
historyEnabled: require__global_external_mobx.observable,
|
|
21
|
+
trackedHistory: require__global_external_mobx.observable,
|
|
13
22
|
fromStore: require__global_external_mobx.action
|
|
14
23
|
});
|
|
15
24
|
}
|
|
16
25
|
fromStore(data) {
|
|
17
26
|
this.enabled = data?.enabled === true;
|
|
27
|
+
this.historyEnabled = data?.historyEnabled === true;
|
|
28
|
+
this.trackedHistory = Array.isArray(data?.trackedHistory) ? data.trackedHistory.filter(require_monitoring_history.validHistoryIdentity).slice(0, 100).map(({ clusterId, scope, uid }) => ({
|
|
29
|
+
clusterId,
|
|
30
|
+
scope,
|
|
31
|
+
uid
|
|
32
|
+
})) : [];
|
|
18
33
|
}
|
|
19
34
|
toJSON() {
|
|
20
|
-
return {
|
|
35
|
+
return {
|
|
36
|
+
enabled: this.enabled,
|
|
37
|
+
historyEnabled: this.historyEnabled,
|
|
38
|
+
trackedHistory: this.trackedHistory.map(({ clusterId, scope, uid }) => ({
|
|
39
|
+
clusterId,
|
|
40
|
+
scope,
|
|
41
|
+
uid
|
|
42
|
+
}))
|
|
43
|
+
};
|
|
21
44
|
}
|
|
22
45
|
};
|
|
23
46
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"monitoring-preferences-store.js","names":[],"sources":["../../../../../src/common/store/monitoring-preferences-store.ts"],"sourcesContent":["import { Common } from \"@freelensapp/extensions\";\nimport { action, makeObservable, observable } from \"mobx\";\n\nexport class MonitoringPreferencesStore extends Common.Store.ExtensionStore<{
|
|
1
|
+
{"version":3,"file":"monitoring-preferences-store.js","names":[],"sources":["../../../../../src/common/store/monitoring-preferences-store.ts"],"sourcesContent":["import { Common } from \"@freelensapp/extensions\";\nimport { action, makeObservable, observable } from \"mobx\";\nimport { type HistoryIdentity, validHistoryIdentity } from \"../monitoring-history\";\n\nexport class MonitoringPreferencesStore extends Common.Store.ExtensionStore<{\n enabled: boolean;\n historyEnabled: boolean;\n trackedHistory: HistoryIdentity[];\n}> {\n enabled = false;\n historyEnabled = false;\n trackedHistory: HistoryIdentity[] = [];\n\n constructor() {\n super({\n configName: \"monitoring-preferences\",\n defaults: { enabled: false, historyEnabled: false, trackedHistory: [] },\n });\n makeObservable(this, {\n enabled: observable,\n historyEnabled: observable,\n trackedHistory: observable,\n fromStore: action,\n });\n }\n\n fromStore(data: { enabled?: boolean; historyEnabled?: boolean; trackedHistory?: HistoryIdentity[] }): void {\n this.enabled = data?.enabled === true;\n this.historyEnabled = data?.historyEnabled === true;\n this.trackedHistory = Array.isArray(data?.trackedHistory)\n ? data.trackedHistory\n .filter(validHistoryIdentity)\n .slice(0, 100)\n .map(({ clusterId, scope, uid }) => ({ clusterId, scope, uid }))\n : [];\n }\n\n toJSON(): { enabled: boolean; historyEnabled: boolean; trackedHistory: HistoryIdentity[] } {\n return {\n enabled: this.enabled,\n historyEnabled: this.historyEnabled,\n trackedHistory: this.trackedHistory.map(({ clusterId, scope, uid }) => ({ clusterId, scope, uid })),\n };\n }\n}\n"],"mappings":";;;;AAIA,IAAa,6BAAb,cAAgD,mBAAA,OAAO,MAAM,eAI1D;CACD,UAAU;CACV,iBAAiB;CACjB,iBAAoC,CAAC;CAErC,cAAc;EACZ,MAAM;GACJ,YAAY;GACZ,UAAU;IAAE,SAAS;IAAO,gBAAgB;IAAO,gBAAgB,CAAC;GAAE;EACxE,CAAC;EACD,8BAAA,eAAe,MAAM;GACnB,SAAS,8BAAA;GACT,gBAAgB,8BAAA;GAChB,gBAAgB,8BAAA;GAChB,WAAW,8BAAA;EACb,CAAC;CACH;CAEA,UAAU,MAAiG;EACzG,KAAK,UAAU,MAAM,YAAY;EACjC,KAAK,iBAAiB,MAAM,mBAAmB;EAC/C,KAAK,iBAAiB,MAAM,QAAQ,MAAM,cAAc,IACpD,KAAK,eACF,OAAO,2BAAA,oBAAoB,CAAC,CAC5B,MAAM,GAAG,GAAG,CAAC,CACb,KAAK,EAAE,WAAW,OAAO,WAAW;GAAE;GAAW;GAAO;EAAI,EAAE,IACjE,CAAC;CACP;CAEA,SAA2F;EACzF,OAAO;GACL,SAAS,KAAK;GACd,gBAAgB,KAAK;GACrB,gBAAgB,KAAK,eAAe,KAAK,EAAE,WAAW,OAAO,WAAW;IAAE;IAAW;IAAO;GAAI,EAAE;EACpG;CACF;AACF"}
|
package/out/renderer/welcome.js
CHANGED
|
@@ -18,7 +18,9 @@ function createWelcomeContent() {
|
|
|
18
18
|
"🔐 Secure Node Shell with custom commands, IPv6 and automatic Colima support",
|
|
19
19
|
"📜 Certificate details in Secrets",
|
|
20
20
|
"🎨 Accent themes for Freelens",
|
|
21
|
-
"🔗 Website dashboards with flexible cards and background refresh",
|
|
21
|
+
"🔗 Website dashboards with flexible cards, pinned windows and background refresh",
|
|
22
|
+
"📈 Cluster, node and pod metrics with optional local history",
|
|
23
|
+
"🔎 Resource consumers, application timelines and Pending diagnostics",
|
|
22
24
|
"🤖 Context-aware AI chat with read-only tools and prompt shortcuts",
|
|
23
25
|
"🔒 Read-only UI controls for safer browsing"
|
|
24
26
|
]) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"welcome.js","names":[],"sources":["../../src/renderer/welcome.ts"],"sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\nconst WELCOME_SELECTOR = '.Welcome [data-testid=\"welcome-text-container\"]';\nconst HOST_ATTRIBUTE = \"data-freelens-power-welcome\";\nconst CONTENT_ATTRIBUTE = \"data-freelens-power-welcome-content\";\n\nfunction createWelcomeContent(): HTMLDivElement {\n const content = document.createElement(\"div\");\n content.setAttribute(CONTENT_ATTRIBUTE, \"\");\n\n const heading = document.createElement(\"h2\");\n heading.textContent = \"🔋 Freelens Power\";\n content.append(heading);\n\n const introduction = document.createElement(\"p\");\n introduction.textContent = \"Make Freelens your own with practical tools for everyday Kubernetes work.\";\n content.append(introduction);\n\n const features = document.createElement(\"ul\");\n features.className = \"freelens-power-features\";\n features.setAttribute(\"role\", \"list\");\n\n for (const text of [\n \"🔐 Secure Node Shell with custom commands, IPv6 and automatic Colima support\",\n \"📜 Certificate details in Secrets\",\n \"🎨 Accent themes for Freelens\",\n \"🔗 Website dashboards with flexible cards and background refresh\",\n \"🤖 Context-aware AI chat with read-only tools and prompt shortcuts\",\n \"🔒 Read-only UI controls for safer browsing\",\n ]) {\n const feature = document.createElement(\"li\");\n feature.setAttribute(\"role\", \"listitem\");\n feature.textContent = text;\n features.append(feature);\n }\n\n content.append(features);\n\n const paragraph = document.createElement(\"p\");\n const link = document.createElement(\"a\");\n link.className = \"link\";\n link.href = \"https://github.com/64mb/freelens-power\";\n link.target = \"_blank\";\n link.rel = \"noopener noreferrer\";\n link.textContent = \"Freelens Power on GitHub\";\n paragraph.append(link);\n content.append(paragraph);\n\n return content;\n}\n\nexport function startWelcomeOverride(): () => void {\n const style = document.createElement(\"style\");\n style.setAttribute(\"data-freelens-power\", \"welcome\");\n style.textContent = `\n .Welcome [${HOST_ATTRIBUTE}] > h2,\n .Welcome [${HOST_ATTRIBUTE}] > p { display: none; }\n .Welcome [${CONTENT_ATTRIBUTE}] { color: var(--textColorSecondary); }\n .Welcome [${CONTENT_ATTRIBUTE}] h2 { color: var(--textColorPrimary); margin: 15px 0 16px; }\n .Welcome [${CONTENT_ATTRIBUTE}] .freelens-power-features { display: flex; flex-direction: column; gap: 12px; list-style: none; padding: 16px 0; margin: 16px 0; border-top: 1px solid var(--borderColor); border-bottom: 1px solid var(--borderColor); text-align: left; line-height: 1.5; }\n .Welcome [${CONTENT_ATTRIBUTE}] .freelens-power-features > li, .Welcome [${CONTENT_ATTRIBUTE}] .freelens-power-features > li:hover { margin: 0; padding: 0; background: none; border: 0; border-radius: 0; box-shadow: none; cursor: default; color: inherit; text-decoration: none; transform: none; transition: none; }\n .Welcome [${CONTENT_ATTRIBUTE}] p { margin-top: 14px; }\n `;\n document.head.append(style);\n\n const hosts = new Map<Element, { content: HTMLDivElement; previousAttribute: string | null }>();\n\n const restore = (host: Element) => {\n const entry = hosts.get(host);\n if (!entry) return;\n\n entry.content.remove();\n if (entry.previousAttribute === null) {\n host.removeAttribute(HOST_ATTRIBUTE);\n } else {\n host.setAttribute(HOST_ATTRIBUTE, entry.previousAttribute);\n }\n hosts.delete(host);\n };\n\n const attach = (host: Element) => {\n if (hosts.has(host)) return;\n\n const content = createWelcomeContent();\n hosts.set(host, { content, previousAttribute: host.getAttribute(HOST_ATTRIBUTE) });\n host.setAttribute(HOST_ATTRIBUTE, \"\");\n host.prepend(content);\n };\n\n const scan = (node: Element) => {\n if (node.matches(WELCOME_SELECTOR)) attach(node);\n for (const host of node.querySelectorAll(WELCOME_SELECTOR)) attach(host);\n };\n\n scan(document.body);\n\n const observer = new MutationObserver((mutations) => {\n for (const host of hosts.keys()) {\n if (!host.isConnected) restore(host);\n }\n\n for (const mutation of mutations) {\n for (const node of mutation.addedNodes) {\n if (node instanceof Element && node.isConnected) scan(node);\n }\n }\n });\n observer.observe(document.body, { childList: true, subtree: true });\n\n return () => {\n observer.disconnect();\n for (const host of hosts.keys()) restore(host);\n style.remove();\n };\n}\n"],"mappings":";AAEA,IAAM,mBAAmB;AACzB,IAAM,iBAAiB;AACvB,IAAM,oBAAoB;AAE1B,SAAS,uBAAuC;CAC9C,MAAM,UAAU,SAAS,cAAc,KAAK;CAC5C,QAAQ,aAAa,mBAAmB,EAAE;CAE1C,MAAM,UAAU,SAAS,cAAc,IAAI;CAC3C,QAAQ,cAAc;CACtB,QAAQ,OAAO,OAAO;CAEtB,MAAM,eAAe,SAAS,cAAc,GAAG;CAC/C,aAAa,cAAc;CAC3B,QAAQ,OAAO,YAAY;CAE3B,MAAM,WAAW,SAAS,cAAc,IAAI;CAC5C,SAAS,YAAY;CACrB,SAAS,aAAa,QAAQ,MAAM;CAEpC,KAAK,MAAM,QAAQ;EACjB;EACA;EACA;EACA;EACA;EACA;CACF,GAAG;EACD,MAAM,UAAU,SAAS,cAAc,IAAI;EAC3C,QAAQ,aAAa,QAAQ,UAAU;EACvC,QAAQ,cAAc;EACtB,SAAS,OAAO,OAAO;CACzB;CAEA,QAAQ,OAAO,QAAQ;CAEvB,MAAM,YAAY,SAAS,cAAc,GAAG;CAC5C,MAAM,OAAO,SAAS,cAAc,GAAG;CACvC,KAAK,YAAY;CACjB,KAAK,OAAO;CACZ,KAAK,SAAS;CACd,KAAK,MAAM;CACX,KAAK,cAAc;CACnB,UAAU,OAAO,IAAI;CACrB,QAAQ,OAAO,SAAS;CAExB,OAAO;AACT;AAEA,SAAgB,uBAAmC;CACjD,MAAM,QAAQ,SAAS,cAAc,OAAO;CAC5C,MAAM,aAAa,uBAAuB,SAAS;CACnD,MAAM,cAAc;gBACN,eAAe;gBACf,eAAe;gBACf,kBAAkB;gBAClB,kBAAkB;gBAClB,kBAAkB;gBAClB,kBAAkB,6CAA6C,kBAAkB;gBACjF,kBAAkB;;CAEhC,SAAS,KAAK,OAAO,KAAK;CAE1B,MAAM,wBAAQ,IAAI,IAA4E;CAE9F,MAAM,WAAW,SAAkB;EACjC,MAAM,QAAQ,MAAM,IAAI,IAAI;EAC5B,IAAI,CAAC,OAAO;EAEZ,MAAM,QAAQ,OAAO;EACrB,IAAI,MAAM,sBAAsB,MAC9B,KAAK,gBAAgB,cAAc;OAEnC,KAAK,aAAa,gBAAgB,MAAM,iBAAiB;EAE3D,MAAM,OAAO,IAAI;CACnB;CAEA,MAAM,UAAU,SAAkB;EAChC,IAAI,MAAM,IAAI,IAAI,GAAG;EAErB,MAAM,UAAU,qBAAqB;EACrC,MAAM,IAAI,MAAM;GAAE;GAAS,mBAAmB,KAAK,aAAa,cAAc;EAAE,CAAC;EACjF,KAAK,aAAa,gBAAgB,EAAE;EACpC,KAAK,QAAQ,OAAO;CACtB;CAEA,MAAM,QAAQ,SAAkB;EAC9B,IAAI,KAAK,QAAQ,gBAAgB,GAAG,OAAO,IAAI;EAC/C,KAAK,MAAM,QAAQ,KAAK,iBAAiB,gBAAgB,GAAG,OAAO,IAAI;CACzE;CAEA,KAAK,SAAS,IAAI;CAElB,MAAM,WAAW,IAAI,kBAAkB,cAAc;EACnD,KAAK,MAAM,QAAQ,MAAM,KAAK,GAC5B,IAAI,CAAC,KAAK,aAAa,QAAQ,IAAI;EAGrC,KAAK,MAAM,YAAY,WACrB,KAAK,MAAM,QAAQ,SAAS,YAC1B,IAAI,gBAAgB,WAAW,KAAK,aAAa,KAAK,IAAI;CAGhE,CAAC;CACD,SAAS,QAAQ,SAAS,MAAM;EAAE,WAAW;EAAM,SAAS;CAAK,CAAC;CAElE,aAAa;EACX,SAAS,WAAW;EACpB,KAAK,MAAM,QAAQ,MAAM,KAAK,GAAG,QAAQ,IAAI;EAC7C,MAAM,OAAO;CACf;AACF"}
|
|
1
|
+
{"version":3,"file":"welcome.js","names":[],"sources":["../../src/renderer/welcome.ts"],"sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\nconst WELCOME_SELECTOR = '.Welcome [data-testid=\"welcome-text-container\"]';\nconst HOST_ATTRIBUTE = \"data-freelens-power-welcome\";\nconst CONTENT_ATTRIBUTE = \"data-freelens-power-welcome-content\";\n\nfunction createWelcomeContent(): HTMLDivElement {\n const content = document.createElement(\"div\");\n content.setAttribute(CONTENT_ATTRIBUTE, \"\");\n\n const heading = document.createElement(\"h2\");\n heading.textContent = \"🔋 Freelens Power\";\n content.append(heading);\n\n const introduction = document.createElement(\"p\");\n introduction.textContent = \"Make Freelens your own with practical tools for everyday Kubernetes work.\";\n content.append(introduction);\n\n const features = document.createElement(\"ul\");\n features.className = \"freelens-power-features\";\n features.setAttribute(\"role\", \"list\");\n\n for (const text of [\n \"🔐 Secure Node Shell with custom commands, IPv6 and automatic Colima support\",\n \"📜 Certificate details in Secrets\",\n \"🎨 Accent themes for Freelens\",\n \"🔗 Website dashboards with flexible cards, pinned windows and background refresh\",\n \"📈 Cluster, node and pod metrics with optional local history\",\n \"🔎 Resource consumers, application timelines and Pending diagnostics\",\n \"🤖 Context-aware AI chat with read-only tools and prompt shortcuts\",\n \"🔒 Read-only UI controls for safer browsing\",\n ]) {\n const feature = document.createElement(\"li\");\n feature.setAttribute(\"role\", \"listitem\");\n feature.textContent = text;\n features.append(feature);\n }\n\n content.append(features);\n\n const paragraph = document.createElement(\"p\");\n const link = document.createElement(\"a\");\n link.className = \"link\";\n link.href = \"https://github.com/64mb/freelens-power\";\n link.target = \"_blank\";\n link.rel = \"noopener noreferrer\";\n link.textContent = \"Freelens Power on GitHub\";\n paragraph.append(link);\n content.append(paragraph);\n\n return content;\n}\n\nexport function startWelcomeOverride(): () => void {\n const style = document.createElement(\"style\");\n style.setAttribute(\"data-freelens-power\", \"welcome\");\n style.textContent = `\n .Welcome [${HOST_ATTRIBUTE}] > h2,\n .Welcome [${HOST_ATTRIBUTE}] > p { display: none; }\n .Welcome [${CONTENT_ATTRIBUTE}] { color: var(--textColorSecondary); }\n .Welcome [${CONTENT_ATTRIBUTE}] h2 { color: var(--textColorPrimary); margin: 15px 0 16px; }\n .Welcome [${CONTENT_ATTRIBUTE}] .freelens-power-features { display: flex; flex-direction: column; gap: 12px; list-style: none; padding: 16px 0; margin: 16px 0; border-top: 1px solid var(--borderColor); border-bottom: 1px solid var(--borderColor); text-align: left; line-height: 1.5; }\n .Welcome [${CONTENT_ATTRIBUTE}] .freelens-power-features > li, .Welcome [${CONTENT_ATTRIBUTE}] .freelens-power-features > li:hover { margin: 0; padding: 0; background: none; border: 0; border-radius: 0; box-shadow: none; cursor: default; color: inherit; text-decoration: none; transform: none; transition: none; }\n .Welcome [${CONTENT_ATTRIBUTE}] p { margin-top: 14px; }\n `;\n document.head.append(style);\n\n const hosts = new Map<Element, { content: HTMLDivElement; previousAttribute: string | null }>();\n\n const restore = (host: Element) => {\n const entry = hosts.get(host);\n if (!entry) return;\n\n entry.content.remove();\n if (entry.previousAttribute === null) {\n host.removeAttribute(HOST_ATTRIBUTE);\n } else {\n host.setAttribute(HOST_ATTRIBUTE, entry.previousAttribute);\n }\n hosts.delete(host);\n };\n\n const attach = (host: Element) => {\n if (hosts.has(host)) return;\n\n const content = createWelcomeContent();\n hosts.set(host, { content, previousAttribute: host.getAttribute(HOST_ATTRIBUTE) });\n host.setAttribute(HOST_ATTRIBUTE, \"\");\n host.prepend(content);\n };\n\n const scan = (node: Element) => {\n if (node.matches(WELCOME_SELECTOR)) attach(node);\n for (const host of node.querySelectorAll(WELCOME_SELECTOR)) attach(host);\n };\n\n scan(document.body);\n\n const observer = new MutationObserver((mutations) => {\n for (const host of hosts.keys()) {\n if (!host.isConnected) restore(host);\n }\n\n for (const mutation of mutations) {\n for (const node of mutation.addedNodes) {\n if (node instanceof Element && node.isConnected) scan(node);\n }\n }\n });\n observer.observe(document.body, { childList: true, subtree: true });\n\n return () => {\n observer.disconnect();\n for (const host of hosts.keys()) restore(host);\n style.remove();\n };\n}\n"],"mappings":";AAEA,IAAM,mBAAmB;AACzB,IAAM,iBAAiB;AACvB,IAAM,oBAAoB;AAE1B,SAAS,uBAAuC;CAC9C,MAAM,UAAU,SAAS,cAAc,KAAK;CAC5C,QAAQ,aAAa,mBAAmB,EAAE;CAE1C,MAAM,UAAU,SAAS,cAAc,IAAI;CAC3C,QAAQ,cAAc;CACtB,QAAQ,OAAO,OAAO;CAEtB,MAAM,eAAe,SAAS,cAAc,GAAG;CAC/C,aAAa,cAAc;CAC3B,QAAQ,OAAO,YAAY;CAE3B,MAAM,WAAW,SAAS,cAAc,IAAI;CAC5C,SAAS,YAAY;CACrB,SAAS,aAAa,QAAQ,MAAM;CAEpC,KAAK,MAAM,QAAQ;EACjB;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,GAAG;EACD,MAAM,UAAU,SAAS,cAAc,IAAI;EAC3C,QAAQ,aAAa,QAAQ,UAAU;EACvC,QAAQ,cAAc;EACtB,SAAS,OAAO,OAAO;CACzB;CAEA,QAAQ,OAAO,QAAQ;CAEvB,MAAM,YAAY,SAAS,cAAc,GAAG;CAC5C,MAAM,OAAO,SAAS,cAAc,GAAG;CACvC,KAAK,YAAY;CACjB,KAAK,OAAO;CACZ,KAAK,SAAS;CACd,KAAK,MAAM;CACX,KAAK,cAAc;CACnB,UAAU,OAAO,IAAI;CACrB,QAAQ,OAAO,SAAS;CAExB,OAAO;AACT;AAEA,SAAgB,uBAAmC;CACjD,MAAM,QAAQ,SAAS,cAAc,OAAO;CAC5C,MAAM,aAAa,uBAAuB,SAAS;CACnD,MAAM,cAAc;gBACN,eAAe;gBACf,eAAe;gBACf,kBAAkB;gBAClB,kBAAkB;gBAClB,kBAAkB;gBAClB,kBAAkB,6CAA6C,kBAAkB;gBACjF,kBAAkB;;CAEhC,SAAS,KAAK,OAAO,KAAK;CAE1B,MAAM,wBAAQ,IAAI,IAA4E;CAE9F,MAAM,WAAW,SAAkB;EACjC,MAAM,QAAQ,MAAM,IAAI,IAAI;EAC5B,IAAI,CAAC,OAAO;EAEZ,MAAM,QAAQ,OAAO;EACrB,IAAI,MAAM,sBAAsB,MAC9B,KAAK,gBAAgB,cAAc;OAEnC,KAAK,aAAa,gBAAgB,MAAM,iBAAiB;EAE3D,MAAM,OAAO,IAAI;CACnB;CAEA,MAAM,UAAU,SAAkB;EAChC,IAAI,MAAM,IAAI,IAAI,GAAG;EAErB,MAAM,UAAU,qBAAqB;EACrC,MAAM,IAAI,MAAM;GAAE;GAAS,mBAAmB,KAAK,aAAa,cAAc;EAAE,CAAC;EACjF,KAAK,aAAa,gBAAgB,EAAE;EACpC,KAAK,QAAQ,OAAO;CACtB;CAEA,MAAM,QAAQ,SAAkB;EAC9B,IAAI,KAAK,QAAQ,gBAAgB,GAAG,OAAO,IAAI;EAC/C,KAAK,MAAM,QAAQ,KAAK,iBAAiB,gBAAgB,GAAG,OAAO,IAAI;CACzE;CAEA,KAAK,SAAS,IAAI;CAElB,MAAM,WAAW,IAAI,kBAAkB,cAAc;EACnD,KAAK,MAAM,QAAQ,MAAM,KAAK,GAC5B,IAAI,CAAC,KAAK,aAAa,QAAQ,IAAI;EAGrC,KAAK,MAAM,YAAY,WACrB,KAAK,MAAM,QAAQ,SAAS,YAC1B,IAAI,gBAAgB,WAAW,KAAK,aAAa,KAAK,IAAI;CAGhE,CAAC;CACD,SAAS,QAAQ,SAAS,MAAM;EAAE,WAAW;EAAM,SAAS;CAAK,CAAC;CAElE,aAAa;EACX,SAAS,WAAW;EACpB,KAAK,MAAM,QAAQ,MAAM,KAAK,GAAG,QAAQ,IAAI;EAC7C,MAAM,OAAO;CACf;AACF"}
|