mirror of https://github.com/nocodb/nocodb
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
439 lines
9.7 KiB
439 lines
9.7 KiB
import type { FunctionalComponent, SVGAttributes } from 'vue' |
|
import type { ButtonType, ColumnType, FormulaType, IntegrationType, LinkToAnotherRecordType } from 'nocodb-sdk' |
|
import { ButtonActionsType, RelationTypes, UITypes, LongTextAiMetaProp as _LongTextAiMetaProp } from 'nocodb-sdk' |
|
|
|
export interface UiTypesType { |
|
name: UITypes | string |
|
icon: FunctionalComponent<SVGAttributes, {}, any, {}> | VNode |
|
virtual?: number | boolean |
|
deprecated?: number | boolean |
|
isNew?: number | boolean |
|
} |
|
|
|
export const AIButton = 'AIButton' |
|
|
|
export const AIPrompt = 'AIPrompt' |
|
|
|
export const LongTextAiMetaProp = _LongTextAiMetaProp |
|
|
|
const uiTypes: UiTypesType[] = [ |
|
{ |
|
name: AIButton, |
|
icon: iconMap.cellAiButton, |
|
virtual: 1, |
|
isNew: 1, |
|
deprecated: 0, |
|
}, |
|
{ |
|
name: AIPrompt, |
|
icon: iconMap.cellAi, |
|
isNew: 1, |
|
deprecated: 0, |
|
}, |
|
{ |
|
name: UITypes.Links, |
|
icon: iconMap.cellLinks, |
|
virtual: 1, |
|
}, |
|
{ |
|
name: UITypes.LinkToAnotherRecord, |
|
icon: iconMap.cellLinks, |
|
virtual: 1, |
|
deprecated: 1, |
|
}, |
|
{ |
|
name: UITypes.Lookup, |
|
icon: iconMap.cellLookup, |
|
virtual: 1, |
|
}, |
|
{ |
|
name: UITypes.SingleLineText, |
|
icon: iconMap.cellText, |
|
}, |
|
{ |
|
name: UITypes.LongText, |
|
icon: iconMap.cellLongText, |
|
}, |
|
{ |
|
name: UITypes.Number, |
|
icon: iconMap.cellNumber, |
|
}, |
|
{ |
|
name: UITypes.Decimal, |
|
icon: iconMap.cellDecimal, |
|
}, |
|
{ |
|
name: UITypes.Attachment, |
|
icon: iconMap.cellAttachment, |
|
}, |
|
{ |
|
name: UITypes.Checkbox, |
|
icon: iconMap.cellCheckbox, |
|
}, |
|
{ |
|
name: UITypes.MultiSelect, |
|
icon: iconMap.cellMultiSelect, |
|
}, |
|
{ |
|
name: UITypes.SingleSelect, |
|
icon: iconMap.cellSingleSelect, |
|
}, |
|
{ |
|
name: UITypes.Date, |
|
icon: iconMap.cellDate, |
|
}, |
|
{ |
|
name: UITypes.Year, |
|
icon: iconMap.cellYear, |
|
}, |
|
{ |
|
name: UITypes.Time, |
|
icon: iconMap.cellTime, |
|
}, |
|
{ |
|
name: UITypes.PhoneNumber, |
|
icon: iconMap.cellPhone, |
|
}, |
|
{ |
|
name: UITypes.Email, |
|
icon: iconMap.cellEmail, |
|
}, |
|
{ |
|
name: UITypes.URL, |
|
icon: iconMap.cellUrl, |
|
}, |
|
{ |
|
name: UITypes.Currency, |
|
icon: iconMap.cellCurrency, |
|
}, |
|
{ |
|
name: UITypes.Percent, |
|
icon: iconMap.cellPercent, |
|
}, |
|
{ |
|
name: UITypes.Duration, |
|
icon: iconMap.cellDuration, |
|
}, |
|
{ |
|
name: UITypes.Rating, |
|
icon: iconMap.cellRating, |
|
}, |
|
{ |
|
name: UITypes.Formula, |
|
icon: iconMap.cellFormula, |
|
virtual: 1, |
|
}, |
|
{ |
|
name: UITypes.Rollup, |
|
icon: iconMap.cellRollup, |
|
virtual: 1, |
|
}, |
|
{ |
|
name: UITypes.DateTime, |
|
icon: iconMap.cellDatetime, |
|
}, |
|
{ |
|
name: UITypes.QrCode, |
|
icon: iconMap.cellQrCode, |
|
virtual: 1, |
|
}, |
|
{ |
|
name: UITypes.Barcode, |
|
icon: iconMap.cellBarcode, |
|
virtual: 1, |
|
}, |
|
{ |
|
name: UITypes.Geometry, |
|
icon: iconMap.cellGeometry, |
|
}, |
|
|
|
{ |
|
name: UITypes.GeoData, |
|
icon: iconMap.geoData, |
|
}, |
|
{ |
|
name: UITypes.JSON, |
|
icon: iconMap.cellJson, |
|
}, |
|
{ |
|
name: UITypes.SpecificDBType, |
|
icon: iconMap.cellDb, |
|
}, |
|
{ |
|
name: UITypes.User, |
|
icon: iconMap.cellUser, |
|
}, |
|
{ |
|
name: UITypes.Button, |
|
icon: iconMap.cellButton, |
|
virtual: 1, |
|
}, |
|
{ |
|
name: UITypes.CreatedTime, |
|
icon: iconMap.cellSystemDate, |
|
}, |
|
{ |
|
name: UITypes.LastModifiedTime, |
|
icon: iconMap.cellSystemDate, |
|
}, |
|
{ |
|
name: UITypes.CreatedBy, |
|
icon: iconMap.cellSystemUser, |
|
}, |
|
{ |
|
name: UITypes.LastModifiedBy, |
|
icon: iconMap.cellSystemUser, |
|
}, |
|
] |
|
|
|
const getUIDTIcon = (uidt: UITypes | string) => { |
|
return ( |
|
[ |
|
...uiTypes, |
|
{ |
|
name: UITypes.CreatedTime, |
|
icon: iconMap.cellSystemDate, |
|
}, |
|
{ |
|
name: UITypes.ID, |
|
icon: iconMap.cellSystemKey, |
|
}, |
|
{ |
|
name: UITypes.ForeignKey, |
|
icon: iconMap.cellLinks, |
|
}, |
|
].find((t) => t.name === uidt) || {} |
|
).icon |
|
} |
|
|
|
// treat column as required if `non_null` is true and one of the following is true |
|
// 1. column not having default value |
|
// 2. column is not auto increment |
|
// 3. column is not auto generated |
|
const isColumnRequired = (col?: ColumnType) => col && col.rqd && !isValidValue(col?.cdf) && !col.ai && !col.meta?.ag |
|
|
|
const isVirtualColRequired = (col: ColumnType, columns: ColumnType[]) => |
|
col.uidt === UITypes.LinkToAnotherRecord && |
|
col.colOptions && |
|
(<LinkToAnotherRecordType>col.colOptions).type === RelationTypes.BELONGS_TO && |
|
isColumnRequired(columns.find((c) => c.id === (<LinkToAnotherRecordType>col.colOptions).fk_child_column_id)) |
|
|
|
const isColumnRequiredAndNull = (col: ColumnType, row: Record<string, any>) => { |
|
return isColumnRequired(col) && (row[col.title!] === undefined || row[col.title!] === null) |
|
} |
|
|
|
const getUniqueColumnName = (initName: string, columns: ColumnType[]) => { |
|
let name = initName |
|
let i = 1 |
|
while (columns.find((c) => c.title === name)) { |
|
name = `${initName}_${i}` |
|
i++ |
|
} |
|
return name |
|
} |
|
|
|
const isTypableInputColumn = (colOrUidt: ColumnType | UITypes) => { |
|
let uidt: UITypes |
|
if (typeof colOrUidt === 'object') { |
|
uidt = colOrUidt.uidt as UITypes |
|
} else { |
|
uidt = colOrUidt |
|
} |
|
return [ |
|
UITypes.LongText, |
|
UITypes.SingleLineText, |
|
UITypes.Number, |
|
UITypes.PhoneNumber, |
|
UITypes.Email, |
|
UITypes.Decimal, |
|
UITypes.Currency, |
|
UITypes.Percent, |
|
UITypes.Duration, |
|
UITypes.JSON, |
|
UITypes.URL, |
|
UITypes.SpecificDBType, |
|
].includes(uidt) |
|
} |
|
|
|
const isColumnSupportsGroupBySettings = (colOrUidt: ColumnType) => { |
|
let uidt: UITypes |
|
if (typeof colOrUidt === 'object') { |
|
uidt = colOrUidt.uidt as UITypes |
|
} else { |
|
uidt = colOrUidt |
|
} |
|
|
|
return [UITypes.SingleSelect, UITypes.User, UITypes.CreatedBy, UITypes.Checkbox, UITypes.Rating].includes(uidt) |
|
} |
|
|
|
const isColumnInvalid = ( |
|
col: ColumnType, |
|
aiIntegrations: Partial<IntegrationType>[] = [], |
|
isReadOnly: boolean = false, |
|
): { isInvalid: boolean; tooltip: string } => { |
|
const result = { |
|
isInvalid: false, |
|
tooltip: 'msg.invalidColumnConfiguration', |
|
} |
|
|
|
switch (col.uidt) { |
|
case UITypes.Formula: |
|
result.isInvalid = !!(col.colOptions as FormulaType).error |
|
break |
|
case UITypes.Button: { |
|
const colOptions = col.colOptions as ButtonType |
|
if (colOptions.type === ButtonActionsType.Webhook) { |
|
result.isInvalid = !colOptions.fk_webhook_id |
|
} else if (colOptions.type === ButtonActionsType.Url) { |
|
result.isInvalid = !!colOptions.error |
|
} else if (colOptions.type === ButtonActionsType.Ai) { |
|
result.isInvalid = |
|
!colOptions.fk_integration_id || |
|
(isReadOnly |
|
? false |
|
: !!colOptions.fk_integration_id && !ncIsArrayIncludes(aiIntegrations, colOptions.fk_integration_id, 'id')) |
|
result.tooltip = 'title.aiIntegrationMissing' |
|
} |
|
break |
|
} |
|
case UITypes.LongText: { |
|
if (parseProp(col.meta)[LongTextAiMetaProp]) { |
|
const colOptions = col.colOptions as ButtonType |
|
|
|
result.isInvalid = |
|
!colOptions.fk_integration_id || |
|
(isReadOnly |
|
? false |
|
: !!colOptions.fk_integration_id && !ncIsArrayIncludes(aiIntegrations, colOptions.fk_integration_id, 'id')) |
|
|
|
result.tooltip = 'title.aiIntegrationMissing' |
|
} |
|
break |
|
} |
|
} |
|
|
|
return result |
|
} |
|
|
|
// cater existing v1 cases |
|
const checkboxIconList = [ |
|
{ |
|
checked: 'mdi-check-bold', |
|
unchecked: 'mdi-crop-square', |
|
}, |
|
{ |
|
checked: 'mdi-check-circle-outline', |
|
unchecked: 'mdi-checkbox-blank-circle-outline', |
|
}, |
|
{ |
|
checked: 'mdi-star', |
|
unchecked: 'mdi-star-outline', |
|
}, |
|
{ |
|
checked: 'mdi-heart', |
|
unchecked: 'mdi-heart-outline', |
|
}, |
|
{ |
|
checked: 'mdi-moon-full', |
|
unchecked: 'mdi-moon-new', |
|
}, |
|
{ |
|
checked: 'mdi-thumb-up', |
|
unchecked: 'mdi-thumb-up-outline', |
|
}, |
|
{ |
|
checked: 'mdi-flag', |
|
unchecked: 'mdi-flag-outline', |
|
}, |
|
] |
|
|
|
const ratingIconList = [ |
|
{ |
|
full: 'mdi-star', |
|
empty: 'mdi-star-outline', |
|
}, |
|
{ |
|
full: 'mdi-heart', |
|
empty: 'mdi-heart-outline', |
|
}, |
|
{ |
|
full: 'mdi-moon-full', |
|
empty: 'mdi-moon-new', |
|
}, |
|
{ |
|
full: 'mdi-thumb-up', |
|
empty: 'mdi-thumb-up-outline', |
|
}, |
|
{ |
|
full: 'mdi-flag', |
|
empty: 'mdi-flag-outline', |
|
}, |
|
] |
|
|
|
function extractCheckboxIcon(meta: string | Record<string, any> = null) { |
|
const parsedMeta = parseProp(meta) |
|
|
|
const icon = { |
|
checked: 'mdi-check-circle-outline', |
|
unchecked: 'mdi-checkbox-blank-circle-outline', |
|
} |
|
|
|
if (parsedMeta.icon) { |
|
icon.checked = parsedMeta.icon.checked || icon.checked |
|
icon.unchecked = parsedMeta.icon.unchecked || icon.unchecked |
|
} else if (typeof parsedMeta.iconIdx === 'number' && checkboxIconList[parsedMeta.iconIdx]) { |
|
icon.checked = checkboxIconList[parsedMeta.iconIdx].checked |
|
icon.unchecked = checkboxIconList[parsedMeta.iconIdx].unchecked |
|
} |
|
return icon |
|
} |
|
|
|
function extractRatingIcon(meta: string | Record<string, any> = null) { |
|
const parsedMeta = parseProp(meta) |
|
|
|
const icon = { |
|
full: 'mdi-star', |
|
empty: 'mdi-star-outline', |
|
} |
|
|
|
if (parsedMeta.icon) { |
|
icon.full = parsedMeta.icon.full || icon.full |
|
icon.empty = parsedMeta.icon.empty || icon.empty |
|
} else if (typeof parsedMeta.iconIdx === 'number' && ratingIconList[parsedMeta.iconIdx]) { |
|
icon.full = ratingIconList[parsedMeta.iconIdx].full |
|
icon.empty = ratingIconList[parsedMeta.iconIdx].empty |
|
} |
|
return icon |
|
} |
|
|
|
const formViewHiddenColTypes = [ |
|
UITypes.Rollup, |
|
UITypes.Lookup, |
|
UITypes.Formula, |
|
UITypes.QrCode, |
|
UITypes.Barcode, |
|
UITypes.Button, |
|
UITypes.SpecificDBType, |
|
UITypes.CreatedTime, |
|
UITypes.LastModifiedTime, |
|
UITypes.CreatedBy, |
|
UITypes.LastModifiedBy, |
|
AIButton, |
|
] |
|
|
|
export { |
|
uiTypes, |
|
isTypableInputColumn, |
|
isColumnSupportsGroupBySettings, |
|
getUIDTIcon, |
|
isColumnInvalid, |
|
getUniqueColumnName, |
|
isColumnRequiredAndNull, |
|
isColumnRequired, |
|
isVirtualColRequired, |
|
checkboxIconList, |
|
ratingIconList, |
|
extractCheckboxIcon, |
|
extractRatingIcon, |
|
formViewHiddenColTypes, |
|
}
|
|
|