Browse Source

Merge branch 'develop' into enhancement/filters

pull/5106/head
Wing-Kam Wong 2 years ago
parent
commit
ec7e60f329
  1. 2
      packages/nc-gui/assets/style.scss
  2. 4
      packages/nc-gui/components/smartsheet/Grid.vue
  3. 4
      packages/nc-gui/components/smartsheet/sidebar/RenameableMenuItem.vue
  4. 8
      packages/nc-gui/components/tabs/auth/UserManagement.vue
  5. 6
      packages/nc-gui/composables/useKanbanViewStore.ts
  6. 5
      packages/nc-gui/composables/useSmartsheetStore.ts
  7. 62
      packages/nc-gui/composables/useViewData.ts
  8. 212
      packages/nc-gui/lang/zh-Hans.json
  9. 2
      packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/CustomKnex.ts
  10. 14
      packages/nocodb/src/lib/meta/api/attachmentApis.ts

2
packages/nc-gui/assets/style.scss

@ -34,7 +34,7 @@ a {
}
.nc-icon {
@apply color-transition;
@apply color-transition inline;
}
// menu item styling

4
packages/nc-gui/components/smartsheet/Grid.vue

@ -101,9 +101,9 @@ const tbodyEl = ref<HTMLElement>()
const gridWrapper = ref<HTMLElement>()
const tableHead = ref<HTMLElement>()
const isAddingColumnAllowed = !readOnly.value && !isLocked.value && isUIAllowed('add-column') && !isSqlView.value
const isAddingColumnAllowed = $computed(() => !readOnly.value && !isLocked.value && isUIAllowed('add-column') && !isSqlView.value)
const isAddingEmptyRowAllowed = !isView && !isLocked.value && hasEditPermission && !isSqlView.value
const isAddingEmptyRowAllowed = $computed(() => !isView && !isLocked.value && hasEditPermission && !isSqlView.value)
const {
isLoading,

4
packages/nc-gui/components/smartsheet/sidebar/RenameableMenuItem.vue

@ -200,7 +200,7 @@ function onStopEdit() {
{{ $t('activity.copyView') }}
</template>
<MdiContentCopy class="hidden group-hover:block text-gray-500 nc-view-copy-icon" @click.stop="onDuplicate" />
<MdiContentCopy class="!hidden !group-hover:block text-gray-500 nc-view-copy-icon" @click.stop="onDuplicate" />
</a-tooltip>
<template v-if="!vModel.is_default">
@ -209,7 +209,7 @@ function onStopEdit() {
{{ $t('activity.deleteView') }}
</template>
<MdiTrashCan class="hidden group-hover:block text-red-500 nc-view-delete-icon" @click.stop="onDelete" />
<MdiTrashCan class="!hidden !group-hover:block text-red-500 nc-view-delete-icon" @click.stop="onDelete" />
</a-tooltip>
</template>
</div>

8
packages/nc-gui/components/tabs/auth/UserManagement.vue

@ -320,7 +320,13 @@ const isSuperAdmin = (user: { main_roles?: string }) => {
</a-button>
</a-tooltip>
<a-dropdown :trigger="['click']" class="flex" placement="bottomRight" overlay-class-name="nc-dropdown-user-mgmt">
<a-dropdown
v-if="user.invite_token"
:trigger="['click']"
class="flex"
placement="bottomRight"
overlay-class-name="nc-dropdown-user-mgmt"
>
<div class="flex flex-row items-center">
<a-button type="text" class="!px-0">
<div class="flex flex-row items-center h-[1.2rem]">

6
packages/nc-gui/composables/useKanbanViewStore.ts

@ -71,7 +71,9 @@ const [useProvideKanbanViewStore, useKanbanViewStore] = useInjectionState(
const { sqlUis } = useProject()
const sqlUi = ref(meta.value?.base_id ? sqlUis.value[meta.value?.base_id] : Object.values(sqlUis.value)[0])
const sqlUi = ref(
(meta.value as TableType)?.base_id ? sqlUis.value[(meta.value as TableType).base_id!] : Object.values(sqlUis.value)[0],
)
const xWhere = computed(() => {
let where
@ -198,6 +200,8 @@ const [useProvideKanbanViewStore, useKanbanViewStore] = useInjectionState(
// See /packages/nocodb/src/lib/version-upgrader/ncAttachmentUpgrader.ts for the details
for (const record of data.value.list) {
for (const attachmentColumn of attachmentColumns.value) {
// attachment column can be hidden
if (!record[attachmentColumn!]) continue
const oldAttachment = JSON.parse(record[attachmentColumn!])
const newAttachment = []
for (const attachmentObj of oldAttachment) {

5
packages/nc-gui/composables/useSmartsheetStore.ts

@ -13,9 +13,12 @@ const [useProvideSmartsheetStore, useSmartsheetStore] = useInjectionState(
initialFilters?: Ref<FilterType[]>,
) => {
const { $api } = useNuxtApp()
const { sqlUis } = useProject()
const sqlUi = ref(meta.value?.base_id ? sqlUis.value[meta.value?.base_id] : Object.values(sqlUis.value)[0])
const sqlUi = ref(
(meta.value as TableType)?.base_id ? sqlUis.value[(meta.value as TableType).base_id!] : Object.values(sqlUis.value)[0],
)
const cellRefs = ref<HTMLTableDataCellElement[]>([])

62
packages/nc-gui/composables/useViewData.ts

@ -1,5 +1,15 @@
import { UITypes, ViewTypes } from 'nocodb-sdk'
import type { Api, ColumnType, FormColumnType, FormType, GalleryType, PaginatedType, TableType, ViewType } from 'nocodb-sdk'
import type {
Api,
AttachmentType,
ColumnType,
FormColumnType,
FormType,
GalleryType,
PaginatedType,
TableType,
ViewType,
} from 'nocodb-sdk'
import type { ComputedRef, Ref } from 'vue'
import {
IsPublicInj,
@ -81,6 +91,10 @@ export function useViewData(
const { isUIAllowed } = useUIPermission()
const attachmentColumns = computed(() =>
(meta.value?.columns as ColumnType[])?.filter((c) => c.uidt === UITypes.Attachment).map((c) => c.title),
)
const routeQuery = $computed(() => route.query as Record<string, string>)
const paginationData = computed({
@ -187,6 +201,28 @@ export function useViewData(
}
}
// TODO: refactor
async function getAttachmentUrl(item: AttachmentType) {
const path = item?.path
// if path doesn't exist, use `item.url`
if (path) {
// try ${appInfo.value.ncSiteUrl}/${item.path} first
const url = `${appInfo.ncSiteUrl}/${item.path}`
try {
const res = await fetch(url)
if (res.ok) {
// use `url` if it is accessible
return Promise.resolve(url)
}
} catch {
// for some cases, `url` is not accessible as expected
// do nothing here
}
}
// if it fails, use the original url
return Promise.resolve(item.url)
}
async function loadData(params: Parameters<Api<any>['dbViewRow']['list']>[4] = {}) {
if ((!project?.value?.id || !meta.value?.id || !viewMeta.value?.id) && !isPublic.value) return
const response = !isPublic.value
@ -198,7 +234,27 @@ export function useViewData(
where: where?.value,
})
: await fetchSharedViewData({ sortsArr: sorts.value, filtersArr: nestedFilters.value })
formattedData.value = formatData(response.list)
// reconstruct the url
// See /packages/nocodb/src/lib/version-upgrader/ncAttachmentUpgrader.ts for the details
const records = []
for (const record of response.list) {
for (const attachmentColumn of attachmentColumns.value) {
// attachment column can be hidden
if (!record[attachmentColumn!]) continue
const oldAttachment =
typeof record[attachmentColumn!] === 'string' ? JSON.parse(record[attachmentColumn!]) : record[attachmentColumn!]
const newAttachment = []
for (const attachmentObj of oldAttachment) {
newAttachment.push({
...attachmentObj,
url: await getAttachmentUrl(attachmentObj),
})
}
record[attachmentColumn!] = newAttachment
}
records.push(record)
}
formattedData.value = formatData(records)
paginationData.value = response.pageInfo
// to cater the case like when querying with a non-zero offset
@ -455,7 +511,7 @@ export function useViewData(
order: (fieldById[c.id] && fieldById[c.id].order) || order++,
id: fieldById[c.id] && fieldById[c.id].id,
}))
.sort((a: Record<string, any>, b: Record<string, any>) => a.order - b.order) as Record<string, any>
.sort((a: Record<string, any>, b: Record<string, any>) => a.order - b.order) as Record<string, any>[]
} catch (e: any) {
return message.error(`${t('msg.error.setFormDataFailed')}: ${await extractSdkResponseErrorMsg(e)}`)
}

212
packages/nc-gui/lang/zh-Hans.json

@ -72,9 +72,9 @@
"groupingField": "分组字段",
"insertAfter": "Insert After",
"insertBefore": "Insert Before",
"hideField": "Hide Field",
"sortAsc": "Sort Ascending",
"sortDesc": "Sort Descending"
"hideField": "隐藏字段",
"sortAsc": "升序",
"sortDesc": "降序"
},
"objects": {
"project": "项目",
@ -110,8 +110,8 @@
"editor": "编辑者",
"commenter": "评论者",
"viewer": "浏览者",
"orgLevelCreator": "Organization Level Creator",
"orgLevelViewer": "Organization Level Viewer"
"orgLevelCreator": "创始人",
"orgLevelViewer": "游客"
},
"sqlVIew": "SQL 视图"
},
@ -123,7 +123,7 @@
"Attachment": "附件",
"Checkbox": "复选框",
"MultiSelect": "多选",
"SingleSelect": "单",
"SingleSelect": "单选",
"Collaborator": "合作者",
"Date": "日期",
"Year": "年",
@ -131,64 +131,64 @@
"PhoneNumber": "电话号码",
"Email": "电子邮件",
"URL": "URL.",
"Number": "数",
"Decimal": "十进制",
"Number": "数",
"Decimal": "小数",
"Currency": "货币",
"Percent": "百分",
"Duration": "期间",
"Percent": "百分",
"Duration": "时长",
"Rating": "评分",
"Formula": "公式",
"Rollup": "卷起",
"Rollup": "聚合",
"Count": "计数",
"Lookup": "查找",
"DateTime": "日期时间",
"CreateTime": "创建时间",
"LastModifiedTime": "最后修改时间",
"AutoNumber": "自动编号",
"Barcode": "条码",
"Barcode": "条码",
"Button": "按钮",
"Password": "密码",
"relationProperties": {
"noAction": "没有任何行动",
"cascade": "级联",
"restrict": "严格",
"setNull": "设置null.",
"setDefault": "默认设置"
"setNull": "设为空(NULL)",
"setDefault": "设为默认值(Default)"
}
},
"filterOperation": {
"isEqual": "完全一致",
"isNotEqual": "完全不一致",
"isEqual": "等于",
"isNotEqual": "不等于",
"isLike": "部分一致",
"isNot like": "部分不一致",
"isEmpty": "是空的",
"isNotEmpty": "不是空的",
"isNull": "一片空白",
"isNotNull": "不是空虚"
"isEmpty": "内容为空",
"isNotEmpty": "内容不为空",
"isNull": "无值(Null)",
"isNotNull": "有值(Not Null)"
},
"title": {
"erdView": "实体关系图",
"newProj": "创建新项目",
"myProject": "我的项目",
"formTitle": "表标题",
"formTitle": "表标题",
"collabView": "合作视图",
"lockedView": "锁定视图",
"personalView": "个人视图",
"appStore": "软件商店",
"teamAndAuth": "团队和认证",
"rolesUserMgmt": "角色和用户管理",
"userMgmt": "用户账号管理",
"apiTokenMgmt": "API Tokens 管理",
"rolesUserMgmt": "权限和成员管理",
"userMgmt": "成员管理",
"apiTokenMgmt": "API 令牌管理",
"rolesMgmt": "角色管理",
"projMeta": "项目基础信息",
"metaMgmt": "项目基础信息管理",
"metadata": "元数据",
"exportImportMeta": "导出/导入元数据",
"uiACL": "UI访问控制",
"uiACL": "UI 访问控制",
"metaOperations": "元数据操作",
"audit": "审计",
"auditLogs": "审计日志",
"sqlMigrations": "SQL迁移",
"sqlMigrations": "SQL 迁移",
"dbCredentials": "数据库链接凭证",
"advancedParameters": "SSL 和高级参数",
"headCreateProject": "新建项目 | NocoDB",
@ -201,25 +201,25 @@
"APIsAndSupport": "API与支持",
"helpCenter": "帮助中心",
"swaggerDocumentation": "Swagger 文档",
"quickImportFrom": "快速导入",
"quickImportFrom": "快速导入",
"quickImport": "快速导入",
"advancedSettings": "高级设置",
"codeSnippet": "代码片段",
"keyboardShortcut": "Keyboard Shortcuts",
"generateRandomName": "Generate Random Name"
"keyboardShortcut": "快捷键",
"generateRandomName": "随机名称"
},
"labels": {
"createdBy": "Created By",
"notifyVia": "通知通过",
"createdBy": "创建自",
"notifyVia": "通知方式",
"projName": "项目名",
"tableName": "表名",
"tableName": "表名",
"viewName": "查看名称",
"viewLink": "查看链接",
"columnName": "列名",
"columnName": "列名",
"columnType": "列类型",
"roleName": "角色名称",
"roleDescription": "角色描述",
"databaseType": "键入数据库",
"roleName": "权限组",
"roleDescription": "权限描述",
"databaseType": "数据库中的类型",
"lengthValue": "长度/值",
"dbType": "数据库类型",
"sqliteFile": "SQLite 文件",
@ -227,36 +227,36 @@
"port": "端口号",
"username": "用户名",
"password": "密码",
"schemaName": "架构名称",
"schemaName": "模式名",
"database": "数据库",
"action": "行动",
"action": "操作",
"actions": "操作",
"operation": "操作",
"operationType": "操作类型",
"operationSubType": "操作类型",
"operationSubType": "操作类型",
"description": "描述",
"authentication": "证",
"authentication": "身份认证",
"token": "令牌",
"where": "在哪里",
"cache": "缓存",
"chat": "聊天",
"email": "电子邮件",
"storage": "存",
"storage": "存",
"uiAcl": "UI-ACL",
"models": "模型",
"syncState": "同步状态",
"created": "创了",
"sqlOutput": "SQL输出",
"created": "创了",
"sqlOutput": "输出 SQL",
"addOption": "添加选项",
"qrCodeValueColumn": "Column with QR code value",
"barcodeValueColumn": "Column with Barcode value",
"barcodeFormat": "Barcode format",
"qrCodeValueTooLong": "Too many characters for a QR code",
"barcodeValueTooLong": "Too many characters for a barcode",
"qrCodeValueColumn": "二维码要显示的数据",
"barcodeValueColumn": "条形码要显示的数据",
"barcodeFormat": "条形码码制",
"qrCodeValueTooLong": "字数超出二维码容量",
"barcodeValueTooLong": "字数超出条形码容量",
"aggregateFunction": "汇总功能",
"dbCreateIfNotExists": "数据库 : 如果不存在则创建",
"clientKey": "客户端 Key",
"clientCert": "客户端 Cert",
"dbCreateIfNotExists": "自动创建数据库",
"clientKey": "客户端密钥",
"clientCert": "客户端证书",
"serverCA": "服务器 CA",
"requriedCa": "必填项-CA",
"requriedIdentity": "必填项-IDENTITY",
@ -275,12 +275,12 @@
"followNocodb": "关注 NocoDB"
},
"docReference": "参考文档",
"selectUserRole": "选择用户角色",
"selectUserRole": "选择成员权限",
"childTable": "子表",
"childColumn": "子列",
"linkToAnotherRecord": "Link to another record",
"onUpdate": "更新",
"onDelete": "删除",
"onUpdate": "更新",
"onDelete": "删除",
"account": "帐户",
"language": "语言",
"primaryColor": "主色调",
@ -288,7 +288,7 @@
"customTheme": "定制样式",
"requestDataSource": "请求您需要的数据源?",
"apiKey": "API 密钥",
"sharedBase": "Shared Base",
"sharedBase": "分享项目",
"importData": "导入数据",
"importSecondaryViews": "导入次要视图",
"importRollupColumns": "Import Rollup Columns",
@ -296,7 +296,7 @@
"importAttachmentColumns": "导入附件列",
"importFormulaColumns": "导入公式列",
"noData": "暂无数据",
"goToDashboard": "前往仪表板",
"goToDashboard": "转到仪表板",
"importing": "导入中",
"flattenNested": "Flatten Nested",
"downloadAllowed": "允许下载",
@ -306,14 +306,14 @@
"belongsTo": "属于",
"manyToMany": "多对多关系",
"extraConnectionParameters": "额外连接参数",
"commentsOnly": "仅注释",
"commentsOnly": "仅评论",
"documentation": "文档",
"subscribeNewsletter": "订阅我们的每周新闻",
"signUpWithGoogle": "使用 Google 注册",
"signInWithGoogle": "使用 Google 登录",
"agreeToTos": "注册即表明您同意服务条款",
"welcomeToNc": "欢迎来到NocoDB!",
"inviteOnlySignup": "Allow signup only using invite url",
"inviteOnlySignup": "只能通过邀请链接注册账户",
"nextRow": "Next Row",
"prevRow": "Previous Row"
},
@ -330,19 +330,19 @@
"saveProject": "保存项目",
"deleteKanbanStack": "Delete stack?",
"createProjectExtended": {
"extDB": "通过连接新建 <br>连接到外部数据库",
"excel": "从Excel创建项目",
"extDB": "新建 <br>从外部数据库",
"excel": "从 Excel 创建项目",
"template": "从模板创建项目"
},
"OkSaveProject": "确认并保存项目",
"upgrade": {
"available": "升级可用",
"available": "有可用的升级",
"releaseNote": "发行说明",
"howTo": "如何升级?"
},
"translate": "帮助翻译",
"account": {
"authToken": "复制auth令牌",
"authToken": "复制 Auth 令牌",
"swagger": "Swagger: REST APIs",
"projInfo": "复制项目信息",
"themes": "主题"
@ -353,33 +353,33 @@
"addFilter": "添加过滤器",
"share": "分享",
"shareBase": {
"disable": "禁用共享基础",
"disable": "停止分享项目",
"enable": "任何有链接的人",
"link": "共享基本链接"
"link": "分享项目链接"
},
"invite": "邀请",
"inviteMore": "邀请更多",
"inviteTeam": "邀请团队",
"inviteUser": "Invite User",
"inviteUser": "邀请新成员",
"inviteToken": "邀请令牌",
"newUser": "新用户",
"editUser": "编辑用户",
"deleteUser": "从项目中删除用户",
"resendInvite": "重新发送邀请电子邮件",
"editUser": "编辑成员",
"deleteUser": "从项目中踢出成员",
"resendInvite": "重新发送邀请邮件",
"copyInviteURL": "复制邀请链接",
"copyPasswordResetURL": "Copy password reset URL",
"newRole": "新角色",
"reloadRoles": "重新加载角色",
"newRole": "新建权限组",
"reloadRoles": "重新加载权限组",
"nextPage": "下一页",
"prevPage": "上一页",
"nextRecord": "下一记录",
"previousRecord": "之前的纪录",
"nextRecord": "下一记录",
"previousRecord": "上一条纪录",
"copyApiURL": "复制 API 链接",
"createTable": "表创造",
"refreshTable": "刷新",
"renameTable": "重命名",
"deleteTable": "删除",
"addField": "将新字段添加到此表",
"createTable": "创建表格",
"refreshTable": "刷新表格",
"renameTable": "重命名表格",
"deleteTable": "删除表格",
"addField": "添加新字段",
"setPrimary": "设置为主要值",
"addRow": "添加新行",
"saveRow": "保存行",
@ -388,11 +388,11 @@
"insertRow": "插入新行",
"deleteRow": "删除行",
"deleteSelectedRow": "删除所选行",
"importExcel": "导入Excel",
"importExcel": "导入 Excel",
"importCSV": "导入 CSV",
"downloadCSV": "下载为CSV",
"downloadExcel": "下载为XLSX",
"uploadCSV": "上传CSV",
"downloadCSV": "下载为 CSV",
"downloadExcel": "下载为 XLSX",
"uploadCSV": "上传 CSV",
"import": "导入",
"importMetadata": "导入元数据",
"exportMetadata": "导出元数据",
@ -414,21 +414,21 @@
"showSystemFields": "显示系统字段",
"copyUrl": "复制链接",
"openTab": "打开新标签",
"iFrame": "复制嵌入HTML代码",
"addWebhook": "添加新的webhook.",
"iFrame": "复制嵌入HTML 代码",
"addWebhook": "添加新的 Webhook",
"newToken": "添加新 Token",
"exportZip": "导出为zip格式",
"importZip": "导入zip格式",
"exportZip": "导出为 zip 格式",
"importZip": "导入 zip 格式",
"metaSync": "立即同步",
"settings": "设置",
"previewAs": "预览",
"resetReview": "重置预览",
"testDbConn": "测试数据库链接",
"removeDbFromEnv": "从环境中删除数据库",
"editConnJson": "编辑链接JSON",
"editConnJson": "编辑链接 JSON",
"sponsorUs": "赞助我们",
"sendEmail": "发送邮件",
"addUserToProject": "添加用户到项目",
"addUserToProject": "添加成员到项目",
"getApiSnippet": "生成代码",
"clearCell": "清除单元格内容",
"addFilterGroup": "添加筛选器组",
@ -464,10 +464,10 @@
"light": "它是黑色吗? (^⇧b)"
},
"addTable": "添加新表",
"inviteMore": "邀请更多用户",
"inviteMore": "邀请更多成员",
"toggleNavDraw": "切换导航抽屉",
"reloadApiToken": "重新加载API令牌",
"generateNewApiToken": "生成新的API令牌",
"generateNewApiToken": "生成新的 API 令牌",
"addRole": "添加新角色",
"reloadList": "重新加载列表",
"metaSync": "同步元数据",
@ -539,36 +539,36 @@
"dragDropHide": "在此处拖放字段以隐藏",
"formInput": "输入表单输入标签",
"formHelpText": "添加一些帮助文本",
"onlyCreator": "仅创人可见",
"onlyCreator": "仅创人可见",
"formDesc": "添加表单描述",
"beforeEnablePwd": "使用密码限制访问",
"afterEnablePwd": "访问受密码限制",
"privateLink": "此视图是通过私人链接共享的",
"privateLink": "此视图通过私有链接共享",
"privateLinkAdditionalInfo": "拥有私人链接的人只能看到此视图中可见的单元格",
"afterFormSubmitted": "表提交后",
"afterFormSubmitted": "表提交后",
"apiOptions": "访问项目通过",
"submitAnotherForm": "显示“提交另一个表单”按钮",
"showBlankForm": "5秒后显示空白表格",
"showBlankForm": "5 秒后显示空表单",
"emailForm": "发电子邮件给我",
"showSysFields": "显示系统字段",
"filterAutoApply": "自动应用",
"showMessage": "显示此消息",
"viewNotShared": "当前视图不共享!",
"showAllViews": "显示此表的所有共享视图",
"collabView": "具有编辑权限或更高的合作者可以更改视图配置。",
"lockedView": "没有人可以编辑视图配置,直到它锁。",
"personalView": "只有您可以编辑视图配置。默认情况下,其他合作者的个人视图隐藏。",
"ownerDesc": "可以添加/删除创建者。和完整编辑数据库结构和字段。",
"creatorDesc": "可以完全编辑数据库结构和值。",
"collabView": "具有编辑及更高权限的合作者可以更改视图配置。",
"lockedView": "视图配置被锁。",
"personalView": "只有您可以编辑视图配置,其他合作者的个人视图默认不显示。",
"ownerDesc": "可以添加/删除创始人。能编辑数据库结构和字段。",
"creatorDesc": "可以自由编辑数据库结构和内容。",
"editorDesc": "可以编辑记录但无法更改数据库/字段的结构。",
"commenterDesc": "可以查看和评论记录,但无法编辑任何内容",
"commenterDesc": "可以查看和评论,但无法编辑任何内容",
"viewerDesc": "可以查看记录但无法编辑任何内容",
"addUser": "添加新用户",
"staticRoleInfo": "无法编辑系统定义的角色",
"exportZip": "导出项目数据为 zip 格式并下载。",
"importZip": "导入项目 zip 格式的元数据并重新启动。",
"importText": "通过上传元数据 zip 文件导入 NocoDB 项目",
"metaNoChange": "没有确定更改",
"addUser": "添加新成员",
"staticRoleInfo": "不允许修改系统权限",
"exportZip": "以 zip 格式下载项目元数据。",
"importZip": "导入 zip 格式的项目元数据并重新启动。",
"importText": "通过上传项目元数据 zip 文件导入 NocoDB 项目",
"metaNoChange": "没有发现变化",
"sqlMigration": "将自动创建架构迁移。创建一个表并刷新此页面。",
"dbConnectionStatus": "环境验证",
"dbConnected": "连接成功",
@ -629,7 +629,7 @@
"generatePublicShareableReadonlyBase": "Generate publicly shareable readonly base",
"deleteViewConfirmation": "您确定要删除此视图?",
"deleteTableConfirmation": "您想要删除该表吗?",
"showM2mTables": "Show M2M Tables",
"showM2mTables": "显示中间表",
"deleteKanbanStackConfirmation": "Deleting this stack will also remove the select option `{stackToBeDeleted}` from the `{groupingField}`. The records will move to the uncategorized stack.",
"computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure",
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content.",

2
packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/CustomKnex.ts

@ -548,7 +548,7 @@ knex.QueryBuilder.extend(
knex.QueryBuilder.extend('concat', function (cn: any) {
switch (this?.client?.config?.client) {
case 'pg':
this.select(this.client.raw(`STRING_AGG(?? , ',')`, [cn]));
this.select(this.client.raw(`STRING_AGG(??::character varying , ',')`, [cn]));
break;
case 'mysql':
case 'mysql2':

14
packages/nocodb/src/lib/meta/api/attachmentApis.ts

@ -96,21 +96,25 @@ export async function uploadViaURL(req: Request, res: Response) {
req.body?.map?.(async (urlMeta) => {
const { url, fileName: _fileName } = urlMeta;
const fileName = `${nanoid(6)}${_fileName || url.split('/').pop()}`;
const fileName = `${nanoid(18)}${_fileName || url.split('/').pop()}`;
let attachmentUrl = await (storageAdapter as any).fileCreateByUrl(
slash(path.join(destPath, fileName)),
url
);
let attachmentPath;
// if `attachmentUrl` is null, then it is local attachment
if (!attachmentUrl) {
attachmentUrl = `${(req as any).ncSiteUrl}/download/${filePath.join(
'/'
)}/${fileName}`;
// then store the attachement path only
// url will be constructued in `useAttachmentCell`
attachmentPath = `download/${filePath.join('/')}/${fileName}`;
}
return {
url: attachmentUrl,
...(attachmentUrl ? { url: attachmentUrl } : {}),
...(attachmentPath ? { path: attachmentPath } : {}),
title: fileName,
mimetype: urlMeta.mimetype,
size: urlMeta.size,

Loading…
Cancel
Save