Browse Source

Merge branch 'nocodb:develop' into Enable-scroll-for-sort-&-filter-#1675

pull/1714/head
Naman Anand 3 years ago committed by GitHub
parent
commit
e35a984682
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 217
      README.md
  2. BIN
      packages/nc-gui/assets/img/discourse-icon.png
  3. 21
      packages/nc-gui/components/importantAnnouncement.vue
  4. 35
      packages/nc-gui/components/project/spreadsheet/components/editColumn/linkedToAnotherOptions.vue
  5. 56
      packages/nc-gui/components/project/spreadsheet/components/extras.vue
  6. 2
      packages/nc-gui/components/project/spreadsheet/components/virtualCell/belongsToCell.vue
  7. 27
      packages/nc-gui/components/project/spreadsheet/components/virtualCell/hasManyCell.vue
  8. 18
      packages/nc-gui/components/project/spreadsheet/components/virtualCell/manyToManyCell.vue
  9. 2
      packages/nc-gui/components/project/spreadsheet/dialog/createViewDialog.vue
  10. 4
      packages/nc-gui/components/project/spreadsheet/views/formView.vue
  11. 9
      packages/nc-gui/components/releaseInfo.vue
  12. 2
      packages/nc-gui/helpers/themes.js
  13. 1
      packages/nc-gui/lang/da.json
  14. 1
      packages/nc-gui/lang/de.json
  15. 1
      packages/nc-gui/lang/en.json
  16. 1
      packages/nc-gui/lang/es.json
  17. 1
      packages/nc-gui/lang/fa.json
  18. 1
      packages/nc-gui/lang/fi.json
  19. 1
      packages/nc-gui/lang/fr.json
  20. 1
      packages/nc-gui/lang/hr.json
  21. 1
      packages/nc-gui/lang/id.json
  22. 1
      packages/nc-gui/lang/it_IT.json
  23. 1
      packages/nc-gui/lang/iw.json
  24. 1
      packages/nc-gui/lang/ja.json
  25. 1
      packages/nc-gui/lang/ko.json
  26. 1
      packages/nc-gui/lang/lv.json
  27. 1
      packages/nc-gui/lang/nl.json
  28. 1
      packages/nc-gui/lang/no.json
  29. 1
      packages/nc-gui/lang/pl.json
  30. 1
      packages/nc-gui/lang/pt.json
  31. 1
      packages/nc-gui/lang/pt_BR.json
  32. 1
      packages/nc-gui/lang/sl.json
  33. 1
      packages/nc-gui/lang/sv.json
  34. 1
      packages/nc-gui/lang/th.json
  35. 1
      packages/nc-gui/lang/tr.json
  36. 1
      packages/nc-gui/lang/uk.json
  37. 1
      packages/nc-gui/lang/vi.json
  38. 1
      packages/nc-gui/lang/zh_CN.json
  39. 1
      packages/nc-gui/lang/zh_HK.json
  40. 1
      packages/nc-gui/lang/zh_TW.json
  41. 5
      packages/nc-gui/layouts/default.vue
  42. 2
      packages/nc-gui/nuxt.config.js
  43. 19755
      packages/nc-gui/package-lock.json
  44. 2
      packages/nc-gui/package.json
  45. 11
      packages/nc-gui/plugins/projectLoader.js
  46. 20
      packages/nc-gui/plugins/tele.js
  47. 12
      packages/nc-gui/store/app.js
  48. 12
      packages/nc-gui/store/users.js
  49. 4
      packages/nc-lib-gui/package.json
  50. 43
      packages/noco-docs-prev/content/en/setup-and-usages/usage-information.md
  51. 33
      packages/noco-docs/content/en/developer-resources/accessing-apis.md
  52. 36
      packages/noco-docs/content/en/developer-resources/api-tokens.md
  53. 9
      packages/noco-docs/content/en/developer-resources/caching.md
  54. 9
      packages/noco-docs/content/en/developer-resources/data-apis.md
  55. 9
      packages/noco-docs/content/en/developer-resources/meta-apis.md
  56. 1349
      packages/noco-docs/content/en/developer-resources/rest-apis.md
  57. 55
      packages/noco-docs/content/en/developer-resources/sdk.md
  58. 2
      packages/noco-docs/content/en/developer-resources/webhooks.md
  59. 18
      packages/noco-docs/content/en/engineering/architecture.md
  60. 31
      packages/noco-docs/content/en/engineering/repository-structure.md
  61. 35
      packages/noco-docs/content/en/getting-started/installation.md
  62. 77
      packages/noco-docs/content/en/index.md
  63. 17
      packages/noco-docs/content/en/setup-and-usages/app-store.md
  64. 2
      packages/noco-docs/content/en/setup-and-usages/column-operations.md
  65. 2
      packages/noco-docs/content/en/setup-and-usages/column-types.md
  66. 14
      packages/noco-docs/content/en/setup-and-usages/primary-value.md
  67. 4
      packages/noco-docs/content/en/setup-and-usages/share-view.md
  68. 18
      packages/noco-docs/content/en/setup-and-usages/table-operations.md
  69. 2
      packages/noco-docs/content/en/setup-and-usages/team-and-auth.md
  70. 56
      packages/noco-docs/content/en/setup-and-usages/usage-information.md
  71. 93
      packages/noco-docs/content/en/setup-and-usages/views.md
  72. 10532
      packages/nocodb-sdk/package-lock.json
  73. 2
      packages/nocodb-sdk/package.json
  74. 62
      packages/nocodb-sdk/src/lib/Api.ts
  75. 25264
      packages/nocodb/package-lock.json
  76. 10
      packages/nocodb/package.json
  77. 4
      packages/nocodb/src/lib/noco-models/Column.ts
  78. 3
      packages/nocodb/src/lib/noco-models/LinkToAnotherRecordColumn.ts
  79. 2
      packages/nocodb/src/lib/noco/meta/api/auditApis.ts
  80. 70
      packages/nocodb/src/lib/noco/meta/api/columnApis.ts
  81. 4
      packages/nocodb/src/lib/noco/meta/api/dataApis/dataAliasNestedApis.ts
  82. 15
      packages/nocodb/src/lib/noco/meta/api/index.ts
  83. 14
      packages/nocodb/src/lib/noco/meta/api/metaDiffApis.ts
  84. 11
      packages/nocodb/src/lib/noco/meta/api/utilApis.ts
  85. 81
      packages/nocodb/src/lib/noco/upgrader/jobs/ncProjectUpgraderV2_0090000.ts
  86. 13
      packages/nocodb/src/lib/utils/projectAcl.ts
  87. 2
      scripts/bumpNocodbSdkVersion.js
  88. 231
      scripts/sdk/swagger.json

217
README.md

@ -21,6 +21,7 @@ Turns any MySQL, PostgreSQL, SQL Server, SQLite & MariaDB into a smart-spreadshe
<p align="center"> <p align="center">
<a href="http://www.nocodb.com"><b>Website</b></a> <a href="http://www.nocodb.com"><b>Website</b></a>
<a href="https://discord.gg/5RgZmkW"><b>Discord</b></a> <a href="https://discord.gg/5RgZmkW"><b>Discord</b></a>
<a href="https://community.nocodb.com/"><b>Community</b></a>
<a href="https://twitter.com/nocodb"><b>Twitter</b></a> <a href="https://twitter.com/nocodb"><b>Twitter</b></a>
<a href="https://www.reddit.com/r/NocoDB/"><b>Reddit</b></a> <a href="https://www.reddit.com/r/NocoDB/"><b>Reddit</b></a>
<a href="https://docs.nocodb.com/"><b>Documentation</b></a> <a href="https://docs.nocodb.com/"><b>Documentation</b></a>
@ -51,9 +52,11 @@ Turns any MySQL, PostgreSQL, SQL Server, SQLite & MariaDB into a smart-spreadshe
<img src="https://static.scarf.sh/a.png?x-pxid=c12a77cc-855e-4602-8a0f-614b2d0da56a" /> <img src="https://static.scarf.sh/a.png?x-pxid=c12a77cc-855e-4602-8a0f-614b2d0da56a" />
# Quick try # Quick try
### 1-Click Deploy
#### Heroku ## 1-Click Deploy to Heroku
Before doing so, make sure you have a Heroku account. By default, an add-on Heroku Postgres will be used as meta database. You can see the connection string defined in `DATABASE_URL` by navigating to Heroku App Settings and selecting Config Vars.
<a href="https://heroku.com/deploy?template=https://github.com/nocodb/nocodb-seed-heroku"> <a href="https://heroku.com/deploy?template=https://github.com/nocodb/nocodb-seed-heroku">
<img <img
src="https://www.herokucdn.com/deploy/button.svg" src="https://www.herokucdn.com/deploy/button.svg"
@ -61,43 +64,100 @@ Turns any MySQL, PostgreSQL, SQL Server, SQLite & MariaDB into a smart-spreadshe
alt="Deploy NocoDB to Heroku with 1-Click" alt="Deploy NocoDB to Heroku with 1-Click"
/> />
</a> </a>
<br>
### Using Docker <br/>
```bash
docker run -d --name nocodb -p 8080:8080 nocodb/nocodb:latest
```
- NocoDB needs a database as input : See [Production Setup](https://github.com/nocodb/nocodb/blob/master/README.md#production-setup). ## NPX
- If this input is absent, we fallback to SQLite. In order too persist sqlite, you can mount `/usr/app/data/`.
Example: You can run below command if you need an interactive configuration.
```
docker run -d -p 8080:8080 --name nocodb -v /local/path:/usr/app/data/ nocodb/nocodb:latest
```
### Using Npm
``` ```
npx create-nocodb-app npx create-nocodb-app
``` ```
### Using Git <img src="https://user-images.githubusercontent.com/35857179/163672964-00ef5d62-0434-447d-ac01-3ebb780099b9.png" width="520px"/>
```
## Node Application
We provide a simple NodeJS Application for getting started.
```bash
git clone https://github.com/nocodb/nocodb-seed git clone https://github.com/nocodb/nocodb-seed
cd nocodb-seed cd nocodb-seed
npm install npm install
npm start npm start
``` ```
### GUI ## Docker
```bash
# for SQLite
docker run -d --name nocodb \
-v /local/path:/usr/app/data/ \
-p 8080:8080 \
nocodb/nocodb:latest
# for MySQL
docker run -d --name nocodb-mysql \
-v /local/path:/usr/app/data/ \
-p 8080:8080 \
-e NC_DB="mysql2://host.docker.internal:3306?u=root&p=password&d=d1" \
-e NC_AUTH_JWT_SECRET="569a1821-0a93-45e8-87ab-eb857f20a010" \
nocodb/nocodb:latest
# for PostgreSQL
docker run -d --name nocodb-postgres \
-v /local/path:/usr/app/data/ \
-p 8080:8080 \
-e NC_DB="pg://host.docker.internal:5432?u=root&p=password&d=d1" \
-e NC_AUTH_JWT_SECRET="569a1821-0a93-45e8-87ab-eb857f20a010" \
nocodb/nocodb:latest
# for MSSQL
docker run -d --name nocodb-mssql \
-v /local/path:/usr/app/data/ \
-p 8080:8080 \
-e NC_DB="mssql://host.docker.internal:1433?u=root&p=password&d=d1" \
-e NC_AUTH_JWT_SECRET="569a1821-0a93-45e8-87ab-eb857f20a010" \
nocodb/nocodb:latest
```
> To persist data in docker you can mount volume at `/usr/app/data/` since 0.10.6. Otherwise your data will be lost after recreating the container.
> If you plan to input some special characters, you may need to change the character set and collation yourself when creating the database. Please check out the examples for [MySQL Docker](https://github.com/nocodb/nocodb/issues/1340#issuecomment-1049481043).
## Docker Compose
We provide different docker-compose.yml files under [this directory](https://github.com/nocodb/nocodb/tree/master/docker-compose). Here are some examples.
```bash
git clone https://github.com/nocodb/nocodb
# for MySQL
cd nocodb/docker-compose/mysql
# for PostgreSQL
cd nocodb/docker-compose/pg
# for MSSQL
cd nocodb/docker-compose/mssql
docker-compose up -d
```
> To persist data in docker, you can mount volume at `/usr/app/data/` since 0.10.6. Otherwise your data will be lost after recreating the container.
> If you plan to input some special characters, you may need to change the character set and collation yourself when creating the database. Please check out the examples for [MySQL Docker Compose](https://github.com/nocodb/nocodb/issues/1313#issuecomment-1046625974).
# GUI
Access Dashboard using : [http://localhost:8080/dashboard](http://localhost:8080/dashboard) Access Dashboard using : [http://localhost:8080/dashboard](http://localhost:8080/dashboard)
# Join Our Community # Join Our Community
<a href="https://discord.gg/5RgZmkW"> <a href="https://discord.gg/5RgZmkW" target="_blank">
<img src="https://discordapp.com/api/guilds/661905455894888490/widget.png?style=banner3" alt=""> <img src="https://discordapp.com/api/guilds/661905455894888490/widget.png?style=banner3" alt="">
</a> </a>
<a href="https://community.nocodb.com/" target="_blank">
<img src="https://i2.wp.com/www.feverbee.com/wp-content/uploads/2018/07/logo-discourse.png" alt="">
</a>
# Screenshots # Screenshots
@ -128,7 +188,8 @@ Access Dashboard using : [http://localhost:8080/dashboard](http://localhost:8080
![10](https://user-images.githubusercontent.com/5435402/133759250-ebd75ecf-31db-4a17-b2d7-2c43af78a54e.png) ![10](https://user-images.githubusercontent.com/5435402/133759250-ebd75ecf-31db-4a17-b2d7-2c43af78a54e.png)
<br> <br>
![8](https://user-images.githubusercontent.com/5435402/133759248-3a7141e0-4b7d-4079-a5f9-cf8611d00bc5.png) ![8](https://user-images.githubusercontent.com/35857179/163675704-54eb644d-3b5e-45e3-aad4-794a0f55c692.png)
<br> <br>
![9](https://user-images.githubusercontent.com/5435402/133759249-8c1a85c2-a55c-48f6-bd58-aa6b4195cce7.png) ![9](https://user-images.githubusercontent.com/5435402/133759249-8c1a85c2-a55c-48f6-bd58-aa6b4195cce7.png)
@ -136,27 +197,25 @@ Access Dashboard using : [http://localhost:8080/dashboard](http://localhost:8080
# Table of Contents # Table of Contents
- [Quick try](#quick-try) - [Quick try](#quick-try)
+ [1-Click Deploy](#1-click-deploy) * [1-Click Deploy to Heroku](#1-click-deploy-to-heroku)
- [Heroku](#heroku) * [NPX](#npx)
+ [Using Docker](#using-docker) * [Node Application](#node-application)
+ [Using Npm](#using-npm) * [Docker](#docker)
+ [Using Git](#using-git) * [Docker Compose](#docker-compose)
+ [GUI](#gui) - [GUI](#gui)
- [Join Our Community](#join-our-community) - [Join Our Community](#join-our-community)
- [Screenshots](#screenshots) - [Screenshots](#screenshots)
- [Table of Contents](#table-of-contents)
- [Features](#features) - [Features](#features)
+ [Rich Spreadsheet Interface](#rich-spreadsheet-interface) + [Rich Spreadsheet Interface](#rich-spreadsheet-interface)
+ [App Store for workflow automations](#app-store-for-workflow-automations) + [App Store for Workflow Automations](#app-store-for-workflow-automations)
+ [Programmatic API access via](#programmatic-api-access-via) + [Programmatic Access](#programmatic-access)
+ [Sync Schema](#sync-schema)
+ [Audit](#audit)
- [Production Setup](#production-setup) - [Production Setup](#production-setup)
* [Docker](#docker)
- [Example: MySQL](#example--mysql)
- [Example: PostgreSQL](#example--postgresql)
- [Example: SQL Server](#example--sql-server)
* [Docker Compose](#docker-compose)
* [Environment variables](#environment-variables) * [Environment variables](#environment-variables)
- [Development Setup](#development-setup) - [Development Setup](#development-setup)
* [Cloning the project](#clone-the-project) * [Cloning the Project](#cloning-the-project)
* [Running Backend locally](#running-backend-locally) * [Running Backend locally](#running-backend-locally)
* [Running Frontend locally](#running-frontend-locally) * [Running Frontend locally](#running-frontend-locally)
* [Running Cypress tests locally](#running-cypress-tests-locally) * [Running Cypress tests locally](#running-cypress-tests-locally)
@ -166,66 +225,44 @@ Access Dashboard using : [http://localhost:8080/dashboard](http://localhost:8080
- [Contributors](#contributors) - [Contributors](#contributors)
# Features # Features
### Rich Spreadsheet Interface ### Rich Spreadsheet Interface
- ⚡ &nbsp;Search, sort, filter, hide columns with uber ease
- ⚡ &nbsp;Create Views : Grid, Gallery, Kanban, Form
- ⚡ &nbsp;Share Views : public & password protected
- ⚡ &nbsp;Personal & locked Views
- ⚡ &nbsp;Upload images to cells (Works with S3, Minio, GCP, Azure, DigitalOcean, Linode, OVH, BackBlaze)
- ⚡ &nbsp;Roles : Owner, Creator, Editor, Viewer, Commenter, Custom Roles.
- ⚡ &nbsp;Access Control : Fine-grained access control even at database, table & column level.
### App Store for workflow automations
- ⚡ &nbsp;Chat : Microsoft Teams, Slack, Discord, Mattermost
- ⚡ &nbsp;Email : SMTP, SES, Mailchimp
- ⚡ &nbsp;SMS : Twilio
- ⚡ &nbsp;Whatsapp
- ⚡ &nbsp;Any 3rd Party APIs
### Programmatic API access via
- ⚡ &nbsp;REST APIs (Swagger)
- ⚡ &nbsp;GraphQL APIs.
- ⚡ &nbsp;Includes JWT Authentication & Social Auth
- ⚡ &nbsp;API tokens to integrate with Zapier, Integromat.
# Production Setup - ⚡ &nbsp;Basic Operations: Create, Read, Update and Delete on Tables, Columns, and Rows
NocoDB requires a database to store metadata of spreadsheets views and external databases. - ⚡ &nbsp;Fields Operations: Sort, Filter, Hide / Unhide Columns
And connection params for this database can be specified in `NC_DB` environment variable. - ⚡ &nbsp;Multiple Views Types: Grid (By default), Gallery and Form View
- ⚡ &nbsp;View Permissions Types: Collaborative Views, & Locked Views
- ⚡ &nbsp;Share Bases / Views: either Public or Private (with Password Protected)
- ⚡ &nbsp;Variant Cell Types: ID, LinkToAnotherRecord, Lookup, Rollup, SingleLineText, Attachement, Currency, Formula and etc
- ⚡ &nbsp;Access Control with Roles : Fine-grained Access Control at different levels
- ⚡ &nbsp;and more ...
## Docker ### App Store for Workflow Automations
#### Example: MySQL We provide different integrations in three main categories. See <a href="https://docs.nocodb.com/setup-and-usages/app-store" target="_blank">App Store</a> for details.
```
docker run -d -p 8080:8080 \
-e NC_DB="mysql2://host.docker.internal:3306?u=root&p=password&d=d1" \
-e NC_AUTH_JWT_SECRET="569a1821-0a93-45e8-87ab-eb857f20a010" \
nocodb/nocodb:latest
```
#### Example: PostgreSQL - ⚡ &nbsp;Chat : Slack, Discord, Mattermost, and etc
``` - ⚡ &nbsp;Email : AWS SES, SMTP, MailerSend, and etc
docker run -d -p 8080:8080 \ - ⚡ &nbsp;Storage : AWS S3, Google Cloud Storage, Minio, and etc
-e NC_DB="pg://host:port?u=user&p=password&d=database" \
-e NC_AUTH_JWT_SECRET="569a1821-0a93-45e8-87ab-eb857f20a010" \
nocodb/nocodb:latest
```
#### Example: SQL Server ### Programmatic Access
```
docker run -d -p 8080:8080 \
-e NC_DB="mssql://host:port?u=user&p=password&d=database" \
-e NC_AUTH_JWT_SECRET="569a1821-0a93-45e8-87ab-eb857f20a010" \
nocodb/nocodb:latest
```
## Docker Compose We provide the following ways to let users to invoke actions in a programmatic way. You can use a token (either JWT or Social Auth) to sign your requests for authorization to NocoDB.
```
git clone https://github.com/nocodb/nocodb - ⚡ &nbsp;REST APIs
cd nocodb - ⚡ &nbsp;NocoDB SDK
cd docker-compose
cd mysql or pg or mssql ### Sync Schema
docker-compose up -d
``` We allow you to sync schema changes if you have made changes outside NocoDB GUI. However, it has to be noted then you will have to bring your own schema migrations for moving from environment to others. See <a href="https://docs.nocodb.com/setup-and-usages/sync-schema/" target="_blank">Sync Schema</a> for details.
### Audit
We are keeping all the user operation logs under one place. See <a href="https://docs.nocodb.com/setup-and-usages/audit" target="_blank">Audit</a> for details.
# Production Setup
By default, SQLite is used for storing meta data. However, you can specify your own database. The connection params for this database can be specified in `NC_DB` environment variable. Moreover, we also provide the below environment variables for configuration.
## Environment variables ## Environment variables
@ -262,7 +299,6 @@ Changes made to code automatically restart.
> nocodb/packages/nocodb includes nc-lib-gui which is the built version of nc-gui hosted in npm registry. You can visit localhost:8000/dashboard in browser after starting the backend locally if you just want to modify the backend only. > nocodb/packages/nocodb includes nc-lib-gui which is the built version of nc-gui hosted in npm registry. You can visit localhost:8000/dashboard in browser after starting the backend locally if you just want to modify the backend only.
## Running Cypress tests locally ## Running Cypress tests locally
```shell ```shell
@ -411,8 +447,3 @@ Our mission is to provide the most powerful no-code interface for databases whic
<!-- prettier-ignore-end --> <!-- prettier-ignore-end -->
<!-- ALL-CONTRIBUTORS-LIST:END --> <!-- ALL-CONTRIBUTORS-LIST:END -->

BIN
packages/nc-gui/assets/img/discourse-icon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

21
packages/nc-gui/components/importantAnnouncement.vue

@ -3,7 +3,7 @@
<template #activator="{on}"> <template #activator="{on}">
<transition name="announcement"> <transition name="announcement">
<v-btn <v-btn
v-if="!loading" v-show="announcementAlert"
text text
small small
class="mb-0 mr-2 py-0 " class="mb-0 mr-2 py-0 "
@ -29,14 +29,21 @@
mdi-script-text-outline mdi-script-text-outline
</v-icon> </v-icon>
<span class="caption"> <span class="caption">
API Changes in v0.90.0 v0.90.0 API Changes
</span>
</v-list-item>
<v-list-item dense href="https://github.com/nocodb/nocodb/releases/tag/0.90.0" target="_blank">
<v-icon small class="mr-2">
mdi-script-text-outline
</v-icon>
<span class="caption">
v0.90.0 Release Note
</span> </span>
</v-list-item> </v-list-item>
<v-list-item @click="announcementAlert = false"> <v-list-item @click="announcementAlert = false">
<v-icon small class="mr-2"> <v-icon small class="mr-2">
mdi-close mdi-close
</v-icon> </v-icon>
<span class="caption"> <span class="caption">
<!--Hide menu--> <!--Hide menu-->
{{ $t('general.hideMenu') }} {{ $t('general.hideMenu') }}
@ -53,6 +60,14 @@ export default {
loading: true loading: true
}), }),
computed: { computed: {
announcementAlert: {
get() {
return !this.loading && !this.$store.state.app.hiddenAnnouncement
},
set(val) {
return this.$store.commit('app/MutHiddenAnnouncement', val ? null : true)
}
},
}, },
mounted() { mounted() {
setTimeout(() => { setTimeout(() => {

35
packages/nc-gui/components/project/spreadsheet/components/editColumn/linkedToAnotherOptions.vue

@ -52,8 +52,7 @@
</v-container> </v-container>
<v-container v-show="advanceOptions" fluid class="wrapper"> <v-container v-show="advanceOptions" fluid class="wrapper">
<v-row> <v-row />
</v-row>
<template v-if="!isSQLite"> <template v-if="!isSQLite">
<v-row> <v-row>
<v-col cols="6"> <v-col cols="6">
@ -67,7 +66,7 @@
:items="onUpdateDeleteOptions" :items="onUpdateDeleteOptions"
required required
dense dense
:disabled="relation.type !== 'real'" :disabled="relation.virtual"
/> />
</v-col> </v-col>
<v-col cols="6"> <v-col cols="6">
@ -81,25 +80,23 @@
:items="onUpdateDeleteOptions" :items="onUpdateDeleteOptions"
required required
dense dense
:disabled="relation.type !== 'real'" :disabled="relation.virtual"
/>
</v-col>
</v-row>
<v-row>
<v-col>
<v-checkbox
v-model="relation.type"
false-value="real"
true-value="virtual"
label="Virtual Relation"
:full-width="false"
required
class="mt-0"
dense
/> />
</v-col> </v-col>
</v-row> </v-row>
</template> </template>
<v-row>
<v-col>
<v-checkbox
v-model="relation.virtual"
label="Virtual Relation"
:full-width="false"
required
class="mt-0"
dense
/>
</v-col>
</v-row>
</v-container> </v-container>
</div> </div>
</template> </template>
@ -148,7 +145,7 @@ export default {
onDelete: 'NO ACTION', onDelete: 'NO ACTION',
onUpdate: 'NO ACTION', onUpdate: 'NO ACTION',
updateRelation: !!this.column.rtn, updateRelation: !!this.column.rtn,
relationType: 'real' virtual: this.isSQLite
} }
}, },
methods: { methods: {

56
packages/nc-gui/components/project/spreadsheet/components/extras.vue

@ -30,7 +30,7 @@
dense dense
> >
<v-list-item dense href="https://discord.gg/5RgZmkW" target="_blank"> <v-list-item dense href="https://discord.gg/5RgZmkW" target="_blank">
<!-- Get your questions answered --> <!-- Join Discord -->
<v-list-item-title> <v-list-item-title>
<v-icon class="mr-1" small :color="textColors[0]"> <v-icon class="mr-1" small :color="textColors[0]">
mdi-discord mdi-discord
@ -40,7 +40,33 @@
}}</span> }}</span>
</v-list-item-title> </v-list-item-title>
</v-list-item> </v-list-item>
<!-- Join Community -->
<v-list-item dense href="https://community.nocodb.com/" target="_blank">
<v-list-item-title>
<v-icon class="mr-1 discourse" small :color="textColors[0]">
mdi-discourse
</v-icon>
<span class="caption" :title="$t('labels.community.joinCommunity')" v-t="['community:discourse']">{{
$t('labels.community.joinCommunity')
}}</span>
</v-list-item-title>
</v-list-item>
<v-list-item dense href="https://twitter.com/NocoDB" target="_blank"> <v-list-item dense href="https://twitter.com/NocoDB" target="_blank">
<!-- Join Reddit -->
<v-list-item-title>
<v-icon class="mr-1" small color="#ff4600">
mdi-reddit
</v-icon>
<span class="caption" :title="$t('labels.community.joinReddit')" v-t="['community:reddit']">{{
$t('labels.community.joinReddit')
}}</span>
</v-list-item-title>
</v-list-item>
<v-list-item
dense
target="_blank"
href="https://calendly.com/nocodb-meeting"
>
<!-- Follow NocoDB --> <!-- Follow NocoDB -->
<v-list-item-title> <v-list-item-title>
<v-icon class="mr-1" small :color="textColors[1]"> <v-icon class="mr-1" small :color="textColors[1]">
@ -52,21 +78,6 @@
</v-list-item-title> </v-list-item-title>
</v-list-item> </v-list-item>
<v-list-item dense href="https://www.reddit.com/r/NocoDB/" target="_blank"> <v-list-item dense href="https://www.reddit.com/r/NocoDB/" target="_blank">
<!-- Get your questions answered -->
<v-list-item-title>
<v-icon class="mr-1" small color="#ff4600">
mdi-reddit
</v-icon>
<span class="caption" :title="$t('labels.community.joinReddit')" v-t="['community:reddit']">{{
$t('labels.community.joinReddit')
}}</span>
</v-list-item-title>
</v-list-item>
<v-list-item
dense
target="_blank"
href="https://calendly.com/nocodb-meeting"
>
<!-- Book a Free DEMO --> <!-- Book a Free DEMO -->
<v-list-item-title> <v-list-item-title>
<v-icon class="mr-1" small :color="textColors[3]"> <v-icon class="mr-1" small :color="textColors[3]">
@ -126,6 +137,19 @@ export default {
} }
} }
.v-icon.discourse {
height: 16px;
width: 16px;
background-image: url('~/assets/img/discourse-icon.png');
background-size: contain;
background-repeat: no-repeat;
}
.v-icon.discourse::before {
visibility: hidden;
content: "";
}
// //
//@keyframes anim { //@keyframes anim {
// 0%, 100% { // 0%, 100% {

2
packages/nc-gui/components/project/spreadsheet/components/virtualCell/belongsToCell.vue

@ -281,7 +281,7 @@ export default {
const id = this.meta.columns.filter(c => c.pk).map(c => this.row[c.title]).join('___') const id = this.meta.columns.filter(c => c.pk).map(c => this.row[c.title]).join('___')
// todo: audit // todo: audit
await this.$api.dbTableRow.nestedDelete( await this.$api.dbTableRow.nestedRemove(
'noco', 'noco',
this.projectName, this.projectName,
this.meta.title, this.meta.title,

27
packages/nc-gui/components/project/spreadsheet/components/virtualCell/hasManyCell.vue

@ -342,11 +342,13 @@ export default {
return return
} }
const id = this.childMeta.columns.filter(c => c.pk).map(c => child[c.title]).join('___') const id = this.childMeta.columns.filter(c => c.pk).map(c => child[c.title]).join('___')
await this.$api.data.nestedDelete( await this.$api.dbTableRow.nestedRemove(
this.meta.id, 'noco',
this.projectName,
this.meta.title,
this.parentId, this.parentId,
this.column.id, RelationTypes.HAS_MANY,
'hm', this.column.title,
id id
) )
@ -440,15 +442,18 @@ export default {
// eslint-disable-next-line no-cond-assign // eslint-disable-next-line no-cond-assign
while (child = this.localState.pop()) { while (child = this.localState.pop()) {
if (row) { if (row) {
// todo: use common method
const pid = this.meta.columns.filter(c => c.pk).map(c => row[c.title]).join('___') const pid = this.meta.columns.filter(c => c.pk).map(c => row[c.title]).join('___')
const id = this.childMeta.columns.filter(c => c.pk).map(c => child[c.title]).join('___') const id = this.childMeta.columns.filter(c => c.pk).map(c => child[c.title]).join('___')
const title = this.childForeignKey
await this.childApi.update(id, { await this.$api.dbTableRow.nestedAdd(
[title]: parseIfInteger(pid) 'noco',
}, { this.projectName,
[title]: child[this.childForeignKey] this.meta.title,
}) pid,
'hm',
this.column.title,
id
)
} else { } else {
await this.addChildToParent(child) await this.addChildToParent(child)
} }

18
packages/nc-gui/components/project/spreadsheet/components/virtualCell/manyToManyCell.vue

@ -318,7 +318,7 @@ export default {
const cid = this.childMeta.columns.filter(c => c.pk).map(c => child[c.title]).join('___') const cid = this.childMeta.columns.filter(c => c.pk).map(c => child[c.title]).join('___')
const pid = this.meta.columns.filter(c => c.pk).map(c => this.row[c.title]).join('___') const pid = this.meta.columns.filter(c => c.pk).map(c => this.row[c.title]).join('___')
await this.$api.dbTableRow.nestedDelete( await this.$api.dbTableRow.nestedRemove(
'noco', 'noco',
this.projectName, this.projectName,
this.meta.title, this.meta.title,
@ -461,16 +461,18 @@ export default {
// eslint-disable-next-line no-cond-assign // eslint-disable-next-line no-cond-assign
while (child = this.localState.pop()) { while (child = this.localState.pop()) {
if (row) { if (row) {
// todo: use common method
const cid = this.childMeta.columns.filter(c => c.pk).map(c => child[c.title]).join('___') const cid = this.childMeta.columns.filter(c => c.pk).map(c => child[c.title]).join('___')
const pid = this.meta.columns.filter(c => c.pk).map(c => row[c.title]).join('___') const pid = this.meta.columns.filter(c => c.pk).map(c => row[c.title]).join('___')
const vcidCol = this.assocMeta.columns.find(c => c.id === this.column.colOptions.fk_mm_parent_column_id).title await this.$api.dbTableRow.nestedAdd(
const vpidCol = this.assocMeta.columns.find(c => c.id === this.column.colOptions.fk_mm_child_column_id).title 'noco',
await this.assocApi.insert({ this.projectName,
[vcidCol]: parseIfInteger(cid), this.meta.title,
[vpidCol]: parseIfInteger(pid) pid,
}) 'mm',
this.column.title,
cid
)
} else { } else {
await this.addChildToParent(child) await this.addChildToParent(child)
} }

2
packages/nc-gui/components/project/spreadsheet/dialog/createViewDialog.vue

@ -4,7 +4,7 @@
<v-card-title class="grey darken-2 subheading" style="height:30px" /> <v-card-title class="grey darken-2 subheading" style="height:30px" />
<v-card-text class="pt-4 pl-4"> <v-card-text class="pt-4 pl-4">
<p class="headline"> <p class="headline">
{{ $t('general.create') }} <span class="text-capitalize">{{ show_as }}</span> {{ $t('objects.view') }} {{ $t('general.create') }} <span class="text-capitalize">{{ typeAlias }}</span> {{ $t('objects.view') }}
</p> </p>
<v-form ref="form" v-model="valid" @submit.prevent="createView"> <v-form ref="form" v-model="valid" @submit.prevent="createView">
<!-- label="View Name" --> <!-- label="View Name" -->

4
packages/nc-gui/components/project/spreadsheet/views/formView.vue

@ -688,6 +688,10 @@ export default {
} }
}, },
async updateView() { async updateView() {
if (this.view.subheading?.length > 255) {
this.$toast.error('Data too long for Form Description').goAway(3000)
return
}
await this.$api.dbView.formUpdate(this.viewId, this.view) await this.$api.dbView.formUpdate(this.viewId, this.view)
}, },
async loadView() { async loadView() {

9
packages/nc-gui/components/releaseInfo.vue

@ -3,7 +3,7 @@
<template #activator="{on}"> <template #activator="{on}">
<transition name="release"> <transition name="release">
<v-btn <v-btn
v-if="releaseAlert" v-show="releaseAlert"
text text
small small
class="mb-0 mr-2 py-0 " class="mb-0 mr-2 py-0 "
@ -54,10 +54,13 @@ export default {
computed: { computed: {
releaseAlert: { releaseAlert: {
get() { get() {
return !this.loading && this.$store.state.app.releaseVersion && this.$store.state.app.releaseVersion !== this.$store.state.app.hiddenRelease return !this.loading && this.$store.state.app.releaseVersion &&
this.$store.state.app.latestRelease &&
this.$store.state.app.releaseVersion !== this.$store.state.app.latestRelease &&
this.$store.state.app.latestRelease !== this.$store.state.app.hiddenRelease
}, },
set(val) { set(val) {
return this.$store.commit('app/MutHiddenRelease', val ? null : this.$store.state.app.releaseVersion) return this.$store.commit('app/MutHiddenRelease', val ? null : this.$store.state.app.latestRelease)
} }
}, },
releaseVersion() { releaseVersion() {

2
packages/nc-gui/helpers/themes.js

@ -11,7 +11,7 @@ export default {
Default: { Default: {
// "primary": "#0989ff", // "primary": "#0989ff",
// "primary": "#1082da", // "primary": "#1082da",
primary: '#1972e6', primary: '#1348ba',
secondary: '#9575CD', secondary: '#9575CD',
accent: '#FF4081', accent: '#FF4081',
info: '#2196F3', info: '#2196F3',

1
packages/nc-gui/lang/da.json

@ -225,6 +225,7 @@
"bookDemo": "Book en gratis demo", "bookDemo": "Book en gratis demo",
"getAnswered": "Få dine spørgsmål besvaret", "getAnswered": "Få dine spørgsmål besvaret",
"joinDiscord": "Deltag Diskord", "joinDiscord": "Deltag Diskord",
"joinCommunity": "Join NocoDB Community",
"joinReddit": "Deltag /r/NocoDB", "joinReddit": "Deltag /r/NocoDB",
"followNocodb": "Følg NocoDB" "followNocodb": "Følg NocoDB"
}, },

1
packages/nc-gui/lang/de.json

@ -225,6 +225,7 @@
"bookDemo": "Eine kostenlose Demo buchen", "bookDemo": "Eine kostenlose Demo buchen",
"getAnswered": "Erhalten Sie Antworten auf Ihre Fragen", "getAnswered": "Erhalten Sie Antworten auf Ihre Fragen",
"joinDiscord": "Discord beitreten", "joinDiscord": "Discord beitreten",
"joinCommunity": "Join NocoDB Community",
"joinReddit": "/r/NocoDB beitreten", "joinReddit": "/r/NocoDB beitreten",
"followNocodb": "Folgen Sie NocoDB" "followNocodb": "Folgen Sie NocoDB"
}, },

1
packages/nc-gui/lang/en.json

@ -225,6 +225,7 @@
"bookDemo": "Book a Free DEMO", "bookDemo": "Book a Free DEMO",
"getAnswered": "Get your questions answered", "getAnswered": "Get your questions answered",
"joinDiscord": "Join Discord", "joinDiscord": "Join Discord",
"joinCommunity": "Join NocoDB Community",
"joinReddit": "Join /r/NocoDB", "joinReddit": "Join /r/NocoDB",
"followNocodb": "Follow NocoDB" "followNocodb": "Follow NocoDB"
}, },

1
packages/nc-gui/lang/es.json

@ -225,6 +225,7 @@
"bookDemo": "Agendar una demostración gratuita", "bookDemo": "Agendar una demostración gratuita",
"getAnswered": "Obtén respuestas a tus preguntas", "getAnswered": "Obtén respuestas a tus preguntas",
"joinDiscord": "Únete a Discord", "joinDiscord": "Únete a Discord",
"joinCommunity": "Join NocoDB Community",
"joinReddit": "Únete /r/NocoDB", "joinReddit": "Únete /r/NocoDB",
"followNocodb": "Seguir a NocoDB" "followNocodb": "Seguir a NocoDB"
}, },

1
packages/nc-gui/lang/fa.json

@ -225,6 +225,7 @@
"bookDemo": "رزرو دموی رایگان", "bookDemo": "رزرو دموی رایگان",
"getAnswered": "پاسخ سوالات خود را دریافت کنید", "getAnswered": "پاسخ سوالات خود را دریافت کنید",
"joinDiscord": "به Discord بپیوندید", "joinDiscord": "به Discord بپیوندید",
"joinCommunity": "Join NocoDB Community",
"joinReddit": "به NocoDB بپیوندید", "joinReddit": "به NocoDB بپیوندید",
"followNocodb": "NocoDB را دنبال کنید" "followNocodb": "NocoDB را دنبال کنید"
}, },

1
packages/nc-gui/lang/fi.json

@ -225,6 +225,7 @@
"bookDemo": "Varaa ilmainen demo", "bookDemo": "Varaa ilmainen demo",
"getAnswered": "Hanki kysymyksesi vastasi", "getAnswered": "Hanki kysymyksesi vastasi",
"joinDiscord": "Liity discordiin", "joinDiscord": "Liity discordiin",
"joinCommunity": "Join NocoDB Community",
"joinReddit": "Liity /r/NocoDB", "joinReddit": "Liity /r/NocoDB",
"followNocodb": "Seuraa NocoDB" "followNocodb": "Seuraa NocoDB"
}, },

1
packages/nc-gui/lang/fr.json

@ -225,6 +225,7 @@
"bookDemo": "Planifier une démonstration gratuite", "bookDemo": "Planifier une démonstration gratuite",
"getAnswered": "Obtenir des réponses à vos questions", "getAnswered": "Obtenir des réponses à vos questions",
"joinDiscord": "Rejoindre le serveur Discord", "joinDiscord": "Rejoindre le serveur Discord",
"joinCommunity": "Join NocoDB Community",
"joinReddit": "Rejoindre /r/NocoDB", "joinReddit": "Rejoindre /r/NocoDB",
"followNocodb": "Suivre NocoDB" "followNocodb": "Suivre NocoDB"
}, },

1
packages/nc-gui/lang/hr.json

@ -225,6 +225,7 @@
"bookDemo": "Rezervirajte besplatni demo", "bookDemo": "Rezervirajte besplatni demo",
"getAnswered": "Odgovorite na vaša pitanja", "getAnswered": "Odgovorite na vaša pitanja",
"joinDiscord": "Pridružite se nesloga", "joinDiscord": "Pridružite se nesloga",
"joinCommunity": "Join NocoDB Community",
"joinReddit": "Pridružite se /r/NocoDB", "joinReddit": "Pridružite se /r/NocoDB",
"followNocodb": "Slijedite NocoDB" "followNocodb": "Slijedite NocoDB"
}, },

1
packages/nc-gui/lang/id.json

@ -225,6 +225,7 @@
"bookDemo": "Pesan demo gratis", "bookDemo": "Pesan demo gratis",
"getAnswered": "Dapatkan pertanyaan Anda dijawab", "getAnswered": "Dapatkan pertanyaan Anda dijawab",
"joinDiscord": "Bergabunglah dengan Perselisihan", "joinDiscord": "Bergabunglah dengan Perselisihan",
"joinCommunity": "Join NocoDB Community",
"joinReddit": "Bergabunglah /r/NocoDB", "joinReddit": "Bergabunglah /r/NocoDB",
"followNocodb": "Ikuti NocoDB" "followNocodb": "Ikuti NocoDB"
}, },

1
packages/nc-gui/lang/it_IT.json

@ -225,6 +225,7 @@
"bookDemo": "Prenota una demo gratuita", "bookDemo": "Prenota una demo gratuita",
"getAnswered": "Ottieni risposte alle tue domande", "getAnswered": "Ottieni risposte alle tue domande",
"joinDiscord": "Unisciti su Discord", "joinDiscord": "Unisciti su Discord",
"joinCommunity": "Join NocoDB Community",
"joinReddit": "Iscriviti /r/NocoDB", "joinReddit": "Iscriviti /r/NocoDB",
"followNocodb": "Segui NocoDB" "followNocodb": "Segui NocoDB"
}, },

1
packages/nc-gui/lang/iw.json

@ -225,6 +225,7 @@
"bookDemo": "להזמין הדגמה חינם", "bookDemo": "להזמין הדגמה חינם",
"getAnswered": "קבל את השאלות שלך ענה", "getAnswered": "קבל את השאלות שלך ענה",
"joinDiscord": "הצטרף לדיסק", "joinDiscord": "הצטרף לדיסק",
"joinCommunity": "Join NocoDB Community",
"joinReddit": "הצטרף /r/NocoDB", "joinReddit": "הצטרף /r/NocoDB",
"followNocodb": "בצע NocoDB" "followNocodb": "בצע NocoDB"
}, },

1
packages/nc-gui/lang/ja.json

@ -225,6 +225,7 @@
"bookDemo": "無料のデモを予約する", "bookDemo": "無料のデモを予約する",
"getAnswered": "あなたの質問に回答しましょう", "getAnswered": "あなたの質問に回答しましょう",
"joinDiscord": "Discordに参加する", "joinDiscord": "Discordに参加する",
"joinCommunity": "Join NocoDB Community",
"joinReddit": "/r/NocoDBに参加する", "joinReddit": "/r/NocoDBに参加する",
"followNocodb": "NocoDBをフォローする" "followNocodb": "NocoDBをフォローする"
}, },

1
packages/nc-gui/lang/ko.json

@ -225,6 +225,7 @@
"bookDemo": "무료 데모를 예약하십시오", "bookDemo": "무료 데모를 예약하십시오",
"getAnswered": "귀하의 질문에 답변 해주십시오", "getAnswered": "귀하의 질문에 답변 해주십시오",
"joinDiscord": "디스코드 참가", "joinDiscord": "디스코드 참가",
"joinCommunity": "Join NocoDB Community",
"joinReddit": "가입 /r/NocoDB", "joinReddit": "가입 /r/NocoDB",
"followNocodb": "NocoDB를 팔로우 하세요" "followNocodb": "NocoDB를 팔로우 하세요"
}, },

1
packages/nc-gui/lang/lv.json

@ -225,6 +225,7 @@
"bookDemo": "Rezervē bezmaksas DEMO", "bookDemo": "Rezervē bezmaksas DEMO",
"getAnswered": "Saņemt atbildi uz jautājumiem", "getAnswered": "Saņemt atbildi uz jautājumiem",
"joinDiscord": "Pievienoties Discord", "joinDiscord": "Pievienoties Discord",
"joinCommunity": "Join NocoDB Community",
"joinReddit": "Pievienoties /r/NocoDB", "joinReddit": "Pievienoties /r/NocoDB",
"followNocodb": "Sekot NocoDB" "followNocodb": "Sekot NocoDB"
}, },

1
packages/nc-gui/lang/nl.json

@ -225,6 +225,7 @@
"bookDemo": "Boek een gratis demonstratie", "bookDemo": "Boek een gratis demonstratie",
"getAnswered": "Krijg je vragen beantwoord", "getAnswered": "Krijg je vragen beantwoord",
"joinDiscord": "Join Discord", "joinDiscord": "Join Discord",
"joinCommunity": "Join NocoDB Community",
"joinReddit": "Join /r/NocoDB", "joinReddit": "Join /r/NocoDB",
"followNocodb": "Volg NocoDB" "followNocodb": "Volg NocoDB"
}, },

1
packages/nc-gui/lang/no.json

@ -225,6 +225,7 @@
"bookDemo": "Bestill en gratis demo", "bookDemo": "Bestill en gratis demo",
"getAnswered": "Få dine spørsmål besvart", "getAnswered": "Få dine spørsmål besvart",
"joinDiscord": "Bli med på Discord", "joinDiscord": "Bli med på Discord",
"joinCommunity": "Join NocoDB Community",
"joinReddit": "Bli med /r/NocoDB", "joinReddit": "Bli med /r/NocoDB",
"followNocodb": "Følg NocoDB" "followNocodb": "Følg NocoDB"
}, },

1
packages/nc-gui/lang/pl.json

@ -225,6 +225,7 @@
"bookDemo": "Zarezerwuj darmowe demo", "bookDemo": "Zarezerwuj darmowe demo",
"getAnswered": "Odpowiedzi na pytania", "getAnswered": "Odpowiedzi na pytania",
"joinDiscord": "Dołącz do Discord.", "joinDiscord": "Dołącz do Discord.",
"joinCommunity": "Join NocoDB Community",
"joinReddit": "Dołącz /r/NocoDB", "joinReddit": "Dołącz /r/NocoDB",
"followNocodb": "Śledź NocoDB" "followNocodb": "Śledź NocoDB"
}, },

1
packages/nc-gui/lang/pt.json

@ -225,6 +225,7 @@
"bookDemo": "Marque uma DEMONSTRAÇÃO gratuita", "bookDemo": "Marque uma DEMONSTRAÇÃO gratuita",
"getAnswered": "Obtenha resposta às suas questões", "getAnswered": "Obtenha resposta às suas questões",
"joinDiscord": "Junte-se ao Discord", "joinDiscord": "Junte-se ao Discord",
"joinCommunity": "Join NocoDB Community",
"joinReddit": "Junte-se /r/NocoDB", "joinReddit": "Junte-se /r/NocoDB",
"followNocodb": "Siga NocoDB" "followNocodb": "Siga NocoDB"
}, },

1
packages/nc-gui/lang/pt_BR.json

@ -225,6 +225,7 @@
"bookDemo": "Marque uma DEMONSTRAÇÃO gratuita", "bookDemo": "Marque uma DEMONSTRAÇÃO gratuita",
"getAnswered": "Obtenha resposta às suas perguntas", "getAnswered": "Obtenha resposta às suas perguntas",
"joinDiscord": "Junte-se ao Discord", "joinDiscord": "Junte-se ao Discord",
"joinCommunity": "Join NocoDB Community",
"joinReddit": "Junte-se /r/NocoDB", "joinReddit": "Junte-se /r/NocoDB",
"followNocodb": "Siga NocoDB" "followNocodb": "Siga NocoDB"
}, },

1
packages/nc-gui/lang/sl.json

@ -225,6 +225,7 @@
"bookDemo": "Rezervirajte brezplačno demo", "bookDemo": "Rezervirajte brezplačno demo",
"getAnswered": "Odgovorili na vaša vprašanja", "getAnswered": "Odgovorili na vaša vprašanja",
"joinDiscord": "Pridružite se nam na Discord-u", "joinDiscord": "Pridružite se nam na Discord-u",
"joinCommunity": "Join NocoDB Community",
"joinReddit": "Pridružite se /r/NocoDB", "joinReddit": "Pridružite se /r/NocoDB",
"followNocodb": "Sledite NocoDB" "followNocodb": "Sledite NocoDB"
}, },

1
packages/nc-gui/lang/sv.json

@ -225,6 +225,7 @@
"bookDemo": "Boka en gratis demo", "bookDemo": "Boka en gratis demo",
"getAnswered": "Få dina frågor besvarade", "getAnswered": "Få dina frågor besvarade",
"joinDiscord": "Gå med i Discord", "joinDiscord": "Gå med i Discord",
"joinCommunity": "Join NocoDB Community",
"joinReddit": "Gå med /r/NocoDB", "joinReddit": "Gå med /r/NocoDB",
"followNocodb": "Följ NocoDB" "followNocodb": "Följ NocoDB"
}, },

1
packages/nc-gui/lang/th.json

@ -225,6 +225,7 @@
"bookDemo": "จองการสาธตฟร", "bookDemo": "จองการสาธตฟร",
"getAnswered": "รบคำถามของคณตอบ", "getAnswered": "รบคำถามของคณตอบ",
"joinDiscord": "เขารวมกบความไมลงรอยกน", "joinDiscord": "เขารวมกบความไมลงรอยกน",
"joinCommunity": "Join NocoDB Community",
"joinReddit": "เขารวม /r/NocoDB", "joinReddit": "เขารวม /r/NocoDB",
"followNocodb": "ตดตาม NocoDB" "followNocodb": "ตดตาม NocoDB"
}, },

1
packages/nc-gui/lang/tr.json

@ -225,6 +225,7 @@
"bookDemo": "Ücretsiz bir demo rezervasyonu yapın", "bookDemo": "Ücretsiz bir demo rezervasyonu yapın",
"getAnswered": "Sorularınıza cevap bulun", "getAnswered": "Sorularınıza cevap bulun",
"joinDiscord": "Discord'a katıl", "joinDiscord": "Discord'a katıl",
"joinCommunity": "Join NocoDB Community",
"joinReddit": "/r/NocoDB'ye katıl", "joinReddit": "/r/NocoDB'ye katıl",
"followNocodb": "NocoDB'yi takip et" "followNocodb": "NocoDB'yi takip et"
}, },

1
packages/nc-gui/lang/uk.json

@ -225,6 +225,7 @@
"bookDemo": "Забронюйте безкоштовну демонстрацію", "bookDemo": "Забронюйте безкоштовну демонстрацію",
"getAnswered": "Отримайте відповіді на запитання", "getAnswered": "Отримайте відповіді на запитання",
"joinDiscord": "Приєднуватися", "joinDiscord": "Приєднуватися",
"joinCommunity": "Join NocoDB Community",
"joinReddit": "Приєднатися /r/NocoDB", "joinReddit": "Приєднатися /r/NocoDB",
"followNocodb": "Слідувати NocoDB" "followNocodb": "Слідувати NocoDB"
}, },

1
packages/nc-gui/lang/vi.json

@ -225,6 +225,7 @@
"bookDemo": "Đặt một bản demo miễn phí", "bookDemo": "Đặt một bản demo miễn phí",
"getAnswered": "Nhận câu hỏi của bạn được trả lời", "getAnswered": "Nhận câu hỏi của bạn được trả lời",
"joinDiscord": "Tham gia thông minh", "joinDiscord": "Tham gia thông minh",
"joinCommunity": "Join NocoDB Community",
"joinReddit": "Tham gia /r/NocoDB", "joinReddit": "Tham gia /r/NocoDB",
"followNocodb": "Theo dõi NocoDB" "followNocodb": "Theo dõi NocoDB"
}, },

1
packages/nc-gui/lang/zh_CN.json

@ -225,6 +225,7 @@
"bookDemo": "查看免费演示", "bookDemo": "查看免费演示",
"getAnswered": "通过这里让你的问题得到解答", "getAnswered": "通过这里让你的问题得到解答",
"joinDiscord": "加入 Discord", "joinDiscord": "加入 Discord",
"joinCommunity": "Join NocoDB Community",
"joinReddit": "加入/r/NocoDB", "joinReddit": "加入/r/NocoDB",
"followNocodb": "关注 NocoDB" "followNocodb": "关注 NocoDB"
}, },

1
packages/nc-gui/lang/zh_HK.json

@ -225,6 +225,7 @@
"bookDemo": "Book個 free demo", "bookDemo": "Book個 free demo",
"getAnswered": "讓您的問題得到解答", "getAnswered": "讓您的問題得到解答",
"joinDiscord": "加入 Discord", "joinDiscord": "加入 Discord",
"joinCommunity": "Join NocoDB Community",
"joinReddit": "加入 /r/NocoDB", "joinReddit": "加入 /r/NocoDB",
"followNocodb": "Fol下NocoDB" "followNocodb": "Fol下NocoDB"
}, },

1
packages/nc-gui/lang/zh_TW.json

@ -225,6 +225,7 @@
"bookDemo": "預訂免費 Demo", "bookDemo": "預訂免費 Demo",
"getAnswered": "解惑您的問題", "getAnswered": "解惑您的問題",
"joinDiscord": "加入 Discord", "joinDiscord": "加入 Discord",
"joinCommunity": "Join NocoDB Community",
"joinReddit": "加入 /r/NocoDB", "joinReddit": "加入 /r/NocoDB",
"followNocodb": "追蹤 NocoDB" "followNocodb": "追蹤 NocoDB"
}, },

5
packages/nc-gui/layouts/default.vue

@ -52,6 +52,7 @@
<div style="flex: 1" class="d-flex justify-end"> <div style="flex: 1" class="d-flex justify-end">
<v-toolbar-items class="hidden-sm-and-down nc-topright-menu"> <v-toolbar-items class="hidden-sm-and-down nc-topright-menu">
<important-announcement />
<release-info /> <release-info />
<language class="mr-3" /> <language class="mr-3" />
@ -282,6 +283,7 @@ import Language from '~/components/utils/language'
import Loader from '~/components/loader' import Loader from '~/components/loader'
import PreviewAs from '~/components/previewAs' import PreviewAs from '~/components/previewAs'
import ShareOrInviteModal from '~/components/auth/shareOrInviteModal' import ShareOrInviteModal from '~/components/auth/shareOrInviteModal'
import ImportantAnnouncement from '../components/importantAnnouncement.vue'
export default { export default {
components: { components: {
@ -293,7 +295,8 @@ export default {
XBtn, XBtn,
Snackbar, Snackbar,
dlgUnexpectedError, dlgUnexpectedError,
settings settings,
ImportantAnnouncement
}, },
data: () => ({ data: () => ({
clickCount: true, clickCount: true,

2
packages/nc-gui/nuxt.config.js

@ -215,7 +215,7 @@ export default {
packageJson.version = `${packageJson.version}-${process.env.targetVersion}` packageJson.version = `${packageJson.version}-${process.env.targetVersion}`
packageJson.name += '-daily' packageJson.name += '-daily'
} else { } else {
packageJson.version = version packageJson.version = process.env.targetVersion
} }
fs.writeFileSync('../nc-lib-gui/package.json', JSON.stringify(packageJson, 0, 2)) fs.writeFileSync('../nc-lib-gui/package.json', JSON.stringify(packageJson, 0, 2))

19755
packages/nc-gui/package-lock.json generated

File diff suppressed because it is too large Load Diff

2
packages/nc-gui/package.json

@ -29,7 +29,7 @@
"monaco-editor": "^0.19.3", "monaco-editor": "^0.19.3",
"monaco-themes": "^0.2.5", "monaco-themes": "^0.2.5",
"nano-assign": "^1.0.1", "nano-assign": "^1.0.1",
"nocodb-sdk": "file:../nocodb-sdk", "nocodb-sdk": "0.90.0",
"nuxt": "^2.14.0", "nuxt": "^2.14.0",
"odometer": "^0.4.8", "odometer": "^0.4.8",
"papaparse": "^5.3.1", "papaparse": "^5.3.1",

11
packages/nc-gui/plugins/projectLoader.js

@ -1,4 +1,4 @@
export default async({ store, redirect, $axios, $toast, route }) => { export default async({ store, redirect, $axios, $toast, $api, route }) => {
// if (!route.path || !route.path.startsWith('/nc/')) { await store.dispatch('plugins/pluginPostInstall', 'Branding') } // if (!route.path || !route.path.startsWith('/nc/')) { await store.dispatch('plugins/pluginPostInstall', 'Branding') }
if (window.location.search && if (window.location.search &&
/\bscope=|\bstate=/.test(window.location.search) && /\bscope=|\bstate=/.test(window.location.search) &&
@ -63,11 +63,14 @@ export default async({ store, redirect, $axios, $toast, route }) => {
// fetch latest release info // fetch latest release info
const fetchReleaseInfo = async() => { const fetchReleaseInfo = async() => {
try { try {
const releaseInfo = await store.dispatch('sqlMgr/ActSqlOp', [null, 'xcRelease']) const releaseInfo = await $api.utils.appInfo()
if (releaseInfo && releaseInfo.docker && releaseInfo.docker.upgrade) { const latestRelease = await $api.utils.appVersion()
store.commit('app/MutReleaseVersion', releaseInfo.docker.name) if (releaseInfo && latestRelease && releaseInfo.version) {
store.commit('app/MutReleaseVersion', releaseInfo.version)
store.commit('app/MutLatestRelease', latestRelease.releaseVersion || null)
} else { } else {
store.commit('app/MutReleaseVersion', null) store.commit('app/MutReleaseVersion', null)
store.commit('app/MutLatestRelease', null)
} }
} catch (e) { } catch (e) {
// ignore // ignore

20
packages/nc-gui/plugins/tele.js

@ -23,7 +23,8 @@ export default function({
socket.disconnect() socket.disconnect()
socket = null socket = null
}) })
} catch { } } catch {
}
} }
app.router.onReady(() => { app.router.onReady(() => {
@ -32,13 +33,11 @@ export default function({
return return
} }
socket.emit('page', { socket.emit('page', {
id: store.state.users.user && store.state.users.user.id,
path: to.matched[0].path + (to.query && to.query.type ? `?type=${to.query.type}` : '') path: to.matched[0].path + (to.query && to.query.type ? `?type=${to.query.type}` : '')
}) })
}) })
if (socket) { if (socket) {
socket.emit('page', { socket.emit('page', {
id: store.state.users.user && store.state.users.user.id,
path: route.matched[0].path + (route.query && route.query.type ? `?type=${route.query.type}` : '') path: route.matched[0].path + (route.query && route.query.type ? `?type=${route.query.type}` : '')
}) })
} }
@ -49,9 +48,8 @@ export default function({
if (socket) { if (socket) {
socket.emit('event', { socket.emit('event', {
event: evt, event: evt,
id: store.state.users.user && store.state.users.user.id,
...(data || {}), ...(data || {}),
$current_url: gatPath(app) path: gatPath(app)
}) })
} }
} }
@ -61,14 +59,14 @@ export default function({
function getListener(binding) { function getListener(binding) {
return function(e) { return function(e) {
if (!socket) { return } if (!socket) {
const cat = window.location.hash.replace(/\d+\/(?=dashboard)/, '') return
}
const event = binding.value && binding.value[0] const event = binding.value && binding.value[0]
const data = binding.value && binding.value[1] const data = binding.value && binding.value[1]
const extra = binding.value && binding.value.slice(2) const extra = binding.value && binding.value.slice(2)
tele.emit(event, tele.emit(event,
{ {
cat,
data, data,
extra extra
}) })
@ -87,14 +85,16 @@ export default function({
store.watch(state => state.project.projectInfo && state.project.projectInfo.teleEnabled && state.users.token, (token) => { store.watch(state => state.project.projectInfo && state.project.projectInfo.teleEnabled && state.users.token, (token) => {
if (token) { if (token) {
init(token).then(() => {}) init(token).then(() => {
})
} else if (socket) { } else if (socket) {
socket.disconnect() socket.disconnect()
socket = null socket = null
} }
}) })
if (store.state.project.projectInfo && store.state.project.projectInfo.teleEnabled && store.state.users.token) { if (store.state.project.projectInfo && store.state.project.projectInfo.teleEnabled && store.state.users.token) {
init(store.state.users.token).then(() => {}) init(store.state.users.token).then(() => {
})
} }
} }

12
packages/nc-gui/store/app.js

@ -1,6 +1,8 @@
export const state = () => ({ export const state = () => ({
releaseVersion: null, releaseVersion: null,
hiddenRelease: null hiddenRelease: null,
latestRelease: null,
hiddenAnnouncement: null,
}) })
export const mutations = { export const mutations = {
@ -9,7 +11,13 @@ export const mutations = {
}, },
MutHiddenRelease(state, hiddenRelease) { MutHiddenRelease(state, hiddenRelease) {
state.hiddenRelease = hiddenRelease state.hiddenRelease = hiddenRelease
} },
MutLatestRelease(state, latestRelease) {
state.latestRelease = latestRelease
},
MutHiddenAnnouncement(state, hiddenAnnouncement) {
state.hiddenAnnouncement = hiddenAnnouncement
},
} }
/** /**

12
packages/nc-gui/store/users.js

@ -153,7 +153,7 @@ export const actions = {
setInterval(async() => { setInterval(async() => {
if (getters.GtrUser) { if (getters.GtrUser) {
try { try {
const res = await this.$api.auth.me() // this.$axios.get('/user/me') const res = await this.$api.auth.me()
if (res === null || !res.email) { if (res === null || !res.email) {
commit('MutSetUser', null) commit('MutSetUser', null)
} else { } else {
@ -239,7 +239,6 @@ export const actions = {
// console.log('in action signin'); // console.log('in action signin');
let err = null let err = null
try { try {
const userPromise = await this.$api.auth.signin(data) const userPromise = await this.$api.auth.signin(data)
commit('MutSetToken', userPromise.token) commit('MutSetToken', userPromise.token)
@ -272,7 +271,7 @@ export const actions = {
async ActGetUserDetails({ commit, state }) { async ActGetUserDetails({ commit, state }) {
try { try {
const user = await this.$api.auth.me({ // await this.$axios.get('/user/me', { const user = await this.$api.auth.me({}, {
headers: { headers: {
'xc-auth': state.token 'xc-auth': state.token
} }
@ -285,11 +284,10 @@ export const actions = {
async ActGetProjectUserDetails({ commit, state }, projectId) { async ActGetProjectUserDetails({ commit, state }, projectId) {
try { try {
const user = await this.$api.auth.me({ // '/user/me?project_id=' + projectId, { const user = await this.$api.auth.me({ project_id: projectId }, {
headers: { headers: {
'xc-auth': state.token 'xc-auth': state.token
}, }
query: { project_id: projectId }
}) })
commit('MutProjectRole', user && user.roles) commit('MutProjectRole', user && user.roles)
} catch (e) { } catch (e) {
@ -299,7 +297,7 @@ export const actions = {
async ActGetBaseUserDetails({ commit, state }, sharedBaseId) { async ActGetBaseUserDetails({ commit, state }, sharedBaseId) {
try { try {
try { try {
const user = await this.$api.auth.me({ // '/user/me', { const user = await this.$api.auth.me({}, {
headers: { headers: {
'xc-shared-base-id': sharedBaseId 'xc-shared-base-id': sharedBaseId
} }

4
packages/nc-lib-gui/package.json

@ -1,6 +1,6 @@
{ {
"name": "nc-lib-gui", "name": "nc-lib-gui",
"version": "0.84.17", "version": "0.90.0",
"description": "> TODO: description", "description": "> TODO: description",
"author": "“pranavxc” <pranavxc@gmail.com>", "author": "“pranavxc” <pranavxc@gmail.com>",
"homepage": "https://gitlab.com/xgenecloud-ts/xgenecloud-ts#readme", "homepage": "https://gitlab.com/xgenecloud-ts/xgenecloud-ts#readme",
@ -30,4 +30,4 @@
"express": "^4.17.1", "express": "^4.17.1",
"vuedraggable": "^2.24.3" "vuedraggable": "^2.24.3"
} }
} }

43
packages/noco-docs-prev/content/en/setup-and-usages/usage-information.md

@ -8,7 +8,7 @@ menuTitle: 'Usage Information'
<announcement></announcement> <announcement></announcement>
NocoDB is a fast growing open source project and we are committed to providing a solution that exceeds the expectations of the users and community. NocoDB is a fast growing open source project which is UI heavy and we are committed to providing a solution that exceeds the expectations of the users and community.
We are also committed to continuing to develop and make NocoDB even better than it is today. We are also committed to continuing to develop and make NocoDB even better than it is today.
To that end, NocoDB contains a feature in which anonymous and otherwise non-sensitive data is collected. To that end, NocoDB contains a feature in which anonymous and otherwise non-sensitive data is collected.
This anonymous and non-sensitive data gives a better understanding of how users are interacting and using the product. This anonymous and non-sensitive data gives a better understanding of how users are interacting and using the product.
@ -18,19 +18,49 @@ We will always continue to do hands-on UI/UX testing, surveys, issue tracking an
Otherwise talk with the Community while striving to understand Otherwise talk with the Community while striving to understand
and deliver what is being asked for and what is needed, by any means available. and deliver what is being asked for and what is needed, by any means available.
However, these above actions alone are often insufficient to maintain an overall picture of the product usage. However, these above actions alone are often insufficient
- To maintain an overall picture of the product usage.
- Prioritising the efforts.
- Impact of any breaking changes.
- To understand whether UI improvements are helpful to users.
## What we collect ? ## What we collect ?
The following data is collected: We collect actions made on models (project, table, view, sharedView, user, hook, image, sharedBase etc) periodically with :
- Unique machine ID (generated with node-machine-id) - Unique machine ID (generated with node-machine-id)
- Environment (dev, staging, production) - Environment (dev, staging, production)
- System information (OS, node version, docker or npm) - System information (OS, node version, docker or npm)
- Failures and errors. - Failures.
- Create and delete events of a project, table, view, linkToAnotherRecord, sharedView, user, hook, image, sharedBase.
Here is an example :
```
{
"machine_id" : "a0885e8e6a38d9fbb5d39e7d04a44da7773d4f",
"evt_type": "project:created"
"package_id" : "0.84.15",
"os_type" : "Linux",
"os_platform" : "linux",
"os_release" : "5.10.25-linuxkit",
"node_version" : "14.18.2",
"docker" : "true",
"xc_version" : "0.84.15",
"env" : "dev",
}
```
Our UI Dashboard is a Vuejs-Nuxtjs app. Actions taken on UI with completely anonymized route names are sent as payload.
Here is an example :
```
{
"id": "a0885e8e6a38d9fbb5d39e7d04a44da7773d4f",
"event": "table:create",
"path": "/nc/:project_id",
}
```
## What we DO NOT collect ? ## What we DO NOT collect ?
We do not collect private or sensitive information, such as: We do not collect any private or sensitive information, such as:
- Personally identifiable information - Personally identifiable information
- Credential information (endpoints, ports, DB connections, username/password) - Credential information (endpoints, ports, DB connections, username/password)
- User data - User data
@ -39,4 +69,3 @@ We do not collect private or sensitive information, such as:
## Opt-out ## Opt-out
To disable usage information collection please set following environment variable. To disable usage information collection please set following environment variable.
> NC_DISABLE_TELE=true > NC_DISABLE_TELE=true

33
packages/noco-docs/content/en/developer-resources/accessing-apis.md

@ -6,13 +6,13 @@ category: 'Developer Resources'
menuTitle: 'Accessing APIs' menuTitle: 'Accessing APIs'
--- ---
## REST APIs NocoDB APIs can be authorized by either Auth Token or API Token.
- Go to NocoDB Project, click the rightmost button and click ``Copy Auth Token``. ## Auth Token
Auth Token is a JWT Token generated based on the logged-in user. By default, the token is only valid for 10 hours. However, you can change the value by defining it using environment variable `NC_JWT_EXPIRES_IN`. If you are passing Auth Token, make sure that the header is called `xc-auth`.
<alert> - Go to NocoDB Project, click the rightmost button and click ``Copy Auth Token``.
Auth Token is a JWT Token generated based on the logged-in user. By default, the token is only valid for 10 hours. However, you can change the value by defining it using environment variable NC_JWT_EXPIRES_IN. If you are passing Auth Token, make sure that the header is called xc-auth.
</alert>
![image](https://user-images.githubusercontent.com/35857179/161957971-e4888983-25e1-46a4-8419-7b9fae6cb6fa.png) ![image](https://user-images.githubusercontent.com/35857179/161957971-e4888983-25e1-46a4-8419-7b9fae6cb6fa.png)
@ -28,4 +28,25 @@ Auth Token is a JWT Token generated based on the logged-in user. By default, the
- Paste the token you just copy in step 1 and click Authorize - Paste the token you just copy in step 1 and click Authorize
![image](https://user-images.githubusercontent.com/35857179/126188510-b3790348-6809-4182-911a-a4031ace2fd2.png) ![image](https://user-images.githubusercontent.com/35857179/126188510-b3790348-6809-4182-911a-a4031ace2fd2.png)
## API Token
NocoDB allows creating API tokens which allow it to be integrated seamlessly with 3rd party apps. API Token is a Nano ID with a length of 40. If you are passing API Token, make sure that the header is called `xc-token`.
- Go to `Team & Settings` from the left navigation drawer
![image](https://user-images.githubusercontent.com/35857179/161902474-fd06678c-a171-4237-b171-dc028b3753de.png)
- Click `API Tokens Management`
![image](https://user-images.githubusercontent.com/35857179/161958345-83cb60bf-80f1-4d11-9e9c-52d0b05c7677.png)
- Click Add New Token
![image](https://user-images.githubusercontent.com/35857179/161958563-dc5d380a-26c5-4b78-9d4b-e40188bef05a.png)
- Type an recognizable name for your token and click `Generate`
![image](https://user-images.githubusercontent.com/35857179/161958676-e4faa321-13ca-4b11-8d22-1332c522dde7.png)
- Copy API token to your clipboard
![image](https://user-images.githubusercontent.com/35857179/161958822-b0689a6a-a864-429f-8bb2-71eb92808339.png)

36
packages/noco-docs/content/en/developer-resources/api-tokens.md

@ -1,36 +0,0 @@
---
title: 'API Tokens'
description: 'API Tokens'
position: 1040
category: 'Developer Resources'
menuTitle: 'API Tokens'
---
## API Tokens
NocoDB allows creating API tokens which allow it to be integrated seamlessly with 3rd party apps.
<alert>
API Token is a Nano ID with a length of 40. If you are passing API Token, make sure that the header is called xc-token.
</alert>
### Which HTTP Header to use ?
- ```xc-token``` header should be set when invoking the NocoDB APIs with the token.
### How to create a token ?
1. Go to `Team & Settings` from the left navigation drawer
![image](https://user-images.githubusercontent.com/35857179/161902474-fd06678c-a171-4237-b171-dc028b3753de.png)
2. Click `API Tokens Management`
![image](https://user-images.githubusercontent.com/35857179/161958345-83cb60bf-80f1-4d11-9e9c-52d0b05c7677.png)
3. Click Add New Token
![image](https://user-images.githubusercontent.com/35857179/161958563-dc5d380a-26c5-4b78-9d4b-e40188bef05a.png)
4. Type an recognizable name for your token and click `Generate`
![image](https://user-images.githubusercontent.com/35857179/161958676-e4faa321-13ca-4b11-8d22-1332c522dde7.png)
5. Copy API token to your clipboard
![image](https://user-images.githubusercontent.com/35857179/161958822-b0689a6a-a864-429f-8bb2-71eb92808339.png)

9
packages/noco-docs/content/en/developer-resources/caching.md

@ -1,9 +0,0 @@
---
title: 'Caching'
description: 'Caching'
position: 1300
category: 'Developer Resources'
menuTitle: 'Caching'
---
We introduced a Caching layer to store meta data by utilising Redis. By default, caching is enabled. If you prefer not to cache, you can configure it by setting environment variable `NC_DISABLE_CACHE` to `true`. You can also use your own Redis instance by setting environment variable `NC_REDIS_URL` (e.g. `redis://:authpassword@127.0.0.1:6380/4`). If you don't specify it, by default, it will be cached in memory.

9
packages/noco-docs/content/en/developer-resources/data-apis.md

@ -1,9 +0,0 @@
---
title: 'Data APIs'
description: 'Data APIs'
position: 1200
category: 'Developer Resources'
menuTitle: 'Data APIs'
---
TBC

9
packages/noco-docs/content/en/developer-resources/meta-apis.md

@ -1,9 +0,0 @@
---
title: 'Meta APIs'
description: 'Meta APIs'
position: 1100
category: 'Developer Resources'
menuTitle: 'Meta APIs'
---
TBC

1349
packages/noco-docs/content/en/developer-resources/rest-apis.md

File diff suppressed because it is too large Load Diff

55
packages/noco-docs/content/en/developer-resources/sdk.md

@ -1,26 +1,67 @@
--- ---
title: 'SDK' title: 'NocoDB SDK'
description: 'SDK' description: 'SDK'
position: 1400 position: 1400
category: 'Developer Resources' category: 'Developer Resources'
menuTitle: 'SDK' menuTitle: 'NocoDB SDK'
--- ---
We provide SDK for users to integrated with their applications. Currently only Javascript is supported. We provide SDK for users to integrate with their applications. Currently only SDK for Javascript is supported.
### SDK For Javascript <alert>
Note: The NocoDB SDK requires authorization token. If you haven't created one, please check out <a href="./accessing-apis" target="_blank">Accessing APIs</a> for details.
</alert>
## SDK For Javascript
### Install nocodb-sdk
```bash
npm i nocodb-sdk
```
### Import Api
```js ```js
import { Api } from 'nocodb-sdk' import { Api } from 'nocodb-sdk'
```
### Configure Api
The Api can be authorizated by either Auth Token or API Token.
#### Example: Auth Token
```js
const api = new Api({ const api = new Api({
baseURL: 'http://<HOST>:<PORT>', baseURL: 'https://<HOST>:<PORT>',
headers: { headers: {
'xc-auth': '<AUTH_TOKEN>' 'xc-auth': '<AUTH_TOKEN>'
} }
}) })
```
// await api.meta.something() #### Example: API Token
// await api.data.something()
```js
const api = new Api({
baseURL: 'https://<HOST>:<PORT>',
headers: {
'xc-token': '<API_TOKEN>'
}
})
``` ```
### Call Functions
Once you have configured `api`, you can call different types of APIs by `api.<Tag>.<FunctionName>`.
<alert>
For Tag and FunctionName, please check out the API table <a href="./rest-apis" target="_blank">here</a>.
</alert>
#### Example: Calling API - /api/v1/db/meta/projects/{projectId}/tables
```js
await api.dbTable.create(params)
```

2
packages/noco-docs/content/en/developer-resources/webhooks.md

@ -1,7 +1,7 @@
--- ---
title: "Webhooks" title: "Webhooks"
description: "Webhooks" description: "Webhooks"
position: 1030 position: 1500
category: "Developer Resources" category: "Developer Resources"
menuTitle: "Webhooks" menuTitle: "Webhooks"
--- ---

18
packages/noco-docs/content/en/engineering/architecture.md

@ -0,0 +1,18 @@
---
title: "NocoDB Architecture"
description: "NocoDB Architecture"
position: 4000
category: "Engineering"
menuTitle: "NocoDB Architecture"
---
By default, if `NC_DB` is not specified, then SQLite will be used to store your meta data. We suggest users to separate the meta data and user data in different databases.
<!-- TODO: update diagram -->
<img src="../architecture.png" style="background: white;border-radius:4px;padding :10px">
| Project Type | Metadata stored in | Data stored in |
|---------|-----------|--------|
| Create new project | NC_DB | NC_DB |
| Create new project with External Database | NC_DB | External Database |
| Create new project from Excel | NC_DB | NC_DB |

31
packages/noco-docs/content/en/engineering/repository-structure.md

@ -0,0 +1,31 @@
---
title: "Repository Structure"
description: "Repository Structure"
position: 3000
category: "Engineering"
menuTitle: "Repository Structure"
---
We use ``Lerna`` to manage multi-packages. We have the following [packages](https://github.com/nocodb/nocodb/tree/master/packages).
- ``packages/nc-cli`` : A CLI to create NocoDB app.
- ``packages/nc-common``: A common library package used internally.
- ``packages/nc-gui``: NocoDB Frontend.
- ``packages/nc-lib-gui``: The build version of ``nc-gui`` which will be used in ``packages/nocodb``.
- ``packages/nc-migrator-archived``: SQL based schema migrations or evolutions.
- ``packages/nc-plugin``: Plugin template.
- ``packages/noco-blog``: NocoDB Blog which will be auto-released to [nocodb/noco-blog](https://github.com/nocodb/noco-blog).
- ``packages/noco-book``: NocoDB Handbook which will be auto-released to [nocodb/noco-book](https://github.com/nocodb/noco-book).
- ``packages/noco-docs``: NocoDB Documentation which will be auto-released to [nocodb/noco-docs](https://github.com/nocodb/noco-docs).
- ``packages/noco-docs-prev``: NocoDB Documentation for previous versions which will be auto-released to [nocodb/noco-docs-prev](https://github.com/nocodb/noco-docs-prev) and will be completely removed on 30 Jun 2022.
- ``packages/nocodb``: NocoDB Backend, hosted in [NPM](https://www.npmjs.com/package/nocodb).

35
packages/noco-docs/content/en/getting-started/installation.md

@ -65,7 +65,10 @@ If you are a Docker user, you may try this way!
<code-block label="SQLite" active> <code-block label="SQLite" active>
```bash ```bash
docker run -d --name nocodb -p 8080:8080 nocodb/nocodb:latest docker run -d --name nocodb \
-v /local/path:/usr/app/data/ \
-p 8080:8080 \
nocodb/nocodb:latest
``` ```
</code-block> </code-block>
@ -73,10 +76,12 @@ If you are a Docker user, you may try this way!
<code-block label="MySQL"> <code-block label="MySQL">
```bash ```bash
docker run -d -p 8080:8080 \ docker run -d --name nocodb-mysql \
-e NC_DB="mysql2://host.docker.internal:3306?u=root&p=password&d=d1" \ -v /local/path:/usr/app/data/ \
-e NC_AUTH_JWT_SECRET="569a1821-0a93-45e8-87ab-eb857f20a010" \ -p 8080:8080 \
nocodb/nocodb:latest -e NC_DB="mysql2://host.docker.internal:3306?u=root&p=password&d=d1" \
-e NC_AUTH_JWT_SECRET="569a1821-0a93-45e8-87ab-eb857f20a010" \
nocodb/nocodb:latest
``` ```
</code-block> </code-block>
@ -84,10 +89,12 @@ If you are a Docker user, you may try this way!
<code-block label="Postgres"> <code-block label="Postgres">
```bash ```bash
docker run -d -p 8080:8080 \ docker run -d --name nocodb-postgres \
-e NC_DB="pg://host.docker.internal:5432?u=root&p=password&d=d1" \ -v /local/path:/usr/app/data/ \
-e NC_AUTH_JWT_SECRET="569a1821-0a93-45e8-87ab-eb857f20a010" \ -p 8080:8080 \
nocodb/nocodb:latest -e NC_DB="pg://host.docker.internal:5432?u=root&p=password&d=d1" \
-e NC_AUTH_JWT_SECRET="569a1821-0a93-45e8-87ab-eb857f20a010" \
nocodb/nocodb:latest
``` ```
</code-block> </code-block>
@ -95,10 +102,12 @@ If you are a Docker user, you may try this way!
<code-block label="SQL Server"> <code-block label="SQL Server">
```bash ```bash
docker run -d -p 8080:8080 \ docker run -d --name nocodb-mssql \
-e NC_DB="mssql://host.docker.internal:1433?u=root&p=password&d=d1" \ -v /local/path:/usr/app/data/ \
-e NC_AUTH_JWT_SECRET="569a1821-0a93-45e8-87ab-eb857f20a010" \ -p 8080:8080 \
nocodb/nocodb:latest -e NC_DB="mssql://host.docker.internal:1433?u=root&p=password&d=d1" \
-e NC_AUTH_JWT_SECRET="569a1821-0a93-45e8-87ab-eb857f20a010" \
nocodb/nocodb:latest
``` ```
</code-block> </code-block>

77
packages/noco-docs/content/en/index.md

@ -13,7 +13,7 @@ menuTitle: 'Introduction'
## Welcome! ## Welcome!
NocoDB is an open source Airtable alternative. NocoDB is a no-code database platform that allows teams to collaborate and build applications with ease of a familiar and intuitive spreadsheet interface. This allows even non-developers or business users to become software creators.
NocoDB works by connecting to any relational database and transforming them into a smart spreadsheet interface! This allows you to build no-code applications collaboratively with teams. NocoDB currently works with MySQL, PostgreSQL, Microsoft SQL Server, SQLite, Amazon Aurora & MariaDB databases. NocoDB works by connecting to any relational database and transforming them into a smart spreadsheet interface! This allows you to build no-code applications collaboratively with teams. NocoDB currently works with MySQL, PostgreSQL, Microsoft SQL Server, SQLite, Amazon Aurora & MariaDB databases.
@ -25,68 +25,43 @@ Also NocoDB's app store allows you to build business workflows on views with com
### Rich Spreadsheet Interface ### Rich Spreadsheet Interface
- ⚡ &nbsp;Search, sort, filter, hide columns with uber ease - ⚡ &nbsp;Basic Operations: Create, Read, Update and Delete on Tables, Columns, and Rows
- ⚡ &nbsp;Create Views : Grid, Gallery, Form - ⚡ &nbsp;Fields Operations: Sort, Filter, Hide / Unhide Columns
- ⚡ &nbsp;Share Views : public & password protected - ⚡ &nbsp;Multiple Views Types: Grid (By default), Gallery and Form View
- ⚡ &nbsp;Collaborative & locked Views - ⚡ &nbsp;View Permissions Types: Collaborative Views, & Locked Views
- ⚡ &nbsp;Upload images to cells (Works with S3, Minio, GCP, Azure, DigitalOcean, Linode, OVH, BackBlaze) - ⚡ &nbsp;Share Bases / Views: either Public or Private (with Password Protected)
- ⚡ &nbsp;Roles : Owner, Creator, Editor, Commenter, Viewer - ⚡ &nbsp;Variant Cell Types: ID, LinkToAnotherRecord, Lookup, Rollup, SingleLineText, Attachement, Currency, Formula and etc
- ⚡ &nbsp;Access Control : Fine-grained access control even at database, table & column level - ⚡ &nbsp;Access Control with Roles : Fine-grained Access Control at different levels
- ⚡ &nbsp;and more ...
### App Store for workflow automations
- ⚡ &nbsp;Chat : Microsoft Teams, Slack, Discord, Mattermost
- ⚡ &nbsp;Email : SMTP, SES, Mailchimp
- ⚡ &nbsp;SMS : Twilio
- ⚡ &nbsp;Whatsapp
- ⚡ &nbsp;Any 3rd Party APIs
### Programmatic API access via
- ⚡ &nbsp;REST APIs
- ⚡ &nbsp;Includes JWT Authentication & Social Auth
- ⚡ &nbsp;API tokens to integrate with Zapier, Integromat
## Why are we building this?
Most internet businesses equip themselves with either spreadsheet or a database to solve their business needs. Spreadsheets are used by a Billion+ humans collaboratively every single day. However, we are way off working at similar speeds on databases which are way more powerful tools when it comes to computing. Attempts to solve this with SaaS offerings has meant horrible access controls, vendor lockin, data lockin, abrupt price changes & most importantly a glass ceiling on what's possible in future.
## Our Mission
Our mission is to provide the most powerful no-code interface for databases which is open source to every single internet business in the world. This would not only democratise access to a powerful computing tool but also bring forth a billion+ people who will have radical tinkering-and-building abilities on internet.
## Architecture - Simple Overview
<img src="architecture.png" style="background: white;border-radius:4px;padding :10px">
| Project Type | Metadata stored in | Data stored in | ### App Store for Workflow Automations
|---------|-----------|--------|
| Create new project | NC_DB | NC_DB |
| Create new project with External Database | NC_DB | External Database |
| Create new project from Excel | NC_DB | NC_DB |
## NocoDB repository structure We provide different integrations in three main categories. See <a href="./setup-and-usages/app-store" target="_blank">App Store</a> for details.
We use ``Lerna`` to manage multi-packages. We have the following [packages](https://github.com/nocodb/nocodb/tree/master/packages). - ⚡ &nbsp;Chat : Slack, Discord, Mattermost, and etc
- ⚡ &nbsp;Email : AWS SES, SMTP, MailerSend, and etc
- ⚡ &nbsp;Storage : AWS S3, Google Cloud Storage, Minio, and etc
- ``packages/nc-cli`` : A CLI to create NocoDB app. ### Programmatic Access
- ``packages/nc-common``: A common library package used internally. We provide the following ways to let users to invoke actions in a programmatic way. You can use a token (either JWT or Social Auth) to sign your requests for authorization to NocoDB.
- ``packages/nc-gui``: NocoDB Frontend. - ⚡ &nbsp;REST APIs
- ⚡ &nbsp;NocoDB SDK
- ``packages/nc-lib-gui``: The build version of ``nc-gui`` which will be used in ``packages/nocodb``.
- ``packages/nc-migrator-archived``: SQL based schema migrations or evolutions.
- ``packages/nc-plugin``: Plugin template.
- ``packages/noco-blog``: NocoDB Blog which will be auto-released to [nocodb/noco-blog](https://github.com/nocodb/noco-blog). ### Sync Schema
- ``packages/noco-book``: NocoDB Handbook which will be auto-released to [nocodb/noco-book](https://github.com/nocodb/noco-book). We allow you to sync schema changes if you have made changes outside NocoDB GUI. However, it has to be noted then you will have to bring your own schema migrations for moving from environment to others. See <a href="./setup-and-usages/sync-schema" target="_blank">Sync Schema</a> for details.
- ``packages/noco-docs``: NocoDB Documentation which will be auto-released to [nocodb/noco-docs](https://github.com/nocodb/noco-docs). ### Audit
- ``packages/noco-docs-prev``: NocoDB Documentation for previous versions which will be auto-released to [nocodb/noco-docs-prev](https://github.com/nocodb/noco-docs-prev) and will be completely removed on 30 Jun 2022. We are keeping all the user operation logs under one place. See <a href="./setup-and-usages/audit" target="_blank">Audit</a> for details.
- ``packages/nocodb``: NocoDB Backend, hosted in [NPM](https://www.npmjs.com/package/nocodb). ## Why are we building this?
Most internet businesses equip themselves with either spreadsheet or a database to solve their business needs. Spreadsheets are used by a Billion+ humans collaboratively every single day. However, we are way off working at similar speeds on databases which are way more powerful tools when it comes to computing. Attempts to solve this with SaaS offerings has meant horrible access controls, vendor lockin, data lockin, abrupt price changes & most importantly a glass ceiling on what's possible in future.
## Our Mission
Our mission is to provide the most powerful no-code interface for databases which is open source to every single internet business in the world. This would not only democratise access to a powerful computing tool but also bring forth a billion+ people who will have radical tinkering-and-building abilities on internet.
## Contributions ## Contributions

17
packages/noco-docs/content/en/setup-and-usages/app-store.md

@ -0,0 +1,17 @@
---
title: 'App Store'
description: 'App Store'
position: 1200
category: 'Product'
menuTitle: 'App Store'
---
## Overview
We provide different integrations in three main categories.
| Category | App Name |
|---|---|
| Chat | Microsoft Teams <br/> Discord <br/> Twilio <br/> Whatsapp Twilio<br/> Mattermost<br/> Slack |
| Email | SMTP<br/> MailerSend<br/> AWS SES |
| Storage | AWS S3 <br/> Minio <br/> Google Cloud Storage <br/> Spaces <br/> Backblaze B2 <br/> Vultr Object Storage <br/> OvhCloud Object Storage <br/> Linode Object Storage <br/> UpCloud Object Storage <br/> Scaleway Object Storage |

2
packages/noco-docs/content/en/setup-and-usages/column-operations.md

@ -1,7 +1,7 @@
--- ---
title: "Column Operations" title: "Column Operations"
description: "Column Operations" description: "Column Operations"
position: 530 position: 520
category: "Product" category: "Product"
menuTitle: "Column Operations" menuTitle: "Column Operations"
--- ---

2
packages/noco-docs/content/en/setup-and-usages/column-types.md

@ -1,7 +1,7 @@
--- ---
title: 'Column Types' title: 'Column Types'
description: 'Column Types' description: 'Column Types'
position: 520 position: 530
category: 'Product' category: 'Product'
menuTitle: 'Column Types' menuTitle: 'Column Types'
--- ---

14
packages/noco-docs/content/en/setup-and-usages/primary-value.md

@ -6,27 +6,27 @@ category: "Product"
menuTitle: "Primary value" menuTitle: "Primary value"
--- ---
## What is a `Primary Value` ? ## What is a Primary Value ?
- Primary value as the name stands is the primary or main value within a row of a table that you generally associate that row with. - Primary value as the name stands is the primary or main value within a row of a table that you generally associate that row with.
- It should be usually associated with a column which is uniquely identifiable. However, this uniqueness is not enforced at the database level. - It should be usually associated with a column which is uniquely identifiable. However, this uniqueness is not enforced at the database level.
## What is the use of `Primary Value` ? ## What is the use of Primary Value ?
- Within a spreadsheet, primary value are always highlighted so that it is easier to recognise what row we are in. - Within a spreadsheet, primary value are always highlighted so that it is easier to recognise what row we are in.
- And when LinkToAnotherRecord is created between two tables - it is the primary value that appears in LinkToAnotheRecord column. - And when LinkToAnotherRecord is created between two tables - it is the primary value that appears in LinkToAnotheRecord column.
#### Example : ```Primary value```highlighted in actor table #### Example : Primary Value highlighted in actor table
<img width="547" alt="actor" src="https://user-images.githubusercontent.com/5435402/152645708-92b83985-4a0a-42b2-9d01-d26be70fd3aa.png"> <img width="547" alt="actor" src="https://user-images.githubusercontent.com/5435402/152645708-92b83985-4a0a-42b2-9d01-d26be70fd3aa.png">
#### Example : ```Primary value``` highlighted in film table #### Example : Primary Value highlighted in film table
<img width="1406" alt="film-table" src="https://user-images.githubusercontent.com/5435402/152645713-b4df99b2-4eb7-4fea-85f9-0baf47470ef3.png"> <img width="1406" alt="film-table" src="https://user-images.githubusercontent.com/5435402/152645713-b4df99b2-4eb7-4fea-85f9-0baf47470ef3.png">
#### Example : ```Primary value``` associated when ```LinkToAnotherRecord``` is created #### Example : Primary Value associated when LinkToAnotherRecord is created
<img width="753" alt="actor-film" src="https://user-images.githubusercontent.com/5435402/152645714-4061c94a-4cfb-44e5-b112-63cf4ed869fe.png"> <img width="753" alt="actor-film" src="https://user-images.githubusercontent.com/5435402/152645714-4061c94a-4cfb-44e5-b112-63cf4ed869fe.png">
## How is ```Primary value``` identfied for existing database tables ? ## How is Primary Value identfied for existing database tables ?
- It is usually the first column after the primary key which is not a number. - It is usually the first column after the primary key which is not a number.
- If there is no column which is not a number then the column adjacent to primary key is chosen. - If there is no column which is not a number then the column adjacent to primary key is chosen.
## Can I change the ```Primary Value``` to another column within tables ? ## Can I change the Primary Value to another column within tables ?
- Yes, you can. Hover over column which you want as primary column and click ```Set as Primary Value``` - Yes, you can. Hover over column which you want as primary column and click ```Set as Primary Value```

4
packages/noco-docs/content/en/setup-and-usages/share-view.md

@ -6,7 +6,7 @@ category: "Product"
menuTitle: "Share View" menuTitle: "Share View"
--- ---
## Generate `Share View` ## Generate Share View
- Open a table or a view - Open a table or a view
@ -22,7 +22,7 @@ menuTitle: "Share View"
![image](https://user-images.githubusercontent.com/35857179/161970131-0fa83989-0673-493d-968f-76913a09cc06.png) ![image](https://user-images.githubusercontent.com/35857179/161970131-0fa83989-0673-493d-968f-76913a09cc06.png)
## Access `Share View` ## Access Share View
- Access the link. If it is password-protected, enter the password to unlock. - Access the link. If it is password-protected, enter the password to unlock.

18
packages/noco-docs/content/en/setup-and-usages/table-operations.md

@ -20,14 +20,14 @@ On click, in modal popup, enter the table name, enable/disable default columns a
![table_create_modal](https://user-images.githubusercontent.com/61551451/126772859-5a301c45-d830-4df2-a05a-43b15dd77728.png) ![table_create_modal](https://user-images.githubusercontent.com/61551451/126772859-5a301c45-d830-4df2-a05a-43b15dd77728.png)
> You can't disable the `id` column since NocoDB need's a primary column for every table. <alert>
You can't disable the `id` column since NocoDB needs a primary column for every table.
</alert>
After the successful submission, the table will be created and open as a new tab. After the successful submission, the table will be created and open as a new tab.
![TableCreated](https://user-images.githubusercontent.com/86527202/144402089-b5e35564-80d5-4105-9e00-7e3e1c4a5030.png) ![TableCreated](https://user-images.githubusercontent.com/86527202/144402089-b5e35564-80d5-4105-9e00-7e3e1c4a5030.png)
### Table Rename ### Table Rename
Right click on Table name on left hand project-tree menu, select `Rename` Right click on Table name on left hand project-tree menu, select `Rename`
@ -35,13 +35,11 @@ In modal popup, enter new table name and click `Submit` button
<img src="https://user-images.githubusercontent.com/86527202/144403447-1b2e4368-eb2b-40c0-901a-54e8adf9a80c.png" width="60%"/> <img src="https://user-images.githubusercontent.com/86527202/144403447-1b2e4368-eb2b-40c0-901a-54e8adf9a80c.png" width="60%"/>
### Table Delete ### Table Delete
The table can be deleted using the `delete` icon present in the toolbar within the table tab. The table can be deleted using the `delete` icon present in the toolbar within the table tab.
<img src="https://user-images.githubusercontent.com/86527202/144403591-5d3d36eb-64b7-4057-9244-56a95b47b97b.png" width="60%"/> <img src="https://user-images.githubusercontent.com/86527202/144403591-5d3d36eb-64b7-4057-9244-56a95b47b97b.png" width="60%"/>
## Column ## Column
### Column Add ### Column Add
@ -109,4 +107,14 @@ Right-click on anywhere in the row and then from the context menu select `Delete
Bulk delete is also possible by selecting multiple rows by using the checkbox in first column and then `Delete Selected Rows` options from the right click context menu. Bulk delete is also possible by selecting multiple rows by using the checkbox in first column and then `Delete Selected Rows` options from the right click context menu.
<img src="https://user-images.githubusercontent.com/86527202/144406191-ccff1382-e808-44e8-babe-bd937faf1b3d.png" width="40%"/> <img src="https://user-images.githubusercontent.com/86527202/144406191-ccff1382-e808-44e8-babe-bd937faf1b3d.png" width="40%"/>
## Export Data
You can export your data from a table as a CSV file by clicking `More` and `Download as CSV`.
![image](https://user-images.githubusercontent.com/35857179/163556138-2aa0a782-12e9-49c7-aadf-b7778e91557f.png)
## Import Data
You can import your data in CSV format to a table by clicking `More` and `Upload CSV`.
![image](https://user-images.githubusercontent.com/35857179/163556175-116b12c2-ca2e-4b54-a65a-39250541d873.png)

2
packages/noco-docs/content/en/setup-and-usages/team-and-auth.md

@ -1,7 +1,7 @@
--- ---
title: 'Team & Auth' title: 'Team & Auth'
description: 'Breakdown of roles & permissions for team user management' description: 'Breakdown of roles & permissions for team user management'
position: 620 position: 630
category: 'Product' category: 'Product'
menuTitle: 'Team & Auth' menuTitle: 'Team & Auth'
--- ---

56
packages/noco-docs/content/en/setup-and-usages/usage-information.md

@ -6,38 +6,66 @@ category: 'Product'
menuTitle: 'Usage Information' menuTitle: 'Usage Information'
--- ---
NocoDB is a fast growing open source project and we are committed to providing a solution that exceeds the expectations of the users and community. <announcement></announcement>
NocoDB is a fast growing open source project which is UI heavy and we are committed to providing a solution that exceeds the expectations of the users and community.
We are also committed to continuing to develop and make NocoDB even better than it is today. We are also committed to continuing to develop and make NocoDB even better than it is today.
To that end, NocoDB contains a feature in which anonymous and otherwise non-sensitive data is collected. To that end, NocoDB contains a feature in which anonymous and otherwise non-sensitive data is collected.
This anonymous and non-sensitive data gives a better understanding of how users are interacting and using the product. This anonymous and non-sensitive data gives a better understanding of how users are interacting and using the product.
## Context ## Context
We will always continue to do hands-on UI/UX testing, surveys, issue tracking and roadmap. We will always continue to do hands-on UI/UX testing, surveys, issue tracking and roadmap.
Otherwise talk with the Community while striving to understand Otherwise talk with the Community while striving to understand
and deliver what is being asked for and what is needed, by any means available. and deliver what is being asked for and what is needed, by any means available.
However, these above actions alone are often insufficient to maintain an overall picture of the product usage. However, these above actions alone are often insufficient
- To maintain an overall picture of the product usage.
- Prioritising the efforts.
- Impact of any breaking changes.
- To understand whether UI improvements are helpful to users.
## What we collect ? ## What we collect ?
The following data is collected: We collect actions made on models (project, table, view, sharedView, user, hook, image, sharedBase etc) periodically with :
- Unique machine ID (generated with node-machine-id) - Unique machine ID (generated with node-machine-id)
- Environment (dev, staging, production) - Environment (dev, staging, production)
- System information (OS, node version, docker or npm) - System information (OS, node version, docker or npm)
- Failures and errors. - Failures.
- Create and delete events of a project, table, view, linkToAnotherRecord, sharedView, user, hook, image, sharedBase.
Here is an example :
```
{
"machine_id" : "a0885e8e6a38d9fbb5d39e7d04a44da7773d4f",
"evt_type": "project:created"
"package_id" : "0.84.15",
"os_type" : "Linux",
"os_platform" : "linux",
"os_release" : "5.10.25-linuxkit",
"node_version" : "14.18.2",
"docker" : "true",
"xc_version" : "0.84.15",
"env" : "dev",
}
```
Our UI Dashboard is a Vuejs-Nuxtjs app. Actions taken on UI with completely anonymized route names are sent as payload.
Here is an example :
```
{
"id": "a0885e8e6a38d9fbb5d39e7d04a44da7773d4f",
"event": "table:create",
"path": "/nc/:project_id",
}
```
## What we DO NOT collect ? ## What we DO NOT collect ?
We do not collect private or sensitive information, such as: We do not collect any private or sensitive information, such as:
- Personally identifiable information - Personally identifiable information
- Credential information (endpoints, ports, DB connections, username/password) - Credential information (endpoints, ports, DB connections, username/password)
- User data - User data
## Opt-out ## Opt-out
To disable usage information collection please set following environment variable. To disable usage information collection please set following environment variable.
> NC_DISABLE_TELE=true
```bash
NC_DISABLE_TELE=true
```

93
packages/noco-docs/content/en/setup-and-usages/views.md

@ -0,0 +1,93 @@
---
title: 'Views'
description: 'Views'
position: 600
category: 'Product'
menuTitle: 'Views'
---
## What's a View?
In a table, you can use different views to display your data. You can show specific fields in a View. You can also apply Sorting or Filtering to the View. Each View is independent, which means the configuration applying to View 1 will not apply to View 2.
To navigate different views, we can select the target one in the view sidebar. By default, Grid View will be created for you after creating the table.You can create multiple views with the same type as you wish, as long as they have unique View names.
![image](https://user-images.githubusercontent.com/35857179/163340916-d1101709-2051-4d0e-9d86-dd14eced49e9.png)
## View Types
### Grid View
Grid View, as a default type of view, allows you to display your data in a spreadsheet-like interface.
![image](https://user-images.githubusercontent.com/35857179/163343433-f6594d6e-5874-45ae-b403-5774247659bb.png)
### Form View
Form View allows you to arrange fields in a form to input data.
![image](https://user-images.githubusercontent.com/35857179/163355269-73d2a9d4-bafb-47c0-8c0d-d0e66503b47a.png)
You can show and hide some fields using drag-and-drop fashion.
![image](https://user-images.githubusercontent.com/35857179/163355377-6b365472-efae-4f73-a103-5dde7c1f8ea7.png)
### Gallery View
Gallery View allows you to display images as thumbnails with other fields just like a gallery.
<!-- TODO: add screenshots -->
## View Permission Types
We can apply permission to each View. By default, Collaborative Views will be used. To see or change the view type, check the first icon above the View sidebar.
![image](https://user-images.githubusercontent.com/35857179/163343598-fd81edea-f160-41ee-8bb2-3ef1eee5348d.png)
### Collaborative Views
Collaborative View allows you to work with your collaborators with edit permissions.
![image](https://user-images.githubusercontent.com/35857179/163343959-7e2f43cb-1a1f-4f36-985c-ca91db262f98.png)
### Locked Views
Locked View allows you to lock the current View so that no one can edit the View including applying operations such as Sorting or Filtering.
![image](https://user-images.githubusercontent.com/35857179/163343845-b07f9d3f-5a83-4dfd-8d45-9cc59b3512c3.png)
## View Operations
### Create a View
Click '+' in View sidebar.
![image](https://user-images.githubusercontent.com/35857179/163353610-ae85967c-91ac-404f-b3b3-bd122e09f492.png)
### Rename a View
Hover the target View, click the icon and enter the new name.
![image](https://user-images.githubusercontent.com/35857179/163353802-1da52cec-ae17-4ced-8679-62d7180683ec.png)
### Delete a View
Hover the target View and click the delete icon.
<alert>
You cannot delete the very first Grid View.
</alert>
![image](https://user-images.githubusercontent.com/35857179/163359795-f4420402-b2a6-41d8-b48c-f0dea8b9abbe.png)
### Duplicate a View
Hover the target View and click the icon and enter the new name.
![image](https://user-images.githubusercontent.com/35857179/163353865-7275499e-c685-44f4-906c-ba08f0ee419e.png)
### Reorder a View
Hover the target View and re-order it as needed by dragging and dropping the drag icon.
![image](https://user-images.githubusercontent.com/35857179/163359674-c4aeff74-1cb4-498d-b79c-c6ddf84ad352.png)

10532
packages/nocodb-sdk/package-lock.json generated

File diff suppressed because it is too large Load Diff

2
packages/nocodb-sdk/package.json

@ -1,6 +1,6 @@
{ {
"name": "nocodb-sdk", "name": "nocodb-sdk",
"version": "0.0.9", "version": "0.90.0",
"description": "NocoDB SDK", "description": "NocoDB SDK",
"main": "build/main/index.js", "main": "build/main/index.js",
"typings": "build/main/index.d.ts", "typings": "build/main/index.d.ts",

62
packages/nocodb-sdk/src/lib/Api.ts

@ -620,6 +620,15 @@ export type ColumnReqType =
} }
| { uidt?: string; formula_raw?: string; formula?: string; title?: string }; | { uidt?: string; formula_raw?: string; formula?: string; title?: string };
export interface UserInfoType {
id?: string;
email?: string;
email_verified?: string;
firstname?: string;
lastname?: string;
roles?: any;
}
import axios, { AxiosInstance, AxiosRequestConfig, ResponseType } from 'axios'; import axios, { AxiosInstance, AxiosRequestConfig, ResponseType } from 'axios';
export type QueryParamsType = Record<string | number, any>; export type QueryParamsType = Record<string | number, any>;
@ -798,7 +807,7 @@ export class Api<
* @summary Signup * @summary Signup
* @request POST:/api/v1/db/auth/user/signup * @request POST:/api/v1/db/auth/user/signup
* @response `200` `{ token?: string }` OK * @response `200` `{ token?: string }` OK
* @response `400` `void` Bad Request * @response `400` `{ msg?: string }` Bad Request
* @response `401` `void` Unauthorized * @response `401` `void` Unauthorized
* @response `403` `void` Forbidden * @response `403` `void` Forbidden
*/ */
@ -806,7 +815,7 @@ export class Api<
data: { email?: string; password?: string }, data: { email?: string; password?: string },
params: RequestParams = {} params: RequestParams = {}
) => ) =>
this.request<{ token?: string }, void>({ this.request<{ token?: string }, { msg?: string } | void>({
path: `/api/v1/db/auth/user/signup`, path: `/api/v1/db/auth/user/signup`,
method: 'POST', method: 'POST',
body: data, body: data,
@ -822,12 +831,13 @@ export class Api<
* @summary Signin * @summary Signin
* @request POST:/api/v1/db/auth/user/signin * @request POST:/api/v1/db/auth/user/signin
* @response `200` `{ token?: string }` OK * @response `200` `{ token?: string }` OK
* @response `400` `{ msg?: string }` Bad Request
*/ */
signin: ( signin: (
data: { email: string; password: string }, data: { email: string; password: string },
params: RequestParams = {} params: RequestParams = {}
) => ) =>
this.request<{ token?: string }, any>({ this.request<{ token?: string }, { msg?: string }>({
path: `/api/v1/db/auth/user/signin`, path: `/api/v1/db/auth/user/signin`,
method: 'POST', method: 'POST',
body: data, body: data,
@ -843,12 +853,13 @@ export class Api<
* @name Me * @name Me
* @summary User Info * @summary User Info
* @request GET:/api/v1/db/auth/user/me * @request GET:/api/v1/db/auth/user/me
* @response `200` `UserType` OK * @response `200` `UserInfoType` OK
*/ */
me: (params: RequestParams = {}) => me: (query?: { project_id?: string }, params: RequestParams = {}) =>
this.request<UserType, any>({ this.request<UserInfoType, any>({
path: `/api/v1/db/auth/user/me`, path: `/api/v1/db/auth/user/me`,
method: 'GET', method: 'GET',
query: query,
format: 'json', format: 'json',
...params, ...params,
}), }),
@ -861,9 +872,10 @@ export class Api<
* @summary Password Forgot * @summary Password Forgot
* @request POST:/api/v1/db/auth/password/forgot * @request POST:/api/v1/db/auth/password/forgot
* @response `200` `void` OK * @response `200` `void` OK
* @response `401` `void` Unauthorized
*/ */
passwordForgot: (data: { email?: string }, params: RequestParams = {}) => passwordForgot: (data: { email?: string }, params: RequestParams = {}) =>
this.request<void, any>({ this.request<void, void>({
path: `/api/v1/db/auth/password/forgot`, path: `/api/v1/db/auth/password/forgot`,
method: 'POST', method: 'POST',
body: data, body: data,
@ -878,21 +890,19 @@ export class Api<
* @name PasswordChange * @name PasswordChange
* @summary Password Change * @summary Password Change
* @request POST:/api/v1/db/auth/password/change * @request POST:/api/v1/db/auth/password/change
* @response `200` `void` OK * @response `200` `{ msg?: string }` OK
* @response `400` `{ msg?: string }` Bad request
*/ */
passwordChange: ( passwordChange: (
data: { data: { currentPassword?: string; newPassword?: string },
currentPassword?: string;
newPassword?: string;
verifyPassword?: string;
},
params: RequestParams = {} params: RequestParams = {}
) => ) =>
this.request<void, any>({ this.request<{ msg?: string }, { msg?: string }>({
path: `/api/v1/db/auth/password/change`, path: `/api/v1/db/auth/password/change`,
method: 'POST', method: 'POST',
body: data, body: data,
type: ContentType.Json, type: ContentType.Json,
format: 'json',
...params, ...params,
}), }),
@ -1310,7 +1320,7 @@ export class Api<
* *
* @tags Project * @tags Project
* @name AuditList * @name AuditList
* @request GET:/api/v1/db/meta/project/{projectId}/audits * @request GET:/api/v1/db/meta/projects/{projectId}/audits
* @response `200` `{ list: (AuditType)[], pageInfo: PaginatedType }` OK * @response `200` `{ list: (AuditType)[], pageInfo: PaginatedType }` OK
*/ */
auditList: ( auditList: (
@ -1319,7 +1329,7 @@ export class Api<
params: RequestParams = {} params: RequestParams = {}
) => ) =>
this.request<{ list: AuditType[]; pageInfo: PaginatedType }, any>({ this.request<{ list: AuditType[]; pageInfo: PaginatedType }, any>({
path: `/api/v1/db/meta/project/${projectId}/audits`, path: `/api/v1/db/meta/projects/${projectId}/audits`,
method: 'GET', method: 'GET',
query: query, query: query,
format: 'json', format: 'json',
@ -2466,11 +2476,11 @@ export class Api<
* No description * No description
* *
* @tags DB table row * @tags DB table row
* @name NestedDelete * @name NestedRemove
* @request DELETE:/api/v1/db/data/{orgs}/{projectName}/{tableName}/{rowId}/{relationType}/{columnName}/{refRowId} * @request DELETE:/api/v1/db/data/{orgs}/{projectName}/{tableName}/{rowId}/{relationType}/{columnName}/{refRowId}
* @response `200` `any` OK * @response `200` `any` OK
*/ */
nestedDelete: ( nestedRemove: (
orgs: string, orgs: string,
projectName: string, projectName: string,
tableName: string, tableName: string,
@ -2945,6 +2955,22 @@ export class Api<
...params, ...params,
}), }),
/**
* No description
*
* @tags Utils
* @name AppVersion
* @request GET:/api/v1/db/meta/nocodb/version
* @response `200` `any` OK
*/
appVersion: (params: RequestParams = {}) =>
this.request<any, any>({
path: `/api/v1/db/meta/nocodb/version`,
method: 'GET',
format: 'json',
...params,
}),
/** /**
* @description Get All K/V pairs in NocoCache * @description Get All K/V pairs in NocoCache
* *

25264
packages/nocodb/package-lock.json generated

File diff suppressed because it is too large Load Diff

10
packages/nocodb/package.json

@ -1,6 +1,6 @@
{ {
"name": "nocodb", "name": "nocodb",
"version": "0.84.16", "version": "0.90.0",
"description": "NocoDB", "description": "NocoDB",
"main": "dist/bundle.js", "main": "dist/bundle.js",
"repository": "https://github.com/nocodb/nocodb", "repository": "https://github.com/nocodb/nocodb",
@ -67,7 +67,7 @@
"help:c": "ts-node ./help/a", "help:c": "ts-node ./help/a",
"watch:build": "nodemon -e ts,js -w ./src -x npm run build", "watch:build": "nodemon -e ts,js -w ./src -x npm run build",
"watch:serve": "nodemon -e ts -w ./build -x npm run debug-local ", "watch:serve": "nodemon -e ts -w ./build -x npm run debug-local ",
"watch:run": "cross-env NC_DISABLE_TELE=true EE=true nodemon -e ts,js -w ./src -x \"ts-node src/example/docker --log-error --project tsconfig.json\"", "watch:run": "cross-env NC_DISABLE_TELE1=true EE=true nodemon -e ts,js -w ./src -x \"ts-node src/example/docker --log-error --project tsconfig.json\"",
"watch:run:cypress": "cross-env EE=true nodemon -e ts,js -w ./src -x \"ts-node src/example/docker --log-error --project tsconfig.json\"", "watch:run:cypress": "cross-env EE=true nodemon -e ts,js -w ./src -x \"ts-node src/example/docker --log-error --project tsconfig.json\"",
"watch:run:mysql": "cross-env NC_DISABLE_TELE=true EE=true nodemon -e ts,js -w ./src -x \"ts-node src/example/dockerRunMysql --log-error --project tsconfig.json\"", "watch:run:mysql": "cross-env NC_DISABLE_TELE=true EE=true nodemon -e ts,js -w ./src -x \"ts-node src/example/dockerRunMysql --log-error --project tsconfig.json\"",
"run": "ts-node src/example/docker", "run": "ts-node src/example/docker",
@ -150,11 +150,11 @@
"mysql2": "^2.2.5", "mysql2": "^2.2.5",
"nanoid": "^3.1.20", "nanoid": "^3.1.20",
"nc-common": "0.0.6", "nc-common": "0.0.6",
"nc-help": "^0.2.31", "nc-help": "^0.2.44",
"nc-lib-gui": "0.84.15", "nc-lib-gui": "0.90.0",
"nc-plugin": "^0.1.1", "nc-plugin": "^0.1.1",
"ncp": "^2.0.0", "ncp": "^2.0.0",
"nocodb-sdk": "file:../nocodb-sdk", "nocodb-sdk": "0.90.0",
"nodemailer": "^6.4.10", "nodemailer": "^6.4.10",
"ora": "^4.0.4", "ora": "^4.0.4",
"os-locale": "^5.0.0", "os-locale": "^5.0.0",

4
packages/nocodb/src/lib/noco-models/Column.ts

@ -207,7 +207,9 @@ export default class Column<T = any> implements ColumnType {
dr: column.dr, dr: column.dr,
fk_index_name: column.fk_index_name, fk_index_name: column.fk_index_name,
fk_related_model_id: column.fk_related_model_id fk_related_model_id: column.fk_related_model_id,
virtual: column.virtual
}, },
ncMeta ncMeta
); );

3
packages/nocodb/src/lib/noco-models/LinkToAnotherRecordColumn.ts

@ -107,7 +107,8 @@ export default class LinkToAnotherRecordColumn {
dr: data.dr, dr: data.dr,
fk_index_name: data.fk_index_name, fk_index_name: data.fk_index_name,
fk_related_model_id: data.fk_related_model_id fk_related_model_id: data.fk_related_model_id,
virtual: data.virtual
}); });
return this.read(data.fk_column_id, ncMeta); return this.read(data.fk_column_id, ncMeta);
} }

2
packages/nocodb/src/lib/noco/meta/api/auditApis.ts

@ -75,7 +75,7 @@ router.get(
ncMetaAclMw(commentsCount, 'commentsCount') ncMetaAclMw(commentsCount, 'commentsCount')
); );
router.get( router.get(
'/api/v1/db/meta/project/:projectId/audits', '/api/v1/db/meta/projects/:projectId/audits',
ncMetaAclMw(auditList, 'auditList') ncMetaAclMw(auditList, 'auditList')
); );
export default router; export default router;

70
packages/nocodb/src/lib/noco/meta/api/columnApis.ts

@ -45,6 +45,7 @@ async function createHmAndBtColumn(
childColumn: Column, childColumn: Column,
type?: RelationTypes, type?: RelationTypes,
alias?: string, alias?: string,
virtual = false,
isSystemCol = false isSystemCol = false
) { ) {
// save bt column // save bt column
@ -65,6 +66,7 @@ async function createHmAndBtColumn(
fk_child_column_id: childColumn.id, fk_child_column_id: childColumn.id,
fk_parent_column_id: parent.primaryKey.id, fk_parent_column_id: parent.primaryKey.id,
fk_related_model_id: parent.id, fk_related_model_id: parent.id,
virtual,
system: isSystemCol system: isSystemCol
}); });
} }
@ -82,6 +84,7 @@ async function createHmAndBtColumn(
fk_child_column_id: childColumn.id, fk_child_column_id: childColumn.id,
fk_parent_column_id: parent.primaryKey.id, fk_parent_column_id: parent.primaryKey.id,
fk_related_model_id: child.id, fk_related_model_id: child.id,
virtual,
system: isSystemCol system: isSystemCol
}); });
} }
@ -275,23 +278,27 @@ export async function columnAdd(req: Request, res: Response<TableType>) {
childColumn = await Column.get({ colId: id }); childColumn = await Column.get({ colId: id });
// create relation // ignore relation creation if virtual
await sqlMgr.sqlOpPlus(base, 'relationCreate', { if (!req.body.virtual) {
childColumn: fkColName, // create relation
childTable: child.table_name, await sqlMgr.sqlOpPlus(base, 'relationCreate', {
parentTable: parent.table_name, childColumn: fkColName,
onDelete: 'NO ACTION', childTable: child.table_name,
onUpdate: 'NO ACTION', parentTable: parent.table_name,
type: 'real', onDelete: 'NO ACTION',
parentColumn: parent.primaryKey.column_name onUpdate: 'NO ACTION',
}); type: 'real',
parentColumn: parent.primaryKey.column_name
});
}
} }
await createHmAndBtColumn( await createHmAndBtColumn(
child, child,
parent, parent,
childColumn, childColumn,
req.body.type, req.body.type,
req.body.title req.body.title,
req.body.virtual
); );
} else if (req.body.type === 'mm') { } else if (req.body.type === 'mm') {
const aTn = `${project?.prefix ?? ''}_nc_m2m_${randomID()}`; const aTn = `${project?.prefix ?? ''}_nc_m2m_${randomID()}`;
@ -352,26 +359,27 @@ export async function columnAdd(req: Request, res: Response<TableType>) {
columns: associateTableCols columns: associateTableCols
}); });
const rel1Args = { if (!req.body.virtual) {
...req.body, const rel1Args = {
childTable: aTn, ...req.body,
childColumn: parentCn, childTable: aTn,
parentTable: parent.table_name, childColumn: parentCn,
parentColumn: parentPK.column_name, parentTable: parent.table_name,
type: 'real' parentColumn: parentPK.column_name,
}; type: 'real'
const rel2Args = { };
...req.body, const rel2Args = {
childTable: aTn, ...req.body,
childColumn: childCn, childTable: aTn,
parentTable: child.table_name, childColumn: childCn,
parentColumn: childPK.column_name, parentTable: child.table_name,
type: 'real' parentColumn: childPK.column_name,
}; type: 'real'
};
await sqlMgr.sqlOpPlus(base, 'relationCreate', rel1Args);
await sqlMgr.sqlOpPlus(base, 'relationCreate', rel2Args);
await sqlMgr.sqlOpPlus(base, 'relationCreate', rel1Args);
await sqlMgr.sqlOpPlus(base, 'relationCreate', rel2Args);
}
const parentCol = (await assocModel.getColumns())?.find( const parentCol = (await assocModel.getColumns())?.find(
c => c.column_name === parentCn c => c.column_name === parentCn
); );
@ -385,6 +393,7 @@ export async function columnAdd(req: Request, res: Response<TableType>) {
childCol, childCol,
null, null,
null, null,
req.body.virtual,
true true
); );
await createHmAndBtColumn( await createHmAndBtColumn(
@ -393,6 +402,7 @@ export async function columnAdd(req: Request, res: Response<TableType>) {
parentCol, parentCol,
null, null,
null, null,
req.body.virtual,
true true
); );

4
packages/nocodb/src/lib/noco/meta/api/dataApis/dataAliasNestedApis.ts

@ -191,7 +191,7 @@ export async function hmList(req: Request, res: Response, next) {
} }
//@ts-ignore //@ts-ignore
async function relationDataDelete(req, res) { async function relationDataRemove(req, res) {
const { model, view } = await getViewAndModelFromRequestByAliasOrId(req); const { model, view } = await getViewAndModelFromRequestByAliasOrId(req);
if (!model) NcError.notFound('Table not found'); if (!model) NcError.notFound('Table not found');
@ -273,7 +273,7 @@ router.post(
); );
router.delete( router.delete(
'/api/v1/db/data/:orgs/:projectName/:tableName/:rowId/:relationType/:columnName/:refRowId', '/api/v1/db/data/:orgs/:projectName/:tableName/:rowId/:relationType/:columnName/:refRowId',
ncMetaAclMw(relationDataDelete, 'relationDataDelete') ncMetaAclMw(relationDataRemove, 'relationDataRemove')
); );
router.get( router.get(

15
packages/nocodb/src/lib/noco/meta/api/index.ts

@ -44,6 +44,8 @@ import { Tele } from 'nc-help';
import { Server } from 'socket.io'; import { Server } from 'socket.io';
import passport from 'passport'; import passport from 'passport';
import crypto from 'crypto';
export default function(router: Router, server) { export default function(router: Router, server) {
initStrategies(router); initStrategies(router);
projectApis(router); projectApis(router);
@ -106,11 +108,20 @@ export default function(router: Router, server) {
} }
)(socket.handshake, {}, next); )(socket.handshake, {}, next);
}).on('connection', socket => { }).on('connection', socket => {
const id = getHash(Tele.id + (socket?.handshake as any)?.user?.id);
socket.on('page', args => { socket.on('page', args => {
Tele.page(args); Tele.page({ ...args, id });
}); });
socket.on('event', args => { socket.on('event', args => {
Tele.event(args); Tele.event({ ...args, id });
}); });
}); });
} }
function getHash(str) {
return crypto
.createHash('md5')
.update(str)
.digest('hex');
}

14
packages/nocodb/src/lib/noco/meta/api/metaDiffApis.ts

@ -31,8 +31,6 @@ export enum MetaDiffType {
VIEW_COLUMN_REMOVE = 'VIEW_COLUMN_REMOVE', VIEW_COLUMN_REMOVE = 'VIEW_COLUMN_REMOVE',
TABLE_RELATION_ADD = 'TABLE_RELATION_ADD', TABLE_RELATION_ADD = 'TABLE_RELATION_ADD',
TABLE_RELATION_REMOVE = 'TABLE_RELATION_REMOVE', TABLE_RELATION_REMOVE = 'TABLE_RELATION_REMOVE',
// TABLE_VIRTUAL_RELATION_ADD = 'TABLE_VIRTUAL_RELATION_ADD',
// TABLE_VIRTUAL_RELATION_REMOVE = 'TABLE_VIRTUAL_RELATION_REMOVE',
TABLE_VIRTUAL_M2M_REMOVE = 'TABLE_VIRTUAL_M2M_REMOVE' TABLE_VIRTUAL_M2M_REMOVE = 'TABLE_VIRTUAL_M2M_REMOVE'
} }
@ -718,12 +716,12 @@ export async function metaDiffSync(req, res) {
res.json({ msg: 'success' }); res.json({ msg: 'success' });
} }
async function isMMRelationAvailable( async function isMMRelationExist(
model: Model, model: Model,
assocModel: Model, assocModel: Model,
belongsToCol: Column<LinkToAnotherRecordColumn> belongsToCol: Column<LinkToAnotherRecordColumn>
) { ) {
let isAvail = false; let isExist = false;
const colChildOpt = await belongsToCol.getColOptions< const colChildOpt = await belongsToCol.getColOptions<
LinkToAnotherRecordColumn LinkToAnotherRecordColumn
>(); >();
@ -737,12 +735,12 @@ async function isMMRelationAvailable(
colOpt.fk_child_column_id === colChildOpt.fk_parent_column_id && colOpt.fk_child_column_id === colChildOpt.fk_parent_column_id &&
colOpt.fk_mm_child_column_id === colChildOpt.fk_child_column_id colOpt.fk_mm_child_column_id === colChildOpt.fk_child_column_id
) { ) {
isAvail = true; isExist = true;
break; break;
} }
} }
} }
return isAvail; return isExist;
} }
// @ts-ignore // @ts-ignore
@ -772,12 +770,12 @@ export async function extractAndGenerateManyToManyRelations(
await modelB.getColumns(); await modelB.getColumns();
// check tableA already have the relation or not // check tableA already have the relation or not
const isRelationAvailInA = await isMMRelationAvailable( const isRelationAvailInA = await isMMRelationExist(
modelA, modelA,
assocModel, assocModel,
belongsToCols[0] belongsToCols[0]
); );
const isRelationAvailInB = await isMMRelationAvailable( const isRelationAvailInB = await isMMRelationExist(
modelB, modelB,
assocModel, assocModel,
belongsToCols[1] belongsToCols[1]

11
packages/nocodb/src/lib/noco/meta/api/utilApis.ts

@ -7,6 +7,7 @@ import SqlMgrv2 from '../../../sqlMgr/v2/SqlMgrv2';
import { defaultConnectionConfig } from '../../../utils/NcConfigFactory'; import { defaultConnectionConfig } from '../../../utils/NcConfigFactory';
import User from '../../../noco-models/User'; import User from '../../../noco-models/User';
import catchError from '../helpers/catchError'; import catchError from '../helpers/catchError';
import axios from 'axios';
export async function testConnection(req: Request, res: Response) { export async function testConnection(req: Request, res: Response) {
res.json(await SqlMgrv2.testConnection(req.body)); res.json(await SqlMgrv2.testConnection(req.body));
@ -43,10 +44,20 @@ export async function appInfo(_req: Request, res: Response) {
res.json(result); res.json(result);
} }
export async function releaseVersion(_req: Request, res: Response) {
const result = await axios.get('https://github.com/nocodb/nocodb/releases/latest')
.then((response) => {
return { releaseVersion: response.request.res.responseUrl.replace('https://github.com/nocodb/nocodb/releases/tag/', '') }
})
res.json(result);
}
export default router => { export default router => {
router.post( router.post(
'/api/v1/db/meta/connection/test', '/api/v1/db/meta/connection/test',
ncMetaAclMw(testConnection, 'testConnection') ncMetaAclMw(testConnection, 'testConnection')
); );
router.get('/api/v1/db/meta/nocodb/info', catchError(appInfo)); router.get('/api/v1/db/meta/nocodb/info', catchError(appInfo));
router.get('/api/v1/db/meta/nocodb/version', catchError(releaseVersion));
}; };

81
packages/nocodb/src/lib/noco/upgrader/jobs/ncProjectUpgraderV2_0090000.ts

@ -227,7 +227,7 @@ interface LinkToAnotherRecordv1 {
} }
interface ModelMetav1 { interface ModelMetav1 {
id: number; id: number | string;
project_id: string; project_id: string;
db_alias: string; db_alias: string;
title: string; title: string;
@ -296,6 +296,7 @@ interface MigrateCtxV1 {
objModelColumnAliasRef: ObjModelColumnAliasRefv1; objModelColumnAliasRef: ObjModelColumnAliasRefv1;
objViewRef: ObjViewRefv1; objViewRef: ObjViewRefv1;
objViewQPRef: ObjViewQPRefv1; objViewQPRef: ObjViewQPRefv1;
metas: ModelMetav1[];
} }
// @ts-ignore // @ts-ignore
@ -312,12 +313,36 @@ const filterV1toV2CompOpMap = {
'is not like': 'nlike' 'is not like': 'nlike'
}; };
interface Relationv1 {
project_id?: string;
db_alias?: string;
tn?: string;
rtn?: string;
_tn?: string;
_rtn?: string;
cn?: string;
rcn?: string;
_cn?: string;
_rcn?: string;
referenced_db_alias?: string;
type?: string;
db_type?: string;
ur?: string;
dr?: string;
}
async function migrateProjectModels( async function migrateProjectModels(
ncMeta = Noco.ncMeta ncMeta = Noco.ncMeta
): Promise<MigrateCtxV1> { ): Promise<MigrateCtxV1> {
// @ts-ignore // @ts-ignore
const metas: ModelMetav1[] = await ncMeta.metaList(null, null, 'nc_models'); const metas: ModelMetav1[] = await ncMeta.metaList(null, null, 'nc_models');
// @ts-ignore
const relations: Relationv1[] = await ncMeta.metaList(
null,
null,
'nc_relations'
);
const models: Model[] = []; const models: Model[] = [];
// variable for keeping all // variable for keeping all
@ -443,6 +468,37 @@ async function migrateProjectModels(
fk_mm_parent_column_id = fk_mm_parent_column_id =
projectModelColumnRefs[rel.vtn][rel.vrcn].id; projectModelColumnRefs[rel.vtn][rel.vrcn].id;
} }
let virtual = false;
if (columnMeta.mm) {
const relation = relations.find(
r =>
r.rtn === columnMeta.mm.tn &&
r.rcn === columnMeta.mm.cn &&
r.tn === columnMeta.mm.vtn &&
r.cn === columnMeta.mm.vcn
);
virtual = relation?.type === 'virtual';
} else if (columnMeta.hm) {
virtual =
relations.find(
r =>
r.rtn === columnMeta.hm.rtn &&
r.tn === columnMeta.hm.tn &&
r.rcn === columnMeta.hm.rcn &&
r.cn === columnMeta.hm.cn
)?.type === 'virtual';
} else if (columnMeta.bt) {
virtual =
relations.find(
r =>
r.rtn === columnMeta.bt.rtn &&
r.tn === columnMeta.bt.tn &&
r.rcn === columnMeta.bt.rcn &&
r.cn === columnMeta.bt.cn
)?.type === 'virtual';
}
const column = await Column.insert<LinkToAnotherRecordColumn>( const column = await Column.insert<LinkToAnotherRecordColumn>(
{ {
project_id: project.id, project_id: project.id,
@ -460,7 +516,8 @@ async function migrateProjectModels(
fk_mm_model_id, fk_mm_model_id,
fk_mm_child_column_id, fk_mm_child_column_id,
fk_mm_parent_column_id, fk_mm_parent_column_id,
fk_related_model_id: columnMeta.hm ? tnId : rtnId fk_related_model_id: columnMeta.hm ? tnId : rtnId,
virtual
}, },
ncMeta ncMeta
); );
@ -636,6 +693,15 @@ async function migrateProjectModels(
// const rtnId = projectModelRefs?.[rel.rtn]?.id; // const rtnId = projectModelRefs?.[rel.rtn]?.id;
const virtual =
relations.find(
r =>
r.rtn === rel.rtn &&
r.tn === rel.tn &&
r.rcn === rel.rcn &&
r.cn === rel.cn
)?.type === 'virtual';
const column = await Column.insert<LinkToAnotherRecordColumn>( const column = await Column.insert<LinkToAnotherRecordColumn>(
{ {
project_id: project.id, project_id: project.id,
@ -651,7 +717,8 @@ async function migrateProjectModels(
ur: rel.ur, ur: rel.ur,
dr: rel.dr, dr: rel.dr,
fk_related_model_id: tnId, fk_related_model_id: tnId,
system: true system: true,
virtual
}, },
ncMeta ncMeta
); );
@ -720,6 +787,7 @@ async function migrateProjectModels(
await migrateProjectModelViews( await migrateProjectModelViews(
{ {
metas,
views, views,
objModelRef, objModelRef,
objModelColumnAliasRef, objModelColumnAliasRef,
@ -733,6 +801,7 @@ async function migrateProjectModels(
await migrateViewsParams( await migrateViewsParams(
{ {
metas,
views, views,
objModelRef, objModelRef,
objModelColumnAliasRef, objModelColumnAliasRef,
@ -745,6 +814,7 @@ async function migrateProjectModels(
); );
return { return {
metas,
views, views,
objModelRef, objModelRef,
objModelColumnAliasRef, objModelColumnAliasRef,
@ -1204,8 +1274,9 @@ async function migrateAutitLog(ctx: MigrateCtxV1, ncMeta: any) {
if (audit.model_name) { if (audit.model_name) {
insertObj.fk_model_id = ( insertObj.fk_model_id = (
ctx.objModelAliasRef?.[audit.project_id]?.[audit.model_name] || ctx.objModelAliasRef?.[audit.project_id]?.[audit.model_name] ||
ctx.objModelRef?.[audit.project_id]?.[audit.model_name] ctx.objModelRef?.[audit.project_id]?.[audit.model_name] ||
).id; ctx.metas?.find(m => m.id == audit.model_id)
)?.id;
} }
await Audit.insert(insertObj, ncMeta); await Audit.insert(insertObj, ncMeta);

13
packages/nocodb/src/lib/utils/projectAcl.ts

@ -116,7 +116,15 @@ export default {
xcModelRowAuditAndCommentList: true, xcModelRowAuditAndCommentList: true,
xcAuditCommentInsert: true, xcAuditCommentInsert: true,
xcAuditModelCommentsCount: true, xcAuditModelCommentsCount: true,
xcExportAsCsv: true xcExportAsCsv: true,
bulkDataInsert: true,
bulkDataUpdate: true,
bulkDataUpdateAll: true,
bulkDataDelete: true,
bulkDataDeleteAll: true,
relationDataRemove: true,
relationDataAdd: true
}, },
commenter: { commenter: {
formViewGet: true, formViewGet: true,
@ -133,8 +141,10 @@ export default {
columnList: true, columnList: true,
mmList: true, mmList: true,
hmList: true,
commentList: true, commentList: true,
commentRow: true, commentRow: true,
projectInfoGet: true,
// data // data
dataList: true, dataList: true,
@ -178,6 +188,7 @@ export default {
// sort & filter // sort & filter
sortList: true, sortList: true,
projectInfoGet: true,
mmList: true, mmList: true,
hmList: true, hmList: true,

2
scripts/bumpNocodbSdkVersion.js

@ -13,6 +13,6 @@ if (process.env.targetEnv === 'DEV') {
packageJson.version = `${packageJson.version}-${process.env.targetVersion}` packageJson.version = `${packageJson.version}-${process.env.targetVersion}`
packageJson.name += '-daily' packageJson.name += '-daily'
} else { } else {
packageJson.version = version packageJson.version = process.env.targetVersion
} }
fs.writeFileSync(path.join(__dirname, '..', 'packages', 'nocodb-sdk', 'package.json'), JSON.stringify(packageJson, 0, 2)) fs.writeFileSync(path.join(__dirname, '..', 'packages', 'nocodb-sdk', 'package.json'), JSON.stringify(packageJson, 0, 2))

231
scripts/sdk/swagger.json

@ -26,12 +26,58 @@
"type": "string" "type": "string"
} }
} }
},
"examples": {
"Successful registration response": {
"value": {
"token": "string"
}
}
} }
} }
} }
}, },
"400": { "400": {
"description": "Bad Request" "description": "Bad Request",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"msg": {
"type": "string"
}
}
},
"examples": {
"Invalid email": {
"value": {
"msg": "Invalid email"
}
},
"Invalid invite url": {
"value": {
"msg": "Invalid invite url"
}
},
"Expired invite url": {
"value": {
"msg": "Expired invite url, Please contact super admin to get a new invite url"
}
},
"User already exist": {
"value": {
"msg": "User already exist"
}
},
"Invite only signup": {
"value": {
"msg": "Not allowed to signup, contact super admin"
}
}
}
}
}
}, },
"401": { "401": {
"description": "Unauthorized" "description": "Unauthorized"
@ -68,6 +114,21 @@
} }
} }
} }
},
"400": {
"description": "Bad Request",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"msg": {
"type": "string"
}
}
}
}
}
} }
}, },
"tags": [ "tags": [
@ -90,6 +151,14 @@
"email", "email",
"password" "password"
] ]
},
"examples": {
"example-1": {
"value": {
"email": "user@nocodb.com",
"password": "Password"
}
}
} }
} }
} }
@ -109,7 +178,21 @@
"content": { "content": {
"application/json": { "application/json": {
"schema": { "schema": {
"$ref": "#/components/schemas/User" "$ref": "#/components/schemas/UserInfo"
},
"examples": {
"example-1": {
"value": {
"id": "string",
"email": "string",
"email_verified": "string",
"firstname": "string",
"lastname": "string",
"roles": {
"editor": true
}
}
}
} }
} }
} }
@ -118,7 +201,17 @@
"tags": [ "tags": [
"Auth" "Auth"
], ],
"description": "Returns authenticated user info" "description": "Returns authenticated user info",
"parameters": [
{
"schema": {
"type": "string"
},
"in": "query",
"name": "project_id",
"description": "Pass project id to get project specific roles along with user info"
}
]
} }
}, },
"/api/v1/db/auth/password/forgot": { "/api/v1/db/auth/password/forgot": {
@ -128,6 +221,9 @@
"responses": { "responses": {
"200": { "200": {
"description": "OK" "description": "OK"
},
"401": {
"description": "Unauthorized"
} }
}, },
"description": "Emails user with a reset url.", "description": "Emails user with a reset url.",
@ -146,7 +242,8 @@
} }
} }
} }
} },
"description": "Pass registered user email id in request body"
} }
}, },
"parameters": [] "parameters": []
@ -157,7 +254,53 @@
"operationId": "auth-password-change", "operationId": "auth-password-change",
"responses": { "responses": {
"200": { "200": {
"description": "OK" "description": "OK",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"msg": {
"type": "string"
}
}
},
"examples": {
"Success response": {
"value": {
"msg": "Password updated successfully"
}
}
}
}
}
},
"400": {
"description": "Bad request",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"msg": {
"type": "string"
}
}
},
"examples": {
"Missing params": {
"value": {
"msg": "Missing new/old password"
}
},
"Wrong password": {
"value": {
"msg": "Current password is wrong"
}
}
}
}
}
} }
}, },
"description": "Change password of authenticated user with a new one.", "description": "Change password of authenticated user with a new one.",
@ -175,14 +318,20 @@
}, },
"newPassword": { "newPassword": {
"type": "string" "type": "string"
}, }
"verifyPassword": { }
"type": "string" },
"examples": {
"example-1": {
"value": {
"currentPassword": "string",
"newPassword": "string"
} }
} }
} }
} }
} },
"description": "Old password need to be passed along with new password for changing password."
} }
}, },
"parameters": [] "parameters": []
@ -292,7 +441,6 @@
}, },
"parameters": [] "parameters": []
}, },
"/api/v1/db/meta/projects/{projectId}/users": { "/api/v1/db/meta/projects/{projectId}/users": {
"get": { "get": {
"summary": "Project Users", "summary": "Project Users",
@ -1522,8 +1670,7 @@
"get": { "get": {
"summary": "", "summary": "",
"operationId": "db-view-column-list", "operationId": "db-view-column-list",
"responses": { "responses": {},
},
"tags": [ "tags": [
"DB View Column" "DB View Column"
] ]
@ -2281,7 +2428,6 @@
} }
} }
}, },
"/api/v1/db/data/{orgs}/{projectName}/{tableName}": { "/api/v1/db/data/{orgs}/{projectName}/{tableName}": {
"parameters": [ "parameters": [
{ {
@ -3104,7 +3250,8 @@
"name": "relationType", "name": "relationType",
"in": "path", "in": "path",
"required": true "required": true
},{ },
{
"schema": { "schema": {
"type": "string" "type": "string"
}, },
@ -3245,7 +3392,7 @@
}, },
"delete": { "delete": {
"summary": "", "summary": "",
"operationId": "db-table-row-nested-delete", "operationId": "db-table-row-nested-remove",
"responses": { "responses": {
"200": { "200": {
"description": "OK", "description": "OK",
@ -3350,7 +3497,6 @@
] ]
} }
}, },
"/api/v1/db/public/shared-view/{sharedViewUuid}/rows": { "/api/v1/db/public/shared-view/{sharedViewUuid}/rows": {
"parameters": [ "parameters": [
{ {
@ -3421,7 +3567,7 @@
"multipart/form-data": { "multipart/form-data": {
"schema": { "schema": {
"type": "object", "type": "object",
"properties": { } "properties": {}
} }
} }
} }
@ -3707,7 +3853,6 @@
] ]
} }
}, },
"/api/v1/db/meta/audits/comments": { "/api/v1/db/meta/audits/comments": {
"parameters": [], "parameters": [],
"get": { "get": {
@ -3830,7 +3975,7 @@
] ]
} }
}, },
"/api/v1/db/meta/project/{projectId}/audits": { "/api/v1/db/meta/projects/{projectId}/audits": {
"parameters": [ "parameters": [
{ {
"schema": { "schema": {
@ -3945,7 +4090,6 @@
} }
} }
}, },
"/api/v1/db/meta/tables/{tableId}/hooks": { "/api/v1/db/meta/tables/{tableId}/hooks": {
"parameters": [ "parameters": [
{ {
@ -4195,7 +4339,6 @@
] ]
} }
}, },
"/api/v1/db/meta/plugins": { "/api/v1/db/meta/plugins": {
"parameters": [], "parameters": [],
"get": { "get": {
@ -4374,7 +4517,6 @@
] ]
} }
}, },
"/api/v1/db/meta/connection/test": { "/api/v1/db/meta/connection/test": {
"parameters": [], "parameters": [],
"post": { "post": {
@ -4434,6 +4576,27 @@
"description": "" "description": ""
} }
}, },
"/api/v1/db/meta/nocodb/version": {
"parameters": [],
"get": {
"summary": "",
"operationId": "utils-app-version",
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {}
}
}
}
},
"tags": [
"Utils"
],
"description": ""
}
},
"/api/v1/db/meta/cache": { "/api/v1/db/meta/cache": {
"get": { "get": {
"summary": "Your GET endpoint", "summary": "Your GET endpoint",
@ -4459,7 +4622,6 @@
}, },
"parameters": [] "parameters": []
}, },
"/api/v1/db/meta/projects/{projectId}/api-tokens": { "/api/v1/db/meta/projects/{projectId}/api-tokens": {
"get": { "get": {
"summary": "Your GET endpoint", "summary": "Your GET endpoint",
@ -4562,7 +4724,6 @@
} }
] ]
}, },
"/api/v1/db/storage/upload": { "/api/v1/db/storage/upload": {
"post": { "post": {
"summary": "Attachment", "summary": "Attachment",
@ -7010,6 +7171,28 @@
], ],
"description": "", "description": "",
"type": "object" "type": "object"
},
"UserInfo": {
"title": "UserInfo",
"type": "object",
"properties": {
"id": {
"type": "string"
},
"email": {
"type": "string"
},
"email_verified": {
"type": "string"
},
"firstname": {
"type": "string"
},
"lastname": {
"type": "string"
},
"roles": {}
}
} }
}, },
"requestBodies": { "requestBodies": {

Loading…
Cancel
Save