Skip to content

Commit 1d8dc1d

Browse files
committed
Et2Nextmatch: Fix updateComplete was finishing too early and some important values were not set
This caused problems with an app's et2_ready and sorting
1 parent 5f1c14e commit 1d8dc1d

1 file changed

Lines changed: 72 additions & 3 deletions

File tree

api/js/etemplate/Et2Nextmatch/Et2Nextmatch.ts

Lines changed: 72 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ import {Et2VfsUpload} from "../Et2Vfs/Et2VfsUpload";
2828
import {
2929
applyLegacyNextmatchColumnPreferences,
3030
datagridColumnPreferenceValue,
31-
legacyColumnSelectionCsv,
32-
type Et2NextmatchResolvedColumn
31+
type Et2NextmatchResolvedColumn,
32+
legacyColumnSelectionCsv
3333
} from "./Et2NextmatchColumnPreferences";
3434
import "./Headers/Header";
3535
import "./Headers/SortableHeader";
@@ -227,6 +227,16 @@ export class Et2Nextmatch extends Et2Widget(LitElement) implements et2_IInput
227227
@property({type: String, attribute: "column-preference-name"})
228228
columnPreferenceName : string = "";
229229

230+
/**
231+
* App that owns this nextmatch's rows - used for sort/refresh/lettersearch preference
232+
* persistence, row-stylesheet loading and legacy action-manager registration (see
233+
* `_getAppName()`). Set this explicitly when a nextmatch is embedded in another app's
234+
* page (eg. InfoLog's CRM view inside addressbook) and the owning app can't be inferred
235+
* from `template`. Leave unset to fall back to `_getAppName()`'s own resolution.
236+
*/
237+
@property({type: String, attribute: "app"})
238+
appName : string = "";
239+
230240
private _view : Et2DatagridView = "row";
231241

232242
/**
@@ -970,6 +980,28 @@ export class Et2Nextmatch extends Et2Widget(LitElement) implements et2_IInput
970980
return this._actionController.findActionTarget(event);
971981
}
972982

983+
/**
984+
* Resolves once `firstUpdated()` has applied the template and seeded sort settings -
985+
* deliberately NOT once initial rows have loaded.
986+
*
987+
* Row loading (`_datagrid.reload()`) and the row stylesheet fetch happen after this
988+
* resolves and are intentionally excluded: they're a network round-trip, and nothing
989+
* that reacts to overall readiness (focus management, `resize()`, the "load" event)
990+
* should be held up waiting for rows to arrive.
991+
*/
992+
private _resolveFirstUpdatedComplete : () => void = () => {};
993+
private _firstUpdatedComplete : Promise<void> = new Promise((resolve) =>
994+
{
995+
this._resolveFirstUpdatedComplete = resolve;
996+
});
997+
998+
async getUpdateComplete() : Promise<boolean>
999+
{
1000+
const result = await super.getUpdateComplete();
1001+
await this._firstUpdatedComplete;
1002+
return result;
1003+
}
1004+
9731005
/**
9741006
* Initialize the widget from attributes/template and trigger first load.
9751007
* We prefer showing provided rows immediately to keep first paint fast.
@@ -981,6 +1013,21 @@ export class Et2Nextmatch extends Et2Widget(LitElement) implements et2_IInput
9811013
this._syncPlaceholderActionAvailability();
9821014
this._initializeExtraAttributeFilters();
9831015

1016+
try
1017+
{
1018+
// Seed sort from already-known `settings` (populated from attrs/content well
1019+
// before firstUpdated() runs) before awaiting anything below. This needs no
1020+
// template/row data, so there's no reason to delay it
1021+
this._initializeSettingsSort();
1022+
}
1023+
finally
1024+
{
1025+
// Resolve as soon as the minimum is ready, not waiting for template/row loading below.
1026+
this._resolveFirstUpdatedComplete();
1027+
}
1028+
1029+
// Everything from here we don't wait for, it will finish on its own. If needed, you can wait for
1030+
// whenColumnsReady() or listen for the appropriate event.
9841031
if(this.template)
9851032
{
9861033
await this._applyTemplateFromName(this.template);
@@ -989,7 +1036,8 @@ export class Et2Nextmatch extends Et2Widget(LitElement) implements et2_IInput
9891036
{
9901037
await this._applyTemplateFromSlots();
9911038
}
992-
this._initializeSettingsSort();
1039+
// Sync any sort headers that just rendered with the sort state seeded above.
1040+
this._updateSortHeaderState();
9931041

9941042
if(this.rows.length)
9951043
{
@@ -2684,9 +2732,30 @@ export class Et2Nextmatch extends Et2Widget(LitElement) implements et2_IInput
26842732

26852733
/**
26862734
* Resolve app-name used for sort preference persistence.
2735+
*
2736+
* Preference order: the explicit `appName` property, then the app that owns this
2737+
* nextmatch's rows (the first segment of `template`, eg. "infolog" from
2738+
* "infolog.index.rows"), then the instance manager's `app` as a last resort.
2739+
*
2740+
* Server-side, the preference is always read back under the app resolved from
2741+
* `get_rows` (Nextmatch.php: `explode('.', $value['get_rows'])[0]`), which is the
2742+
* same owning app - not necessarily the surrounding page/tab's app. Views that embed
2743+
* one app's nextmatch inside another (eg. InfoLog's CRM view inside addressbook, which
2744+
* forces currentapp to "addressbook") would otherwise save the sort preference under
2745+
* the wrong namespace and never see it applied again. Set `appName` explicitly for
2746+
* cases where `template` doesn't carry the owning app as its first segment.
26872747
*/
26882748
_getAppName() : string
26892749
{
2750+
if(this.appName)
2751+
{
2752+
return this.appName;
2753+
}
2754+
const template = this.template;
2755+
if(typeof template === "string" && template.includes("."))
2756+
{
2757+
return template.split(".")[0];
2758+
}
26902759
return String(this.getInstanceManager?.()?.app || this.egw()?.app_name?.() || "");
26912760
}
26922761

0 commit comments

Comments
 (0)