mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
(core) "add column with type" and "add formula column" options in new column menu
Summary: New Column menu was enhanced by "add column with type" and "add formula column" options. First one allow user to chose the type of newly created column, to save time for selecting this option in creator menu. "Add formula column" opens formula editor in popup state right after creating the column. In this case, renaming column popup is ignored to not overburden user with to many popup at once. Test Plan: new nbrowser test was added to check validity of menu items, and output of menu action - if columns have given types or if formula editor popup is opened and functionin, accordingly. Reviewers: georgegevoian Differential Revision: https://phab.getgrist.com/D4113
This commit is contained in:
parent
707a8c7b32
commit
c04f61738c
@ -1,12 +1,15 @@
|
||||
import {allCommands} from 'app/client/components/commands';
|
||||
import GridView from 'app/client/components/GridView';
|
||||
import {makeT} from 'app/client/lib/localization';
|
||||
import {ColumnRec} from "app/client/models/entities/ColumnRec";
|
||||
import {ViewFieldRec} from 'app/client/models/entities/ViewFieldRec';
|
||||
import {GristTooltips} from 'app/client/ui/GristTooltips';
|
||||
import {withInfoTooltip} from 'app/client/ui/tooltips';
|
||||
import {testId, theme, vars} from 'app/client/ui2018/cssVars';
|
||||
import {IconName} from "app/client/ui2018/IconList";
|
||||
import {icon} from 'app/client/ui2018/icons';
|
||||
import {
|
||||
menuCssClass,
|
||||
menuDivider,
|
||||
menuIcon,
|
||||
menuItem,
|
||||
@ -19,11 +22,12 @@ import {
|
||||
searchableMenu,
|
||||
SearchableMenuItem,
|
||||
} from 'app/client/ui2018/menus';
|
||||
import * as UserType from "app/client/widgets/UserType";
|
||||
import {isListType, RecalcWhen} from "app/common/gristTypes";
|
||||
import {Sort} from 'app/common/SortSpec';
|
||||
import {dom, DomElementArg, styled} from 'grainjs';
|
||||
import {isListType, RecalcWhen} from "app/common/gristTypes";
|
||||
import {ColumnRec} from "app/client/models/entities/ColumnRec";
|
||||
import * as weasel from 'popweasel';
|
||||
import * as commands from "../components/commands";
|
||||
import isEqual = require('lodash/isEqual');
|
||||
|
||||
const t = makeT('GridViewMenus');
|
||||
@ -31,12 +35,7 @@ const t = makeT('GridViewMenus');
|
||||
export function buildAddColumnMenu(gridView: GridView, index?: number) {
|
||||
const isSummaryTable = Boolean(gridView.viewSection.table().summarySourceTable());
|
||||
return [
|
||||
menuItem(
|
||||
async () => { await gridView.insertColumn(null, {index}); },
|
||||
menuIcon('Plus'),
|
||||
t("Add Column"),
|
||||
testId('new-columns-menu-add-new'),
|
||||
),
|
||||
buildAddNewColumMenuSection(gridView, index),
|
||||
buildHiddenColumnsMenuItems(gridView, index),
|
||||
isSummaryTable ? null : [
|
||||
buildLookupSection(gridView, index),
|
||||
@ -45,6 +44,87 @@ export function buildAddColumnMenu(gridView: GridView, index?: number) {
|
||||
];
|
||||
}
|
||||
|
||||
function buildAddNewColumMenuSection(gridView: GridView, index?: number): DomElementArg[] {
|
||||
function buildEmptyNewColumMenuItem() {
|
||||
return menuItem(
|
||||
async () => {
|
||||
await gridView.insertColumn(null, {index});
|
||||
},
|
||||
t("Add Column"),
|
||||
testId('new-columns-menu-add-new'),
|
||||
);
|
||||
}
|
||||
|
||||
function BuildNewColumnWithTypeSubmenu() {
|
||||
const columnTypes = [
|
||||
"Text",
|
||||
"Numeric",
|
||||
"Int",
|
||||
"Bool",
|
||||
"Date",
|
||||
`DateTime:${gridView.gristDoc.docModel.docInfoRow.timezone()}`,
|
||||
"Choice",
|
||||
"ChoiceList",
|
||||
`Ref:${gridView.tableModel.tableMetaRow.tableId()}`,
|
||||
`RefList:${gridView.tableModel.tableMetaRow.tableId()}`,
|
||||
"Attachments"].map(type => ({type, obj: UserType.typeDefs[type.split(':')[0]]}))
|
||||
.map((ct): { displayName: string, colType: string, testIdName: string, icon: IconName | undefined } => ({
|
||||
displayName: t(ct.obj.label),
|
||||
colType: ct.type,
|
||||
testIdName: ct.obj.label.toLowerCase().replace(' ', '-'),
|
||||
icon: ct.obj.icon
|
||||
}));
|
||||
|
||||
return menuItemSubmenu(
|
||||
(ctl) => [
|
||||
...columnTypes.map((colType) =>
|
||||
menuItem(
|
||||
async () => {
|
||||
await gridView.insertColumn(null, {index, colInfo: {type: colType.colType}});
|
||||
},
|
||||
menuIcon(colType.icon as IconName),
|
||||
colType.displayName === 'Reference'?
|
||||
gridView.gristDoc.behavioralPromptsManager.attachTip('referenceColumns', {
|
||||
popupOptions: {
|
||||
attach: `.${menuCssClass}`,
|
||||
placement: 'left-start',
|
||||
}
|
||||
}):null,
|
||||
colType.displayName,
|
||||
testId(`new-columns-menu-add-${colType.testIdName}`)),
|
||||
),
|
||||
testId('new-columns-menu-add-with-type-submenu'),
|
||||
],
|
||||
{allowNothingSelected: false},
|
||||
t('Add column with type'),
|
||||
testId('new-columns-menu-add-with-type')
|
||||
);
|
||||
}
|
||||
|
||||
function buildNewFunctionColumnMenuItem() {
|
||||
return menuItem(
|
||||
async () => {
|
||||
await gridView.insertColumn(null, {index, skipPopup: true, colInfo: {isFormula: true}});
|
||||
gridView.activateEditorAtCursor();
|
||||
commands.allCommands.makeFormula.run();
|
||||
commands.allCommands.detachEditor.run();
|
||||
},
|
||||
withInfoTooltip(
|
||||
t('Add formula column'),
|
||||
GristTooltips.formulaColumn(),
|
||||
{variant: 'hover'}
|
||||
),
|
||||
testId('new-columns-menu-add-formula'),
|
||||
);
|
||||
}
|
||||
|
||||
return [
|
||||
buildEmptyNewColumMenuItem(),
|
||||
BuildNewColumnWithTypeSubmenu(),
|
||||
buildNewFunctionColumnMenuItem()
|
||||
];
|
||||
}
|
||||
|
||||
function buildHiddenColumnsMenuItems(gridView: GridView, index?: number) {
|
||||
const {viewSection} = gridView;
|
||||
const hiddenColumns = viewSection.hiddenColumns();
|
||||
|
@ -37,7 +37,8 @@ export type Tooltip =
|
||||
| 'addRowConditionalStyle'
|
||||
| 'addColumnConditionalStyle'
|
||||
| 'uuid'
|
||||
| 'lookups';
|
||||
| 'lookups'
|
||||
| 'formulaColumn'
|
||||
|
||||
export type TooltipContentFunc = (...domArgs: DomElementArg[]) => DomContents;
|
||||
|
||||
@ -115,6 +116,13 @@ see or edit which parts of your document.')
|
||||
),
|
||||
...args,
|
||||
),
|
||||
formulaColumn: (...args: DomElementArg[]) => cssTooltipContent(
|
||||
dom('div', t('Formulas support many Excel functions, full Python syntax, and include a helpful AI Assistant.')),
|
||||
dom('div',
|
||||
cssLink({href: commonUrls.formulas, target: '_blank'}, t('Learn more.')),
|
||||
),
|
||||
...args,
|
||||
),
|
||||
};
|
||||
|
||||
export interface BehavioralPromptContent {
|
||||
|
@ -88,6 +88,7 @@ export const commonUrls = {
|
||||
community: 'https://community.getgrist.com',
|
||||
functions: 'https://support.getgrist.com/functions',
|
||||
formulaSheet: 'https://support.getgrist.com/formula-cheat-sheet',
|
||||
formulas: 'https://support.getgrist.com/formulas',
|
||||
|
||||
basicTutorial: 'https://templates.getgrist.com/woXtXUBmiN5T/Grist-Basics',
|
||||
basicTutorialImage: 'https://www.getgrist.com/wp-content/uploads/2021/08/lightweight-crm.png',
|
||||
|
@ -7,11 +7,13 @@ import {UserAPIImpl} from 'app/common/UserAPI';
|
||||
describe('GridViewNewColumnMenu', function () {
|
||||
this.timeout('2m');
|
||||
const cleanup = setupTestSuite();
|
||||
gu.bigScreen();
|
||||
let api: UserAPIImpl;
|
||||
let docId: string;
|
||||
let session: gu.Session;
|
||||
|
||||
before(async function () {
|
||||
const session = await gu.session().login();
|
||||
session = await gu.session().login({showTips:true});
|
||||
api = session.createHomeApi();
|
||||
docId = await session.tempNewDoc(cleanup, 'ColumnMenu');
|
||||
|
||||
@ -142,6 +144,140 @@ describe('GridViewNewColumnMenu', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('create column with type', function () {
|
||||
revertThis();
|
||||
it('should show "Add Column With type" option', async function () {
|
||||
// open add new colum menu
|
||||
await clickAddColumn();
|
||||
// check if "Add Column With type" option is persent
|
||||
const addWithType = await driver.findWait(
|
||||
'.test-new-columns-menu-add-with-type',
|
||||
100,
|
||||
'Add Column With Type is not present');
|
||||
assert.equal(await addWithType.getText(), 'Add column with type');
|
||||
});
|
||||
|
||||
it('should display reference column popup when opened for the first time', async function(){
|
||||
// open add new colum menu
|
||||
await clickAddColumn();
|
||||
// select "Add Column With type" option
|
||||
await driver.findWait('.test-new-columns-menu-add-with-type', 100).click();
|
||||
// wait for submenu to appear
|
||||
await driver.findWait('.test-new-columns-menu-add-with-type-submenu', 100);
|
||||
// check if popup is showed
|
||||
await driver.findWait('.test-behavioral-prompt', 100, 'Reference column popup is not present');
|
||||
// close popup
|
||||
await gu.dismissBehavioralPrompts();
|
||||
// close menu
|
||||
await closeAddColumnMenu();
|
||||
// open it again
|
||||
await clickAddColumn();
|
||||
await driver.findWait('.test-new-columns-menu-add-with-type', 100).click();
|
||||
await driver.findWait('.test-new-columns-menu-add-with-type-submenu', 100);
|
||||
// popup should not be showed
|
||||
assert.isFalse(await driver.find('.test-behavioral-prompt').isPresent());
|
||||
await gu.disableTips(session.email);
|
||||
await closeAddColumnMenu();
|
||||
});
|
||||
|
||||
const optionsToBeDisplayed = [
|
||||
"Text",
|
||||
"Numeric",
|
||||
"Integer",
|
||||
"Toggle",
|
||||
"Date",
|
||||
"DateTime",
|
||||
"Choice",
|
||||
"Choice List",
|
||||
"Reference",
|
||||
"Reference List",
|
||||
"Attachment",
|
||||
].map((option) => ({type:option, testClass: option.toLowerCase().replace(' ', '-')}));
|
||||
for (const option of optionsToBeDisplayed) {
|
||||
it(`should allow to select column type ${option.type}`, async function () {
|
||||
// open add new colum menu
|
||||
await clickAddColumn();
|
||||
// select "Add Column With type" option
|
||||
await driver.findWait('.test-new-columns-menu-add-with-type', 100).click();
|
||||
// wait for submenu to appear
|
||||
await driver.findWait('.test-new-columns-menu-add-with-type-submenu', 100);
|
||||
// check if it is present in the menu
|
||||
const element = await driver.findWait(
|
||||
`.test-new-columns-menu-add-${option.testClass}`.toLowerCase(),
|
||||
100,
|
||||
`${option.type} option is not present`);
|
||||
// click on the option and check if column is added with a proper type
|
||||
await element.click();
|
||||
//discard rename menu
|
||||
await driver.findWait('.test-column-title-close', 100).click();
|
||||
//check if new column is present
|
||||
await gu.waitForServer();
|
||||
await gu.selectColumn('D');
|
||||
await gu.openColumnPanel();
|
||||
const type = await gu.getType();
|
||||
assert.equal(type, option.type);
|
||||
|
||||
await gu.undo(1);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe('create formula column', function(){
|
||||
revertThis();
|
||||
it('should show "create formula column" option with tooltip', async function () {
|
||||
// open add new colum menu
|
||||
await clickAddColumn();
|
||||
// check if "create formula column" option is present
|
||||
const addWithType = await driver.findWait('.test-new-columns-menu-add-formula', 100,
|
||||
'Add formula column is not present');
|
||||
// check if it has a tooltip button
|
||||
const tooltip = await addWithType.findWait('.test-info-tooltip', 100,
|
||||
'Tooltip button is not present');
|
||||
// check if tooltip is show after hovering
|
||||
await tooltip.mouseMove();
|
||||
const tooltipContainer = await driver.findWait('.test-info-tooltip-popup',
|
||||
100,
|
||||
'Tooltip is not shown');
|
||||
// check if tooltip is showing valid message
|
||||
const tooltipText = await tooltipContainer.getText();
|
||||
assert.include(tooltipText,
|
||||
'Formulas support many Excel functions, full Python syntax, and include a helpful AI Assistant.',
|
||||
'Tooltip is showing wrong message');
|
||||
// check if link in tooltip has a proper href
|
||||
const hrefAddress = await tooltipContainer.findWait('a',
|
||||
100,
|
||||
'Tooltip link is not present');
|
||||
assert.equal(await hrefAddress.getText(), 'Learn more.');
|
||||
assert.equal(await hrefAddress.getAttribute('href'),
|
||||
'https://support.getgrist.com/formulas',
|
||||
'Tooltip link has wrong href');
|
||||
});
|
||||
|
||||
it('should allow to select formula column', async function () {
|
||||
// open column panel - we will need it later
|
||||
await gu.openColumnPanel();
|
||||
// open add new colum menu
|
||||
await clickAddColumn();
|
||||
// select "create formula column" option
|
||||
await driver.findWait('.test-new-columns-menu-add-formula', 100).click();
|
||||
// there should not be a rename poup
|
||||
assert.isFalse(await driver.find('test-column-title-popup').isPresent());
|
||||
//check if new column is present
|
||||
await gu.waitForServer();
|
||||
// check if editor popup is opened
|
||||
await driver.findWait('.test-floating-editor-popup', 200, 'Editor popup is not present');
|
||||
// write some formula
|
||||
await gu.sendKeys('1+1');
|
||||
await driver.find('.test-formula-editor-save-button').click();
|
||||
await gu.waitForServer();
|
||||
// check if column is created with a proper type
|
||||
const type = await gu.columnBehavior();
|
||||
assert.equal(type, 'Formula Column');
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('hidden columns', function () {
|
||||
revertThis();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user