Skip to content

Commit

Permalink
(core) updates from grist-core
Browse files Browse the repository at this point in the history
  • Loading branch information
paulfitz committed Oct 1, 2024
2 parents bda7935 + 437d7e6 commit 05d8976
Show file tree
Hide file tree
Showing 19 changed files with 116 additions and 250 deletions.
19 changes: 13 additions & 6 deletions app/client/components/Clipboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ Base.setBaseFor(Clipboard);

Clipboard.commands = {
contextMenuCopy: function() { this._doContextMenuCopy(); },
contextMenuCopyWithHeaders: function() { this._doContextMenuCopyWithHeaders(); },
contextMenuCut: function() { this._doContextMenuCut(); },
contextMenuPaste: function() { this._doContextMenuPaste(); },
};
Expand All @@ -126,7 +127,13 @@ Clipboard.prototype._onCopy = function(elem, event) {
Clipboard.prototype._doContextMenuCopy = function() {
let pasteObj = commands.allCommands.copy.run();

this._copyToClipboard(pasteObj, 'copy');
this._copyToClipboard(pasteObj, 'copy', false);
};

Clipboard.prototype._doContextMenuCopyWithHeaders = function() {
let pasteObj = commands.allCommands.copy.run();

this._copyToClipboard(pasteObj, 'copy', true);
};

Clipboard.prototype._onCut = function(elem, event) {
Expand All @@ -146,21 +153,21 @@ Clipboard.prototype._doContextMenuCut = function() {
Clipboard.prototype._setCBdata = function(pasteObj, clipboardData) {
if (!pasteObj) { return; }

const plainText = tableUtil.makePasteText(pasteObj.data, pasteObj.selection);
const plainText = tableUtil.makePasteText(pasteObj.data, pasteObj.selection, false);
clipboardData.setData('text/plain', plainText);
const htmlText = tableUtil.makePasteHtml(pasteObj.data, pasteObj.selection);
const htmlText = tableUtil.makePasteHtml(pasteObj.data, pasteObj.selection, false);
clipboardData.setData('text/html', htmlText);

this._setCutCallback(pasteObj, plainText);
};

Clipboard.prototype._copyToClipboard = async function(pasteObj, action) {
Clipboard.prototype._copyToClipboard = async function(pasteObj, action, includeColHeaders) {
if (!pasteObj) { return; }

const plainText = tableUtil.makePasteText(pasteObj.data, pasteObj.selection);
const plainText = tableUtil.makePasteText(pasteObj.data, pasteObj.selection, includeColHeaders);
let data;
if (typeof ClipboardItem === 'function') {
const htmlText = tableUtil.makePasteHtml(pasteObj.data, pasteObj.selection);
const htmlText = tableUtil.makePasteHtml(pasteObj.data, pasteObj.selection, includeColHeaders);
// eslint-disable-next-line no-undef
data = new ClipboardItem({
// eslint-disable-next-line no-undef
Expand Down
5 changes: 5 additions & 0 deletions app/client/components/commandList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ export type CommandName =
| 'cut'
| 'paste'
| 'contextMenuCopy'
| 'contextMenuCopyWithHeaders'
| 'contextMenuCut'
| 'contextMenuPaste'
| 'fillSelectionDown'
Expand Down Expand Up @@ -470,6 +471,10 @@ export const groups: CommendGroupDef[] = [{
keys: ['Mod+C'],
desc: 'Copy current selection to clipboard',
bindKeys: false,
}, {
name: 'contextMenuCopyWithHeaders',
keys: [],
desc: 'Copy current selection to clipboard including headers',
}, {
name: 'contextMenuCut',
keys: ['Mod+X'],
Expand Down
14 changes: 9 additions & 5 deletions app/client/lib/tableUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,16 @@ export function fieldInsertPositions(viewFields: KoArray<ViewFieldRec>, index: n
* @param {CopySelection} selection - a CopySelection instance
* @return {String}
**/
export function makePasteText(tableData: TableData, selection: CopySelection) {
export function makePasteText(tableData: TableData, selection: CopySelection, includeColHeaders: boolean) {
// tsvEncode expects data as a 2-d array with each a array representing a row
// i.e. [["1-1", "1-2", "1-3"],["2-1", "2-2", "2-3"]]
const values = selection.rowIds.map(rowId =>
selection.columns.map(col => col.fmtGetter(rowId)));
return tsvEncode(values);
const result = [];
if (includeColHeaders) {
result.push(selection.fields.map(f => f.label()));
}
result.push(...selection.rowIds.map(rowId =>
selection.columns.map(col => col.fmtGetter(rowId))));
return tsvEncode(result);
}

/**
Expand Down Expand Up @@ -70,7 +74,7 @@ export function makePasteHtml(tableData: TableData, selection: CopySelection, in
)),
// Include column headers if requested.
(includeColHeaders ?
dom('tr', selection.colIds.map(colId => dom('th', colId))) :
dom('tr', selection.fields.map(field => dom('th', field.label()))) :
null
),
// Fill with table cells.
Expand Down
5 changes: 4 additions & 1 deletion app/client/ui/AdminPanel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,10 @@ Please log in as an administrator.`)),
const success = result?.status === 'success';
const details = result?.details as SandboxingBootProbeDetails|undefined;
if (!details) {
return cssValueLabel(t('unknown'));
// Sandbox details get filled out relatively slowly if
// this is first time on admin panel. So show "checking"
// if we don't have a reported status yet.
return cssValueLabel(result?.status ? t('unknown') : t('checking'));
}
const flavor = details.flavor;
const configured = details.configured;
Expand Down
1 change: 1 addition & 0 deletions app/client/ui/CellContextMenu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export function CellContextMenu(cellOptions: ICellContextMenu, colOptions: IMult
result.push(
menuItemCmd(allCommands.contextMenuCut, t('Cut'), disableForReadonlyColumn),
menuItemCmd(allCommands.contextMenuCopy, t('Copy')),
menuItemCmd(allCommands.contextMenuCopyWithHeaders, t('Copy with headers')),
menuItemCmd(allCommands.contextMenuPaste, t('Paste'), disableForReadonlyColumn),
menuDivider(),
colOptions.isFormula ?
Expand Down
62 changes: 0 additions & 62 deletions app/gen-server/lib/Housekeeper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@ import { ApiError } from 'app/common/ApiError';
import { delay } from 'app/common/delay';
import { buildUrlId } from 'app/common/gristUrls';
import { normalizedDateTimeString } from 'app/common/normalizedDateTimeString';
import { BillingAccount } from 'app/gen-server/entity/BillingAccount';
import { Document } from 'app/gen-server/entity/Document';
import { Organization } from 'app/gen-server/entity/Organization';
import { Product } from 'app/gen-server/entity/Product';
import { Workspace } from 'app/gen-server/entity/Workspace';
import { HomeDBManager, Scope } from 'app/gen-server/lib/homedb/HomeDBManager';
import { fromNow } from 'app/gen-server/sqlUtils';
Expand Down Expand Up @@ -438,63 +436,3 @@ async function forEachWithBreaks<T>(logText: string, items: T[], callback: (item
}
log.rawInfo(logText, {itemsProcesssed, itemsTotal, timeMs: Date.now() - start});
}

/**
* For a brief moment file `stubs/app/server/server.ts` was ignoring the GRIST_DEFAULT_PRODUCT
* variable, which is currently set for all deployment types to 'Free' product. As a result orgs
* created after 2024-06-12 (1.1.15) were created with 'teamFree' product instead of 'Free'.
* It only affected deployments that were using:
* - GRIST_DEFAULT_PRODUCT variable set to 'Free'
* - GRIST_SINGLE_ORG set to enforce single org mode.
*
* This method fixes the product for all orgs created with 'teamFree' product, if the default
* product that should be used is 'Free' and the deployment type is not 'saas' ('saas' deployment
* isn't using GRIST_DEFAULT_PRODUCT variable). This method should be removed after 2024.10.01.
*
* There is a corresponding test that will fail if this method (and that test) are not removed.
*
* @returns true if the method was run, false otherwise.
*/
export async function fixSiteProducts(options: {
deploymentType: string,
db: HomeDBManager
}) {
const {deploymentType, db} = options;

const hasDefaultProduct = () => Boolean(process.env.GRIST_DEFAULT_PRODUCT);
const defaultProductIsFree = () => process.env.GRIST_DEFAULT_PRODUCT === 'Free';
const notSaasDeployment = () => deploymentType !== 'saas';
const mustRun = hasDefaultProduct() && defaultProductIsFree() && notSaasDeployment();
if (!mustRun) {
return false;
}
const removeMeDate = new Date('2024-10-01');
const warningMessage = `WARNING: This method should be removed after ${removeMeDate.toDateString()}.`;
if (new Date() > removeMeDate) {
console.warn(warningMessage);
}

// Find all billing accounts on teamFree product and change them to the Free.
return await db.connection.transaction(async (t) => {
const freeProduct = await t.findOne(Product, {where: {name: 'Free'}});
const freeTeamProduct = await t.findOne(Product, {where: {name: 'teamFree'}});

if (!freeTeamProduct) {
console.warn('teamFree product not found.');
return false;
}

if (!freeProduct) {
console.warn('Free product not found.');
return false;
}

await t.createQueryBuilder()
.update(BillingAccount)
.set({product: freeProduct.id})
.where({product: freeTeamProduct.id})
.execute();

return true;
});
}
6 changes: 0 additions & 6 deletions app/server/MergedServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,12 +192,6 @@ export class MergedServer {
this.flexServer.checkOptionCombinations();
this.flexServer.summary();
this.flexServer.ready();

// Some tests have their timing perturbed by having this earlier
// TODO: update those tests.
if (this.hasComponent("docs")) {
await this.flexServer.checkSandbox();
}
} catch(e) {
await this.flexServer.close();
throw e;
Expand Down
2 changes: 1 addition & 1 deletion app/server/lib/BootProbes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ const _sandboxingProbe: Probe = {
id: 'sandboxing',
name: 'Is document sandboxing effective',
apply: async (server, req) => {
const details = server.getSandboxInfo();
const details = await server.getSandboxInfo();
return {
status: (details?.configured && details?.functional) ? 'success' : 'fault',
details,
Expand Down
12 changes: 6 additions & 6 deletions app/server/lib/FlexServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1397,8 +1397,9 @@ export class FlexServer implements GristServer {
}
}

public async checkSandbox() {
if (this._check('sandbox', 'doc')) { return; }
public async getSandboxInfo(): Promise<SandboxInfo> {
if (this._sandboxInfo) { return this._sandboxInfo; }

const flavor = process.env.GRIST_SANDBOX_FLAVOR || 'unknown';
const info = this._sandboxInfo = {
flavor,
Expand All @@ -1408,6 +1409,8 @@ export class FlexServer implements GristServer {
sandboxed: false,
lastSuccessfulStep: 'none',
} as SandboxInfo;
// Only meaningful on instances that handle documents.
if (!this._docManager) { return info; }
try {
const sandbox = createSandbox({
server: this,
Expand All @@ -1432,10 +1435,7 @@ export class FlexServer implements GristServer {
} catch (e) {
info.error = String(e);
}
}

public getSandboxInfo(): SandboxInfo|undefined {
return this._sandboxInfo;
return info;
}

public getInfo(key: string): any {
Expand Down
4 changes: 2 additions & 2 deletions app/server/lib/GristServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export interface GristServer {
servesPlugins(): boolean;
getBundledWidgets(): ICustomWidget[];
getBootKey(): string|undefined;
getSandboxInfo(): SandboxInfo|undefined;
getSandboxInfo(): Promise<SandboxInfo>;
getInfo(key: string): any;
getJobs(): GristJobs;
}
Expand Down Expand Up @@ -165,7 +165,7 @@ export function createDummyGristServer(): GristServer {
getPlugins() { return []; },
getBundledWidgets() { return []; },
getBootKey() { return undefined; },
getSandboxInfo() { return undefined; },
getSandboxInfo() { throw new Error('no sandbox'); },
getInfo(key: string) { return undefined; },
getJobs(): GristJobs { throw new Error('no job system'); },
};
Expand Down
2 changes: 1 addition & 1 deletion buildtools/.grist-ee-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.9.9
0.9.10
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "grist-core",
"version": "1.1.18",
"version": "1.2.0",
"license": "Apache-2.0",
"description": "Grist is the evolution of spreadsheets",
"homepage": "https://github.com/gristlabs/grist-core",
Expand Down
15 changes: 11 additions & 4 deletions static/locales/en.client.json
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,8 @@
"Comment": "Comment",
"Copy": "Copy",
"Cut": "Cut",
"Paste": "Paste"
"Paste": "Paste",
"Copy with headers": "Copy with headers"
},
"ChartView": {
"Create separate series for each value of the selected column.": "Create separate series for each value of the selected column.",
Expand Down Expand Up @@ -1213,7 +1214,10 @@
"Community widgets are created and maintained by Grist community members.": "Community widgets are created and maintained by Grist community members.",
"Creates a reverse column in target table that can be edited from either end.": "Creates a reverse column in target table that can be edited from either end.",
"This limitation occurs when one end of a two-way reference is configured as a single Reference.": "This limitation occurs when one end of a two-way reference is configured as a single Reference.",
"To allow multiple assignments, change the type of the Reference column to Reference List.": "To allow multiple assignments, change the type of the Reference column to Reference List."
"To allow multiple assignments, change the type of the Reference column to Reference List.": "To allow multiple assignments, change the type of the Reference column to Reference List.",
"This limitation occurs when one column in a two-way reference has the Reference type.": "This limitation occurs when one column in a two-way reference has the Reference type.",
"To allow multiple assignments, change the referenced column's type to Reference List.": "To allow multiple assignments, change the referenced column's type to Reference List.",
"Two-way references are not currently supported for Formula or Trigger Formula columns": "Two-way references are not currently supported for Formula or Trigger Formula columns"
},
"DescriptionConfig": {
"DESCRIPTION": "DESCRIPTION"
Expand Down Expand Up @@ -1594,7 +1598,8 @@
"Key to sign sessions with": "Key to sign sessions with",
"Session Secret": "Session Secret",
"Enable Grist Enterprise": "Enable Grist Enterprise",
"Enterprise": "Enterprise"
"Enterprise": "Enterprise",
"checking": "checking"
},
"Columns": {
"Remove Column": "Remove Column"
Expand Down Expand Up @@ -1761,7 +1766,9 @@
"Delete column {{column}} in table {{table}}?": "Delete column {{column}} in table {{table}}?",
"It is the reverse of the reference column {{column}} in table {{table}}.": "It is the reverse of the reference column {{column}} in table {{table}}.",
"Table": "Table",
"Two-way Reference": "Two-way Reference"
"Two-way Reference": "Two-way Reference",
"Delete two-way reference?": "Delete two-way reference?",
"Target table": "Target table"
},
"SupportGristButton": {
"Admin Panel": "Admin Panel",
Expand Down
5 changes: 0 additions & 5 deletions stubs/app/server/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import {commonUrls} from 'app/common/gristUrls';
import {isAffirmative} from 'app/common/gutil';
import {HomeDBManager} from 'app/gen-server/lib/homedb/HomeDBManager';
import {fixSiteProducts} from 'app/gen-server/lib/Housekeeper';

const debugging = isAffirmative(process.env.DEBUG) || isAffirmative(process.env.VERBOSE);

Expand Down Expand Up @@ -132,10 +131,6 @@ export async function main() {
if (process.env.GRIST_SERVE_PLUGINS_PORT) {
await mergedServer.flexServer.startCopy('pluginServer', parseInt(process.env.GRIST_SERVE_PLUGINS_PORT, 10));
}
await fixSiteProducts({
deploymentType: mergedServer.flexServer.getDeploymentType(),
db: mergedServer.flexServer.getHomeDBManager()
});

return mergedServer.flexServer;
}
Expand Down
4 changes: 2 additions & 2 deletions test/nbrowser/CopyPaste.ts
Original file line number Diff line number Diff line change
Expand Up @@ -637,7 +637,7 @@ async function copyAndCheck(
}
}

function createDummyTextArea() {
export function createDummyTextArea() {
const textarea = document.createElement('textarea');
textarea.style.position = "absolute";
textarea.style.top = "0";
Expand All @@ -647,7 +647,7 @@ function createDummyTextArea() {
window.document.body.appendChild(textarea);
}

function removeDummyTextArea() {
export function removeDummyTextArea() {
const textarea = document.getElementById('dummyText');
if (textarea) {
window.document.body.removeChild(textarea);
Expand Down
Loading

0 comments on commit 05d8976

Please sign in to comment.