diff --git a/app/client/widgets/FieldEditor.ts b/app/client/widgets/FieldEditor.ts index d2162b96..81e65346 100644 --- a/app/client/widgets/FieldEditor.ts +++ b/app/client/widgets/FieldEditor.ts @@ -443,8 +443,10 @@ function setupReadonlyEditorCleanup( * - Arrange for UnsavedChange protection against leaving the page with unsaved changes. */ function setupEditorCleanup( - owner: MultiHolder, gristDoc: GristDoc, field: ViewFieldRec, saveEdit: () => Promise + owner: MultiHolder, gristDoc: GristDoc, field: ViewFieldRec, _saveEdit: () => Promise ) { + const saveEdit = () => _saveEdit().catch(reportError); + // Whenever focus returns to the Clipboard component, close the editor by saving the value. gristDoc.app.on('clipboard_focus', saveEdit); diff --git a/app/server/lib/PermissionInfo.ts b/app/server/lib/PermissionInfo.ts index 1bcee652..c1b32658 100644 --- a/app/server/lib/PermissionInfo.ts +++ b/app/server/lib/PermissionInfo.ts @@ -25,11 +25,17 @@ export type PermissionSetWithContext = PermissionSetWithContextOf; -// Merge MemoSets straightforwardly, by concatenation. +// Merge MemoSets by collecting all memos with de-duplication. export function mergeMemoSets(psets: MemoSet[]): MemoSet { const result: Partial = {}; for (const prop of ALL_PERMISSION_PROPS) { - result[prop] = ([] as string[]).concat(...psets.map(p => p[prop])); + const merged = new Set(); + for (const p of psets) { + for (const memo of p[prop]) { + merged.add(memo); + } + } + result[prop] = [...merged]; } return result as MemoSet; }