mirror of
https://github.com/gristlabs/grist-core.git
synced 2026-03-02 04:09:24 +00:00
(core) Add new UI for writing memos
Summary: Adds a new UI for writing access rule memos. Migrates old memos (written as Python comments) to the new UI. Test Plan: Browser and migration tests. Reviewers: jarek, dsagal Reviewed By: jarek Subscribers: dsagal, paulfitz Differential Revision: https://phab.getgrist.com/D3726
This commit is contained in:
35
app/client/aclui/ACLMemoEditor.ts
Normal file
35
app/client/aclui/ACLMemoEditor.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import {theme} from 'app/client/ui2018/cssVars';
|
||||
import {dom, DomElementArg, Observable, styled} from 'grainjs';
|
||||
|
||||
export function aclMemoEditor(obs: Observable<string>, ...args: DomElementArg[]): HTMLInputElement {
|
||||
return cssMemoInput(
|
||||
dom.prop('value', obs),
|
||||
dom.on('input', (_e, elem) => obs.set(elem.value)),
|
||||
...args,
|
||||
);
|
||||
}
|
||||
|
||||
const cssMemoInput = styled('input', `
|
||||
width: 100%;
|
||||
min-height: 28px;
|
||||
padding: 4px 5px;
|
||||
border-radius: 3px;
|
||||
border: 1px solid transparent;
|
||||
cursor: pointer;
|
||||
color: ${theme.accentText};
|
||||
background-color: ${theme.inputBg};
|
||||
caret-color : ${theme.inputFg};
|
||||
font: 12px 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
&:hover {
|
||||
border: 1px solid ${theme.inputBorder};
|
||||
}
|
||||
&:not(&-disabled):focus-within {
|
||||
outline: none !important;
|
||||
cursor: text;
|
||||
box-shadow: inset 0 0 0 1px ${theme.accentBorder};
|
||||
border-color: ${theme.accentBorder};
|
||||
}
|
||||
`);
|
||||
@@ -3,6 +3,7 @@
|
||||
*/
|
||||
import {aclColumnList} from 'app/client/aclui/ACLColumnList';
|
||||
import {aclFormulaEditor} from 'app/client/aclui/ACLFormulaEditor';
|
||||
import {aclMemoEditor} from 'app/client/aclui/ACLMemoEditor';
|
||||
import {aclSelect} from 'app/client/aclui/ACLSelect';
|
||||
import {ACLUsersPopup} from 'app/client/aclui/ACLUsers';
|
||||
import {PermissionKey, permissionsWidget} from 'app/client/aclui/PermissionsWidget';
|
||||
@@ -264,6 +265,7 @@ export class AccessRules extends Disposable {
|
||||
aclFormula: rule.aclFormula!,
|
||||
permissionsText: rule.permissionsText!,
|
||||
rulePos: rule.rulePos || null,
|
||||
memo: rule.memo ?? '',
|
||||
});
|
||||
}
|
||||
|
||||
@@ -397,6 +399,7 @@ export class AccessRules extends Disposable {
|
||||
cssCellIcon(),
|
||||
cssCell2(cssColHeaderCell(t('Condition'))),
|
||||
cssCell1(cssColHeaderCell(t('Permissions'))),
|
||||
cssCellIconWithMargins(),
|
||||
cssCellIcon(),
|
||||
)
|
||||
)
|
||||
@@ -641,6 +644,7 @@ class TableRules extends Disposable {
|
||||
cssCellIcon(),
|
||||
cssCell2(cssColHeaderCell(t('Condition'))),
|
||||
cssCell1(cssColHeaderCell(t('Permissions'))),
|
||||
cssCellIconWithMargins(),
|
||||
cssCellIcon(),
|
||||
)
|
||||
),
|
||||
@@ -1050,6 +1054,7 @@ class SpecialObsRuleSet extends ColumnObsRuleSet {
|
||||
cssCellIcon(),
|
||||
cssCell4(cssColHeaderCell(getSpecialRuleName(this.getColIds()))),
|
||||
cssCell1(cssColHeaderCell('Permissions')),
|
||||
cssCellIconWithMargins(),
|
||||
cssCellIcon(),
|
||||
),
|
||||
cssTableRow(
|
||||
@@ -1272,6 +1277,16 @@ class ObsRulePart extends Disposable {
|
||||
private _permissions = Observable.create<PartialPermissionSet>(
|
||||
this, this._rulePart?.permissions || emptyPermissionSet());
|
||||
|
||||
// The memo text. Updated whenever changes are made within `_memoEditor`.
|
||||
private _memo: Observable<string>;
|
||||
|
||||
// Reference to the memo editor element, for triggering focus. Shown when
|
||||
// `_showMemoEditor` is true.
|
||||
private _memoEditor: HTMLInputElement | undefined;
|
||||
|
||||
// Is the memo editor visible? Initialized to true if a saved memo exists for this rule.
|
||||
private _showMemoEditor: Observable<boolean>;
|
||||
|
||||
// Whether the rule is being checked after a change. Saving will wait for such checks to finish.
|
||||
private _checkPending = Observable.create(this, false);
|
||||
|
||||
@@ -1283,13 +1298,20 @@ class ObsRulePart extends Disposable {
|
||||
// Error message if any validation failed.
|
||||
private _error: Computed<string>;
|
||||
|
||||
// rulePart is omitted for a new ObsRulePart added by the user. If given, isNew may be set to
|
||||
// treat the rule as new and only use the rulePart for its initialization.
|
||||
constructor(private _ruleSet: ObsRuleSet, private _rulePart?: RulePart, isNew = false) {
|
||||
super();
|
||||
this._memo = Observable.create(this, _rulePart?.memo ?? '');
|
||||
|
||||
// If this rule has a blank memo, don't show the editor.
|
||||
this._showMemoEditor = Observable.create(this, !this.isBuiltIn() && this._memo.get() !== '');
|
||||
|
||||
|
||||
if (_rulePart && isNew) {
|
||||
// rulePart is omitted for a new ObsRulePart added by the user. If given, isNew may be set to
|
||||
// treat the rule as new and only use the rulePart for its initialization.
|
||||
this._rulePart = undefined;
|
||||
}
|
||||
|
||||
this._error = Computed.create(this, (use) => {
|
||||
return use(this._formulaError) ||
|
||||
this._warnInvalidColIds(use(this._formulaProperties).usedColIds) ||
|
||||
@@ -1305,6 +1327,7 @@ class ObsRulePart extends Disposable {
|
||||
if (use(this._checkPending)) { return RuleStatus.CheckPending; }
|
||||
return getChangedStatus(
|
||||
use(this._aclFormula) !== this._rulePart?.aclFormula ||
|
||||
use(this._memo) !== (this._rulePart?.memo ?? '') ||
|
||||
!isEqual(use(this._permissions), this._rulePart?.permissions)
|
||||
);
|
||||
});
|
||||
@@ -1318,6 +1341,7 @@ class ObsRulePart extends Disposable {
|
||||
aclFormula: this._aclFormula.get(),
|
||||
permissionsText: permissionSetToText(this._permissions.get()),
|
||||
rulePos: this._rulePart?.origRecord?.rulePos as number|undefined,
|
||||
memo: this._memo.get(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1347,50 +1371,98 @@ class ObsRulePart extends Disposable {
|
||||
}
|
||||
|
||||
public buildRulePartDom(wide: boolean = false) {
|
||||
return cssColumnGroup(
|
||||
cssCellIcon(
|
||||
(this._isNonFirstBuiltIn() ?
|
||||
null :
|
||||
cssIconButton(icon('Plus'),
|
||||
dom.on('click', () => this._ruleSet.addRulePart(this)),
|
||||
testId('rule-add'),
|
||||
)
|
||||
return cssRulePartAndMemo(
|
||||
cssColumnGroup(
|
||||
cssCellIcon(
|
||||
(this._isNonFirstBuiltIn() ?
|
||||
null :
|
||||
cssIconButton(icon('Plus'),
|
||||
dom.on('click', () => this._ruleSet.addRulePart(this)),
|
||||
testId('rule-add'),
|
||||
)
|
||||
),
|
||||
),
|
||||
),
|
||||
cssCell2(
|
||||
wide ? cssCell4.cls('') : null,
|
||||
aclFormulaEditor({
|
||||
initialValue: this._aclFormula.get(),
|
||||
readOnly: this.isBuiltIn(),
|
||||
setValue: (value) => this._setAclFormula(value),
|
||||
placeholder: dom.text((use) => {
|
||||
return (
|
||||
this._ruleSet.isSoleCondition(use, this) ? t('Everyone') :
|
||||
this._ruleSet.isLastCondition(use, this) ? t('EveryoneElse') :
|
||||
t('EnterCondition')
|
||||
);
|
||||
cssCell2(
|
||||
wide ? cssCell4.cls('') : null,
|
||||
aclFormulaEditor({
|
||||
initialValue: this._aclFormula.get(),
|
||||
readOnly: this.isBuiltIn(),
|
||||
setValue: (value) => this._setAclFormula(value),
|
||||
placeholder: dom.text((use) => {
|
||||
return (
|
||||
this._ruleSet.isSoleCondition(use, this) ? t('Everyone') :
|
||||
this._ruleSet.isLastCondition(use, this) ? t('EveryoneElse') :
|
||||
t('EnterCondition')
|
||||
);
|
||||
}),
|
||||
getSuggestions: (prefix) => this._completions.get(),
|
||||
}),
|
||||
getSuggestions: (prefix) => this._completions.get(),
|
||||
}),
|
||||
testId('rule-acl-formula'),
|
||||
testId('rule-acl-formula'),
|
||||
),
|
||||
cssCell1(cssCell.cls('-stretch'),
|
||||
permissionsWidget(this._ruleSet.getAvailableBits(), this._permissions,
|
||||
{disabled: this.isBuiltIn(), sanityCheck: (pset) => this.sanityCheck(pset)},
|
||||
testId('rule-permissions')
|
||||
),
|
||||
),
|
||||
cssCellIconWithMargins(
|
||||
dom.maybe(use => !this.isBuiltIn() && !use(this._showMemoEditor), () =>
|
||||
cssIconButton(icon('Memo'),
|
||||
dom.on('click', () => {
|
||||
this._showMemoEditor.set(true);
|
||||
// Note that focus is set when the memo icon is clicked, and not when
|
||||
// the editor is attached to the DOM; because rules with non-blank
|
||||
// memos have their editors visible by default when the page is first
|
||||
// loaded, focusing on creation could cause unintended focusing.
|
||||
setTimeout(() => this._memoEditor?.focus(), 0);
|
||||
}),
|
||||
testId('rule-memo-add'),
|
||||
)
|
||||
),
|
||||
),
|
||||
cssCellIcon(
|
||||
(this.isBuiltIn() ?
|
||||
null :
|
||||
cssIconButton(icon('Remove'),
|
||||
dom.on('click', () => this._ruleSet.removeRulePart(this)),
|
||||
testId('rule-remove'),
|
||||
)
|
||||
),
|
||||
),
|
||||
dom.maybe(this._error, (msg) => cssConditionError(msg, testId('rule-error'))),
|
||||
testId('rule-part'),
|
||||
),
|
||||
cssCell1(cssCell.cls('-stretch'),
|
||||
permissionsWidget(this._ruleSet.getAvailableBits(), this._permissions,
|
||||
{disabled: this.isBuiltIn(), sanityCheck: (pset) => this.sanityCheck(pset)},
|
||||
testId('rule-permissions')
|
||||
dom.maybe(this._showMemoEditor, () =>
|
||||
cssMemoColumnGroup(
|
||||
cssCellIcon(),
|
||||
cssMemoIcon('Memo'),
|
||||
cssCell2(
|
||||
wide ? cssCell4.cls('') : null,
|
||||
this._memoEditor = aclMemoEditor(this._memo,
|
||||
{
|
||||
placeholder: t('MemoEditorPlaceholder'),
|
||||
},
|
||||
dom.onKeyDown({
|
||||
// Match the behavior of the formula editor.
|
||||
Enter: (_ev, el) => el.blur(),
|
||||
}),
|
||||
),
|
||||
testId('rule-memo-editor'),
|
||||
),
|
||||
cssCellIconWithMargins(),
|
||||
cssCellIcon(
|
||||
cssIconButton(icon('Remove'),
|
||||
dom.on('click', () => {
|
||||
this._showMemoEditor.set(false);
|
||||
this._memo.set('');
|
||||
}),
|
||||
testId('rule-memo-remove'),
|
||||
),
|
||||
),
|
||||
testId('rule-memo'),
|
||||
),
|
||||
),
|
||||
cssCellIcon(
|
||||
(this.isBuiltIn() ?
|
||||
null :
|
||||
cssIconButton(icon('Remove'),
|
||||
dom.on('click', () => this._ruleSet.removeRulePart(this)),
|
||||
testId('rule-remove'),
|
||||
)
|
||||
),
|
||||
),
|
||||
dom.maybe(this._error, (msg) => cssConditionError(msg, testId('rule-error'))),
|
||||
testId('rule-part'),
|
||||
testId('rule-part-and-memo'),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1652,6 +1724,7 @@ const cssCell = styled('div', `
|
||||
|
||||
// Variations on columns of different widths.
|
||||
const cssCellIcon = styled(cssCell, `flex: none; width: 24px;`);
|
||||
const cssCellIconWithMargins = styled(cssCellIcon, `margin: 0px 8px;`);
|
||||
const cssCell1 = styled(cssCell, `flex: 1;`);
|
||||
const cssCell2 = styled(cssCell, `flex: 2;`);
|
||||
const cssCell4 = styled(cssCell, `flex: 4;`);
|
||||
@@ -1704,3 +1777,19 @@ const cssRuleProblems = styled('div', `
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
`);
|
||||
|
||||
const cssRulePartAndMemo = styled('div', `
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
row-gap: 4px;
|
||||
`);
|
||||
|
||||
const cssMemoColumnGroup = styled(cssColumnGroup, `
|
||||
margin-bottom: 8px;
|
||||
`);
|
||||
|
||||
const cssMemoIcon = styled(icon, `
|
||||
--icon-color: ${theme.accentIcon};
|
||||
margin-left: 8px;
|
||||
margin-right: 8px;
|
||||
`);
|
||||
|
||||
@@ -98,7 +98,7 @@ function buildNotificationDom(item: Notification, options: IBeaconOpenOptions) {
|
||||
item.options.actions.map((action) => buildAction(action, item, options))
|
||||
) : null,
|
||||
item.options.memos.length ? cssToastMemos(
|
||||
item.options.memos.map(memo => cssToastMemo(memo))
|
||||
item.options.memos.map(memo => cssToastMemo(memo, testId('toast-memo')))
|
||||
) : null,
|
||||
),
|
||||
dom.maybe(item.options.canUserClose, () =>
|
||||
|
||||
@@ -77,6 +77,7 @@ export type IconName = "ChartArea" |
|
||||
"Lock" |
|
||||
"Log" |
|
||||
"Mail" |
|
||||
"Memo" |
|
||||
"Message" |
|
||||
"Minus" |
|
||||
"MobileChat" |
|
||||
@@ -209,6 +210,7 @@ export const IconList: IconName[] = ["ChartArea",
|
||||
"Lock",
|
||||
"Log",
|
||||
"Mail",
|
||||
"Memo",
|
||||
"Message",
|
||||
"Minus",
|
||||
"MobileChat",
|
||||
|
||||
@@ -454,7 +454,7 @@ function readAclRules(docData: DocData, {log, compile, includeHelperCols}: ReadA
|
||||
origRecord: rule,
|
||||
aclFormula: String(rule.aclFormula),
|
||||
matchFunc: rule.aclFormula ? compile?.(aclFormulaParsed) : defaultMatchFunc,
|
||||
memo: aclFormulaParsed && aclFormulaParsed[0] === 'Comment' && aclFormulaParsed[2],
|
||||
memo: rule.memo,
|
||||
permissions: parsePermissions(String(rule.permissionsText)),
|
||||
permissionsText: String(rule.permissionsText),
|
||||
});
|
||||
|
||||
@@ -4,7 +4,7 @@ import { GristObjCode } from "app/plugin/GristData";
|
||||
|
||||
// tslint:disable:object-literal-key-quotes
|
||||
|
||||
export const SCHEMA_VERSION = 34;
|
||||
export const SCHEMA_VERSION = 35;
|
||||
|
||||
export const schema = {
|
||||
|
||||
@@ -170,6 +170,7 @@ export const schema = {
|
||||
permissionsText : "Text",
|
||||
rulePos : "PositionNumber",
|
||||
userAttributes : "Text",
|
||||
memo : "Text",
|
||||
},
|
||||
|
||||
"_grist_ACLResources": {
|
||||
@@ -374,6 +375,7 @@ export interface SchemaTypes {
|
||||
permissionsText: string;
|
||||
rulePos: number;
|
||||
userAttributes: string;
|
||||
memo: string;
|
||||
};
|
||||
|
||||
"_grist_ACLResources": {
|
||||
|
||||
@@ -6,7 +6,7 @@ export const GRIST_DOC_SQL = `
|
||||
PRAGMA foreign_keys=OFF;
|
||||
BEGIN TRANSACTION;
|
||||
CREATE TABLE IF NOT EXISTS "_grist_DocInfo" (id INTEGER PRIMARY KEY, "docId" TEXT DEFAULT '', "peers" TEXT DEFAULT '', "basketId" TEXT DEFAULT '', "schemaVersion" INTEGER DEFAULT 0, "timezone" TEXT DEFAULT '', "documentSettings" TEXT DEFAULT '');
|
||||
INSERT INTO _grist_DocInfo VALUES(1,'','','',34,'','');
|
||||
INSERT INTO _grist_DocInfo VALUES(1,'','','',35,'','');
|
||||
CREATE TABLE IF NOT EXISTS "_grist_Tables" (id INTEGER PRIMARY KEY, "tableId" TEXT DEFAULT '', "primaryViewId" INTEGER DEFAULT 0, "summarySourceTable" INTEGER DEFAULT 0, "onDemand" BOOLEAN DEFAULT 0, "rawViewSectionRef" INTEGER DEFAULT 0);
|
||||
CREATE TABLE IF NOT EXISTS "_grist_Tables_column" (id INTEGER PRIMARY KEY, "parentId" INTEGER DEFAULT 0, "parentPos" NUMERIC DEFAULT 1e999, "colId" TEXT DEFAULT '', "type" TEXT DEFAULT '', "widgetOptions" TEXT DEFAULT '', "isFormula" BOOLEAN DEFAULT 0, "formula" TEXT DEFAULT '', "label" TEXT DEFAULT '', "untieColIdFromLabel" BOOLEAN DEFAULT 0, "summarySourceCol" INTEGER DEFAULT 0, "displayCol" INTEGER DEFAULT 0, "visibleCol" INTEGER DEFAULT 0, "rules" TEXT DEFAULT NULL, "recalcWhen" INTEGER DEFAULT 0, "recalcDeps" TEXT DEFAULT NULL);
|
||||
CREATE TABLE IF NOT EXISTS "_grist_Imports" (id INTEGER PRIMARY KEY, "tableRef" INTEGER DEFAULT 0, "origFileName" TEXT DEFAULT '', "parseFormula" TEXT DEFAULT '', "delimiter" TEXT DEFAULT '', "doublequote" BOOLEAN DEFAULT 0, "escapechar" TEXT DEFAULT '', "quotechar" TEXT DEFAULT '', "skipinitialspace" BOOLEAN DEFAULT 0, "encoding" TEXT DEFAULT '', "hasHeaders" BOOLEAN DEFAULT 0);
|
||||
@@ -23,8 +23,8 @@ CREATE TABLE IF NOT EXISTS "_grist_Validations" (id INTEGER PRIMARY KEY, "formul
|
||||
CREATE TABLE IF NOT EXISTS "_grist_REPL_Hist" (id INTEGER PRIMARY KEY, "code" TEXT DEFAULT '', "outputText" TEXT DEFAULT '', "errorText" TEXT DEFAULT '');
|
||||
CREATE TABLE IF NOT EXISTS "_grist_Attachments" (id INTEGER PRIMARY KEY, "fileIdent" TEXT DEFAULT '', "fileName" TEXT DEFAULT '', "fileType" TEXT DEFAULT '', "fileSize" INTEGER DEFAULT 0, "imageHeight" INTEGER DEFAULT 0, "imageWidth" INTEGER DEFAULT 0, "timeDeleted" DATETIME DEFAULT NULL, "timeUploaded" DATETIME DEFAULT NULL);
|
||||
CREATE TABLE IF NOT EXISTS "_grist_Triggers" (id INTEGER PRIMARY KEY, "tableRef" INTEGER DEFAULT 0, "eventTypes" TEXT DEFAULT NULL, "isReadyColRef" INTEGER DEFAULT 0, "actions" TEXT DEFAULT '');
|
||||
CREATE TABLE IF NOT EXISTS "_grist_ACLRules" (id INTEGER PRIMARY KEY, "resource" INTEGER DEFAULT 0, "permissions" INTEGER DEFAULT 0, "principals" TEXT DEFAULT '', "aclFormula" TEXT DEFAULT '', "aclColumn" INTEGER DEFAULT 0, "aclFormulaParsed" TEXT DEFAULT '', "permissionsText" TEXT DEFAULT '', "rulePos" NUMERIC DEFAULT 1e999, "userAttributes" TEXT DEFAULT '');
|
||||
INSERT INTO _grist_ACLRules VALUES(1,1,63,'[1]','',0,'','',1e999,'');
|
||||
CREATE TABLE IF NOT EXISTS "_grist_ACLRules" (id INTEGER PRIMARY KEY, "resource" INTEGER DEFAULT 0, "permissions" INTEGER DEFAULT 0, "principals" TEXT DEFAULT '', "aclFormula" TEXT DEFAULT '', "aclColumn" INTEGER DEFAULT 0, "aclFormulaParsed" TEXT DEFAULT '', "permissionsText" TEXT DEFAULT '', "rulePos" NUMERIC DEFAULT 1e999, "userAttributes" TEXT DEFAULT '', "memo" TEXT DEFAULT '');
|
||||
INSERT INTO _grist_ACLRules VALUES(1,1,63,'[1]','',0,'','',1e999,'','');
|
||||
CREATE TABLE IF NOT EXISTS "_grist_ACLResources" (id INTEGER PRIMARY KEY, "tableId" TEXT DEFAULT '', "colIds" TEXT DEFAULT '');
|
||||
INSERT INTO _grist_ACLResources VALUES(1,'','');
|
||||
CREATE TABLE IF NOT EXISTS "_grist_ACLPrincipals" (id INTEGER PRIMARY KEY, "type" TEXT DEFAULT '', "userEmail" TEXT DEFAULT '', "userName" TEXT DEFAULT '', "groupName" TEXT DEFAULT '', "instanceId" TEXT DEFAULT '');
|
||||
@@ -43,7 +43,7 @@ export const GRIST_DOC_WITH_TABLE1_SQL = `
|
||||
PRAGMA foreign_keys=OFF;
|
||||
BEGIN TRANSACTION;
|
||||
CREATE TABLE IF NOT EXISTS "_grist_DocInfo" (id INTEGER PRIMARY KEY, "docId" TEXT DEFAULT '', "peers" TEXT DEFAULT '', "basketId" TEXT DEFAULT '', "schemaVersion" INTEGER DEFAULT 0, "timezone" TEXT DEFAULT '', "documentSettings" TEXT DEFAULT '');
|
||||
INSERT INTO _grist_DocInfo VALUES(1,'','','',34,'','');
|
||||
INSERT INTO _grist_DocInfo VALUES(1,'','','',35,'','');
|
||||
CREATE TABLE IF NOT EXISTS "_grist_Tables" (id INTEGER PRIMARY KEY, "tableId" TEXT DEFAULT '', "primaryViewId" INTEGER DEFAULT 0, "summarySourceTable" INTEGER DEFAULT 0, "onDemand" BOOLEAN DEFAULT 0, "rawViewSectionRef" INTEGER DEFAULT 0);
|
||||
INSERT INTO _grist_Tables VALUES(1,'Table1',1,0,0,2);
|
||||
CREATE TABLE IF NOT EXISTS "_grist_Tables_column" (id INTEGER PRIMARY KEY, "parentId" INTEGER DEFAULT 0, "parentPos" NUMERIC DEFAULT 1e999, "colId" TEXT DEFAULT '', "type" TEXT DEFAULT '', "widgetOptions" TEXT DEFAULT '', "isFormula" BOOLEAN DEFAULT 0, "formula" TEXT DEFAULT '', "label" TEXT DEFAULT '', "untieColIdFromLabel" BOOLEAN DEFAULT 0, "summarySourceCol" INTEGER DEFAULT 0, "displayCol" INTEGER DEFAULT 0, "visibleCol" INTEGER DEFAULT 0, "rules" TEXT DEFAULT NULL, "recalcWhen" INTEGER DEFAULT 0, "recalcDeps" TEXT DEFAULT NULL);
|
||||
@@ -76,8 +76,8 @@ CREATE TABLE IF NOT EXISTS "_grist_Validations" (id INTEGER PRIMARY KEY, "formul
|
||||
CREATE TABLE IF NOT EXISTS "_grist_REPL_Hist" (id INTEGER PRIMARY KEY, "code" TEXT DEFAULT '', "outputText" TEXT DEFAULT '', "errorText" TEXT DEFAULT '');
|
||||
CREATE TABLE IF NOT EXISTS "_grist_Attachments" (id INTEGER PRIMARY KEY, "fileIdent" TEXT DEFAULT '', "fileName" TEXT DEFAULT '', "fileType" TEXT DEFAULT '', "fileSize" INTEGER DEFAULT 0, "imageHeight" INTEGER DEFAULT 0, "imageWidth" INTEGER DEFAULT 0, "timeDeleted" DATETIME DEFAULT NULL, "timeUploaded" DATETIME DEFAULT NULL);
|
||||
CREATE TABLE IF NOT EXISTS "_grist_Triggers" (id INTEGER PRIMARY KEY, "tableRef" INTEGER DEFAULT 0, "eventTypes" TEXT DEFAULT NULL, "isReadyColRef" INTEGER DEFAULT 0, "actions" TEXT DEFAULT '');
|
||||
CREATE TABLE IF NOT EXISTS "_grist_ACLRules" (id INTEGER PRIMARY KEY, "resource" INTEGER DEFAULT 0, "permissions" INTEGER DEFAULT 0, "principals" TEXT DEFAULT '', "aclFormula" TEXT DEFAULT '', "aclColumn" INTEGER DEFAULT 0, "aclFormulaParsed" TEXT DEFAULT '', "permissionsText" TEXT DEFAULT '', "rulePos" NUMERIC DEFAULT 1e999, "userAttributes" TEXT DEFAULT '');
|
||||
INSERT INTO _grist_ACLRules VALUES(1,1,63,'[1]','',0,'','',1e999,'');
|
||||
CREATE TABLE IF NOT EXISTS "_grist_ACLRules" (id INTEGER PRIMARY KEY, "resource" INTEGER DEFAULT 0, "permissions" INTEGER DEFAULT 0, "principals" TEXT DEFAULT '', "aclFormula" TEXT DEFAULT '', "aclColumn" INTEGER DEFAULT 0, "aclFormulaParsed" TEXT DEFAULT '', "permissionsText" TEXT DEFAULT '', "rulePos" NUMERIC DEFAULT 1e999, "userAttributes" TEXT DEFAULT '', "memo" TEXT DEFAULT '');
|
||||
INSERT INTO _grist_ACLRules VALUES(1,1,63,'[1]','',0,'','',1e999,'','');
|
||||
CREATE TABLE IF NOT EXISTS "_grist_ACLResources" (id INTEGER PRIMARY KEY, "tableId" TEXT DEFAULT '', "colIds" TEXT DEFAULT '');
|
||||
INSERT INTO _grist_ACLResources VALUES(1,'','');
|
||||
CREATE TABLE IF NOT EXISTS "_grist_ACLPrincipals" (id INTEGER PRIMARY KEY, "type" TEXT DEFAULT '', "userEmail" TEXT DEFAULT '', "userName" TEXT DEFAULT '', "groupName" TEXT DEFAULT '', "instanceId" TEXT DEFAULT '');
|
||||
|
||||
Reference in New Issue
Block a user