Browse Source

Merge branch 'develop' into feat/backend-refactoring-nest

pull/5444/head
Wing-Kam Wong 2 years ago
parent
commit
735b7568f0
  1. 2
      packages/nc-gui/components/cell/attachment/Image.vue
  2. 2
      packages/nc-gui/components/dlg/TableCreate.vue
  3. 2
      packages/nc-gui/components/smartsheet/Cell.vue
  4. 1
      packages/nc-gui/composables/useAttachment.ts
  5. 2
      packages/nc-gui/lang/pt_BR.json
  6. 2
      packages/noco-docs/content/en/developer-resources/rest-apis.md
  7. 4
      packages/noco-docs/content/en/developer-resources/sdk.md
  8. 2
      packages/noco-docs/content/en/getting-started/upgrading.md
  9. 6
      packages/noco-docs/content/en/index.md
  10. 2
      packages/noco-docs/content/en/setup-and-usages/meta-management.md
  11. 6
      packages/noco-docs/content/en/setup-and-usages/table-operations.md
  12. 1
      packages/nocodb/src/lib/controllers/publicControllers/publicData.ctl.ts
  13. 10
      packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/pg.ts
  14. 4
      packages/nocodb/src/lib/services/attachment.svc.ts
  15. 17
      packages/nocodb/src/lib/services/public/publicData.svc.ts
  16. 15
      packages/nocodb/src/schema/swagger.json
  17. 12
      tests/playwright/tests/columnFormula.spec.ts

2
packages/nc-gui/components/cell/attachment/Image.vue

@ -1,4 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { iconMap } from '#imports'
interface Props { interface Props {
srcs: string[] srcs: string[]
alt?: string alt?: string

2
packages/nc-gui/components/dlg/TableCreate.vue

@ -53,7 +53,7 @@ const validators = computed(() => {
validator: (_: any, value: any) => { validator: (_: any, value: any) => {
// validate duplicate alias // validate duplicate alias
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if ((tables.value || []).some((t) => t.title === (value || ''))) { if ((tables.value || []).some((t) => t.title === (value || '') && t.base_id === props.baseId)) {
return reject(new Error('Duplicate table alias')) return reject(new Error('Duplicate table alias'))
} }
return resolve(true) return resolve(true)

2
packages/nc-gui/components/smartsheet/Cell.vue

@ -193,7 +193,7 @@ onUnmounted(() => {
`nc-cell-${(column?.uidt || 'default').toLowerCase()}`, `nc-cell-${(column?.uidt || 'default').toLowerCase()}`,
{ 'text-blue-600': isPrimary(column) && !props.virtual && !isForm }, { 'text-blue-600': isPrimary(column) && !props.virtual && !isForm },
{ 'nc-grid-numeric-cell': isGrid && !isForm && isNumericField }, { 'nc-grid-numeric-cell': isGrid && !isForm && isNumericField },
{ 'h-[40px]': !props.editEnabled && isForm && !isSurveyForm }, { 'h-[40px]': !props.editEnabled && isForm && !isSurveyForm && !isAttachment(column) },
]" ]"
@keydown.enter.exact="navigate(NavigateDir.NEXT, $event)" @keydown.enter.exact="navigate(NavigateDir.NEXT, $event)"
@keydown.shift.enter.exact="navigate(NavigateDir.PREV, $event)" @keydown.shift.enter.exact="navigate(NavigateDir.PREV, $event)"

1
packages/nc-gui/composables/useAttachment.ts

@ -5,6 +5,7 @@ const useAttachment = () => {
const getPossibleAttachmentSrc = (item: Record<string, any>) => { const getPossibleAttachmentSrc = (item: Record<string, any>) => {
const res: string[] = [] const res: string[] = []
if (item?.data) res.push(item.data)
if (item?.path) res.push(`${appInfo.value.ncSiteUrl}/${item.path}`) if (item?.path) res.push(`${appInfo.value.ncSiteUrl}/${item.path}`)
if (item?.url) res.push(item.url) if (item?.url) res.push(item.url)
return res return res

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

@ -698,7 +698,7 @@
"allowedSpecialCharList": "Lista de caracteres especiais permitidos" "allowedSpecialCharList": "Lista de caracteres especiais permitidos"
}, },
"invalidURL": "URL inválido", "invalidURL": "URL inválido",
"invalidEmail": "Invalid Email", "invalidEmail": "E-mail inválido",
"internalError": "Ocorreu algum erro interno", "internalError": "Ocorreu algum erro interno",
"templateGeneratorNotFound": "O Gerador de Modelos não pode ser encontrado!", "templateGeneratorNotFound": "O Gerador de Modelos não pode ser encontrado!",
"fileUploadFailed": "Falha no carregamento do ficheiro", "fileUploadFailed": "Falha no carregamento do ficheiro",

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

@ -12,7 +12,7 @@ Once you've created the schemas, you can manipulate the data or invoke actions u
Here's the overview of all APIs. For the details, please check out <a href="https://all-apis.nocodb.com/" target="_blank">NocoDB API Documentation</a>. Here's the overview of all APIs. For the details, please check out <a href="https://all-apis.nocodb.com/" target="_blank">NocoDB API Documentation</a>.
You may also interact with the API's resources via <a href="./accessing-apis#swagger-ui" target="_blank">Swagger UI</a>. You may also interact with the API's resources via <NuxtLink to="/developer-resources/accessing-apis#swagger-ui" target="_blank">Swagger UI</NuxtLink>.
<alert type="success"> <alert type="success">
Currently, the default value for {orgs} is <b>noco</b>. Users will be able to change it in the future release. Currently, the default value for {orgs} is <b>noco</b>. Users will be able to change it in the future release.

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

@ -9,7 +9,7 @@ menuTitle: 'NocoDB SDK'
We provide SDK for users to integrate with their applications. Currently only SDK for Javascript is supported. We provide SDK for users to integrate with their applications. Currently only SDK for Javascript is supported.
<alert> <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. Note: The NocoDB SDK requires authorization token. If you haven't created one, please check out <NuxtLink to="/developer-resources/accessing-apis" target="_blank">Accessing APIs</NuxtLink> for details.
</alert> </alert>
## SDK For Javascript ## SDK For Javascript
@ -57,7 +57,7 @@ const api = new Api({
Once you have configured `api`, you can call different types of APIs by `api.<Tag>.<FunctionName>`. Once you have configured `api`, you can call different types of APIs by `api.<Tag>.<FunctionName>`.
<alert> <alert>
For Tag and FunctionName, please check out the API table <a href="./rest-apis" target="_blank">here</a>. For Tag and FunctionName, please check out the API table <NuxtLink to="/developer-resources/rest-apis" target="_blank">here</NuxtLink>.
</alert> </alert>
#### Example: Calling API - /api/v1/db/meta/projects/{projectId}/tables #### Example: Calling API - /api/v1/db/meta/projects/{projectId}/tables

2
packages/noco-docs/content/en/getting-started/upgrading.md

@ -8,7 +8,7 @@ link: https://codesandbox.io/embed/vigorous-firefly-80kq5?hidenavigation=1&theme
--- ---
By default, if `NC_DB` is not specified upon By default, if `NC_DB` is not specified upon
<a href="./installation" target="_blank">installation</a>, then SQLite will be used to store metadata. We suggest users to separate the metadata and user data in different databases as pictured in our <a href="../engineering/architecture" target="_blank">architecture</a>. <NuxtLink to="/getting-started/installation" target="_blank">installation</NuxtLink>, then SQLite will be used to store metadata. We suggest users to separate the metadata and user data in different databases as pictured in our <NuxtLink to="/engineering/architecture" target="_blank">architecture</NuxtLink>.
## Docker ## Docker

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

@ -31,7 +31,7 @@ Also NocoDB's app store allows you to build business workflows on views with com
### App Store for Workflow Automations ### App Store for Workflow Automations
We provide different integrations in three main categories. See <a href="./setup-and-usages/app-store" target="_blank">App Store</a> for details. We provide different integrations in three main categories. See <NuxtLink to="/setup-and-usages/account-settings#app-store" target="_blank">App Store</NuxtLink> for details.
- ⚡ &nbsp;Chat : Slack, Discord, Mattermost, and etc - ⚡ &nbsp;Chat : Slack, Discord, Mattermost, and etc
- ⚡ &nbsp;Email : AWS SES, SMTP, MailerSend, and etc - ⚡ &nbsp;Email : AWS SES, SMTP, MailerSend, and etc
@ -46,11 +46,11 @@ We provide the following ways to let users to invoke actions in a programmatic w
### Sync Schema ### Sync Schema
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. 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 <NuxtLink to="/setup-and-usages/sync-schema" target="_blank">Sync Schema</NuxtLink> for details.
### Audit ### Audit
We are keeping all the user operation logs under one place. See <a href="./setup-and-usages/audit" target="_blank">Audit</a> for details. We are keeping all the user operation logs under one place. See <NuxtLink to="/setup-and-usages/audit" target="_blank">Audit</NuxtLink> for details.
## Why are we building this? ## 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. 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.

2
packages/noco-docs/content/en/setup-and-usages/meta-management.md

@ -28,7 +28,7 @@ To access it, click the down arrow button next to Project Name on the top left s
## Sync Metadata ## Sync Metadata
Go to `Data Sources`, click ``Sync Metadata``, you can see your metadata sync status. If it is out of sync, you can sync the schema. See <a href="./sync-schema">Sync Schema</a> for more.0 Go to `Data Sources`, click ``Sync Metadata``, you can see your metadata sync status. If it is out of sync, you can sync the schema. See <NuxtLink to="/setup-and-usages/sync-schema">Sync Schema</NuxtLink> for more.
![image](https://user-images.githubusercontent.com/35857179/219833485-3bcaa6ec-88bc-47cc-b938-5abb4835dc31.png) ![image](https://user-images.githubusercontent.com/35857179/219833485-3bcaa6ec-88bc-47cc-b938-5abb4835dc31.png)

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

@ -155,7 +155,7 @@ You can use Quick Import when you have data from external sources such as Airtab
### Import Airtable into an Existing Project ### Import Airtable into an Existing Project
- See <a href="./import-airtable-to-sql-database-within-a-minute-for-free">here</a> - See <NuxtLink to="/setup-and-usages/import-airtable-to-sql-database-within-a-minute-for-free">here</NuxtLink>
### Import CSV data into an Existing Project ### Import CSV data into an Existing Project
@ -165,7 +165,7 @@ You can use Quick Import when you have data from external sources such as Airtab
- **Use First Row as Headers**: If it is checked, the first row will be treated as header row. - **Use First Row as Headers**: If it is checked, the first row will be treated as header row.
- **Import Data**: If it is checked, all data will be imported. Otherwise, only table will be created. - **Import Data**: If it is checked, all data will be imported. Otherwise, only table will be created.
![image](https://user-images.githubusercontent.com/35857179/197454479-1ed18dce-1d0b-4ee3-88b3-9b6a132dea2a.png) ![image](https://user-images.githubusercontent.com/35857179/197454479-1ed18dce-1d0b-4ee3-88b3-9b6a132dea2a.png)
- You can revise the table name by double clicking it, column name and column type. By default, the first column will be chosen as <a href="./display-value" target="_blank">Display Value</a> and cannot be deleted. - You can revise the table name by double clicking it, column name and column type. By default, the first column will be chosen as <NuxtLink to="/setup-and-usages/display-value" target="_blank">Display Value</NuxtLink> and cannot be deleted.
![image](https://user-images.githubusercontent.com/35857179/197454633-5b30323e-2b13-4c55-843a-948c093d373e.png) ![image](https://user-images.githubusercontent.com/35857179/197454633-5b30323e-2b13-4c55-843a-948c093d373e.png)
- Click `Import` to start importing process. The table will be created and the data will be imported. - Click `Import` to start importing process. The table will be created and the data will be imported.
![image](https://user-images.githubusercontent.com/35857179/197455547-2d93df5e-a7f0-4c88-af53-990067625967.png) ![image](https://user-images.githubusercontent.com/35857179/197455547-2d93df5e-a7f0-4c88-af53-990067625967.png)
@ -178,7 +178,7 @@ You can use Quick Import when you have data from external sources such as Airtab
- **Use First Row as Headers**: If it is checked, the first row will be treated as header row. - **Use First Row as Headers**: If it is checked, the first row will be treated as header row.
- **Import Data**: If it is checked, all data will be imported. Otherwise, only table will be created. - **Import Data**: If it is checked, all data will be imported. Otherwise, only table will be created.
![image](https://user-images.githubusercontent.com/35857179/197455788-8dd8a7d1-38f3-48c3-a05e-6ab0cf25045c.png) ![image](https://user-images.githubusercontent.com/35857179/197455788-8dd8a7d1-38f3-48c3-a05e-6ab0cf25045c.png)
- You can revise the table name, column name and column type. By default, the first column will be chosen as <a href="./display-value" target="_blank">Display Value</a> and cannot be deleted. - You can revise the table name, column name and column type. By default, the first column will be chosen as <NuxtLink to="/setup-and-usages/display-value" target="_blank">Display Value</NuxtLink> and cannot be deleted.
<alert> <alert>
Note: If your Excel file contains multiple sheets, each sheet will be stored in a separate table. Note: If your Excel file contains multiple sheets, each sheet will be stored in a separate table.
</alert> </alert>

1
packages/nocodb/src/lib/controllers/publicControllers/publicData.ctl.ts

@ -31,6 +31,7 @@ async function dataInsert(req: Request & { files: any[] }, res: Response) {
password: req.headers?.['xc-password'] as string, password: req.headers?.['xc-password'] as string,
body: req.body?.data, body: req.body?.data,
siteUrl: (req as any).ncSiteUrl, siteUrl: (req as any).ncSiteUrl,
// req.files is enriched by multer
files: req.files, files: req.files,
}); });

10
packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/pg.ts

@ -157,11 +157,13 @@ const pg = {
builder: args.knex.raw( builder: args.knex.raw(
`CASE WHEN ${args.knex `CASE WHEN ${args.knex
.raw( .raw(
`${args.pt.arguments `${(
.map(async (ar) => await Promise.all(
(await args.fn(ar, '', 'OR')).builder.toQuery() args.pt.arguments.map(async (ar) =>
(await args.fn(ar, '', 'OR')).builder.toQuery()
)
) )
.join(' OR ')}` ).join(' OR ')}`
) )
.wrap('(', ')') .wrap('(', ')')
.toQuery()} THEN TRUE ELSE FALSE END ${args.colAlias}` .toQuery()} THEN TRUE ELSE FALSE END ${args.colAlias}`

4
packages/nocodb/src/lib/services/attachment.svc.ts

@ -30,8 +30,8 @@ export async function upload(param: {
// if `url` is null, then it is local attachment // if `url` is null, then it is local attachment
if (!url) { if (!url) {
// then store the attachement path only // then store the attachment path only
// url will be constructued in `useAttachmentCell` // url will be constructed in `useAttachmentCell`
attachmentPath = `download/${filePath.join('/')}/${fileName}`; attachmentPath = `download/${filePath.join('/')}/${fileName}`;
} }

17
packages/nocodb/src/lib/services/public/publicData.svc.ts

@ -235,7 +235,7 @@ export async function dataInsert(param: {
const fieldName = file?.fieldname?.replace(/^_|\[\d*]$/g, ''); const fieldName = file?.fieldname?.replace(/^_|\[\d*]$/g, '');
const filePath = sanitizeUrlPath([ const filePath = sanitizeUrlPath([
'v1', 'noco',
project.title, project.title,
model.title, model.title,
fieldName, fieldName,
@ -243,18 +243,25 @@ export async function dataInsert(param: {
if (fieldName in fields && fields[fieldName].uidt === UITypes.Attachment) { if (fieldName in fields && fields[fieldName].uidt === UITypes.Attachment) {
attachments[fieldName] = attachments[fieldName] || []; attachments[fieldName] = attachments[fieldName] || [];
const fileName = `${nanoid(6)}_${file.originalname}`; const fileName = `${nanoid(18)}${path.extname(file.originalname)}`;
let url = await storageAdapter.fileCreate(
const url = await storageAdapter.fileCreate(
slash(path.join('nc', 'uploads', ...filePath, fileName)), slash(path.join('nc', 'uploads', ...filePath, fileName)),
file file
); );
let attachmentPath;
// if `url` is null, then it is local attachment
if (!url) { if (!url) {
url = `${param.siteUrl}/download/${filePath.join('/')}/${fileName}`; // then store the attachment path only
// url will be constructed in `useAttachmentCell`
attachmentPath = `download/${filePath.join('/')}/${fileName}`;
} }
attachments[fieldName].push({ attachments[fieldName].push({
url, ...(url ? { url } : {}),
...(attachmentPath ? { path: attachmentPath } : {}),
title: file.originalname, title: file.originalname,
mimetype: file.mimetype, mimetype: file.mimetype,
size: file.size, size: file.size,

15
packages/nocodb/src/schema/swagger.json

@ -10886,20 +10886,7 @@
}, },
"requestBody": { "requestBody": {
"content": { "content": {
"application/json": { "multipart/form-data": {}
"schema": {
"type": "object",
"description": "Data Object where the key is column and the value is the data value"
},
"examples": {
"Example 1": {
"value": {
"col1": "foo",
"col2": "bar"
}
}
}
}
}, },
"description": "" "description": ""
}, },

12
tests/playwright/tests/columnFormula.spec.ts

@ -122,6 +122,18 @@ const formulaDataByDbType = (context: NcContext) => [
formula: `NOW()`, formula: `NOW()`,
result: ['1', '1', '1', '1', '1'], result: ['1', '1', '1', '1', '1'],
}, },
{
formula: `OR(true, false)`,
result: isPg(context) ? ['true', 'true', 'true', 'true', 'true'] : ['1', '1', '1', '1', '1'],
},
{
formula: `AND(false, false)`,
result: isPg(context) ? ['false', 'false', 'false', 'false', 'false'] : ['0', '0', '0', '0', '0'],
},
{
formula: `IF((SEARCH({Address List}, "Parkway") != 0), "2.0","WRONG")`,
result: ['WRONG', 'WRONG', 'WRONG', '2.0', '2.0'],
},
]; ];
test.describe('Virtual Columns', () => { test.describe('Virtual Columns', () => {

Loading…
Cancel
Save