Bei einem Kunden aus der Automatisierungstechnik läuft die Disposition über das Schedule Board von Project Operations. Jeder Tab, den die Disponenten oben sehen, ist ein Datensatz der Tabelle Schedule Board Setting: ein paar Dutzend Spalten, ein JSON mit Zeitskala, Arbeitszeit, Zeilenhöhen, Schedule-Typen und Anforderungsbereichen, die gespeicherten Filterwerte, und drei Verweise auf eigene Konfigurationszeilen, nämlich Filterlayout, Ressourcenzellen-Vorlage und Ressourcenabfrage. In der Testumgebung stehen acht solcher Boards: drei vom System, die erste öffentliche Ansicht und vier eigene. Wer ein fünftes für ein neues Team braucht, hat bisher eines von Hand nachgebaut.
Das Werkzeug, das es schon gab
Microsoft liefert für diese Tabelle ein FastTrack-Steuerelement, Schedule Board Settings Management. Es kann Boards lesen, kopieren, löschen und aktivieren, und es kann nicht bearbeiten. Das wäre zu verschmerzen, wenn die Kopie vollständig wäre. Sie ist es nicht: Das Steuerelement übernimmt nur Schlüssel, deren Name mit msdyn_ beginnt, und die drei Verweise auf die Konfigurationen heißen in der Web API anders. Sie fallen weg. In der Testumgebung des Kunden hängen genau dort die eigenen Konfigurationen, das Filterlayout für Project Operations und die eigene Ressourcenabfrage. Eine Kopie ohne sie ist ein Board, das anders filtert als das Original, und niemand sieht auf den ersten Blick, warum.
Dazu kommt der Schutz. Das Steuerelement erkennt die Systemboards an ihrem Namen. Die Freigabeart „System“ und die festen Kennungen von Universal Resource Scheduling sind das bessere Merkmal, mit einer Ausnahme, die ich erst in der Testumgebung gesehen habe: Die erste öffentliche Ansicht hat in jeder Umgebung eine andere Kennung und steht dort auf „Nur ich“. Sie wird deshalb doch über ihren Namen erkannt, in drei Sprachen, und ist vor dem Löschen geschützt.
Ein Feld filtert erst, wenn die Abfrage seinen Schlüssel kennt.
Bearbeiten, ohne das JSON anzufassen
Am 1. Oktober entstand daraus eine Code App. Die Kopie nimmt die drei Verweise mit, auf Wunsch auch die Datensatz-Freigaben, und aus „System“ wird „Jeder“, denn eine Kopie ist nie ein Systemboard. Das Formular folgt dem Field Mapping, das Microsoft für die Einstellungen dokumentiert: Board-Ansicht, Farben, Schedule Assistant, Karte, Sonstiges, Schedule-Typen, Anforderungsbereiche. Was ein Board nicht setzt, erbt es vom Default-Board, und das Formular zeigt den geerbten Wert, statt ein leeres Feld.
Die Regel, die den Editor trägt, steht nicht im Field Mapping: Das JSON wird nie neu aufgebaut. Der Editor ändert genau den Pfad, den jemand angefasst hat, und lässt alle anderen Schlüssel stehen. Davon gibt es reichlich, undokumentierte Gruppierungen, versteckte Legenden, die Kopien der Schedule-Assistant-Konfigurationen in den Schedule-Typen. Schalter, die das Board nur als vorhandenen Schlüssel kennt, werden beim Ausschalten entfernt und nicht auf null gesetzt, weil das Board es selbst so macht. Und vor jedem Speichern steht der Diff bis hinunter zum einzelnen Wert; geschrieben werden nur die geänderten Spalten, vorher prüft die App die Versionsnummer. Das ist nötig, weil das Schedule Board selbst die Einstellungen bei jeder Ansichtsänderung zurückschreibt. Wer gleichzeitig im Board klickt und in der App speichert, überschreibt sonst den anderen.
Vier Boards, ein Filterlayout
Die Felder links im Ressourcenfilter des Boards stehen nicht im Board. Sie stehen als XML in der Konfigurationszeile hinter dem Verweis Filterlayout, und in der Testumgebung teilen sich vier Boards dieselbe Zeile. Wer dort ein Feld ändert, ändert es für alle vier. Die App zeigt deshalb über dem Editor, welche Boards das Layout teilen, und bietet an, eine Kopie nur für das aktuelle Board anzulegen und zuzuweisen. Bearbeitet werden nur die Felder der obersten Ebene; unbekannte Attribute und verschachtelte Elemente bleiben, wie sie sind, und der Diff läuft über den Schlüssel des Feldes, damit reine Formatierung keine Änderung ist.
Die zweite Erkenntnis war unangenehmer. Ein Feld im Filterlayout filtert erst, wenn die Ressourcenabfrage seinen Schlüssel als Eingabe auswertet. Ein Feld anzulegen ist leicht, und es sieht danach genauso aus wie die anderen. Es tut nur nichts. Die App liest deshalb die Ressourcenabfrage des Boards, oder die geerbte des Default-Boards, und markiert jedes Feld ohne Gegenstück mit „filtert nichts“. Umgekehrt listet sie jeden Schlüssel, den die Abfrage kennt und der im Layout fehlt, mit seiner Wirkung in Klartext, und füllt beim Übernehmen Art, Tabelle, Spalte und Beschriftung vor. Die Abfrage selbst parst ein kleiner Tag-Scanner statt eines XML-Parsers, weil die Abfragen das Präfix ihres Namensraums oft nicht deklarieren und ein strenger Parser dann aussteigt.
Freigaben mit den Rechten des Nutzers
Boards mit „Bestimmte Personen“ sieht nur, wer eine Freigabe hat. Die App zeigt die Freigaben, ändert die Stufe zwischen Lesen und Bearbeiten und vergibt neue, über den Dataverse-Konnektor an einer Verbindung des angemeldeten Benutzers. Eine Verbindung mit einem Dienstkonto wäre bequemer gewesen, und dann könnte jeder Nutzer der App mit dessen Rechten beliebige Boards teilen. Deshalb legt jeder Nutzer beim ersten Start seine eigene Verbindung an, und was er nicht darf, darf die App auch nicht.
Der Fehler des Tages steckte in der Personensuche. Sie lief erst nach einem Klick auf „Suchen“ und lieferte höchstens fünfzehn Treffer. Ein Vorname mit drei Buchstaben ergab in der Testumgebung achtzehn, und die gesuchte Person war nur zufällig dabei. Seit dem Nachmittag läuft die Suche eine Viertelsekunde nach der letzten Eingabe von selbst, jedes Wort muss in Name oder E-Mail vorkommen, Treffer, deren Name mit dem Begriff beginnt, stehen oben, und bei fünfundzwanzig steht ein Hinweis zum Weitertippen. Am selben Nachmittag kam der Besitzerwechsel dazu, einzeln und für mehrere Boards auf einmal, als Weg, ein „Nur ich“-Board an jemand anderen zu übergeben. Zugriffsteams fehlen in dieser Suche, weil sie nichts besitzen können.
Am Abend des 1. Oktober lief die App in der Testumgebung des Kunden. Was der Disponent von all dem sieht, Buchungskachel, Ressourcenzelle und Farben, und wie ein Board von dort nach Produktion kommt, ist der zweite Teil. Alle Funktionen stehen auf der Produktseite.