hmgr 0.0.6 → 0.0.7
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/dist/adapter/bundle-yaml.js +87 -0
- package/dist/adapter/git.js +148 -0
- package/dist/adapter/paket-version.js +25 -0
- package/dist/adapter/zustand-json.js +9 -2
- package/dist/cli/hilfe.js +99 -0
- package/dist/cli/main.js +159 -5
- package/dist/gui/main.js +101 -0
- package/dist/gui/preload.cjs +4 -0
- package/dist/gui/renderer/index.html +12 -1
- package/dist/gui/renderer/renderer.js +415 -107
- package/dist/gui/renderer/styles.css +20 -0
- package/dist/kern/anwendungsfaelle.js +450 -9
- package/dist/kern/modell.js +80 -0
- package/dist/ports/zustand.js +15 -1
- package/package.json +20 -5
|
@@ -303,6 +303,11 @@
|
|
|
303
303
|
var ZIELE = [];
|
|
304
304
|
var SKILLS = [];
|
|
305
305
|
var MARKETPLACES = [];
|
|
306
|
+
// Bundles aller bekannten Quellen (E69), entdeckt beim Quellen-Scan: kein eigener Katalog, keine
|
|
307
|
+
// eigene Ansicht. Grundlage der Bundle-Sektion im Dialog „Skills hinzufügen" (F68).
|
|
308
|
+
var BUNDLES = [];
|
|
309
|
+
// Definitionen, die sich nicht lesen ließen: genannt, damit eine kaputte Datei nicht stumm fehlt.
|
|
310
|
+
var BUNDLES_KAPUTT = [];
|
|
306
311
|
var QUELLEN = [];
|
|
307
312
|
var HARNESSE_ALLE = [];
|
|
308
313
|
var AKTIVE_HARNESSE = [];
|
|
@@ -404,6 +409,7 @@
|
|
|
404
409
|
rufe(function () { return window.hmgr.nichtVorhandeneHarnesses(); }),
|
|
405
410
|
rufe(function () { return window.hmgr.mcpUebersicht(); }),
|
|
406
411
|
rufe(function () { return window.hmgr.mcpPlaetze(); }),
|
|
412
|
+
rufe(function () { return window.hmgr.bundles(); }),
|
|
407
413
|
]);
|
|
408
414
|
ZIELE = ergebnisse[0];
|
|
409
415
|
SKILLS = ergebnisse[1];
|
|
@@ -418,6 +424,9 @@
|
|
|
418
424
|
MCP_FREMD = ergebnisse[7].unbekannt;
|
|
419
425
|
MCP_FREMD_GETEILT = ergebnisse[7].unbekannteGeteilteFundorte;
|
|
420
426
|
MCP_PLAETZE = ergebnisse[8];
|
|
427
|
+
BUNDLES = ergebnisse[9].bundles;
|
|
428
|
+
BUNDLES.sort(function (a, b) { return a.name.localeCompare(b.name, 'de') || a.quelleText.localeCompare(b.quelleText, 'de'); });
|
|
429
|
+
BUNDLES_KAPUTT = ergebnisse[9].kaputte;
|
|
421
430
|
STANDARD_REF = {};
|
|
422
431
|
SKILLS.forEach(function (s) { if (STANDARD_REF[s.quelleText] === undefined) STANDARD_REF[s.quelleText] = s.ref; });
|
|
423
432
|
|
|
@@ -652,6 +661,110 @@
|
|
|
652
661
|
return kz;
|
|
653
662
|
}
|
|
654
663
|
|
|
664
|
+
/** Defekte Links (ohne Quelle) zuerst, sie brauchen Aufmerksamkeit (E45), sonst alphabetisch. */
|
|
665
|
+
function sortiereEintraege(eintraege) {
|
|
666
|
+
return eintraege.slice().sort(function (a, b) {
|
|
667
|
+
var da = a.art === 'link-ohne-quelle', db = b.art === 'link-ohne-quelle';
|
|
668
|
+
if (da !== db) return da ? -1 : 1;
|
|
669
|
+
var na = a.art === 'link' ? a.link.name : a.name;
|
|
670
|
+
var nb = b.art === 'link' ? b.link.name : b.name;
|
|
671
|
+
return na.localeCompare(nb, 'de');
|
|
672
|
+
});
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
/** Eine Zeile der Link-Tabelle. `bundle` gesetzt heißt: die Zeile steht in einer Bundle-Gruppe
|
|
676
|
+
(E69), das Entfernen zerbricht dort das Bundle und der Dialog sagt es. */
|
|
677
|
+
function linkZeile(ei, z, bundle) {
|
|
678
|
+
var name = ei.art === 'link' ? ei.link.name : ei.name;
|
|
679
|
+
var li = e('li');
|
|
680
|
+
|
|
681
|
+
if (ei.art === 'link') li.appendChild(repoIcon(ei.link.checkout.quelle));
|
|
682
|
+
else li.appendChild(repoIcon({ art: 'lokal', pfad: ei.checkoutPfad }));
|
|
683
|
+
|
|
684
|
+
li.appendChild(e('span', 'name', name));
|
|
685
|
+
|
|
686
|
+
// Die Beschreibung aus der SKILL.md (E39): die Frage, wegen der die Zeile gelesen wird,
|
|
687
|
+
// deshalb die breiteste Spalte. Ein Link ohne bekannte Quelle kennt seinen Skill nicht.
|
|
688
|
+
li.appendChild(wasZelle(ei.art === 'link' ? ei.link.skill : null));
|
|
689
|
+
|
|
690
|
+
// Quelle: der Name, anklickbar, dahinter nur, was vom Normalfall abweicht — ein Ref, das
|
|
691
|
+
// vom Standard-Ref der Quelle abweicht, und der Grund „über Zeiger" (E57). „Manuell" (der
|
|
692
|
+
// Normalfall) entfällt ersatzlos, ein Plugin-Grund steht stattdessen in der Aktionsspalte.
|
|
693
|
+
var qz = e('span', 'quelle');
|
|
694
|
+
if (ei.art === 'link') {
|
|
695
|
+
var einschraenkung = z.einschraenkungen[name];
|
|
696
|
+
if (einschraenkung) qz.appendChild(document.createTextNode(einschraenkung + ' → '));
|
|
697
|
+
qz.appendChild(quelleLinkElement(ei.link.checkout.quelle));
|
|
698
|
+
var standardRef = STANDARD_REF[quelleKurz(ei.link.checkout.quelle)];
|
|
699
|
+
if (ei.link.checkout.ref && standardRef && ei.link.checkout.ref !== standardRef) {
|
|
700
|
+
qz.appendChild(e('span', 'ref', '@' + ei.link.checkout.ref));
|
|
701
|
+
}
|
|
702
|
+
} else {
|
|
703
|
+
qz.appendChild(e('span', 'mono', pfadKurz(ei.checkoutPfad)));
|
|
704
|
+
}
|
|
705
|
+
var grund = z.gruende[name];
|
|
706
|
+
if (grund && grund.art === 'zeiger') qz.appendChild(e('span', 'grundmarke', 'über Zeiger'));
|
|
707
|
+
li.appendChild(qz);
|
|
708
|
+
|
|
709
|
+
// Aus einem Plugin verlinkt: kein Entfernen-Knopf, das geht nur über das Plugin — der
|
|
710
|
+
// Grund erklärt hier zugleich, warum der Knopf fehlt.
|
|
711
|
+
if (grund && grund.art === 'plugin') {
|
|
712
|
+
li.appendChild(e('span', 'kein-weg', 'nur über Plugin „' + grund.plugin.split('@')[0] + '“'));
|
|
713
|
+
} else {
|
|
714
|
+
var weg = e('button', 'knopf leise klein', 'Entfernen');
|
|
715
|
+
weg.type = 'button';
|
|
716
|
+
weg.setAttribute('aria-label', 'Link auf ' + name + ' entfernen');
|
|
717
|
+
weg.addEventListener('click', function () { frageEntfernen(name, z.ziel, bundle ? bundle.name : null); });
|
|
718
|
+
li.appendChild(weg);
|
|
719
|
+
}
|
|
720
|
+
return li;
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
/** Ein installiertes Bundle als Gruppe über seinen Skill-Zeilen (E69, F68): Kopf mit Name, Quelle
|
|
724
|
+
und „Entfernen" für das Ganze, darunter die Zeilen seiner Mitglieder. */
|
|
725
|
+
function bundleGruppe(b, z, eintraege) {
|
|
726
|
+
var gruppe = e('div', 'bundlegruppe');
|
|
727
|
+
var kopf = e('div', 'bundlekopf');
|
|
728
|
+
var titel = e('span', 'bundletitel');
|
|
729
|
+
titel.appendChild(e('span', 'etikett', 'Bundle'));
|
|
730
|
+
titel.appendChild(e('b', 'bundlename', b.name));
|
|
731
|
+
kopf.appendChild(titel);
|
|
732
|
+
var quelleEl = e('span', 'mono bundlequelle', b.quelleName);
|
|
733
|
+
quelleEl.title = b.quelleText;
|
|
734
|
+
kopf.appendChild(quelleEl);
|
|
735
|
+
kopf.appendChild(e('span', 'bundlezahl', zahlwort(b.skills.length, 'Skill', 'Skills')));
|
|
736
|
+
var weg = e('button', 'knopf leise klein', 'Entfernen');
|
|
737
|
+
weg.type = 'button';
|
|
738
|
+
weg.setAttribute('aria-label', 'Bundle ' + b.name + ' aus ' + zielTitel(z) + ' entfernen');
|
|
739
|
+
weg.addEventListener('click', function () { frageBundleEntfernen(b, z.ziel); });
|
|
740
|
+
kopf.appendChild(weg);
|
|
741
|
+
gruppe.appendChild(kopf);
|
|
742
|
+
var ul = e('ul', 'linkliste');
|
|
743
|
+
eintraege.forEach(function (ei) { ul.appendChild(linkZeile(ei, z, b)); });
|
|
744
|
+
gruppe.appendChild(ul);
|
|
745
|
+
return gruppe;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
/** Ein Bundle als einzelner Streifen (Chip „Alle" einer Verzeichnis-Karte, E69/E53): Harness-
|
|
749
|
+
Zeichen, Name, seine Mitglieder als Text, Entfernen. Ohne eigene Tabelle. */
|
|
750
|
+
function bundleStreifen(b, z) {
|
|
751
|
+
var streifen = e('div', 'bundlegruppe');
|
|
752
|
+
var kopf = e('div', 'bundlekopf');
|
|
753
|
+
var titel = e('span', 'bundletitel');
|
|
754
|
+
titel.appendChild(harnessZeichen(z.ziel.harness));
|
|
755
|
+
titel.appendChild(e('span', 'etikett', 'Bundle'));
|
|
756
|
+
titel.appendChild(e('b', 'bundlename', b.name));
|
|
757
|
+
kopf.appendChild(titel);
|
|
758
|
+
kopf.appendChild(e('span', 'bundlemitglieder', b.skills.join(', ')));
|
|
759
|
+
var weg = e('button', 'knopf leise klein', 'Entfernen');
|
|
760
|
+
weg.type = 'button';
|
|
761
|
+
weg.setAttribute('aria-label', 'Bundle ' + b.name + ' aus ' + zielTitel(z) + ' entfernen');
|
|
762
|
+
weg.addEventListener('click', function () { frageBundleEntfernen(b, z.ziel); });
|
|
763
|
+
kopf.appendChild(weg);
|
|
764
|
+
streifen.appendChild(kopf);
|
|
765
|
+
return streifen;
|
|
766
|
+
}
|
|
767
|
+
|
|
655
768
|
function linkTeil(z) {
|
|
656
769
|
var teil = document.createDocumentFragment();
|
|
657
770
|
var eigene = z.eintraege.filter(function (ei) { return ei.art !== 'fremd'; });
|
|
@@ -697,63 +810,26 @@
|
|
|
697
810
|
kopf.appendChild(e('span'));
|
|
698
811
|
teil.appendChild(kopf);
|
|
699
812
|
|
|
700
|
-
|
|
701
|
-
//
|
|
702
|
-
|
|
813
|
+
// Bundles zuerst (E69): sie stehen als Gruppe über den Einzel-Zeilen, ihre Mitglieder liegen
|
|
814
|
+
// in der Gruppe statt in der allgemeinen Liste. Was zum Bundle gehört, sagt der Kern.
|
|
815
|
+
var bundles = (z.bundles || []).filter(function (b) { return b.skills.length > 0; });
|
|
816
|
+
var bundleVon = {};
|
|
817
|
+
bundles.forEach(function (b) { b.skills.forEach(function (n) { bundleVon[n] = b; }); });
|
|
818
|
+
bundles
|
|
703
819
|
.slice()
|
|
704
|
-
.sort(function (a, b) {
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
})
|
|
711
|
-
.forEach(function (ei) {
|
|
712
|
-
var name = ei.art === 'link' ? ei.link.name : ei.name;
|
|
713
|
-
var li = e('li');
|
|
714
|
-
|
|
715
|
-
if (ei.art === 'link') li.appendChild(repoIcon(ei.link.checkout.quelle));
|
|
716
|
-
else li.appendChild(repoIcon({ art: 'lokal', pfad: ei.checkoutPfad }));
|
|
717
|
-
|
|
718
|
-
li.appendChild(e('span', 'name', name));
|
|
719
|
-
|
|
720
|
-
// Die Beschreibung aus der SKILL.md (E39): die Frage, wegen der die Zeile gelesen wird,
|
|
721
|
-
// deshalb die breiteste Spalte. Ein Link ohne bekannte Quelle kennt seinen Skill nicht.
|
|
722
|
-
li.appendChild(wasZelle(ei.art === 'link' ? ei.link.skill : null));
|
|
723
|
-
|
|
724
|
-
// Quelle: der Name, anklickbar, dahinter nur, was vom Normalfall abweicht — ein Ref, das
|
|
725
|
-
// vom Standard-Ref der Quelle abweicht, und der Grund „über Zeiger" (E57). „Manuell" (der
|
|
726
|
-
// Normalfall) entfällt ersatzlos, ein Plugin-Grund steht stattdessen in der Aktionsspalte.
|
|
727
|
-
var qz = e('span', 'quelle');
|
|
728
|
-
if (ei.art === 'link') {
|
|
729
|
-
var einschraenkung = z.einschraenkungen[name];
|
|
730
|
-
if (einschraenkung) qz.appendChild(document.createTextNode(einschraenkung + ' → '));
|
|
731
|
-
qz.appendChild(quelleLinkElement(ei.link.checkout.quelle));
|
|
732
|
-
var standardRef = STANDARD_REF[quelleKurz(ei.link.checkout.quelle)];
|
|
733
|
-
if (ei.link.checkout.ref && standardRef && ei.link.checkout.ref !== standardRef) {
|
|
734
|
-
qz.appendChild(e('span', 'ref', '@' + ei.link.checkout.ref));
|
|
735
|
-
}
|
|
736
|
-
} else {
|
|
737
|
-
qz.appendChild(e('span', 'mono', pfadKurz(ei.checkoutPfad)));
|
|
738
|
-
}
|
|
739
|
-
var grund = z.gruende[name];
|
|
740
|
-
if (grund && grund.art === 'zeiger') qz.appendChild(e('span', 'grundmarke', 'über Zeiger'));
|
|
741
|
-
li.appendChild(qz);
|
|
742
|
-
|
|
743
|
-
// Aus einem Plugin verlinkt: kein Entfernen-Knopf, das geht nur über das Plugin — der
|
|
744
|
-
// Grund erklärt hier zugleich, warum der Knopf fehlt.
|
|
745
|
-
if (grund && grund.art === 'plugin') {
|
|
746
|
-
li.appendChild(e('span', 'kein-weg', 'nur über Plugin „' + grund.plugin.split('@')[0] + '“'));
|
|
747
|
-
} else {
|
|
748
|
-
var weg = e('button', 'knopf leise klein', 'Entfernen');
|
|
749
|
-
weg.type = 'button';
|
|
750
|
-
weg.setAttribute('aria-label', 'Link auf ' + name + ' entfernen');
|
|
751
|
-
weg.addEventListener('click', function () { frageEntfernen(name, z.ziel); });
|
|
752
|
-
li.appendChild(weg);
|
|
753
|
-
}
|
|
754
|
-
ul.appendChild(li);
|
|
820
|
+
.sort(function (a, b) { return a.name.localeCompare(b.name, 'de'); })
|
|
821
|
+
.forEach(function (b) {
|
|
822
|
+
var mitglieder = eigene.filter(function (ei) {
|
|
823
|
+
return b.skills.indexOf(ei.art === 'link' ? ei.link.name : ei.name) > -1;
|
|
824
|
+
});
|
|
825
|
+
teil.appendChild(bundleGruppe(b, z, sortiereEintraege(mitglieder)));
|
|
755
826
|
});
|
|
756
|
-
|
|
827
|
+
|
|
828
|
+
var ul = e('ul', 'linkliste');
|
|
829
|
+
sortiereEintraege(
|
|
830
|
+
eigene.filter(function (ei) { return !bundleVon[ei.art === 'link' ? ei.link.name : ei.name]; }),
|
|
831
|
+
).forEach(function (ei) { ul.appendChild(linkZeile(ei, z, null)); });
|
|
832
|
+
if (ul.childNodes.length > 0) teil.appendChild(ul);
|
|
757
833
|
|
|
758
834
|
// MCP-Abschnitt (E61-GUI-Nachtrag): unter der Skill-Link-Tabelle, vor dem Kartenfuß mit den
|
|
759
835
|
// Knöpfen, Gegenrichtung zur MCP-Ansicht.
|
|
@@ -894,6 +970,44 @@
|
|
|
894
970
|
return knopf;
|
|
895
971
|
}
|
|
896
972
|
|
|
973
|
+
/** Eigene Links eines Verzeichnisses über alle Harnesses gebündelt: Schlüssel Name+Quelle,
|
|
974
|
+
hängt ein Name je Harness aus verschiedener Quelle, gibt es je Quelle eine eigene Zeile
|
|
975
|
+
(E53 Pkt. 2). Einzige Zählregel für Skills: der Körper zeilt daraus, die Kartenköpfe zählen
|
|
976
|
+
dieselbe Struktur (E71). Ein einzelnes Ziel kommt als einelementige Liste.
|
|
977
|
+
Fremde Einträge bleiben draußen, defekte Links (ohne Quelle) zählen mit. */
|
|
978
|
+
function buendleEigene(teile) {
|
|
979
|
+
var zeilen = {};
|
|
980
|
+
var reihenfolge = [];
|
|
981
|
+
teile.forEach(function (z) {
|
|
982
|
+
z.eintraege.filter(function (ei) { return ei.art !== 'fremd'; }).forEach(function (ei) {
|
|
983
|
+
var defekt = ei.art === 'link-ohne-quelle';
|
|
984
|
+
var name = defekt ? ei.name : ei.link.name;
|
|
985
|
+
var quelleSchluessel = defekt ? ('defekt\u0000' + ei.checkoutPfad)
|
|
986
|
+
: (quelleKurz(ei.link.checkout.quelle) + '@' + ei.link.checkout.ref);
|
|
987
|
+
// NUL als Trenner, kein Leerzeichen: Skill-Namen dürfen Leerzeichen enthalten, Quellen-Namen
|
|
988
|
+
// seit E59 auch, ein lokaler Pfad ohnehin — „a b“ + „x“ und „a“ + „b x“ ergäben sonst
|
|
989
|
+
// denselben Schlüssel. Immer als Escape geschrieben, nie als rohes Byte im Quelltext.
|
|
990
|
+
var key = name + '\u0000' + quelleSchluessel;
|
|
991
|
+
if (!zeilen[key]) {
|
|
992
|
+
zeilen[key] = {
|
|
993
|
+
name: name,
|
|
994
|
+
defekt: defekt,
|
|
995
|
+
icon: defekt ? { art: 'lokal', pfad: ei.checkoutPfad } : ei.link.checkout.quelle,
|
|
996
|
+
checkoutPfad: defekt ? ei.checkoutPfad : null,
|
|
997
|
+
quelle: defekt ? null : ei.link.checkout.quelle,
|
|
998
|
+
ref: defekt ? null : ei.link.checkout.ref,
|
|
999
|
+
einschraenkung: defekt ? null : z.einschraenkungen[name],
|
|
1000
|
+
skill: defekt ? null : ei.link.skill,
|
|
1001
|
+
teile: [],
|
|
1002
|
+
};
|
|
1003
|
+
reihenfolge.push(key);
|
|
1004
|
+
}
|
|
1005
|
+
zeilen[key].teile.push(z);
|
|
1006
|
+
});
|
|
1007
|
+
});
|
|
1008
|
+
return { zeilen: zeilen, reihenfolge: reihenfolge };
|
|
1009
|
+
}
|
|
1010
|
+
|
|
897
1011
|
function zielKarte(z) {
|
|
898
1012
|
var karte = e('div', 'ziel');
|
|
899
1013
|
var kopf = e('div', 'zielkopf');
|
|
@@ -917,8 +1031,10 @@
|
|
|
917
1031
|
warnspan.setAttribute('aria-label', 'braucht Aufmerksamkeit');
|
|
918
1032
|
kopf.appendChild(warnspan);
|
|
919
1033
|
}
|
|
920
|
-
|
|
921
|
-
|
|
1034
|
+
// Der Kopf zählt Skills, nicht Einträge (E71), über dieselbe Bündelung, aus der der Körper zeilt.
|
|
1035
|
+
// Bei einem Harness fällt die Zahl mit der Zahl eigener Einträge zusammen, die Regel bleibt eine.
|
|
1036
|
+
var zahl = buendleEigene([z]).reihenfolge.length;
|
|
1037
|
+
kopf.appendChild(e('span', 'zahl', zahl + (zahl === 1 ? ' Skill' : ' Skills')));
|
|
922
1038
|
var pfeil = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
|
923
1039
|
pfeil.setAttribute('viewBox', '0 0 16 16');
|
|
924
1040
|
pfeil.setAttribute('class', 'akkordeonpfeil');
|
|
@@ -981,37 +1097,9 @@
|
|
|
981
1097
|
if (beachteteAlle.length > 0) teil.appendChild(fremdKasten(beachteteAlle, true));
|
|
982
1098
|
if (ignorierteAlle.length > 0) teil.appendChild(ignoriertZeile(ignorierteAlle, true));
|
|
983
1099
|
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
var
|
|
987
|
-
var reihenfolge = [];
|
|
988
|
-
teile.forEach(function (z) {
|
|
989
|
-
z.eintraege.filter(function (ei) { return ei.art !== 'fremd'; }).forEach(function (ei) {
|
|
990
|
-
var defekt = ei.art === 'link-ohne-quelle';
|
|
991
|
-
var name = defekt ? ei.name : ei.link.name;
|
|
992
|
-
var quelleSchluessel = defekt ? ('defekt\u0000' + ei.checkoutPfad)
|
|
993
|
-
: (quelleKurz(ei.link.checkout.quelle) + '@' + ei.link.checkout.ref);
|
|
994
|
-
// NUL als Trenner, kein Leerzeichen: Skill-Namen dürfen Leerzeichen enthalten, Quellen-Namen
|
|
995
|
-
// seit E59 auch, ein lokaler Pfad ohnehin — „a b“ + „x“ und „a“ + „b x“ ergäben sonst
|
|
996
|
-
// denselben Schlüssel. Immer als Escape geschrieben, nie als rohes Byte im Quelltext.
|
|
997
|
-
var key = name + '\u0000' + quelleSchluessel;
|
|
998
|
-
if (!zeilen[key]) {
|
|
999
|
-
zeilen[key] = {
|
|
1000
|
-
name: name,
|
|
1001
|
-
defekt: defekt,
|
|
1002
|
-
icon: defekt ? { art: 'lokal', pfad: ei.checkoutPfad } : ei.link.checkout.quelle,
|
|
1003
|
-
checkoutPfad: defekt ? ei.checkoutPfad : null,
|
|
1004
|
-
quelle: defekt ? null : ei.link.checkout.quelle,
|
|
1005
|
-
ref: defekt ? null : ei.link.checkout.ref,
|
|
1006
|
-
einschraenkung: defekt ? null : z.einschraenkungen[name],
|
|
1007
|
-
skill: defekt ? null : ei.link.skill,
|
|
1008
|
-
teile: [],
|
|
1009
|
-
};
|
|
1010
|
-
reihenfolge.push(key);
|
|
1011
|
-
}
|
|
1012
|
-
zeilen[key].teile.push(z);
|
|
1013
|
-
});
|
|
1014
|
-
});
|
|
1100
|
+
var gebuendelt = buendleEigene(teile);
|
|
1101
|
+
var zeilen = gebuendelt.zeilen;
|
|
1102
|
+
var reihenfolge = gebuendelt.reihenfolge;
|
|
1015
1103
|
|
|
1016
1104
|
// MCPs hängen am Verzeichnis, nicht am Harness-Chip (E61-GUI-Nachtrag): der Abschnitt unter
|
|
1017
1105
|
// „Alle" zeigt jedes Ziel, das an genau diesem Pfad MCP kann — dieselbe Fähigkeitsfrage wie unter
|
|
@@ -1038,6 +1126,18 @@
|
|
|
1038
1126
|
return teil;
|
|
1039
1127
|
}
|
|
1040
1128
|
|
|
1129
|
+
// Bundles unter „Alle" (E69): die Zeilen bleiben nach Name und Quelle gebündelt (E53), ein
|
|
1130
|
+
// Bundle gehört aber zu genau einem Harness — deshalb hier ein Streifen je Bundle mit seinem
|
|
1131
|
+
// Harness-Zeichen statt einer Umgruppierung der Tabelle. Unter dem Harness-Chip zeigt linkTeil
|
|
1132
|
+
// die volle Gruppe über den Zeilen.
|
|
1133
|
+
teile.forEach(function (z) {
|
|
1134
|
+
(z.bundles || [])
|
|
1135
|
+
.filter(function (b) { return b.skills.length > 0; })
|
|
1136
|
+
.slice()
|
|
1137
|
+
.sort(function (a, b) { return a.name.localeCompare(b.name, 'de'); })
|
|
1138
|
+
.forEach(function (b) { teil.appendChild(bundleStreifen(b, z)); });
|
|
1139
|
+
});
|
|
1140
|
+
|
|
1041
1141
|
var kopf = e('div', 'linkkopf');
|
|
1042
1142
|
kopf.appendChild(e('span'));
|
|
1043
1143
|
kopf.appendChild(e('span', 'etikett', 'Skill'));
|
|
@@ -1173,10 +1273,10 @@
|
|
|
1173
1273
|
warnspan.setAttribute('aria-label', 'braucht Aufmerksamkeit');
|
|
1174
1274
|
kopf.appendChild(warnspan);
|
|
1175
1275
|
}
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
kopf.appendChild(e('span', 'zahl', gesamtZahl + (gesamtZahl === 1 ? '
|
|
1276
|
+
// Skills statt Einträge (E71): eine Summe über die Harness-Abschnitte zählte jeden Skill so oft,
|
|
1277
|
+
// wie ihn Harnesses am selben Verzeichnis führen — der Körper bündelt sie zu einer Zeile.
|
|
1278
|
+
var gesamtZahl = buendleEigene(teile).reihenfolge.length;
|
|
1279
|
+
kopf.appendChild(e('span', 'zahl', gesamtZahl + (gesamtZahl === 1 ? ' Skill' : ' Skills')));
|
|
1180
1280
|
var pfeil = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
|
1181
1281
|
pfeil.setAttribute('viewBox', '0 0 16 16');
|
|
1182
1282
|
pfeil.setAttribute('class', 'akkordeonpfeil');
|
|
@@ -1326,10 +1426,24 @@
|
|
|
1326
1426
|
// entfernenKontext.eintraege: [{harness, ort}], immer eines bei frageEntfernen (Einzel-Ziel),
|
|
1327
1427
|
// mehrere bei frageEntfernenAlle (E53 Pkt. 2, „Alle"-Zeile über mehrere Harnesses).
|
|
1328
1428
|
var entfernenKontext = null;
|
|
1329
|
-
|
|
1330
|
-
|
|
1429
|
+
/** `bundleName` gesetzt heißt: der Link gehört zu einem Bundle, das Entfernen zerbricht es (E69). */
|
|
1430
|
+
function frageEntfernen(name, ziel, bundleName) {
|
|
1431
|
+
entfernenKontext = { art: 'link', name: name, eintraege: [{ harness: ziel.harness, ort: ziel.ort }] };
|
|
1331
1432
|
$('dx-titel').textContent = 'Link auf ' + name + ' entfernen?';
|
|
1332
|
-
|
|
1433
|
+
var text = 'Der Link in ' + zielTitel({ ziel: ziel }) + ' verschwindet. Der Checkout bleibt liegen, bis kein Link mehr darauf zeigt.';
|
|
1434
|
+
if (bundleName) {
|
|
1435
|
+
text += ' Damit zerbricht das Bundle „' + bundleName + '“ hier: seine übrigen Links bleiben liegen, aber nicht mehr als Bundle.';
|
|
1436
|
+
}
|
|
1437
|
+
$('dx-text').textContent = text;
|
|
1438
|
+
zeige($('d-entfernen'));
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1441
|
+
/** Entfernen des ganzen Bundles an einem Ziel (E69): alle seine Links auf einmal. */
|
|
1442
|
+
function frageBundleEntfernen(b, ziel) {
|
|
1443
|
+
entfernenKontext = { art: 'bundle', bundle: b.name, ziel: ziel };
|
|
1444
|
+
$('dx-titel').textContent = 'Bundle ' + b.name + ' entfernen?';
|
|
1445
|
+
$('dx-text').textContent = zahlwort(b.skills.length, 'Link', 'Links') + ' aus ' + zielTitel({ ziel: ziel })
|
|
1446
|
+
+ ' verschwinden: ' + b.skills.join(', ') + '. Die Checkouts bleiben liegen, bis kein Link mehr darauf zeigt.';
|
|
1333
1447
|
zeige($('d-entfernen'));
|
|
1334
1448
|
}
|
|
1335
1449
|
/** Entfernen einer „Alle"-Zeile (E53 Pkt. 2): entfernbareZiele sind die Ziele (voller z.ziel), in
|
|
@@ -1337,6 +1451,7 @@
|
|
|
1337
1451
|
und liegen bleibt. Der Dialog nennt beides. */
|
|
1338
1452
|
function frageEntfernenAlle(name, pfad, entfernbareZiele, nichtEntfernbareHarnesse) {
|
|
1339
1453
|
entfernenKontext = {
|
|
1454
|
+
art: 'link',
|
|
1340
1455
|
name: name,
|
|
1341
1456
|
eintraege: entfernbareZiele.map(function (z) { return { harness: z.ziel.harness, ort: z.ziel.ort }; }),
|
|
1342
1457
|
};
|
|
@@ -1353,6 +1468,19 @@
|
|
|
1353
1468
|
nachDialog($('d-entfernen'), async function (wert) {
|
|
1354
1469
|
if (wert !== 'ja' || entfernenKontext === null) return;
|
|
1355
1470
|
var kontext = entfernenKontext;
|
|
1471
|
+
// Bundle als Ganzes (E69): ein Aufruf, der Kern nimmt alle Links des Bundles weg.
|
|
1472
|
+
if (kontext.art === 'bundle') {
|
|
1473
|
+
var wegB = await rufe(function () {
|
|
1474
|
+
return window.hmgr.bundleEntfernen({
|
|
1475
|
+
bundle: kontext.bundle,
|
|
1476
|
+
harness: kontext.ziel.harness,
|
|
1477
|
+
ort: kontext.ziel.ort,
|
|
1478
|
+
});
|
|
1479
|
+
});
|
|
1480
|
+
await ladeAlles();
|
|
1481
|
+
melde('Bundle ' + kontext.bundle + ' entfernt, ' + zahlwort(wegB.entfernt.length, 'Link', 'Links') + ' weniger.');
|
|
1482
|
+
return;
|
|
1483
|
+
}
|
|
1356
1484
|
// Ein Fehlschlag in einem Harness hält die übrigen nicht auf: rufe hat ihn schon gemeldet, die
|
|
1357
1485
|
// Schleife läuft weiter, und die Liste wird danach in jedem Fall neu geladen. Sonst stünde nach
|
|
1358
1486
|
// einem Fehler die halb erledigte Arbeit unsichtbar in einer veralteten Liste.
|
|
@@ -1663,6 +1791,14 @@
|
|
|
1663
1791
|
return zeilen;
|
|
1664
1792
|
}
|
|
1665
1793
|
|
|
1794
|
+
/** ISO-Zeitpunkt als deutsches Datum (E70). Ungültiges oder fehlendes Datum ergibt null. */
|
|
1795
|
+
function datumDeutsch(iso) {
|
|
1796
|
+
if (!iso) return null;
|
|
1797
|
+
var d = new Date(iso);
|
|
1798
|
+
if (isNaN(d.getTime())) return null;
|
|
1799
|
+
return d.toLocaleDateString('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric' });
|
|
1800
|
+
}
|
|
1801
|
+
|
|
1666
1802
|
function baueSkills() {
|
|
1667
1803
|
var liste = $('katalog');
|
|
1668
1804
|
liste.textContent = '';
|
|
@@ -1686,12 +1822,17 @@
|
|
|
1686
1822
|
// title. Fehlt die Quelle in der Liste (Katalog und Quellen kämen auseinander), bleibt es
|
|
1687
1823
|
// beim reinen Text — angeschrieben ist die Zeile so oder so.
|
|
1688
1824
|
var herkunft = e('p', 'herkunft mono');
|
|
1825
|
+
// Das Änderungsdatum steht hinter dem Ref (E70, F70=O1): der jüngste Commit, der den
|
|
1826
|
+
// Skill-Ordner berührt. Nicht der Pull-Zeitpunkt — der steht als „Zuletzt geprüft" in der
|
|
1827
|
+
// Update-Ansicht und wäre für alle Skills einer Quelle derselbe.
|
|
1828
|
+
var geaendert = datumDeutsch(skill.geaendert);
|
|
1829
|
+
var nachRef = ' · Ref ' + skill.ref + (geaendert ? ' · geändert ' + geaendert : '');
|
|
1689
1830
|
if (herkunftQuelle) {
|
|
1690
1831
|
herkunft.appendChild(quelleLinkElement(herkunftQuelle));
|
|
1691
|
-
herkunft.appendChild(e('b', null,
|
|
1832
|
+
herkunft.appendChild(e('b', null, nachRef));
|
|
1692
1833
|
} else {
|
|
1693
1834
|
herkunft.title = skill.quelleText;
|
|
1694
|
-
herkunft.appendChild(e('b', null, skill.quelleName +
|
|
1835
|
+
herkunft.appendChild(e('b', null, skill.quelleName + nachRef));
|
|
1695
1836
|
}
|
|
1696
1837
|
links.appendChild(herkunft);
|
|
1697
1838
|
|
|
@@ -1840,7 +1981,8 @@
|
|
|
1840
1981
|
Skill nur aus, wenn er in ALLEN beteiligten Harnesses hängt, und verlinkt je Harness, wo er fehlt. */
|
|
1841
1982
|
var skillsKontext = null;
|
|
1842
1983
|
function dskBilanzAktualisieren() {
|
|
1843
|
-
var n = $('dsk-liste').querySelectorAll('input:checked').length
|
|
1984
|
+
var n = $('dsk-liste').querySelectorAll('input:checked').length
|
|
1985
|
+
+ $('dsk-bundles').querySelectorAll('input:checked').length;
|
|
1844
1986
|
$('dsk-bilanz').textContent = zahlwort(n, 'ausgewählt', 'ausgewählt');
|
|
1845
1987
|
}
|
|
1846
1988
|
function filtereDskListe() {
|
|
@@ -1849,6 +1991,60 @@
|
|
|
1849
1991
|
var skill = SKILLS[+label.dataset.index];
|
|
1850
1992
|
label.hidden = !!suche && skill.name.toLowerCase().indexOf(suche) === -1;
|
|
1851
1993
|
});
|
|
1994
|
+
// Die Suche gilt auch für Bundles (E69): sonst bliebe die Sektion bei jeder Eingabe voll stehen.
|
|
1995
|
+
document.querySelectorAll('#dsk-bundles .wahlzeile').forEach(function (label) {
|
|
1996
|
+
var bundle = BUNDLES[+label.dataset.index];
|
|
1997
|
+
label.hidden = !!suche && bundle.name.toLowerCase().indexOf(suche) === -1;
|
|
1998
|
+
});
|
|
1999
|
+
}
|
|
2000
|
+
|
|
2001
|
+
/**
|
|
2002
|
+
* Bundle-Sektion des Dialogs (E69, F68): je Bundle eine Wahlzeile mit Beschreibung, Zahl seiner
|
|
2003
|
+
* Mitglieder und Herkunft. `installiertIn(bundle)` sagt, in welchen der angesteuerten Ziele es
|
|
2004
|
+
* schon hängt — hängt es überall, ist die Zeile ausgegraut, wie bei einem Skill.
|
|
2005
|
+
*/
|
|
2006
|
+
function fuelleBundleSektion(installiertIn, zieleZahl) {
|
|
2007
|
+
var box = $('dsk-bundles');
|
|
2008
|
+
box.textContent = '';
|
|
2009
|
+
BUNDLES.forEach(function (bundle, i) {
|
|
2010
|
+
var schon = installiertIn(bundle);
|
|
2011
|
+
var ueberall = schon >= zieleZahl;
|
|
2012
|
+
var label = e('label', 'wahlzeile quellfarbe');
|
|
2013
|
+
label.dataset.index = i;
|
|
2014
|
+
var idx = quellenIndex(bundle.quelleText);
|
|
2015
|
+
label.style.borderLeftColor = 'var(--q' + (idx + 1) + ')';
|
|
2016
|
+
var input = document.createElement('input');
|
|
2017
|
+
input.type = 'checkbox';
|
|
2018
|
+
input.value = String(i);
|
|
2019
|
+
input.disabled = ueberall;
|
|
2020
|
+
input.addEventListener('change', dskBilanzAktualisieren);
|
|
2021
|
+
label.appendChild(input);
|
|
2022
|
+
var txt = e('span');
|
|
2023
|
+
txt.appendChild(e('b', null, bundle.name));
|
|
2024
|
+
txt.appendChild(e('span', 'notiz', bundle.beschreibung));
|
|
2025
|
+
var herkunft = e('span', 'mono', zahlwort(bundle.mitglieder, 'Skill', 'Skills')
|
|
2026
|
+
+ ' aus ' + zahlwort(bundle.quellen.length, 'Quelle', 'Quellen') + ' · ' + bundle.quelleName);
|
|
2027
|
+
herkunft.title = bundle.quellen.join('\n');
|
|
2028
|
+
txt.appendChild(herkunft);
|
|
2029
|
+
if (ueberall) txt.appendChild(e('span', 'notiz', zieleZahl > 1 ? 'Hängt schon überall.' : 'Hängt hier schon.'));
|
|
2030
|
+
else if (schon > 0) txt.appendChild(e('span', 'notiz', 'Hängt schon in ' + schon + ' von ' + zieleZahl + ' Harnesses.'));
|
|
2031
|
+
label.appendChild(txt);
|
|
2032
|
+
box.appendChild(label);
|
|
2033
|
+
});
|
|
2034
|
+
$('dsk-bundlebox').hidden = BUNDLES.length === 0 && BUNDLES_KAPUTT.length === 0;
|
|
2035
|
+
// Eine Definition, die sich nicht lesen ließ, wird genannt statt verschluckt (E69).
|
|
2036
|
+
var fehlerZeile = $('dsk-bundlefehler');
|
|
2037
|
+
fehlerZeile.hidden = BUNDLES_KAPUTT.length === 0;
|
|
2038
|
+
fehlerZeile.textContent = BUNDLES_KAPUTT.map(function (k) {
|
|
2039
|
+
return k.quelleName + ': ' + k.datei + ' — ' + k.fehler;
|
|
2040
|
+
}).join('\n');
|
|
2041
|
+
}
|
|
2042
|
+
|
|
2043
|
+
/** Wie oft ein Bundle in den angesteuerten Zielen schon installiert ist (Name plus Quelle, E69). */
|
|
2044
|
+
function bundleHaengtIn(teile, bundle) {
|
|
2045
|
+
return teile.filter(function (z) {
|
|
2046
|
+
return (z.bundles || []).some(function (b) { return b.name === bundle.name && b.quelleText === bundle.quelleText; });
|
|
2047
|
+
}).length;
|
|
1852
2048
|
}
|
|
1853
2049
|
$('dsk-suche').addEventListener('input', filtereDskListe);
|
|
1854
2050
|
|
|
@@ -1883,6 +2079,7 @@
|
|
|
1883
2079
|
label.appendChild(txt);
|
|
1884
2080
|
box.appendChild(label);
|
|
1885
2081
|
});
|
|
2082
|
+
fuelleBundleSektion(function (bundle) { return bundleHaengtIn([z], bundle); }, 1);
|
|
1886
2083
|
dskBilanzAktualisieren();
|
|
1887
2084
|
zeige($('d-skills'));
|
|
1888
2085
|
$('dsk-suche').focus();
|
|
@@ -1927,6 +2124,7 @@
|
|
|
1927
2124
|
label.appendChild(txt);
|
|
1928
2125
|
box.appendChild(label);
|
|
1929
2126
|
});
|
|
2127
|
+
fuelleBundleSektion(function (bundle) { return bundleHaengtIn(teile, bundle); }, teile.length);
|
|
1930
2128
|
dskBilanzAktualisieren();
|
|
1931
2129
|
zeige($('d-skills'));
|
|
1932
2130
|
$('dsk-suche').focus();
|
|
@@ -1934,7 +2132,8 @@
|
|
|
1934
2132
|
|
|
1935
2133
|
$('d-skills').addEventListener('submit', function (ev) {
|
|
1936
2134
|
if (ev.submitter && ev.submitter.value === 'los') {
|
|
1937
|
-
var gewaehlt = Array.from($('dsk-liste').querySelectorAll('input:checked'))
|
|
2135
|
+
var gewaehlt = Array.from($('dsk-liste').querySelectorAll('input:checked'))
|
|
2136
|
+
.concat(Array.from($('dsk-bundles').querySelectorAll('input:checked')));
|
|
1938
2137
|
if (gewaehlt.length === 0) ev.preventDefault();
|
|
1939
2138
|
}
|
|
1940
2139
|
});
|
|
@@ -1943,6 +2142,7 @@
|
|
|
1943
2142
|
if (wert !== 'los' || skillsKontext === null) return;
|
|
1944
2143
|
var kontext = skillsKontext;
|
|
1945
2144
|
var indizes = Array.from($('dsk-liste').querySelectorAll('input:checked')).map(function (i) { return +i.value; });
|
|
2145
|
+
var bundleIndizes = Array.from($('dsk-bundles').querySelectorAll('input:checked')).map(function (i) { return +i.value; });
|
|
1946
2146
|
|
|
1947
2147
|
if (kontext.modus === 'einzeln') {
|
|
1948
2148
|
var z = kontext.z;
|
|
@@ -1952,6 +2152,26 @@
|
|
|
1952
2152
|
// Der zweite gehört daher als Fehler in die Bilanz, sonst meldet der Dialog Links, die es nicht gibt.
|
|
1953
2153
|
var vergeben = [];
|
|
1954
2154
|
var hinweiseZiel = [];
|
|
2155
|
+
// Bundles zuerst (E69): sie wirken als Ganzes und bringen ihre Mitglieder mit, ein danach
|
|
2156
|
+
// einzeln gewählter Skill gleichen Namens würde den eben gelegten Link stumm ersetzen.
|
|
2157
|
+
for (var bi = 0; bi < bundleIndizes.length; bi++) {
|
|
2158
|
+
var bundle = BUNDLES[bundleIndizes[bi]];
|
|
2159
|
+
try {
|
|
2160
|
+
var erg = await rufe(function () {
|
|
2161
|
+
return window.hmgr.bundleInstallieren({
|
|
2162
|
+
bundle: bundle.name,
|
|
2163
|
+
harness: z.ziel.harness,
|
|
2164
|
+
ort: z.ziel.ort,
|
|
2165
|
+
quelle: bundle.quelleText,
|
|
2166
|
+
});
|
|
2167
|
+
});
|
|
2168
|
+
hinweiseZiel.push(erg.hinweis);
|
|
2169
|
+
erg.gelegt.concat(erg.uebernommen).forEach(function (n) { vergeben.push(n); });
|
|
2170
|
+
ergebnisZeilen.push({ ok: true, bundle: bundle, erg: erg });
|
|
2171
|
+
} catch (fehler) {
|
|
2172
|
+
ergebnisZeilen.push({ ok: false, bundle: bundle, fehler: fehler.message });
|
|
2173
|
+
}
|
|
2174
|
+
}
|
|
1955
2175
|
for (var n = 0; n < indizes.length; n++) {
|
|
1956
2176
|
var skill = SKILLS[indizes[n]];
|
|
1957
2177
|
if (vergeben.indexOf(skill.name) > -1) {
|
|
@@ -1977,18 +2197,30 @@
|
|
|
1977
2197
|
// Arbeitsverzeichnis ist das die gebündelte Verzeichnis-Karte, nicht das Ziel allein (E49).
|
|
1978
2198
|
ZIEL_OFFEN[kartenKey(z.ziel)] = true;
|
|
1979
2199
|
await ladeAlles();
|
|
1980
|
-
|
|
2200
|
+
// Ein Bundle zählt als eines, egal wie viele Links es mitbringt: die Zeile darunter nennt sie.
|
|
2201
|
+
var erfolge = ergebnisZeilen.filter(function (r) { return r.ok && !r.bundle; }).length;
|
|
2202
|
+
var erfolgeBundle = ergebnisZeilen.filter(function (r) { return r.ok && r.bundle; }).length;
|
|
1981
2203
|
$('de-titel').textContent = 'Verlinkt';
|
|
1982
|
-
$('de-text').textContent = zahlwort(
|
|
2204
|
+
$('de-text').textContent = (erfolgeBundle > 0 ? zahlwort(erfolgeBundle, 'Bundle', 'Bundles') + ' und ' : '')
|
|
2205
|
+
+ zahlwort(erfolge, 'Skill hängt', 'Skills hängen') + ' jetzt in ' + zielTitel(z) + '.';
|
|
1983
2206
|
setzeErfolgHinweise(hinweiseZiel);
|
|
1984
2207
|
var ul = $('de-liste');
|
|
1985
2208
|
ul.textContent = '';
|
|
1986
2209
|
ergebnisZeilen.forEach(function (r) {
|
|
1987
2210
|
var li = e('li');
|
|
1988
|
-
li.appendChild(e('span', r.ok ? 'ok' : 'aus', r.ok ? 'Link' : 'Fehler'));
|
|
2211
|
+
li.appendChild(e('span', r.ok ? 'ok' : 'aus', r.ok ? (r.bundle ? 'Bundle' : 'Link') : 'Fehler'));
|
|
1989
2212
|
var s = e('span');
|
|
1990
|
-
s.appendChild(e('b', null, r.skill.name));
|
|
2213
|
+
s.appendChild(e('b', null, r.bundle ? r.bundle.name : r.skill.name));
|
|
1991
2214
|
if (!r.ok) s.appendChild(e('span', 'mono', r.fehler));
|
|
2215
|
+
else if (r.bundle) {
|
|
2216
|
+
var teileText = r.erg.gelegt.concat(r.erg.uebernommen).join(', ');
|
|
2217
|
+
if (r.erg.neueQuellen.length > 0) {
|
|
2218
|
+
// Neue Quellen (F66) gehören genannt: hmgr hat sie beim Installieren selbst angelegt.
|
|
2219
|
+
teileText += ' · neue ' + zahlwort(r.erg.neueQuellen.length, 'Quelle', 'Quellen') + ': '
|
|
2220
|
+
+ r.erg.neueQuellen.join(', ');
|
|
2221
|
+
}
|
|
2222
|
+
s.appendChild(e('span', 'mono', teileText));
|
|
2223
|
+
}
|
|
1992
2224
|
li.appendChild(s);
|
|
1993
2225
|
ul.appendChild(li);
|
|
1994
2226
|
});
|
|
@@ -2007,6 +2239,32 @@
|
|
|
2007
2239
|
// den eben gelegten Link sonst stumm.
|
|
2008
2240
|
var vergebenJeHarness = {};
|
|
2009
2241
|
var hinweiseAlle = [];
|
|
2242
|
+
// Bundles zuerst, je Harness, in dem sie noch nicht hängen (E69): ein Bundle gehört zu genau
|
|
2243
|
+
// einem Ziel, unter „Alle" also einmal je beteiligtem Harness.
|
|
2244
|
+
for (var bj = 0; bj < bundleIndizes.length; bj++) {
|
|
2245
|
+
var bundleAlle = BUNDLES[bundleIndizes[bj]];
|
|
2246
|
+
for (var bt = 0; bt < teile.length; bt++) {
|
|
2247
|
+
var zb = teile[bt];
|
|
2248
|
+
if (bundleHaengtIn([zb], bundleAlle) > 0) continue;
|
|
2249
|
+
try {
|
|
2250
|
+
var ergAlle = await rufe(function () {
|
|
2251
|
+
return window.hmgr.bundleInstallieren({
|
|
2252
|
+
bundle: bundleAlle.name,
|
|
2253
|
+
harness: zb.ziel.harness,
|
|
2254
|
+
ort: zb.ziel.ort,
|
|
2255
|
+
quelle: bundleAlle.quelleText,
|
|
2256
|
+
});
|
|
2257
|
+
});
|
|
2258
|
+
hinweiseAlle.push(ergAlle.hinweis);
|
|
2259
|
+
ergAlle.gelegt.concat(ergAlle.uebernommen).forEach(function (n) {
|
|
2260
|
+
vergebenJeHarness[zb.ziel.harness + '\u0000' + n] = true;
|
|
2261
|
+
});
|
|
2262
|
+
zeilenErgebnis.push({ ok: true, bundle: bundleAlle, harness: zb.ziel.harness, erg: ergAlle });
|
|
2263
|
+
} catch (fehler) {
|
|
2264
|
+
zeilenErgebnis.push({ ok: false, bundle: bundleAlle, harness: zb.ziel.harness, fehler: fehler.message });
|
|
2265
|
+
}
|
|
2266
|
+
}
|
|
2267
|
+
}
|
|
2010
2268
|
for (var m = 0; m < indizes.length; m++) {
|
|
2011
2269
|
var sk = SKILLS[indizes[m]];
|
|
2012
2270
|
for (var t = 0; t < teile.length; t++) {
|
|
@@ -2089,15 +2347,34 @@
|
|
|
2089
2347
|
if (c.aktualisierung.ergebnis === 'aktualisiert') quellen[quelleKurz(c.checkout.quelle)] = true;
|
|
2090
2348
|
});
|
|
2091
2349
|
var neue = Object.keys(quellen).length;
|
|
2350
|
+
// Skill-Ebene (E70): Namen über alle Checkouts, doppelte zählen einmal. Damit sagt der
|
|
2351
|
+
// Standknopf „5 Skills aktualisiert" statt nur „1 Quelle mit Neuem".
|
|
2352
|
+
var geaenderteSkills = {};
|
|
2353
|
+
ergebnis.checkouts.forEach(function (c) {
|
|
2354
|
+
(c.geaenderteSkills || []).forEach(function (name) { geaenderteSkills[name] = true; });
|
|
2355
|
+
});
|
|
2356
|
+
var skillZahl = Object.keys(geaenderteSkills).length;
|
|
2357
|
+
// Ein nachgezogenes Bundle ist Neues wie ein neuer Commit (E69, F64=O1): sonst bliebe der
|
|
2358
|
+
// Standknopf still, obwohl sich am Ziel gerade Links geändert haben.
|
|
2359
|
+
var bundlesNeu = (ergebnis.bundles || []).filter(function (b) { return b.ergebnis === 'aktualisiert'; }).length;
|
|
2092
2360
|
var fehlgeschlagen = ergebnis.checkouts.filter(function (c) { return c.aktualisierung.ergebnis === 'fehlgeschlagen'; }).length;
|
|
2093
2361
|
var gesamt = ergebnis.checkouts.length;
|
|
2094
2362
|
standFehlerZustand = fehlgeschlagen === 0 ? 'keine' : fehlgeschlagen === gesamt ? 'alle' : 'gemischt';
|
|
2095
2363
|
// Von Hand läuft es in der Update-Ansicht, der Bericht ist schon sichtbar: nichts anzukündigen.
|
|
2096
|
-
if (neue === 0 || !automatisch || !$('ansicht-update').hidden) return standRuhig();
|
|
2364
|
+
if ((neue === 0 && bundlesNeu === 0) || !automatisch || !$('ansicht-update').hidden) return standRuhig();
|
|
2097
2365
|
var p = $('standtext');
|
|
2098
2366
|
p.textContent = '';
|
|
2099
|
-
|
|
2100
|
-
|
|
2367
|
+
// Ist die Skill-Zahl bekannt, sagt sie mehr als die Zahl der Quellen (E70). Sonst bleibt es
|
|
2368
|
+
// beim alten Signal: eine Quelle kann Neues haben, ohne dass ein Skill davon betroffen ist.
|
|
2369
|
+
if (skillZahl > 0) {
|
|
2370
|
+
p.appendChild(e('b', null, zahlwort(skillZahl, 'Skill', 'Skills')));
|
|
2371
|
+
p.appendChild(document.createTextNode(' aktualisiert'));
|
|
2372
|
+
} else {
|
|
2373
|
+
p.appendChild(e('b', null, neue > 0
|
|
2374
|
+
? zahlwort(neue, 'Quelle', 'Quellen')
|
|
2375
|
+
: zahlwort(bundlesNeu, 'Bundle', 'Bundles')));
|
|
2376
|
+
p.appendChild(document.createTextNode(' mit Neuem'));
|
|
2377
|
+
}
|
|
2101
2378
|
$('standknopf').classList.add('neu');
|
|
2102
2379
|
$('standknopf').textContent = 'Ansehen';
|
|
2103
2380
|
}
|
|
@@ -2184,7 +2461,11 @@
|
|
|
2184
2461
|
: a.ergebnis === 'fehlgeschlagen' ? 'fehlgeschlagen (' + a.fehler + ')'
|
|
2185
2462
|
: 'übersprungen (lokale Änderung)';
|
|
2186
2463
|
li.appendChild(e('span', 'marke-' + art, text));
|
|
2187
|
-
|
|
2464
|
+
// Skill-Ebene an der Checkout-Zeile (E70): sonst steht hier nur, dass die Quelle neue
|
|
2465
|
+
// Commits hat, und wer sein eigenes Push sucht, findet es nicht wieder.
|
|
2466
|
+
var skills = c.geaenderteSkills || [];
|
|
2467
|
+
li.appendChild(quelleSpan('pfad', c.checkout.quelle, ' @ ' + c.checkout.ref
|
|
2468
|
+
+ (skills.length > 0 ? ' · ' + zahlwort(skills.length, 'Skill', 'Skills') + ': ' + skills.join(', ') : '')));
|
|
2188
2469
|
cul.appendChild(li);
|
|
2189
2470
|
});
|
|
2190
2471
|
checkoutBlock.appendChild(cul);
|
|
@@ -2204,6 +2485,33 @@
|
|
|
2204
2485
|
box.appendChild(pluginBlock);
|
|
2205
2486
|
}
|
|
2206
2487
|
|
|
2488
|
+
// Bundles im selben Lauf (E69, F64=O1): eine geänderte Definition wird beim Aktualisieren
|
|
2489
|
+
// nachgezogen, eine Zeile je Bundle im Stil der Checkout-Zeilen darüber.
|
|
2490
|
+
var bundleEintraege = ergebnis.bundles || [];
|
|
2491
|
+
if (bundleEintraege.length > 0) {
|
|
2492
|
+
var bundleBlock = e('div', 'block');
|
|
2493
|
+
bundleBlock.appendChild(e('span', 'etikett', 'Bundles'));
|
|
2494
|
+
var bul = e('ul');
|
|
2495
|
+
bundleEintraege.forEach(function (b) {
|
|
2496
|
+
var li = e('li');
|
|
2497
|
+
var text = b.ergebnis === 'aktualisiert' ? 'aktualisiert'
|
|
2498
|
+
: b.ergebnis === 'unveraendert' ? 'unverändert'
|
|
2499
|
+
: 'fehlgeschlagen (' + (b.fehler || '').split('\n')[0] + ')';
|
|
2500
|
+
li.appendChild(e('span', b.ergebnis === 'fehlgeschlagen' ? 'marke-aus' : 'marke-ok', text));
|
|
2501
|
+
// Was sich geändert hat, steht hinter dem Namen; ein Fehlschlag sagt, dass nichts geschah.
|
|
2502
|
+
var teile = [];
|
|
2503
|
+
if (b.gelegt.length > 0) teile.push('+ ' + b.gelegt.join(', '));
|
|
2504
|
+
if (b.entfernt.length > 0) teile.push('− ' + b.entfernt.join(', '));
|
|
2505
|
+
if (b.neueQuellen.length > 0) teile.push('neue Quellen: ' + b.neueQuellen.length);
|
|
2506
|
+
if (b.ergebnis === 'fehlgeschlagen') teile.push('bleibt auf dem alten Stand');
|
|
2507
|
+
li.appendChild(e('span', 'pfad', b.bundle + ' · ' + harnessName(b.ziel.harness) + ' · ' + ortName(b.ziel.ort)
|
|
2508
|
+
+ (teile.length > 0 ? ' · ' + teile.join(' · ') : '')));
|
|
2509
|
+
bul.appendChild(li);
|
|
2510
|
+
});
|
|
2511
|
+
bundleBlock.appendChild(bul);
|
|
2512
|
+
box.appendChild(bundleBlock);
|
|
2513
|
+
}
|
|
2514
|
+
|
|
2207
2515
|
if (ergebnis.aufraeumen.verwaiste.length > 0) {
|
|
2208
2516
|
var raeumBlock = e('div', 'block entfernt');
|
|
2209
2517
|
raeumBlock.appendChild(e('span', 'etikett', 'Verwaiste Checkouts'));
|