diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 00000000..471554fd --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,8 @@ +# Welcome to the contribution guide for Grist! + +You are eager to contribute to Grist? That's awesome! See below some contributions you can make: +- [translate](/documentation/translate.md) +- [write tutorials and user documentation](https://github.com/gristlabs/grist-help) +- [develop](/documentation/develop.md) +- [report issues or suggest enhancement](https://github.com/gristlabs/grist-core/issues/new) + diff --git a/app/client/widgets/ChoiceEditor.js b/app/client/widgets/ChoiceEditor.js index 85f4facb..1e7aef72 100644 --- a/app/client/widgets/ChoiceEditor.js +++ b/app/client/widgets/ChoiceEditor.js @@ -7,9 +7,10 @@ const {ACIndexImpl, buildHighlightedDom} = require('app/client/lib/ACIndex'); const {ChoiceItem, cssChoiceList, cssMatchText, cssPlusButton, cssPlusIcon} = require('app/client/widgets/ChoiceListEditor'); const {menuCssClass} = require('app/client/ui2018/menus'); -const {testId} = require('app/client/ui2018/cssVars'); +const {testId, colors} = require('app/client/ui2018/cssVars'); const {choiceToken, cssChoiceACItem} = require('app/client/widgets/ChoiceToken'); -const {dom} = require('grainjs'); +const {dom, styled} = require('grainjs'); +const {icon} = require('../ui2018/icons'); /** * ChoiceEditor - TextEditor with a dropdown for possible choices. @@ -19,7 +20,10 @@ function ChoiceEditor(options) { this.choices = options.field.widgetOptionsJson.peek().choices || []; this.choiceOptions = options.field.widgetOptionsJson.peek().choiceOptions || {}; - + if (!options.readonly && options.field.viewSection().parentKey() === "single") { + this.cellEditorDiv.classList.add(cssChoiceEditor.className); + this.cellEditorDiv.appendChild(cssChoiceEditIcon('Dropdown')); + } // Whether to include a button to show a new choice. // TODO: Disable when the user cannot change column configuration. this.enableAddNew = true; @@ -107,4 +111,18 @@ ChoiceEditor.prototype.maybeShowAddNew = function(result, text) { return result; } +const cssChoiceEditIcon = styled(icon, ` + background-color: ${colors.slate}; + position: absolute; + top: 0; + left: 0; + margin: 3px 3px 0 3px; +`); + +const cssChoiceEditor = styled('div', ` + & > .celleditor_text_editor, & > .celleditor_content_measure { + padding-left: 18px; + } +`); + module.exports = ChoiceEditor; diff --git a/app/client/widgets/ChoiceTextBox.ts b/app/client/widgets/ChoiceTextBox.ts index e8635d70..558328fc 100644 --- a/app/client/widgets/ChoiceTextBox.ts +++ b/app/client/widgets/ChoiceTextBox.ts @@ -4,7 +4,8 @@ import {ViewFieldRec} from 'app/client/models/entities/ViewFieldRec'; import {KoSaveableObservable} from 'app/client/models/modelUtil'; import {Style} from 'app/client/models/Styles'; import {cssLabel, cssRow} from 'app/client/ui/RightPanelStyles'; -import {testId} from 'app/client/ui2018/cssVars'; +import {colors, testId} from 'app/client/ui2018/cssVars'; +import {icon} from 'app/client/ui2018/icons'; import {ChoiceListEntry} from 'app/client/widgets/ChoiceListEntry'; import {choiceToken, DEFAULT_FILL_COLOR, DEFAULT_TEXT_COLOR} from 'app/client/widgets/ChoiceToken'; import {NTextBox} from 'app/client/widgets/NTextBox'; @@ -45,9 +46,13 @@ export class ChoiceTextBox extends NTextBox { public buildDom(row: DataRowModel) { const value = row.cells[this.field.colId()]; + const isSingle = this.field.viewSection().parentKey() === "single"; + const maybeDropDownCssChoiceEditIcon = isSingle ? cssChoiceEditIcon('Dropdown') : null; + return cssChoiceField( cssChoiceTextWrapper( dom.style('justify-content', (use) => use(this.alignment) === 'right' ? 'flex-end' : use(this.alignment)), + maybeDropDownCssChoiceEditIcon, dom.domComputed((use) => { if (this.isDisposed() || use(row._isAddRow)) { return null; } @@ -150,3 +155,9 @@ const cssChoiceText = styled('div', ` height: min-content; line-height: 16px; `); + +const cssChoiceEditIcon = styled(icon, ` + background-color: ${colors.slate}; + display: block; + height: inherit; +`); diff --git a/app/client/widgets/TextEditor.js b/app/client/widgets/TextEditor.js index 0dee97d4..593317c4 100644 --- a/app/client/widgets/TextEditor.js +++ b/app/client/widgets/TextEditor.js @@ -39,7 +39,7 @@ function TextEditor(options) { this.dom = dom('div.default_editor', kd.toggleClass("readonly_editor", options.readonly), - dom('div.celleditor_cursor_editor', dom.testId('TextEditor_editor'), + this.cellEditorDiv = dom('div.celleditor_cursor_editor', dom.testId('TextEditor_editor'), testId('widget-text-editor'), // new-style testId matches NTextEditor, for more uniform tests. this.contentSizer = dom('div.celleditor_content_measure'), this.textInput = dom('textarea.celleditor_text_editor', diff --git a/buildtools/build.sh b/buildtools/build.sh index 0571eaa5..c87643a6 100755 --- a/buildtools/build.sh +++ b/buildtools/build.sh @@ -3,7 +3,6 @@ set -e PROJECT="" -export GRIST_EXT=stubs if [[ -e ext/app ]]; then PROJECT="tsconfig-ext.json" fi diff --git a/documentation/develop.md b/documentation/develop.md new file mode 100644 index 00000000..56f12c1b --- /dev/null +++ b/documentation/develop.md @@ -0,0 +1,134 @@ +# Development + +Please as a first start, tell the community about your intent to develop a feature or fix a bug. Search for the associated issue if it exists or open one with steps to reproduce (for bugs) or a [user story](https://en.wikipedia.org/wiki/User_story#Principle) (for features). + +## Setup + +### Prerequisites + +To setup your environment, you would need to install the following dependencies: + - git + - [nvm](https://github.com/nvm-sh/nvm/blob/master/README.md) (recommended) or nodejs installed on your system + - Chromium to run the end-to-end tests + - Python (preferably Python 3.9) and virtualenv + - :warning: As of 2023-06-06, Python 3.11 is not supported due to the version of the [wrapt dependency](https://github.com/GrahamDumpleton/wrapt/issues/196) + +### Clone the repository + +```bash +$ git clone https://github.com/gristlabs/grist-core +``` + +And then, enter the grist-core root directory: + +```bash +$ cd grist-core/ +``` + +### Setup nodejs + +#### Using nvm (recommanded) + +You need to install the supported nodejs version as well as yarn. To do so, in the grist-core root directory, run the following command to install nodejs via nvm: + +```bash +$ nvm install +``` + +Now check that node is installed in the version specified in the `.nvmrc` file: + +```bash +$ node --version +``` + +Then install yarn (the `-g` flag here means that yarn will be available globally): +```bash +$ npm install -g yarn +``` + +Now each time you want to load nodejs and yarn in your environment, just run the following command at grist-core root directory: + +```bash +$ nvm use +``` + +#### Using nodejs + +You can also use nodejs installed in your system. To prevent incompatibilities, ensure that the `node --version` command reports a version equal or greater to the one in `.nvmrc`. + +### Install the python packages + +Be sure to have Python and virtualenv installed. On debian-based Linux distributions, you can simply run the following command as root: + +```bash +# apt install python3.9 python3.9-venv +``` + +### Install the project dependencies and build + +First install the nodejs dependencies: + +```bash +$ yarn install +``` + +Then prepare the virtual environment with all the python dependencies: + +```bash +$ yarn install:python +``` + +Finally run this to do an initial build: + +```bash +$ yarn run build:prod +``` + +## Start the server in development mode + +Just run the following command: +```bash +$ yarn start +``` + +Each time you change something, just reload the webpage in your browser. + +Happy coding! + +### Pick an issue + +Lost on what you can do to help? If you are new to Grist, you may just pick one of the issues labelled `good first issue`: + +https://github.com/gristlabs/grist-core/labels/good%20first%20issue + +## Debug the server + +You can debug the NodeJS application using this command: + +```bash +$ yarn start:debug +``` + +And start using your nodejs debugger client (like the Chrome Devtools). See https://nodejs.org/en/docs/guides/debugging-getting-started#inspector-clients + +## Run tests + +You may run the tests using one of these commands: + - `yarn test` to run all the tests + - `yarn test:smoke` to run the minimal test checking Grist can open, create and edit a document + - `yarn test:nbrowser` to run the end-to-end tests + - `yarn test:client` to run the tests for the client libraries + - `yarn test:common` to run the tests for the common libraries shared between the client and the server + - `yarn test:server` to run the backend tests + - `yarn test:docker` to run some end-to-end tests under docker + - `yarn test:python` to run the data engine tests + +## Develop widgets + +Check out this repository: https://github.com/gristlabs/grist-widget#readme + +## Documentation + +Some documentation to help you starting developing: + - [Grainjs](https://github.com/gristlabs/grainjs/) (The library used to build the DOM) + - [The user support documentation](https://support.getgrist.com/) diff --git a/package.json b/package.json index 071256ea..f0c5f83b 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "repository": "git://github.com/gristlabs/grist-core.git", "scripts": { "start": "sandbox/watch.sh", + "start:debug": "NODE_INSPECT=1 sandbox/watch.sh", "install:python": "buildtools/prepare_python.sh", "install:python2": "buildtools/prepare_python2.sh", "install:python3": "buildtools/prepare_python3.sh", diff --git a/sandbox/watch.sh b/sandbox/watch.sh index d8b8d642..cac00b81 100755 --- a/sandbox/watch.sh +++ b/sandbox/watch.sh @@ -3,7 +3,6 @@ set -x PROJECT="" -export GRIST_EXT=stubs if [[ -e ext/app ]]; then PROJECT="tsconfig-ext.json" fi @@ -18,6 +17,6 @@ fi tsc --build -w --preserveWatchOutput $PROJECT & catw app/client/*.css app/client/*/*.css -o static/bundle.css -v & webpack --config $WEBPACK_CONFIG --mode development --watch & -NODE_PATH=_build:_build/stubs:_build/ext nodemon --delay 1 -w _build/app/server -w _build/app/common _build/stubs/app/server/server.js & +NODE_PATH=_build:_build/stubs:_build/ext nodemon ${NODE_INSPECT:+--inspect} --delay 1 -w _build/app/server -w _build/app/common _build/stubs/app/server/server.js & wait diff --git a/static/locales/fr.client.json b/static/locales/fr.client.json index ba8fb79d..91382661 100644 --- a/static/locales/fr.client.json +++ b/static/locales/fr.client.json @@ -190,7 +190,7 @@ "Raw Data Tables": "Données sources", "Click to copy": "Cliquez ici pour copier", "Table ID copied to clipboard": "Identifiant de table copié", - "Duplicate Table": "Dupliquer la page", + "Duplicate Table": "Dupliquer la table", "You do not have edit access to this document": "Vous n’avez pas accès en écriture à ce document", "Delete {{formattedTableName}} data, and remove it from all pages?": "Supprimer les données de {{formattedTableName}} et les supprimer de toutes les pages ?" }, diff --git a/test/test_under_docker.sh b/test/test_under_docker.sh index 73682fc7..3e54603c 100755 --- a/test/test_under_docker.sh +++ b/test/test_under_docker.sh @@ -64,4 +64,4 @@ TEST_ADD_SAMPLES=1 TEST_ACCOUNT_PASSWORD=not-needed \ GRIST_SESSION_COOKIE=grist_test_cookie \ GRIST_TEST_LOGIN=1 \ NODE_PATH=_build:_build/stubs \ - $MOCHA _build/test/deployment/*.js --slow 6000 -g ${GREP_TESTS:-''} "$@" + $MOCHA _build/test/deployment/*.js --slow 6000 -g "${GREP_TESTS}" "$@"