mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
(core) With ?aclUI=1 in the URL, UserManager for documents includes a button to open 'Access Rules'
Summary: AccessRules class that implements that UI is intended to look vaguely like detailed rules might look in the future, but only supports the very limited set we have now. In addition, UserManager and BillingPage code is separated into their own webpack bundles, to reduce the sizes of primary bundles, and relevant code from them is loaded asynchronously. Also add two TableData methods: filterRowIds() and findMatchingRowId(). Test Plan: Only tested manually, proper automated tests don't seem warranted for this temporary UI. Reviewers: paulfitz Reviewed By: paulfitz Differential Revision: https://phab.getgrist.com/D2620
This commit is contained in:
parent
2edf64c132
commit
bac070de91
@ -251,21 +251,16 @@ export class TableData extends ActionDispatcher {
|
||||
return records;
|
||||
}
|
||||
|
||||
public filterRowIds(properties: {[key: string]: any}): number[] {
|
||||
return this._filterRowIndices(properties).map(i => this._rowIdCol[i]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds and returns the list of records in this table that match the given properties object.
|
||||
* Properties may include 'id' and any table columns. Returned records are not sorted.
|
||||
*/
|
||||
public filterRecords(properties: {[key: string]: any}): RowRecord[] {
|
||||
const rowIndices: number[] = [];
|
||||
// Pairs of [valueToMatch, arrayOfColValues]
|
||||
const props = Object.keys(properties).map(p => [properties[p], this._columns.get(p)]);
|
||||
this._rowIdCol.forEach((id, i) => {
|
||||
for (const p of props) {
|
||||
if (p[1].values[i] !== p[0]) { return; }
|
||||
}
|
||||
// Collect the indices of the matching rows.
|
||||
rowIndices.push(i);
|
||||
});
|
||||
const rowIndices: number[] = this._filterRowIndices(properties);
|
||||
|
||||
// Convert the array of indices to an array of RowRecords.
|
||||
const records: RowRecord[] = rowIndices.map(i => ({id: this._rowIdCol[i]}));
|
||||
@ -289,6 +284,20 @@ export class TableData extends ActionDispatcher {
|
||||
return index < 0 ? 0 : this._rowIdCol[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first rowId matching the given filters, or 0 if no match. If there are multiple
|
||||
* matches, it is unspecified which will be returned.
|
||||
*/
|
||||
public findMatchingRowId(properties: {[key: string]: CellValue}): number {
|
||||
const props = Object.keys(properties).map(p => ({col: this._columns.get(p)!, value: properties[p]}));
|
||||
if (!props.every((p) => p.col)) {
|
||||
return 0;
|
||||
}
|
||||
return this._rowIdCol.find((id, i) =>
|
||||
props.every((p) => (p.col.values[i] === p.value))
|
||||
) || 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a DocAction received from the server; returns true, or false if it was skipped.
|
||||
*/
|
||||
@ -419,6 +428,19 @@ export class TableData extends ActionDispatcher {
|
||||
// Stop dispatching actions if we've been deleted. We might also want to clean up in the future.
|
||||
this._isLoaded = false;
|
||||
}
|
||||
|
||||
private _filterRowIndices(properties: {[key: string]: any}): number[] {
|
||||
const rowIndices: number[] = [];
|
||||
// Array of {col: arrayOfColValues, value: valueToMatch}
|
||||
const props = Object.keys(properties).map(p => ({col: this._columns.get(p)!, value: properties[p]}));
|
||||
this._rowIdCol.forEach((id, i) => {
|
||||
// Collect the indices of the matching rows.
|
||||
if (props.every((p) => (p.col.values[i] === p.value))) {
|
||||
rowIndices.push(i);
|
||||
}
|
||||
});
|
||||
return rowIndices;
|
||||
}
|
||||
}
|
||||
|
||||
function reassignArray<T>(targetArray: T[], sourceArray: T[]): void {
|
||||
|
@ -66,6 +66,7 @@ export interface IGristUrlState {
|
||||
embed?: boolean;
|
||||
style?: InterfaceStyle;
|
||||
compare?: string;
|
||||
aclUI?: boolean;
|
||||
};
|
||||
hash?: HashLink; // if present, this specifies an individual row within a section of a page.
|
||||
}
|
||||
@ -260,6 +261,9 @@ export function decodeUrl(gristConfig: Partial<GristLoadConfig>, location: Locat
|
||||
if (sp.has('compare')) {
|
||||
state.params!.compare = sp.get('compare')!;
|
||||
}
|
||||
if (sp.has('aclUI')) {
|
||||
state.params!.aclUI = isAffirmative(sp.get('aclUI'));
|
||||
}
|
||||
if (location.hash) {
|
||||
const hash = location.hash;
|
||||
const hashParts = hash.split('.');
|
||||
|
@ -75,6 +75,7 @@ export class GranularAccess {
|
||||
public update() {
|
||||
this._resources = this._docData.getTable('_grist_ACLResources')!;
|
||||
this._ownerOnlyTableIds.clear();
|
||||
this._onlyOwnersCanModifyStructure = false;
|
||||
for (const res of this._resources.getRecords()) {
|
||||
const code = String(res.colIds);
|
||||
if (res.tableId && code === '~o') {
|
||||
|
Loading…
Reference in New Issue
Block a user