diff --git a/charts/nocodb/templates/pvc.yaml b/charts/nocodb/templates/pvc.yaml index 67656c01d1..092a1b0439 100644 --- a/charts/nocodb/templates/pvc.yaml +++ b/charts/nocodb/templates/pvc.yaml @@ -5,10 +5,10 @@ metadata: labels: {{- include "nocodb.selectorLabels" . | nindent 8 }} spec: - accessModes: - - ReadWriteMany resources: requests: storage: {{ .Values.storage.size }} storageClassName: {{ .Values.storage.storageClassName }} + accessModes: + {{- default (toYaml .Values.storage.accessModes) "- ReadWriteMany" | nindent 4 }} volumeMode: Filesystem diff --git a/packages/nc-gui/components.d.ts b/packages/nc-gui/components.d.ts index e3914200e0..b08a5350cc 100644 --- a/packages/nc-gui/components.d.ts +++ b/packages/nc-gui/components.d.ts @@ -89,6 +89,7 @@ declare module '@vue/runtime-core' { IcTwotoneWidthNormal: typeof import('~icons/ic/twotone-width-normal')['default'] LogosGoogleGmail: typeof import('~icons/logos/google-gmail')['default'] LogosMysqlIcon: typeof import('~icons/logos/mysql-icon')['default'] + LogosOracle: typeof import('~icons/logos/oracle')['default'] LogosPostgresql: typeof import('~icons/logos/postgresql')['default'] LogosRedditIcon: typeof import('~icons/logos/reddit-icon')['default'] LogosSnowflakeIcon: typeof import('~icons/logos/snowflake-icon')['default'] diff --git a/packages/nc-gui/components/cell/Checkbox.vue b/packages/nc-gui/components/cell/Checkbox.vue index 1de2de9d79..f482d24511 100644 --- a/packages/nc-gui/components/cell/Checkbox.vue +++ b/packages/nc-gui/components/cell/Checkbox.vue @@ -89,7 +89,7 @@ useSelectedCellKeyupListener(active, (e) => { diff --git a/packages/nc-gui/components/dlg/KeyboardShortcuts.vue b/packages/nc-gui/components/dlg/KeyboardShortcuts.vue index 8079cd6bf8..d3cf53b122 100644 --- a/packages/nc-gui/components/dlg/KeyboardShortcuts.vue +++ b/packages/nc-gui/components/dlg/KeyboardShortcuts.vue @@ -15,6 +15,9 @@ const dialogShow = computed({ const renderCmdOrCtrlKey = () => { return isMac() ? '⌘' : 'CTRL' } +const renderAltOrOptlKey = () => { + return isMac() ? '⌥' : 'ALT' +} const shortcutList = [ { @@ -197,6 +200,22 @@ const shortcutList = [ keys: [renderCmdOrCtrlKey(), 'Enter'], behaviour: 'Save current expanded form item', }, + { + keys: [renderAltOrOptlKey(), '→'], + behaviour: 'Switch to next row', + }, + { + keys: [renderAltOrOptlKey(), '←'], + behaviour: 'Switch to previous row', + }, + { + keys: [renderAltOrOptlKey(), 'S'], + behaviour: 'Save current expanded form item', + }, + { + keys: [renderAltOrOptlKey(), 'N'], + behaviour: 'Create a new row', + }, ], }, ] diff --git a/packages/nc-gui/components/general/ShortcutLabel.vue b/packages/nc-gui/components/general/ShortcutLabel.vue new file mode 100644 index 0000000000..2e861cd948 --- /dev/null +++ b/packages/nc-gui/components/general/ShortcutLabel.vue @@ -0,0 +1,57 @@ + + + + + + {{ getLabel(key) }} + + + + + diff --git a/packages/nc-gui/components/smartsheet/Cell.vue b/packages/nc-gui/components/smartsheet/Cell.vue index be23b134d5..f39454f7f4 100644 --- a/packages/nc-gui/components/smartsheet/Cell.vue +++ b/packages/nc-gui/components/smartsheet/Cell.vue @@ -139,6 +139,15 @@ const isNumericField = computed(() => { isDuration(column.value) ) }) + +// disable contexxtmenu event propagation when cell is in +// editable state and typable (e.g. text area) +// this is to prevent the custom grid view context menu from opening +const onContextmenu = (e: MouseEvent) => { + if (props.editEnabled && isTypableInputColumn(column.value)) { + e.stopPropagation() + } +} @@ -151,6 +160,7 @@ const isNumericField = computed(() => { ]" @keydown.enter.exact="syncAndNavigate(NavigateDir.NEXT, $event)" @keydown.shift.enter.exact="syncAndNavigate(NavigateDir.PREV, $event)" + @contextmenu="onContextmenu" > diff --git a/packages/nc-gui/components/smartsheet/Grid.vue b/packages/nc-gui/components/smartsheet/Grid.vue index d1ede98050..d358804fa9 100644 --- a/packages/nc-gui/components/smartsheet/Grid.vue +++ b/packages/nc-gui/components/smartsheet/Grid.vue @@ -118,6 +118,7 @@ const { selectedAllRecords, removeRowIfNew, navigateToSiblingRow, + getExpandedRowIndex, } = useViewData(meta, view, xWhere) const { getMeta } = useMetas() @@ -980,6 +981,8 @@ const closeAddColumnDropdown = () => { :row-id="routeQuery.rowId" :view="view" show-next-prev-icons + :first-row="getExpandedRowIndex() === 0" + :last-row="getExpandedRowIndex() === data.length - 1" @next="navigateToSiblingRow(NavigateDir.NEXT)" @prev="navigateToSiblingRow(NavigateDir.PREV)" /> @@ -1056,7 +1059,7 @@ const closeAddColumnDropdown = () => { position: sticky !important; left: 80px; z-index: 5; - @apply border-r-1 border-r-gray-300; + @apply border-r-2 border-r-gray-300; } tbody td:nth-child(2) { @@ -1064,7 +1067,7 @@ const closeAddColumnDropdown = () => { left: 80px; z-index: 4; background: white; - @apply shadow-lg border-r-1 border-r-gray-300; + @apply border-r-2 border-r-gray-300; } } diff --git a/packages/nc-gui/components/smartsheet/expanded-form/Header.vue b/packages/nc-gui/components/smartsheet/expanded-form/Header.vue index 80ed48f93d..b78e093089 100644 --- a/packages/nc-gui/components/smartsheet/expanded-form/Header.vue +++ b/packages/nc-gui/components/smartsheet/expanded-form/Header.vue @@ -18,7 +18,7 @@ const route = useRoute() const { meta, isSqlView } = useSmartsheetStoreOrThrow() -const { commentsDrawer, displayValue, primaryKey, save: _save, loadRow } = useExpandedFormStoreOrThrow() +const { commentsDrawer, displayValue, primaryKey, save: _save, loadRow, saveRowAndStay } = useExpandedFormStoreOrThrow() const { isNew, syncLTARRefs, state } = useSmartsheetRowStoreOrThrow() @@ -26,8 +26,6 @@ const { isUIAllowed } = useUIPermission() const reloadTrigger = inject(ReloadRowDataHookInj, createEventHook()) -const saveRowAndStay = ref(0) - const save = async () => { if (isNew.value) { const data = await _save(state.value) @@ -103,17 +101,6 @@ const onConfirmDeleteRowClick = async () => { - - - - {{ $t('general.reload') }} - - - @@ -139,32 +126,6 @@ const onConfirmDeleteRowClick = async () => { /> - - - - {{ $t('activity.duplicateRow') }} - - - - - - - - {{ $t('activity.deleteRow') }} - - - - @@ -194,17 +155,39 @@ const onConfirmDeleteRowClick = async () => { - - - - {{ $t('general.close') }} + + + + + + + + {{ $t('general.reload') }} + + + + + + {{ $t('activity.duplicateRow') }} + + + + + + {{ $t('activity.deleteRow') }} + + + + + + {{ $t('general.close') }} + + + - - - + Are you sure you want to delete this row? diff --git a/packages/nc-gui/components/smartsheet/expanded-form/index.vue b/packages/nc-gui/components/smartsheet/expanded-form/index.vue index 6ad8dd0b84..35cb7b852f 100644 --- a/packages/nc-gui/components/smartsheet/expanded-form/index.vue +++ b/packages/nc-gui/components/smartsheet/expanded-form/index.vue @@ -22,6 +22,7 @@ import { useVModel, watch, } from '#imports' +import { useActiveKeyupListener } from '~/composables/useSelectedCellKeyupListener' import type { Row } from '~/lib' interface Props { @@ -34,12 +35,16 @@ interface Props { rowId?: string view?: ViewType showNextPrevIcons?: boolean + firstRow?: boolean + lastRow?: boolean } const props = defineProps() const emits = defineEmits(['update:modelValue', 'cancel', 'next', 'prev']) +const key = ref(0) + const { t } = useI18n() const row = ref(props.row) @@ -64,7 +69,16 @@ const isKanban = inject(IsKanbanInj, ref(false)) provide(MetaInj, meta) -const { commentsDrawer, changedColumns, state: rowState, isNew, loadRow } = useProvideExpandedFormStore(meta, row) +const { + commentsDrawer, + changedColumns, + state: rowState, + isNew, + loadRow, + saveRowAndStay, + syncLTARRefs, + save, +} = useProvideExpandedFormStore(meta, row) const duplicatingRowInProgress = ref(false) @@ -126,6 +140,25 @@ const onDuplicateRow = () => { }, 500) } +const onNext = async () => { + if (changedColumns.value.size > 0) { + await Modal.confirm({ + title: 'Do you want to save the changes?', + okText: 'Save', + cancelText: 'Discard', + onOk: async () => { + await save() + emits('next') + }, + onCancel: () => { + emits('next') + }, + }) + } else { + emits('next') + } +} + const reloadParentRowHook = inject(ReloadRowDataHookInj, createEventHook()) // override reload trigger and use it to reload grid and the form itself @@ -152,6 +185,92 @@ const cellWrapperEl = ref() onMounted(() => { setTimeout(() => (cellWrapperEl.value?.querySelector('input,select,textarea') as HTMLInputElement)?.focus()) }) + +const addNewRow = () => { + setTimeout(async () => { + row.value = { + row: {}, + oldRow: {}, + rowMeta: { new: true }, + } + rowState.value = {} + key.value++ + isExpanded.value = true + }, 500) +} + +// attach keyboard listeners to switch between rows +// using alt + left/right arrow keys +useActiveKeyupListener( + isExpanded, + async (e: KeyboardEvent) => { + if (!e.altKey) return + if (e.key === 'ArrowLeft') { + e.stopPropagation() + emits('prev') + } else if (e.key === 'ArrowRight') { + e.stopPropagation() + onNext() + } + // on alt + s save record + else if (e.code === 'KeyS') { + // remove focus from the active input if any + document.activeElement?.blur() + + e.stopPropagation() + + if (isNew.value) { + const data = await save(rowState.value) + await syncLTARRefs(data) + reloadHook?.trigger(null) + } else { + await save() + reloadHook?.trigger(null) + } + if (!saveRowAndStay.value) { + onClose() + } + // on alt + n create new record + } else if (e.code === 'KeyN') { + // remove focus from the active input if any to avoid unwanted input + ;(document.activeElement as HTMLInputElement)?.blur?.() + + if (changedColumns.value.size > 0) { + await Modal.confirm({ + title: 'Do you want to save the changes?', + okText: 'Save', + cancelText: 'Discard', + onOk: async () => { + await save() + reloadHook?.trigger(null) + addNewRow() + }, + onCancel: () => { + addNewRow() + }, + }) + } else if (isNew.value) { + await Modal.confirm({ + title: 'Do you want to save the record?', + okText: 'Save', + cancelText: 'Discard', + onOk: async () => { + const data = await save(rowState.value) + await syncLTARRefs(data) + reloadHook?.trigger(null) + addNewRow() + }, + onCancel: () => { + addNewRow() + }, + }) + } else { + addNewRow() + } + } + }, + { immediate: true }, +) @@ -35,7 +40,7 @@ async function editHook(hook: Record) { - + diff --git a/packages/nc-gui/components/webhook/Editor.vue b/packages/nc-gui/components/webhook/Editor.vue index 98a7cf8537..37cf556cc4 100644 --- a/packages/nc-gui/components/webhook/Editor.vue +++ b/packages/nc-gui/components/webhook/Editor.vue @@ -225,7 +225,7 @@ function onNotTypeChange(reset = false) { } if (hook.notification.type === 'Slack') { - slackChannels.value = (apps.value && apps.value.Slack && apps.Slack.parsedInput) || [] + slackChannels.value = (apps.value && apps.value.Slack && apps.value.Slack.parsedInput) || [] } if (hook.notification.type === 'Microsoft Teams') { @@ -651,6 +651,7 @@ onMounted(loadPluginList) ([]) const comment = ref('') - const commentsDrawer = ref(false) + const commentsDrawer = ref(true) + + const saveRowAndStay = ref(0) const changedColumns = ref(new Set()) @@ -243,6 +245,7 @@ const [useProvideExpandedFormStore, useExpandedFormStore] = useInjectionState((m changedColumns, loadRow, primaryKey, + saveRowAndStay, } }, 'expanded-form-store') diff --git a/packages/nc-gui/composables/useSelectedCellKeyupListener/index.ts b/packages/nc-gui/composables/useSelectedCellKeyupListener/index.ts index da1eb4fa0a..b6e5d8a78c 100644 --- a/packages/nc-gui/composables/useSelectedCellKeyupListener/index.ts +++ b/packages/nc-gui/composables/useSelectedCellKeyupListener/index.ts @@ -1,15 +1,15 @@ import { isClient } from '@vueuse/core' -import type { Ref } from 'vue' +import type { ComputedRef, Ref } from 'vue' function useSelectedCellKeyupListener( - selected: Ref, + selected: Ref | ComputedRef, handler: (e: KeyboardEvent) => void, { immediate = false }: { immediate?: boolean } = {}, ) { if (isClient) { watch( selected, - (nextVal: boolean, _: boolean, cleanup) => { + (nextVal: boolean | undefined, _: boolean | undefined, cleanup) => { // bind listener when `selected` is truthy if (nextVal) { document.addEventListener('keydown', handler, true) diff --git a/packages/nc-gui/composables/useViewData.ts b/packages/nc-gui/composables/useViewData.ts index 2ff504dbe2..75f6d79189 100644 --- a/packages/nc-gui/composables/useViewData.ts +++ b/packages/nc-gui/composables/useViewData.ts @@ -477,15 +477,24 @@ export function useViewData( } } - const navigateToSiblingRow = async (dir: NavigateDir) => { - // get current expanded row index - const expandedRowIndex = formattedData.value.findIndex( + // get current expanded row index + function getExpandedRowIndex() { + return formattedData.value.findIndex( (row: Row) => routeQuery.rowId === extractPkFromRow(row.row, meta.value?.columns as ColumnType[]), ) + } + + const navigateToSiblingRow = async (dir: NavigateDir) => { + const expandedRowIndex = getExpandedRowIndex() // calculate next row index based on direction let siblingRowIndex = expandedRowIndex + (dir === NavigateDir.NEXT ? 1 : -1) + // if unsaved row skip it + while (formattedData.value[siblingRowIndex]?.rowMeta?.new) { + siblingRowIndex = siblingRowIndex + (dir === NavigateDir.NEXT ? 1 : -1) + } + const currentPage = paginationData?.value?.page || 1 // if next row index is less than 0, go to previous page and point to last element @@ -547,5 +556,6 @@ export function useViewData( removeLastEmptyRow, removeRowIfNew, navigateToSiblingRow, + getExpandedRowIndex, } } diff --git a/packages/nc-gui/composables/useViewFilters.ts b/packages/nc-gui/composables/useViewFilters.ts index baa276b366..d3fc0da851 100644 --- a/packages/nc-gui/composables/useViewFilters.ts +++ b/packages/nc-gui/composables/useViewFilters.ts @@ -140,6 +140,25 @@ export function useViewFilters( return isNullOrEmptyOp ? projectMeta.value.showNullAndEmptyInFilter : true } + const isComparisonSubOpAllowed = ( + filter: FilterType, + compOp: { + text: string + value: string + ignoreVal?: boolean + includedTypes?: UITypes[] + excludedTypes?: UITypes[] + }, + ) => { + if (compOp.includedTypes) { + // include allowed values only if selected column type matches + return filter.fk_column_id && compOp.includedTypes.includes(types.value[filter.fk_column_id]) + } else if (compOp.excludedTypes) { + // include not allowed values only if selected column type not matches + return filter.fk_column_id && !compOp.excludedTypes.includes(types.value[filter.fk_column_id]) + } + } + const placeholderFilter = (): Filter => { return { comparison_op: comparisonOpList(options.value?.[0].uidt as UITypes).filter((compOp) => @@ -327,5 +346,6 @@ export function useViewFilters( addFilterGroup, saveOrUpdateDebounced, isComparisonOpAllowed, + isComparisonSubOpAllowed, } } diff --git a/packages/nc-gui/lang/ar.json b/packages/nc-gui/lang/ar.json index 12bf7e1643..26c204e25b 100644 --- a/packages/nc-gui/lang/ar.json +++ b/packages/nc-gui/lang/ar.json @@ -235,6 +235,7 @@ "action": "إجراء", "actions": "إجراءات", "operation": "عملية", + "operationSub": "Sub Operation", "operationType": "نوع العملية", "operationSubType": "نوع العملية الفرعية", "description": "وصف", diff --git a/packages/nc-gui/lang/bn_IN.json b/packages/nc-gui/lang/bn_IN.json index 0076d7f265..f33c7f131c 100644 --- a/packages/nc-gui/lang/bn_IN.json +++ b/packages/nc-gui/lang/bn_IN.json @@ -235,6 +235,7 @@ "action": "কর্ম", "actions": "ক্রিয়া", "operation": "অপারেশন", + "operationSub": "Sub Operation", "operationType": "অপারেশন টাইপ", "operationSubType": "অপারেশন সাব-টাইপ", "description": "বর্ণনা", diff --git a/packages/nc-gui/lang/cs.json b/packages/nc-gui/lang/cs.json index bbddc339ee..9e37208137 100644 --- a/packages/nc-gui/lang/cs.json +++ b/packages/nc-gui/lang/cs.json @@ -235,6 +235,7 @@ "action": "Akce", "actions": "Akce", "operation": "Operace", + "operationSub": "Sub Operation", "operationType": "Typ operace", "operationSubType": "Podtyp operace", "description": "Popis", diff --git a/packages/nc-gui/lang/da.json b/packages/nc-gui/lang/da.json index 5e6e82e416..ff663368a2 100644 --- a/packages/nc-gui/lang/da.json +++ b/packages/nc-gui/lang/da.json @@ -1,31 +1,31 @@ { "general": { - "home": "Hjem", - "load": "belastning", - "open": "Åben", - "close": "Tæt", + "home": "Forside", + "load": "Indlæs", + "open": "Åbn", + "close": "Luk", "yes": "Ja", - "no": "Ingen", + "no": "Nej", "ok": "Okay", "and": "Og", "or": "Eller", - "add": "Tilføje", - "edit": "Redigere", - "remove": "Fjerne", - "save": "Gemme", - "cancel": "Afbestille", + "add": "Tilføj", + "edit": "Redigér", + "remove": "Fjern", + "save": "Gem", + "cancel": "Fortryd", "submit": "Indsend", - "create": "skab", + "create": "Opret", "duplicate": "Duplikat", - "insert": "Indsættes", - "delete": "Delete.", - "update": "UPDATE.", + "insert": "Indsæt", + "delete": "Slet", + "update": "Opdatér", "rename": "Omdøb", - "reload": "Genindlæsning", + "reload": "Genindlæs", "reset": "Nulstil", - "install": "Installere", - "show": "At vise", - "hide": "Skjule", + "install": "Installer", + "show": "Vis", + "hide": "Skjul", "showAll": "Vis alt", "hideAll": "Gem alt", "showMore": "Vis mere", @@ -75,7 +75,7 @@ "hideField": "Skjul felt", "sortAsc": "Sortere stigende", "sortDesc": "Sortere nedadgående", - "geoDataField": "GeoData Field" + "geoDataField": "GeoData-felt" }, "objects": { "project": "Projekt", @@ -92,15 +92,15 @@ "records": "Optegnelser.", "webhook": "WebHook.", "webhooks": "Webhooks.", - "view": "Udsigt", - "views": "Visninger.", + "view": "Visning", + "views": "Visninger", "viewType": { - "grid": "Grid.", + "grid": "Grid", "gallery": "Galleri", "form": "Formular", "kanban": "Kanban.", "calendar": "Kalender", - "map": "Map" + "map": "Kort" }, "user": "Bruger", "users": "Brugere", @@ -209,7 +209,7 @@ "advancedSettings": "Avancerede indstillinger", "codeSnippet": "Kodeuddrag", "keyboardShortcut": "Tastaturgenveje", - "generateRandomName": "Generate Random Name" + "generateRandomName": "Generér Tilfældigt Navn" }, "labels": { "createdBy": "Oprettet af", @@ -217,7 +217,7 @@ "projName": "Projekt navn", "tableName": "Tabelnavn.", "viewName": "Se navn", - "viewLink": "Se Link.", + "viewLink": "Vis Link", "columnName": "Kolonne navn", "columnType": "Kolonne type", "roleName": "Rolle navn", @@ -235,6 +235,7 @@ "action": "Handling", "actions": "Handlinger", "operation": "Operation", + "operationSub": "Underordnet operation", "operationType": "Driftstype", "operationSubType": "Drift Undertype", "description": "Beskrivelse", @@ -256,7 +257,7 @@ "barcodeFormat": "Stregkodeformat", "qrCodeValueTooLong": "For mange tegn til en QR-kode", "barcodeValueTooLong": "For mange tegn til en stregkode", - "yourLocation": "Your Location", + "yourLocation": "Din Placering", "lng": "Lng", "lat": "Lat", "aggregateFunction": "Aggregate Function.", @@ -282,8 +283,8 @@ }, "docReference": "Dokumentreference.", "selectUserRole": "Vælg brugerrolle", - "childTable": "Børnebord", - "childColumn": "Barn kolonne", + "childTable": "Undertabel", + "childColumn": "Underkolonner", "linkToAnotherRecord": "Link til en anden post", "onUpdate": "På opdatering", "onDelete": "På Delete.", @@ -378,36 +379,36 @@ "reloadRoles": "Genindlæs roller", "nextPage": "Næste side", "prevPage": "Forrige side", - "nextRecord": "Næste rekord.", - "previousRecord": "Tidligere rekord.", + "nextRecord": "Næste post", + "previousRecord": "Forrige post", "copyApiURL": "COPY API URL.", - "createTable": "Tabel Create.", - "refreshTable": "Tabeller opdatere", - "renameTable": "Bord omdøb", - "deleteTable": "TABEL DELETE.", + "createTable": "Opret tabel", + "refreshTable": "Genopfrisk Tabeller", + "renameTable": "Omdøb Tabel", + "deleteTable": "Slet Tabel", "addField": "Tilføj nyt felt til denne tabel", - "setDisplay": "Set as Display value", - "addRow": "Tilføj ny række", - "saveRow": "Gem ro", + "setDisplay": "Sæt som visningsværdi", + "addRow": "Tilføj ny post", + "saveRow": "Gem række", "saveAndExit": "Gem og afslutning", "saveAndStay": "Gem og bliv", "insertRow": "Indsæt ny række", - "deleteRow": "DELETE ROW.", - "duplicateRow": "Duplicate Row", + "deleteRow": "Slet Række", + "duplicateRow": "Dupliker Række", "deleteSelectedRow": "Slet de valgte rækker", "importExcel": "Import Excel.", "importCSV": "Import CSV.", "downloadCSV": "Download som CSV.", "downloadExcel": "Download som XLSX", "uploadCSV": "Upload CSV.", - "import": "Importere", + "import": "Import", "importMetadata": "Import metadata.", "exportMetadata": "Eksport metadata.", "clearMetadata": "Klare metadata.", "exportToFile": "Eksporter til filer", "changePwd": "Skift kodeord", "createView": "Opret en visning", - "shareView": "Del View", + "shareView": "Del Visning", "listSharedView": "Shared View List.", "ListView": "Visninger List", "copyView": "Kopi visning", @@ -428,23 +429,23 @@ "importZip": "Import Zip.", "metaSync": "Synkroniser nu", "settings": "Indstillinger.", - "previewAs": "Forhåndsvisning så", - "resetReview": "Nulstil preview.", - "testDbConn": "Test Database Connection.", + "previewAs": "Forhåndsvisning som", + "resetReview": "Nulstil forhåndsvisning", + "testDbConn": "Test Database Forbindelse", "removeDbFromEnv": "Fjern databasen fra miljøet", "editConnJson": "Rediger forbindelse JSON", - "sponsorUs": "Sponsor os", + "sponsorUs": "Sponsorer os", "sendEmail": "SEND E-MAIL", "addUserToProject": "Tilføj bruger til projekt", "getApiSnippet": "Hent API-snippet", - "clearCell": "Klar celle", + "clearCell": "Ryd celle", "addFilterGroup": "Tilføj filtergruppe", "linkRecord": "Link record", "addNewRecord": "Tilføj ny post", "useConnectionUrl": "Brug forbindelses-URL", "toggleCommentsDraw": "Toggle kommentarer tegne", "expandRecord": "Udvid optegnelse", - "deleteRecord": "Slet registrering", + "deleteRecord": "Slet Post", "erd": { "showColumns": "Vis kolonner", "showPkAndFk": "Vis primære og fremmede nøgler", @@ -460,8 +461,8 @@ "addOrEditStack": "Tilføj / Rediger stak" }, "map": { - "mappedBy": "Mapped By", - "chooseMappingField": "Choose a Mapping Field" + "mappedBy": "Kortlagt af", + "chooseMappingField": "Vælg et kortlægningsfelt" } }, "tooltip": { @@ -529,9 +530,9 @@ "orgViewer": "Seeren har ikke lov til at oprette nye projekter, men kan få adgang til alle inviterede projekter." }, "map": { - "overLimit": "You're over the limit.", - "closeLimit": "You're getting close to the limit.", - "limitNumber": "The limit of markers shown in a Map View is 1000 records." + "overLimit": "Du er over grænsen.", + "closeLimit": "Du nærmer dig grænsen.", + "limitNumber": "Grænsen for antallet af markeringer, der vises i en kortvisning, er 1000 poster." }, "footerInfo": "Rækker per side", "upload": "Vælg fil for at uploade", @@ -615,7 +616,7 @@ "gallery": "Tilføj Gallery View.", "form": "Tilføj formularvisning", "kanban": "Tilføj Kanban View.", - "map": "Add Map View", + "map": "Tilføj Kortvisning", "calendar": "Tilføj kalendervisning" }, "tablesMetadataInSync": "Tabeller Metadata er synkroniseret", @@ -647,11 +648,11 @@ "deleteViewConfirmation": "Er du sikker på, at du vil slette denne visning?", "deleteTableConfirmation": "Ønsker du at slette tabellen", "showM2mTables": "Vis M2M-tabeller", - "showM2mTablesDesc": "Many-to-many relation is supported via a junction table & is hidden by default. Enable this option to list all such tables along with existing tables.", - "showNullInCells": "Show NULL in Cells", + "showM2mTablesDesc": "Mange-til-mange-relationer understøttes via en sammenknytnings-tabel (junction table) og er skjult som standard. Aktiver denne indstilling for at få vist alle sådanne tabeller sammen med eksisterende tabeller.", + "showNullInCells": "Vis NULL i celler", "showNullInCellsDesc": "Display 'NULL' tag in cells holding NULL value. This helps differentiate against cells holding EMPTY string.", - "showNullAndEmptyInFilter": "Show NULL and EMPTY in Filter", - "showNullAndEmptyInFilterDesc": "Enable 'additional' filters to differentiate fields containing NULL & Empty Strings. Default support for Blank treats both NULL & Empty strings alike.", + "showNullAndEmptyInFilter": "Vis NULL og EMPTY i Filter", + "showNullAndEmptyInFilterDesc": "Aktiver \"yderligere\" filtre for at skelne mellem felter, der indeholder NULL og tomme strenge. Standardunderstøttelse for Blank behandler både NULL- og tomme strenge ens.", "deleteKanbanStackConfirmation": "Hvis du sletter denne stak, fjernes også valgmuligheden `{stackToBeDeleted}` fra `{groupingField}`. Posterne vil blive flyttet til stakken \"uncategorized\".", "computedFieldEditWarning": "Beregnet felt: indholdet er skrivebeskyttet. Brug kolonne-redigeringsmenuen til at omkonfigurere", "computedFieldDeleteWarning": "Beregnet felt: indholdet er skrivebeskyttet. Det er ikke muligt at slette indholdet.", @@ -706,7 +707,7 @@ "nameShouldStartWithAnAlphabetOr_": "Navnet skal starte med et alfabet eller _", "followingCharactersAreNotAllowed": "Følgende tegn er ikke tilladt", "columnNameRequired": "Kolonnens navn er påkrævet", - "columnNameExceedsCharacters": "The length of column name exceeds the max {value} characters", + "columnNameExceedsCharacters": "Længden af kolonnenavnet overstiger maks. {value} tegn", "projectNameExceeds50Characters": "Projektnavnet overstiger 50 tegn", "projectNameCannotStartWithSpace": "Projektnavnet kan ikke begynde med et mellemrum", "requiredField": "Obligatorisk felt", @@ -739,7 +740,7 @@ }, "success": { "columnDuplicated": "Kolonne duplikeret med succes", - "rowDuplicatedWithoutSavedYet": "Row duplicated (not saved)", + "rowDuplicatedWithoutSavedYet": "Række duplikeret (ikke gemt)", "updatedUIACL": "Opdateret UI ACL for tabeller med succes", "pluginUninstalled": "Plugin afinstalleret med succes", "pluginSettingsSaved": "Plugin-indstillingerne er gemt med succes", diff --git a/packages/nc-gui/lang/de.json b/packages/nc-gui/lang/de.json index f7b7de89da..7755573d83 100644 --- a/packages/nc-gui/lang/de.json +++ b/packages/nc-gui/lang/de.json @@ -100,7 +100,7 @@ "form": "Formular", "kanban": "Kanban", "calendar": "Kalender", - "map": "Karte" + "map": "Map" }, "user": "Nutzer", "users": "Benutzer", @@ -235,6 +235,7 @@ "action": "Aktion", "actions": "Aktionen", "operation": "Vorgang", + "operationSub": "Sub Operation", "operationType": "Vorgangstyp", "operationSubType": "Vorgangsuntertyp", "description": "Beschreibung", diff --git a/packages/nc-gui/lang/en.json b/packages/nc-gui/lang/en.json index 6617006c05..cdc9492167 100644 --- a/packages/nc-gui/lang/en.json +++ b/packages/nc-gui/lang/en.json @@ -236,6 +236,7 @@ "action": "Action", "actions": "Actions", "operation": "Operation", + "operationSub": "Sub Operation", "operationType": "Operation type", "operationSubType": "Operation sub-type", "description": "Description", diff --git a/packages/nc-gui/lang/es.json b/packages/nc-gui/lang/es.json index ade0869efe..8083d12c77 100644 --- a/packages/nc-gui/lang/es.json +++ b/packages/nc-gui/lang/es.json @@ -235,6 +235,7 @@ "action": "Acción", "actions": "Acciones", "operation": "Operación", + "operationSub": "Sub Operation", "operationType": "Tipo de operación", "operationSubType": "Sub-tipo de operación", "description": "Descripción", diff --git a/packages/nc-gui/lang/eu.json b/packages/nc-gui/lang/eu.json index 225443c97e..5c07152283 100644 --- a/packages/nc-gui/lang/eu.json +++ b/packages/nc-gui/lang/eu.json @@ -235,6 +235,7 @@ "action": "Ekintza", "actions": "Ekintzak", "operation": "Operation", + "operationSub": "Sub Operation", "operationType": "Operation type", "operationSubType": "Operation sub-type", "description": "Deskribapena", diff --git a/packages/nc-gui/lang/fa.json b/packages/nc-gui/lang/fa.json index 143ebc22da..9d0f71daf5 100644 --- a/packages/nc-gui/lang/fa.json +++ b/packages/nc-gui/lang/fa.json @@ -235,6 +235,7 @@ "action": "اقدام", "actions": "اقدامات", "operation": "عملیات", + "operationSub": "Sub Operation", "operationType": "نوع عملیات", "operationSubType": "زیرگونه عملیات", "description": "شرح", diff --git a/packages/nc-gui/lang/fi.json b/packages/nc-gui/lang/fi.json index d9d6af711b..df9f79d663 100644 --- a/packages/nc-gui/lang/fi.json +++ b/packages/nc-gui/lang/fi.json @@ -235,6 +235,7 @@ "action": "Toiminta", "actions": "Toiminnot", "operation": "Operaatio", + "operationSub": "Sub Operation", "operationType": "Käyttötyyppi", "operationSubType": "Käyttö Alatyyppi", "description": "Kuvaus", diff --git a/packages/nc-gui/lang/fr.json b/packages/nc-gui/lang/fr.json index 8607928f95..3fc72b3c50 100644 --- a/packages/nc-gui/lang/fr.json +++ b/packages/nc-gui/lang/fr.json @@ -235,6 +235,7 @@ "action": "Action", "actions": "Actions", "operation": "Opération", + "operationSub": "Sub Operation", "operationType": "Type d'opération", "operationSubType": "Sous-type d'opération", "description": "Description", diff --git a/packages/nc-gui/lang/he.json b/packages/nc-gui/lang/he.json index cacce26319..e94b64fda4 100644 --- a/packages/nc-gui/lang/he.json +++ b/packages/nc-gui/lang/he.json @@ -235,6 +235,7 @@ "action": "פעולה", "actions": "פעולות", "operation": "מבצע", + "operationSub": "Sub Operation", "operationType": "סוג הפעולה", "operationSubType": "מבצע תת-סוג", "description": "תיאור", diff --git a/packages/nc-gui/lang/hi.json b/packages/nc-gui/lang/hi.json index 5740c4e26a..d2ee6cf202 100644 --- a/packages/nc-gui/lang/hi.json +++ b/packages/nc-gui/lang/hi.json @@ -235,6 +235,7 @@ "action": "गतिविधि", "actions": "कार्रवाई", "operation": "संचालन", + "operationSub": "Sub Operation", "operationType": "प्रचालन प्रकार", "operationSubType": "प्रचालन उप-प्रकार", "description": "विवरण", diff --git a/packages/nc-gui/lang/hr.json b/packages/nc-gui/lang/hr.json index d24505daeb..b8d4e65de4 100644 --- a/packages/nc-gui/lang/hr.json +++ b/packages/nc-gui/lang/hr.json @@ -235,6 +235,7 @@ "action": "Akcijski", "actions": "Akcije", "operation": "Operacija", + "operationSub": "Sub Operation", "operationType": "Vrsta rada", "operationSubType": "Operacija pod-vrsti", "description": "Opis", diff --git a/packages/nc-gui/lang/id.json b/packages/nc-gui/lang/id.json index dd5ae4a49c..b010e87ffb 100644 --- a/packages/nc-gui/lang/id.json +++ b/packages/nc-gui/lang/id.json @@ -235,6 +235,7 @@ "action": "Tindakan", "actions": "Tindakan", "operation": "Operasi", + "operationSub": "Sub Operation", "operationType": "Jenis operasi", "operationSubType": "SUB-tipe operasi", "description": "Keterangan", diff --git a/packages/nc-gui/lang/it.json b/packages/nc-gui/lang/it.json index f9ad41d9b6..0c013a7a2e 100644 --- a/packages/nc-gui/lang/it.json +++ b/packages/nc-gui/lang/it.json @@ -235,6 +235,7 @@ "action": "Azione", "actions": "Azioni", "operation": "Operazione", + "operationSub": "Sub Operation", "operationType": "Tipo di operazioni", "operationSubType": "Sottotipo di operazioni", "description": "Descrizione", diff --git a/packages/nc-gui/lang/ja.json b/packages/nc-gui/lang/ja.json index 03e492f329..32660df6c9 100644 --- a/packages/nc-gui/lang/ja.json +++ b/packages/nc-gui/lang/ja.json @@ -235,6 +235,7 @@ "action": "アクション", "actions": "アクション", "operation": "操作", + "operationSub": "Sub Operation", "operationType": "操作タイプ", "operationSubType": "操作サブタイプ", "description": "説明", diff --git a/packages/nc-gui/lang/ko.json b/packages/nc-gui/lang/ko.json index 99ab014235..8750b16da6 100644 --- a/packages/nc-gui/lang/ko.json +++ b/packages/nc-gui/lang/ko.json @@ -235,6 +235,7 @@ "action": "동작", "actions": "행위", "operation": "작업", + "operationSub": "Sub Operation", "operationType": "작업 유형", "operationSubType": "작업 하위 유형", "description": "설명", diff --git a/packages/nc-gui/lang/lv.json b/packages/nc-gui/lang/lv.json index b859e014fd..e829794413 100644 --- a/packages/nc-gui/lang/lv.json +++ b/packages/nc-gui/lang/lv.json @@ -235,6 +235,7 @@ "action": "Darbība", "actions": "Darbības", "operation": "Operācija", + "operationSub": "Sub Operation", "operationType": "Operācijas tips", "operationSubType": "Operācijas apakštips", "description": "Apraksts", diff --git a/packages/nc-gui/lang/nl.json b/packages/nc-gui/lang/nl.json index 004c5205aa..87c859c727 100644 --- a/packages/nc-gui/lang/nl.json +++ b/packages/nc-gui/lang/nl.json @@ -235,6 +235,7 @@ "action": "Actie", "actions": "Acties", "operation": "Operatie", + "operationSub": "Sub Operation", "operationType": "Operatietype", "operationSubType": "Operatiesubtype", "description": "Beschrijving", diff --git a/packages/nc-gui/lang/no.json b/packages/nc-gui/lang/no.json index c4ec420be1..48578f91a4 100644 --- a/packages/nc-gui/lang/no.json +++ b/packages/nc-gui/lang/no.json @@ -235,6 +235,7 @@ "action": "Handling", "actions": "Handlinger", "operation": "Operasjon", + "operationSub": "Sub Operation", "operationType": "Operasjonstype", "operationSubType": "OPERATION SUB-TYPE", "description": "Beskrivelse", diff --git a/packages/nc-gui/lang/pl.json b/packages/nc-gui/lang/pl.json index d3c9dae2c4..6b40787b6a 100644 --- a/packages/nc-gui/lang/pl.json +++ b/packages/nc-gui/lang/pl.json @@ -235,6 +235,7 @@ "action": "Akcja", "actions": "Akcje", "operation": "Operacja", + "operationSub": "Sub Operation", "operationType": "Typ operacji", "operationSubType": "Podtypowy akcji", "description": "Opis", diff --git a/packages/nc-gui/lang/pt.json b/packages/nc-gui/lang/pt.json index 93427b42bd..4acd062047 100644 --- a/packages/nc-gui/lang/pt.json +++ b/packages/nc-gui/lang/pt.json @@ -235,6 +235,7 @@ "action": "Açao", "actions": "Ações", "operation": "Operação", + "operationSub": "Sub Operation", "operationType": "Tipo de operação", "operationSubType": "Sub-tipo de operação", "description": "Descrição", diff --git a/packages/nc-gui/lang/pt_BR.json b/packages/nc-gui/lang/pt_BR.json index 49ee9dff36..1ce3a257f7 100644 --- a/packages/nc-gui/lang/pt_BR.json +++ b/packages/nc-gui/lang/pt_BR.json @@ -235,6 +235,7 @@ "action": "Açao", "actions": "Ações", "operation": "Operação", + "operationSub": "Sub Operation", "operationType": "Tipo de operação", "operationSubType": "Sub-tipo de operação", "description": "Descrição", diff --git a/packages/nc-gui/lang/ru.json b/packages/nc-gui/lang/ru.json index b388d7eb7d..f4af5a6914 100644 --- a/packages/nc-gui/lang/ru.json +++ b/packages/nc-gui/lang/ru.json @@ -235,6 +235,7 @@ "action": "Действие", "actions": "Действия", "operation": "Операция", + "operationSub": "Sub Operation", "operationType": "Тип операции", "operationSubType": "Подтип операции", "description": "Описание", diff --git a/packages/nc-gui/lang/sk.json b/packages/nc-gui/lang/sk.json index 33846c7b85..1e44b4a008 100644 --- a/packages/nc-gui/lang/sk.json +++ b/packages/nc-gui/lang/sk.json @@ -235,6 +235,7 @@ "action": "Akcia", "actions": "Činnosti", "operation": "Operácia", + "operationSub": "Sub Operation", "operationType": "Typ operácie", "operationSubType": "Podtyp operácie", "description": "Popis", diff --git a/packages/nc-gui/lang/sl.json b/packages/nc-gui/lang/sl.json index 628409afd4..342f80a0c1 100644 --- a/packages/nc-gui/lang/sl.json +++ b/packages/nc-gui/lang/sl.json @@ -235,6 +235,7 @@ "action": "Akcija", "actions": "Akcijah", "operation": "Operacija", + "operationSub": "Sub Operation", "operationType": "Tip operacije.", "operationSubType": "Podpis delovanja", "description": "Opis", diff --git a/packages/nc-gui/lang/sv.json b/packages/nc-gui/lang/sv.json index ee63c50cfd..dfda739496 100644 --- a/packages/nc-gui/lang/sv.json +++ b/packages/nc-gui/lang/sv.json @@ -235,6 +235,7 @@ "action": "Handling", "actions": "Handlingar", "operation": "Drift", + "operationSub": "Sub Operation", "operationType": "Driftstyp", "operationSubType": "Driftstyp", "description": "Beskrivning", diff --git a/packages/nc-gui/lang/th.json b/packages/nc-gui/lang/th.json index 53197156b0..589a2b476b 100644 --- a/packages/nc-gui/lang/th.json +++ b/packages/nc-gui/lang/th.json @@ -235,6 +235,7 @@ "action": "หนังบู๊", "actions": "การกระทำ", "operation": "การดำเนินการ", + "operationSub": "Sub Operation", "operationType": "ประเภทการทำงาน", "operationSubType": "การดำเนินงานประเภทย่อย", "description": "คำอธิบาย", diff --git a/packages/nc-gui/lang/tr.json b/packages/nc-gui/lang/tr.json index 23ad9a2bf6..c3ce9382e3 100644 --- a/packages/nc-gui/lang/tr.json +++ b/packages/nc-gui/lang/tr.json @@ -235,6 +235,7 @@ "action": "Aksiyon", "actions": "Aksiyonlar", "operation": "İşlem", + "operationSub": "Sub Operation", "operationType": "İşlem türü", "operationSubType": "İşlem alt-türü", "description": "Tanım", diff --git a/packages/nc-gui/lang/uk.json b/packages/nc-gui/lang/uk.json index 2ed4552a0a..37e1d4d4d0 100644 --- a/packages/nc-gui/lang/uk.json +++ b/packages/nc-gui/lang/uk.json @@ -235,6 +235,7 @@ "action": "Дія", "actions": "Дії", "operation": "Операція", + "operationSub": "Sub Operation", "operationType": "Тип операції", "operationSubType": "Підтип операції", "description": "Опис", diff --git a/packages/nc-gui/lang/vi.json b/packages/nc-gui/lang/vi.json index 95b6ae905c..9c58464de0 100644 --- a/packages/nc-gui/lang/vi.json +++ b/packages/nc-gui/lang/vi.json @@ -235,6 +235,7 @@ "action": "Hoạt động", "actions": "Hành động", "operation": "Hoạt động", + "operationSub": "Sub Operation", "operationType": "Loại hoạt động", "operationSubType": "Loại phụ hoạt động", "description": "Sự miêu tả", diff --git a/packages/nc-gui/lang/zh-Hans.json b/packages/nc-gui/lang/zh-Hans.json index 328a296f47..30cda803b1 100644 --- a/packages/nc-gui/lang/zh-Hans.json +++ b/packages/nc-gui/lang/zh-Hans.json @@ -75,7 +75,7 @@ "hideField": "隐藏字段", "sortAsc": "升序", "sortDesc": "降序", - "geoDataField": "GeoData Field" + "geoDataField": "地理数据字段" }, "objects": { "project": "项目", @@ -138,7 +138,7 @@ "Currency": "货币", "Percent": "百分比", "Duration": "时长", - "GeoData": "GeoData", + "GeoData": "地理数据", "Rating": "评分", "Formula": "公式", "Rollup": "聚合", @@ -235,6 +235,7 @@ "action": "操作", "actions": "操作", "operation": "操作", + "operationSub": "Sub Operation", "operationType": "操作类型", "operationSubType": "子操作类型", "description": "描述", @@ -256,9 +257,9 @@ "barcodeFormat": "条形码码制", "qrCodeValueTooLong": "字数超出二维码容量", "barcodeValueTooLong": "字数超出条形码容量", - "yourLocation": "Your Location", - "lng": "Lng", - "lat": "Lat", + "yourLocation": "您所在的位置", + "lng": "经度", + "lat": "纬度", "aggregateFunction": "汇总功能", "dbCreateIfNotExists": "自动创建数据库", "clientKey": "客户端密钥", @@ -529,8 +530,8 @@ "orgViewer": "游客不能创建新项目,仅允许访问受邀项目。" }, "map": { - "overLimit": "You're over the limit.", - "closeLimit": "You're getting close to the limit.", + "overLimit": "你已经超出了限制。", + "closeLimit": "您已接近上限。", "limitNumber": "The limit of markers shown in a Map View is 1000 records." }, "footerInfo": "每页行驶", @@ -615,7 +616,7 @@ "gallery": "添加画廊视图", "form": "添加表单视图", "kanban": "添加看板视图", - "map": "Add Map View", + "map": "添加地图视图", "calendar": "添加日历视图" }, "tablesMetadataInSync": "表元数据同步", diff --git a/packages/nc-gui/lang/zh-Hant.json b/packages/nc-gui/lang/zh-Hant.json index 18a6d91fe0..94b2e029b4 100644 --- a/packages/nc-gui/lang/zh-Hant.json +++ b/packages/nc-gui/lang/zh-Hant.json @@ -235,6 +235,7 @@ "action": "行動", "actions": "行動", "operation": "操作", + "operationSub": "Sub Operation", "operationType": "操作類型", "operationSubType": "操作子類型", "description": "描述", diff --git a/packages/nc-gui/utils/filterUtils.ts b/packages/nc-gui/utils/filterUtils.ts index 599a5cb5dc..71af46a26d 100644 --- a/packages/nc-gui/utils/filterUtils.ts +++ b/packages/nc-gui/utils/filterUtils.ts @@ -3,7 +3,11 @@ import { UITypes, isNumericCol, numericUITypes } from 'nocodb-sdk' const getEqText = (fieldUiType: UITypes) => { if (isNumericCol(fieldUiType)) { return '=' - } else if ([UITypes.SingleSelect, UITypes.Collaborator, UITypes.LinkToAnotherRecord].includes(fieldUiType)) { + } else if ( + [UITypes.SingleSelect, UITypes.Collaborator, UITypes.LinkToAnotherRecord, UITypes.Date, UITypes.DateTime].includes( + fieldUiType, + ) + ) { return 'is' } return 'is equal' @@ -12,7 +16,11 @@ const getEqText = (fieldUiType: UITypes) => { const getNeqText = (fieldUiType: UITypes) => { if (isNumericCol(fieldUiType)) { return '!=' - } else if ([UITypes.SingleSelect, UITypes.Collaborator, UITypes.LinkToAnotherRecord].includes(fieldUiType)) { + } else if ( + [UITypes.SingleSelect, UITypes.Collaborator, UITypes.LinkToAnotherRecord, UITypes.Date, UITypes.DateTime].includes( + fieldUiType, + ) + ) { return 'is not' } return 'is not equal' @@ -32,12 +40,40 @@ const getNotLikeText = (fieldUiType: UITypes) => { return 'is not like' } +const getGtText = (fieldUiType: UITypes) => { + if ([UITypes.Date, UITypes.DateTime].includes(fieldUiType)) { + return 'is after' + } + return '>' +} + +const getLtText = (fieldUiType: UITypes) => { + if ([UITypes.Date, UITypes.DateTime].includes(fieldUiType)) { + return 'is before' + } + return '<' +} + +const getGteText = (fieldUiType: UITypes) => { + if ([UITypes.Date, UITypes.DateTime].includes(fieldUiType)) { + return 'is on or after' + } + return '>=' +} + +const getLteText = (fieldUiType: UITypes) => { + if ([UITypes.Date, UITypes.DateTime].includes(fieldUiType)) { + return 'is on or before' + } + return '<=' +} + export const comparisonOpList = ( fieldUiType: UITypes, ): { text: string value: string - ignoreVal?: boolean + ignoreVal: boolean includedTypes?: UITypes[] excludedTypes?: UITypes[] }[] => [ @@ -56,22 +92,42 @@ export const comparisonOpList = ( { text: getEqText(fieldUiType), value: 'eq', + ignoreVal: false, excludedTypes: [UITypes.Checkbox, UITypes.MultiSelect, UITypes.Attachment], }, { text: getNeqText(fieldUiType), value: 'neq', + ignoreVal: false, excludedTypes: [UITypes.Checkbox, UITypes.MultiSelect, UITypes.Attachment], }, { text: getLikeText(fieldUiType), value: 'like', - excludedTypes: [UITypes.Checkbox, UITypes.SingleSelect, UITypes.MultiSelect, UITypes.Collaborator, ...numericUITypes], + ignoreVal: false, + excludedTypes: [ + UITypes.Checkbox, + UITypes.SingleSelect, + UITypes.MultiSelect, + UITypes.Collaborator, + UITypes.Date, + UITypes.DateTime, + ...numericUITypes, + ], }, { text: getNotLikeText(fieldUiType), value: 'nlike', - excludedTypes: [UITypes.Checkbox, UITypes.SingleSelect, UITypes.MultiSelect, UITypes.Collaborator, ...numericUITypes], + ignoreVal: false, + excludedTypes: [ + UITypes.Checkbox, + UITypes.SingleSelect, + UITypes.MultiSelect, + UITypes.Collaborator, + UITypes.Date, + UITypes.DateTime, + ...numericUITypes, + ], }, { text: 'is empty', @@ -85,6 +141,8 @@ export const comparisonOpList = ( UITypes.Attachment, UITypes.LinkToAnotherRecord, UITypes.Lookup, + UITypes.Date, + UITypes.DateTime, ...numericUITypes, ], }, @@ -100,6 +158,8 @@ export const comparisonOpList = ( UITypes.Attachment, UITypes.LinkToAnotherRecord, UITypes.Lookup, + UITypes.Date, + UITypes.DateTime, ...numericUITypes, ], }, @@ -116,6 +176,8 @@ export const comparisonOpList = ( UITypes.Attachment, UITypes.LinkToAnotherRecord, UITypes.Lookup, + UITypes.Date, + UITypes.DateTime, ], }, { @@ -131,47 +193,63 @@ export const comparisonOpList = ( UITypes.Attachment, UITypes.LinkToAnotherRecord, UITypes.Lookup, + UITypes.Date, + UITypes.DateTime, ], }, { text: 'contains all of', value: 'allof', + ignoreVal: false, includedTypes: [UITypes.MultiSelect], }, { text: 'contains any of', value: 'anyof', + ignoreVal: false, includedTypes: [UITypes.MultiSelect, UITypes.SingleSelect], }, { text: 'does not contain all of', value: 'nallof', + ignoreVal: false, includedTypes: [UITypes.MultiSelect], }, { text: 'does not contain any of', value: 'nanyof', + ignoreVal: false, includedTypes: [UITypes.MultiSelect, UITypes.SingleSelect], }, { - text: '>', + text: getGtText(fieldUiType), value: 'gt', - includedTypes: [...numericUITypes], + ignoreVal: false, + includedTypes: [...numericUITypes, UITypes.Date, UITypes.DateTime], }, { - text: '<', + text: getLtText(fieldUiType), value: 'lt', - includedTypes: [...numericUITypes], + ignoreVal: false, + includedTypes: [...numericUITypes, UITypes.Date, UITypes.DateTime], }, { - text: '>=', + text: getGteText(fieldUiType), value: 'gte', - includedTypes: [...numericUITypes], + ignoreVal: false, + includedTypes: [...numericUITypes, UITypes.Date, UITypes.DateTime], }, { - text: '<=', + text: getLteText(fieldUiType), value: 'lte', - includedTypes: [...numericUITypes], + ignoreVal: false, + includedTypes: [...numericUITypes, UITypes.Date, UITypes.DateTime], + }, + { + text: 'is within', + value: 'isWithin', + ignoreVal: true, + includedTypes: [UITypes.Date, UITypes.DateTime], }, { text: 'is blank', @@ -186,3 +264,129 @@ export const comparisonOpList = ( excludedTypes: [UITypes.Checkbox], }, ] + +export const comparisonSubOpList = ( + // TODO: type + comparison_op: string, +): { + text: string + value: string + ignoreVal: boolean + includedTypes?: UITypes[] + excludedTypes?: UITypes[] +}[] => { + if (comparison_op === 'isWithin') { + return [ + { + text: 'the past week', + value: 'pastWeek', + ignoreVal: true, + includedTypes: [UITypes.Date, UITypes.DateTime], + }, + { + text: 'the past month', + value: 'pastMonth', + ignoreVal: true, + includedTypes: [UITypes.Date, UITypes.DateTime], + }, + { + text: 'the past year', + value: 'pastYear', + ignoreVal: true, + includedTypes: [UITypes.Date, UITypes.DateTime], + }, + { + text: 'the next week', + value: 'nextWeek', + ignoreVal: true, + includedTypes: [UITypes.Date, UITypes.DateTime], + }, + { + text: 'the next month', + value: 'nextMonth', + ignoreVal: true, + includedTypes: [UITypes.Date, UITypes.DateTime], + }, + { + text: 'the next year', + value: 'nextYear', + ignoreVal: true, + includedTypes: [UITypes.Date, UITypes.DateTime], + }, + { + text: 'the next number of days', + value: 'nextNumberOfDays', + ignoreVal: false, + includedTypes: [UITypes.Date, UITypes.DateTime], + }, + { + text: 'the past number of days', + value: 'pastNumberOfDays', + ignoreVal: false, + includedTypes: [UITypes.Date, UITypes.DateTime], + }, + ] + } + return [ + { + text: 'today', + value: 'today', + ignoreVal: true, + includedTypes: [UITypes.Date, UITypes.DateTime], + }, + { + text: 'tomorrow', + value: 'tomorrow', + ignoreVal: true, + includedTypes: [UITypes.Date, UITypes.DateTime], + }, + { + text: 'yesterday', + value: 'yesterday', + ignoreVal: true, + includedTypes: [UITypes.Date, UITypes.DateTime], + }, + { + text: 'one week ago', + value: 'oneWeekAgo', + ignoreVal: true, + includedTypes: [UITypes.Date, UITypes.DateTime], + }, + { + text: 'one week from now', + value: 'oneWeekFromNow', + ignoreVal: true, + includedTypes: [UITypes.Date, UITypes.DateTime], + }, + { + text: 'one month ago', + value: 'oneMonthAgo', + ignoreVal: true, + includedTypes: [UITypes.Date, UITypes.DateTime], + }, + { + text: 'one month from now', + value: 'oneMonthFromNow', + ignoreVal: true, + includedTypes: [UITypes.Date, UITypes.DateTime], + }, + { + text: 'number of days ago', + value: 'daysAgo', + ignoreVal: false, + includedTypes: [UITypes.Date, UITypes.DateTime], + }, + { + text: 'number of days from now', + value: 'daysFromNow', + ignoreVal: false, + includedTypes: [UITypes.Date, UITypes.DateTime], + }, + { + text: 'exact date', + value: 'exactDate', + ignoreVal: false, + includedTypes: [UITypes.Date, UITypes.DateTime], + }, + ] +} diff --git a/packages/nc-plugin/package-lock.json b/packages/nc-plugin/package-lock.json index aef2ac34db..574708a321 100644 --- a/packages/nc-plugin/package-lock.json +++ b/packages/nc-plugin/package-lock.json @@ -714,18 +714,6 @@ "node": ">= 4" } }, - "node_modules/@eslint/eslintrc/node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@eslint/eslintrc/node_modules/type-fest": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", @@ -1111,12 +1099,30 @@ } }, "node_modules/ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, "engines": { - "node": ">=4" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/ansi-regex": { @@ -1195,33 +1201,6 @@ "node": ">=0.6.10" } }, - "node_modules/arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/array-find-index": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", @@ -1280,15 +1259,6 @@ "node": ">=0.10.0" } }, - "node_modules/array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/array.prototype.flat": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz", @@ -1345,15 +1315,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/astral-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", @@ -1381,18 +1342,6 @@ "node": ">= 4.0.0" } }, - "node_modules/atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "dev": true, - "bin": { - "atob": "bin/atob.js" - }, - "engines": { - "node": ">= 4.5.0" - } - }, "node_modules/ava": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ava/-/ava-5.2.0.tgz", @@ -1666,73 +1615,25 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, - "node_modules/base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "dev": true, - "dependencies": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/base/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/base/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/base/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/base/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, "node_modules/binary-extensions": { "version": "2.2.0", @@ -1743,6 +1644,17 @@ "node": ">=8" } }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, "node_modules/blueimp-md5": { "version": "2.18.0", "resolved": "https://registry.npmjs.org/blueimp-md5/-/blueimp-md5-2.18.0.tgz", @@ -1810,36 +1722,40 @@ "integrity": "sha512-Mi2m55JrX2BFbNZGKYR+2ItcGnR4O5HhrvgoRRyZQlaMGQULqDhoGkLWHzJoshSzi7k1PUofxcDbNhlFrDZNhg==", "dev": true }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "node_modules/buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", "dev": true }, - "node_modules/cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "dev": true, - "dependencies": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/cachedir": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.2.0.tgz", - "integrity": "sha512-VvxA0xhNqIIfg0V9AmJkDg91DaJwryutH5rVEZAhcNi4iJFj9f+QxmAjgK1LT9I8OgToX27fypX6/MeCXVbBjQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.3.0.tgz", + "integrity": "sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==", "dev": true, "engines": { "node": ">=6" @@ -1933,9 +1849,9 @@ } }, "node_modules/chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { "ansi-styles": "^4.1.0", @@ -2023,33 +1939,6 @@ "integrity": "sha512-uvzpYrpmidaoxvIQHM+rKSrigjOe9feHYbw4uOI2gdfe1C3xIlxO+kVXq83WQWNniTf8bAxVpy+cQeFQsMERKg==", "dev": true }, - "node_modules/class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "dev": true, - "dependencies": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/class-utils/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", @@ -2068,6 +1957,30 @@ "node": ">=0.10.0" } }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.7.0.tgz", + "integrity": "sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/cli-truncate": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-3.1.0.tgz", @@ -2135,10 +2048,13 @@ } }, "node_modules/cli-width": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", - "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", - "dev": true + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true, + "engines": { + "node": ">= 10" + } }, "node_modules/cliui": { "version": "7.0.4", @@ -2151,6 +2067,15 @@ "wrap-ansi": "^7.0.0" } }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, "node_modules/code-excerpt": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/code-excerpt/-/code-excerpt-4.0.0.tgz", @@ -2195,19 +2120,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "dev": true, - "dependencies": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -2258,25 +2170,25 @@ } }, "node_modules/commitizen": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/commitizen/-/commitizen-4.2.3.tgz", - "integrity": "sha512-pYlYEng7XMV2TW4xtjDKBGqeJ0Teq2zyRSx2S3Ml1XAplHSlJZK8vm1KdGclpMEZuGafbS5TeHXIVnHk8RWIzQ==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/commitizen/-/commitizen-4.3.0.tgz", + "integrity": "sha512-H0iNtClNEhT0fotHvGV3E9tDejDeS04sN1veIebsKYGMuGscFaswRoYJKmT3eW85eIJAs0F28bG2+a/9wCOfPw==", "dev": true, "dependencies": { - "cachedir": "2.2.0", - "cz-conventional-changelog": "3.2.0", + "cachedir": "2.3.0", + "cz-conventional-changelog": "3.3.0", "dedent": "0.7.0", - "detect-indent": "6.0.0", - "find-node-modules": "2.0.0", + "detect-indent": "6.1.0", + "find-node-modules": "^2.1.2", "find-root": "1.1.0", - "fs-extra": "8.1.0", - "glob": "7.1.4", - "inquirer": "6.5.2", + "fs-extra": "9.1.0", + "glob": "7.2.3", + "inquirer": "8.2.5", "is-utf8": "^0.2.1", - "lodash": "^4.17.20", - "minimist": "1.2.5", + "lodash": "4.17.21", + "minimist": "1.2.7", "strip-bom": "4.0.0", - "strip-json-comments": "3.0.1" + "strip-json-comments": "3.1.1" }, "bin": { "commitizen": "bin/commitizen", @@ -2284,195 +2196,40 @@ "git-cz": "bin/git-cz" }, "engines": { - "node": ">= 10" - } - }, - "node_modules/commitizen/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" + "node": ">= 12" } }, - "node_modules/commitizen/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "node_modules/commitizen/node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/commitizen/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } + "node_modules/common-path-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", + "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", + "dev": true }, - "node_modules/commitizen/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", "dev": true }, - "node_modules/commitizen/node_modules/cz-conventional-changelog": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/cz-conventional-changelog/-/cz-conventional-changelog-3.2.0.tgz", - "integrity": "sha512-yAYxeGpVi27hqIilG1nh4A9Bnx4J3Ov+eXy4koL3drrR+IO9GaWPsKjik20ht608Asqi8TQPf0mczhEeyAtMzg==", - "dev": true, - "dependencies": { - "chalk": "^2.4.1", - "commitizen": "^4.0.3", - "conventional-commit-types": "^3.0.0", - "lodash.map": "^4.5.1", - "longest": "^2.0.1", - "word-wrap": "^1.0.3" - }, - "engines": { - "node": ">= 10" - }, - "optionalDependencies": { - "@commitlint/load": ">6.1.1" - } - }, - "node_modules/commitizen/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/commitizen/node_modules/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/commitizen/node_modules/glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - } - }, - "node_modules/commitizen/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/commitizen/node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "dev": true, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/commitizen/node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/commitizen/node_modules/strip-json-comments": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", - "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/commitizen/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/commitizen/node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/common-path-prefix": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", - "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", - "dev": true - }, - "node_modules/commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", - "dev": true - }, - "node_modules/compare-func": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", - "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", + "node_modules/compare-func": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", + "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", "dev": true, "dependencies": { "array-ify": "^1.0.0", "dot-prop": "^5.1.0" } }, - "node_modules/component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true - }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -3296,15 +3053,6 @@ "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, - "node_modules/copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -3697,15 +3445,6 @@ "node": ">=0.10.0" } }, - "node_modules/decode-uri-component": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", - "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", - "dev": true, - "engines": { - "node": ">=0.10" - } - }, "node_modules/dedent": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", @@ -3748,6 +3487,18 @@ "node": ">=8" } }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/define-lazy-prop": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", @@ -3769,57 +3520,6 @@ "node": ">= 0.4" } }, - "node_modules/define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/define-property/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/define-property/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/define-property/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/del": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/del/-/del-7.0.0.tgz", @@ -3876,16 +3576,16 @@ "node_modules/detect-file": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", - "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", + "integrity": "sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==", "dev": true, "engines": { "node": ">=0.10.0" } }, "node_modules/detect-indent": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.0.0.tgz", - "integrity": "sha512-oSyFlqaTHCItVRGK5RmrmjB+CmaMOW7IaNA/kdxqhoa6d17j/5ce9O9eWXmV/KEdRwqpQA+Vqe8a8Bsybu4YnA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", + "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", "dev": true, "engines": { "node": ">=8" @@ -4523,18 +4223,6 @@ "node": ">= 4" } }, - "node_modules/eslint/node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/espree": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", @@ -4643,67 +4331,10 @@ "node": ">=0.10.0" } }, - "node_modules/expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "dependencies": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/expand-brackets/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, "node_modules/expand-tilde": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", + "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==", "dev": true, "dependencies": { "homedir-polyfill": "^1.0.1" @@ -4712,43 +4343,6 @@ "node": ">=0.10.0" } }, - "node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extend-shallow/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extend-shallow/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/external-editor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", @@ -4775,92 +4369,11 @@ "node": ">=0.10.0" } }, - "node_modules/extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "dependencies": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true }, "node_modules/fast-diff": { "version": "1.2.0", @@ -5024,13 +4537,13 @@ } }, "node_modules/find-node-modules": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/find-node-modules/-/find-node-modules-2.0.0.tgz", - "integrity": "sha512-8MWIBRgJi/WpjjfVXumjPKCtmQ10B+fjx6zmSA+770GMJirLhWIzg8l763rhjl9xaeaHbnxPNRQKq2mgMhr+aw==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/find-node-modules/-/find-node-modules-2.1.3.tgz", + "integrity": "sha512-UC2I2+nx1ZuOBclWVNdcnbDR5dlrOdVb7xNjmT/lHE+LsgztWks3dG7boJ37yTS/venXw84B/mAW9uHVoC5QRg==", "dev": true, "dependencies": { - "findup-sync": "^3.0.0", - "merge": "^1.2.1" + "findup-sync": "^4.0.0", + "merge": "^2.1.1" } }, "node_modules/find-root": { @@ -5053,139 +4566,18 @@ } }, "node_modules/findup-sync": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", - "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-4.0.0.tgz", + "integrity": "sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ==", "dev": true, "dependencies": { "detect-file": "^1.0.0", "is-glob": "^4.0.0", - "micromatch": "^3.0.4", + "micromatch": "^4.0.2", "resolve-dir": "^1.0.1" }, "engines": { - "node": ">= 0.10" - } - }, - "node_modules/findup-sync/node_modules/braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "dependencies": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/braces/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "dependencies": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/fill-range/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/is-number/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "dependencies": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - }, - "engines": { - "node": ">=0.10.0" + "node": ">= 8" } }, "node_modules/flat-cache": { @@ -5207,15 +4599,6 @@ "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", "dev": true }, - "node_modules/for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/foreground-child": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", @@ -5229,18 +4612,6 @@ "node": ">=8.0.0" } }, - "node_modules/fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "dev": true, - "dependencies": { - "map-cache": "^0.2.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/fromentries": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz", @@ -5657,15 +5028,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/gh-pages": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/gh-pages/-/gh-pages-3.1.0.tgz", @@ -6033,22 +5395,16 @@ "ini": "^1.3.2" } }, - "node_modules/gitconfiglocal/node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, "node_modules/glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" }, @@ -6088,7 +5444,7 @@ "node_modules/global-prefix": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", - "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", + "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==", "dev": true, "dependencies": { "expand-tilde": "^2.0.2", @@ -6101,12 +5457,6 @@ "node": ">=0.10.0" } }, - "node_modules/global-prefix/node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, "node_modules/globals": { "version": "13.7.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.7.0.tgz", @@ -6241,69 +5591,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "dev": true, - "dependencies": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "dev": true, - "dependencies": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-values/node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-values/node_modules/is-number/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-values/node_modules/kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/hasha": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", @@ -6553,296 +5840,87 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, "node_modules/inquirer": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", - "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.5.tgz", + "integrity": "sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==", "dev": true, "dependencies": { - "ansi-escapes": "^3.2.0", - "chalk": "^2.4.2", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", "external-editor": "^3.0.3", - "figures": "^2.0.0", - "lodash": "^4.17.12", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rxjs": "^6.4.0", - "string-width": "^2.1.0", - "strip-ansi": "^5.1.0", - "through": "^2.3.6" + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^7.0.0" }, "engines": { - "node": ">=6.0.0" + "node": ">=12.0.0" } }, - "node_modules/inquirer/node_modules/ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", "dev": true, "engines": { - "node": ">=4" + "node": ">= 0.10" } }, - "node_modules/inquirer/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "node_modules/irregular-plurals": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-3.4.0.tgz", + "integrity": "sha512-YXxECO/W6N9aMBVKMKKZ8TXESgq7EFrp3emCGGUcrYY1cgJIeZjoB75MTu8qi+NAKntS9NwPU8VdcQ3r6E6aWQ==", "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/inquirer/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "node_modules/is-bigint": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.1.tgz", + "integrity": "sha512-J0ELF4yHFxHy0cmSxZuheDOz2luOdVvqjwmEcj8H/L1JHeuEDSDbeRP+Dk9kFVk5RTFzbucJ2Kb9F7ixY2QaCg==", "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/inquirer/node_modules/cli-cursor": { + "node_modules/is-binary-path": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, "dependencies": { - "restore-cursor": "^2.0.0" + "binary-extensions": "^2.0.0" }, "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/inquirer/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/inquirer/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "node_modules/inquirer/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/inquirer/node_modules/figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", - "dev": true, - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/inquirer/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/inquirer/node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/inquirer/node_modules/mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/inquirer/node_modules/onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "dev": true, - "dependencies": { - "mimic-fn": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/inquirer/node_modules/restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", - "dev": true, - "dependencies": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/inquirer/node_modules/string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "dependencies": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/inquirer/node_modules/string-width/node_modules/strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "dependencies": { - "ansi-regex": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/inquirer/node_modules/strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "dependencies": { - "ansi-regex": "^4.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/inquirer/node_modules/strip-ansi/node_modules/ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/inquirer/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/interpret": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/irregular-plurals": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-3.4.0.tgz", - "integrity": "sha512-YXxECO/W6N9aMBVKMKKZ8TXESgq7EFrp3emCGGUcrYY1cgJIeZjoB75MTu8qi+NAKntS9NwPU8VdcQ3r6E6aWQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-accessor-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "node_modules/is-bigint": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.1.tgz", - "integrity": "sha512-J0ELF4yHFxHy0cmSxZuheDOz2luOdVvqjwmEcj8H/L1JHeuEDSDbeRP+Dk9kFVk5RTFzbucJ2Kb9F7ixY2QaCg==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-boolean-object": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.0.tgz", - "integrity": "sha512-a7Uprx8UtD+HWdyYwnD1+ExtTgqQtD2k/1yJgtXP6wnMm8byhkoTZRl+95LLThpzNZJ5aEvi46cdH+ayMFRwmA==", + "node_modules/is-boolean-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.0.tgz", + "integrity": "sha512-a7Uprx8UtD+HWdyYwnD1+ExtTgqQtD2k/1yJgtXP6wnMm8byhkoTZRl+95LLThpzNZJ5aEvi46cdH+ayMFRwmA==", "dev": true, "dependencies": { "call-bind": "^1.0.0" @@ -6854,12 +5932,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, "node_modules/is-callable": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", @@ -6884,30 +5956,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-data-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-date-object": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", @@ -6920,29 +5968,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-descriptor/node_modules/kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-docker": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", @@ -6964,15 +5989,6 @@ "integrity": "sha512-IOQqts/aHWbiisY5DuPJQ0gcbvaLFCa7fBa9xoLfxBZvQ+ZI/Zh9xoI7Gk+G64N0FdK4AbibytHht2tWgpJWLg==", "dev": true }, - "node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -7015,6 +6031,15 @@ "node": ">=0.10.0" } }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/is-negative-zero": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", @@ -7226,15 +6251,6 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/istanbul-lib-coverage": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", @@ -7573,6 +6589,34 @@ "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", "dev": true }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/longest": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/longest/-/longest-2.0.1.tgz", @@ -7655,15 +6699,6 @@ "node": ">=6" } }, - "node_modules/map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/map-obj": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.2.1.tgz", @@ -7676,18 +6711,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "dev": true, - "dependencies": { - "object-visit": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/marked": { "version": "1.2.9", "resolved": "https://registry.npmjs.org/marked/-/marked-1.2.9.tgz", @@ -8029,9 +7052,9 @@ } }, "node_modules/merge": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/merge/-/merge-1.2.1.tgz", - "integrity": "sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/merge/-/merge-2.1.1.tgz", + "integrity": "sha512-jz+Cfrg9GWOZbQAnDQ4hlVnQky+341Yk5ru8bZSe6sIDTCIg8n9i/u7hSQGSVOF3C7lH6mGtqjkiT9G4wFLL0w==", "dev": true }, "node_modules/merge2": { @@ -8090,10 +7113,13 @@ } }, "node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/minimist-options": { "version": "4.1.0", @@ -8118,43 +7144,6 @@ "node": ">=0.10.0" } }, - "node_modules/mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "dev": true, - "dependencies": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/mixin-deep/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/mixin-deep/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/modify-values": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz", @@ -8171,33 +7160,11 @@ "dev": true }, "node_modules/mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, - "node_modules/nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "dev": true, - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -8663,44 +7630,6 @@ "node": ">=0.10.0" } }, - "node_modules/object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "dev": true, - "dependencies": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/object-inspect": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz", @@ -8719,18 +7648,6 @@ "node": ">= 0.4" } }, - "node_modules/object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "dev": true, - "dependencies": { - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/object.assign": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", @@ -8767,18 +7684,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/object.values": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.3.tgz", @@ -8806,6 +7711,30 @@ "wrappy": "1" } }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/onetime/node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/open": { "version": "8.4.0", "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", @@ -8874,10 +7803,45 @@ "node": ">= 0.8.0" } }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", "dev": true, "engines": { "node": ">=0.10.0" @@ -9074,16 +8038,7 @@ "node_modules/parse-passwd": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", "dev": true, "engines": { "node": ">=0.10.0" @@ -9314,15 +8269,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -9698,19 +8644,6 @@ "node": ">=8" } }, - "node_modules/regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "dev": true, - "dependencies": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/regexpp": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", @@ -9735,15 +8668,6 @@ "node": ">=4" } }, - "node_modules/repeat-element": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", - "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", @@ -9817,7 +8741,7 @@ "node_modules/resolve-dir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", - "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", + "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==", "dev": true, "dependencies": { "expand-tilde": "^2.0.0", @@ -9855,31 +8779,22 @@ "dev": true, "dependencies": { "ini": "^1.3.4" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/resolve-global/node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, - "node_modules/resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", - "deprecated": "https://github.com/lydell/resolve-url#deprecated", - "dev": true + }, + "engines": { + "node": ">=4" + } }, - "node_modules/ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, "engines": { - "node": ">=0.12" + "node": ">=8" } }, "node_modules/reusify": { @@ -9940,32 +8855,26 @@ } }, "node_modules/rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.0.tgz", + "integrity": "sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==", "dev": true, "dependencies": { - "tslib": "^1.9.0" - }, - "engines": { - "npm": ">=2.0.0" + "tslib": "^2.1.0" } }, + "node_modules/rxjs/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "dev": true + }, "node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, - "node_modules/safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "dev": true, - "dependencies": { - "ret": "~0.1.10" - } - }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -10008,45 +8917,6 @@ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true }, - "node_modules/set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "dev": true, - "dependencies": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/set-value/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/set-value/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -10134,161 +9004,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "dev": true, - "dependencies": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "dev": true, - "dependencies": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "dev": true, - "dependencies": { - "kind-of": "^3.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-util/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/snapdragon/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/snapdragon/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/sort-keys": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", @@ -10310,20 +9025,6 @@ "node": ">=0.10.0" } }, - "node_modules/source-map-resolve": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", - "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", - "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated", - "dev": true, - "dependencies": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, "node_modules/source-map-support": { "version": "0.5.19", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", @@ -10334,13 +9035,6 @@ "source-map": "^0.6.0" } }, - "node_modules/source-map-url": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", - "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", - "deprecated": "See https://github.com/lydell/source-map-url#deprecated", - "dev": true - }, "node_modules/spawn-wrap": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", @@ -10417,18 +9111,6 @@ "node": "*" } }, - "node_modules/split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "dev": true, - "dependencies": { - "extend-shallow": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/split2": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", @@ -10627,31 +9309,6 @@ "node": ">=4" } }, - "node_modules/static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "dev": true, - "dependencies": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-extend/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/stream-events": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/stream-events/-/stream-events-1.0.5.tgz", @@ -10816,6 +9473,18 @@ "node": ">=8" } }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/strip-outer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz", @@ -11189,45 +9858,6 @@ "node": ">=4" } }, - "node_modules/to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-object-path/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "dev": true, - "dependencies": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -11340,15 +9970,6 @@ "strip-bom": "^3.0.0" } }, - "node_modules/tsconfig-paths/node_modules/minimist": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", - "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", @@ -11487,21 +10108,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", - "dev": true, - "dependencies": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/unique-string": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", @@ -11515,60 +10121,12 @@ } }, "node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "dev": true, - "dependencies": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, - "dependencies": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "dependencies": { - "isarray": "1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">= 10.0.0" } }, "node_modules/uri-js": { @@ -11580,28 +10138,12 @@ "punycode": "^2.1.0" } }, - "node_modules/urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "deprecated": "Please see https://github.com/lydell/urix#deprecated", - "dev": true - }, "node_modules/urlgrey": { "version": "0.4.4", "resolved": "https://registry.npmjs.org/urlgrey/-/urlgrey-0.4.4.tgz", "integrity": "sha1-iS/pWWCAXoVRnxzUOJ8stMu3ZS8=", "dev": true }, - "node_modules/use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -11640,6 +10182,15 @@ "integrity": "sha512-jkjy6pjU1fxUvI51P+gCsxg1u2n8LSt0W6KrCNQceaziKzff74GoWmjVG46KieVzybO1sttPQmYfrwSHey7GUA==", "dev": true }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "dependencies": { + "defaults": "^1.0.3" + } + }, "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", @@ -12467,12 +11018,6 @@ "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", "dev": true }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - }, "type-fest": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", @@ -12732,10 +11277,21 @@ "dev": true }, "ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", - "dev": true + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + }, + "dependencies": { + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true + } + } }, "ansi-regex": { "version": "5.0.0", @@ -12795,24 +11351,6 @@ "integrity": "sha1-7L0W+JSbFXGDcRsb2jNPN4QBhas=", "dev": true }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true - }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "dev": true - }, "array-find-index": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", @@ -12856,12 +11394,6 @@ "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", "dev": true }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, "array.prototype.flat": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz", @@ -12897,12 +11429,6 @@ "integrity": "sha512-tLkvA81vQG/XqE2mjDkGQHoOINtMHtysSnemrmoGe6PydDPMRbVugqyk4A6V/WDWEfm3l+0d8anA9r8cv/5Jaw==", "dev": true }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "dev": true - }, "astral-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", @@ -12924,12 +11450,6 @@ "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", "dev": true }, - "atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "dev": true - }, "ava": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ava/-/ava-5.2.0.tgz", @@ -13126,60 +11646,11 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "dev": true, - "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true }, "binary-extensions": { "version": "2.2.0", @@ -13187,6 +11658,17 @@ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", "dev": true }, + "bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, "blueimp-md5": { "version": "2.18.0", "resolved": "https://registry.npmjs.org/blueimp-md5/-/blueimp-md5-2.18.0.tgz", @@ -13239,33 +11721,26 @@ } } }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", "dev": true }, - "cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "dev": true, - "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - } - }, "cachedir": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.2.0.tgz", - "integrity": "sha512-VvxA0xhNqIIfg0V9AmJkDg91DaJwryutH5rVEZAhcNi4iJFj9f+QxmAjgK1LT9I8OgToX27fypX6/MeCXVbBjQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.3.0.tgz", + "integrity": "sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==", "dev": true }, "caching-transform": { @@ -13331,9 +11806,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -13391,29 +11866,6 @@ "integrity": "sha512-uvzpYrpmidaoxvIQHM+rKSrigjOe9feHYbw4uOI2gdfe1C3xIlxO+kVXq83WQWNniTf8bAxVpy+cQeFQsMERKg==", "dev": true }, - "class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, "clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", @@ -13426,6 +11878,21 @@ "integrity": "sha1-Y/sRDcLOGoTcIfbZM0h20BCui2g=", "dev": true }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-spinners": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.7.0.tgz", + "integrity": "sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==", + "dev": true + }, "cli-truncate": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-3.1.0.tgz", @@ -13471,9 +11938,9 @@ } }, "cli-width": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", - "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", "dev": true }, "cliui": { @@ -13487,6 +11954,12 @@ "wrap-ansi": "^7.0.0" } }, + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true + }, "code-excerpt": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/code-excerpt/-/code-excerpt-4.0.0.tgz", @@ -13507,214 +11980,87 @@ "js-yaml": "3.14.0", "teeny-request": "6.0.1", "urlgrey": "0.4.4" - }, - "dependencies": { - "js-yaml": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", - "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - } - } - }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "dev": true, - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "colorette": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", - "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==", - "dev": true - }, - "commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "dev": true - }, - "comment-json": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/comment-json/-/comment-json-4.1.0.tgz", - "integrity": "sha512-WEghmVYaNq9NlWbrkzQTSsya9ycLyxJxpTQfZEan6a5Jomnjw18zS3Podf8q1Zf9BvonvQd/+Z7Z39L7KKzzdQ==", - "dev": true, - "requires": { - "array-timsort": "^1.0.3", - "core-util-is": "^1.0.2", - "esprima": "^4.0.1", - "has-own-prop": "^2.0.0", - "repeat-string": "^1.6.1" - } - }, - "commitizen": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/commitizen/-/commitizen-4.2.3.tgz", - "integrity": "sha512-pYlYEng7XMV2TW4xtjDKBGqeJ0Teq2zyRSx2S3Ml1XAplHSlJZK8vm1KdGclpMEZuGafbS5TeHXIVnHk8RWIzQ==", - "dev": true, - "requires": { - "cachedir": "2.2.0", - "cz-conventional-changelog": "3.2.0", - "dedent": "0.7.0", - "detect-indent": "6.0.0", - "find-node-modules": "2.0.0", - "find-root": "1.1.0", - "fs-extra": "8.1.0", - "glob": "7.1.4", - "inquirer": "6.5.2", - "is-utf8": "^0.2.1", - "lodash": "^4.17.20", - "minimist": "1.2.5", - "strip-bom": "4.0.0", - "strip-json-comments": "3.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "cz-conventional-changelog": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/cz-conventional-changelog/-/cz-conventional-changelog-3.2.0.tgz", - "integrity": "sha512-yAYxeGpVi27hqIilG1nh4A9Bnx4J3Ov+eXy4koL3drrR+IO9GaWPsKjik20ht608Asqi8TQPf0mczhEeyAtMzg==", - "dev": true, - "requires": { - "@commitlint/load": ">6.1.1", - "chalk": "^2.4.1", - "commitizen": "^4.0.3", - "conventional-commit-types": "^3.0.0", - "lodash.map": "^4.5.1", - "longest": "^2.0.1", - "word-wrap": "^1.0.3" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dev": true, - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, - "glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + }, + "dependencies": { + "js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", "dev": true, "requires": { - "graceful-fs": "^4.1.6" + "argparse": "^1.0.7", + "esprima": "^4.0.0" } - }, + } + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "colorette": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", + "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==", + "dev": true + }, + "commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true + }, + "comment-json": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/comment-json/-/comment-json-4.1.0.tgz", + "integrity": "sha512-WEghmVYaNq9NlWbrkzQTSsya9ycLyxJxpTQfZEan6a5Jomnjw18zS3Podf8q1Zf9BvonvQd/+Z7Z39L7KKzzdQ==", + "dev": true, + "requires": { + "array-timsort": "^1.0.3", + "core-util-is": "^1.0.2", + "esprima": "^4.0.1", + "has-own-prop": "^2.0.0", + "repeat-string": "^1.6.1" + } + }, + "commitizen": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/commitizen/-/commitizen-4.3.0.tgz", + "integrity": "sha512-H0iNtClNEhT0fotHvGV3E9tDejDeS04sN1veIebsKYGMuGscFaswRoYJKmT3eW85eIJAs0F28bG2+a/9wCOfPw==", + "dev": true, + "requires": { + "cachedir": "2.3.0", + "cz-conventional-changelog": "3.3.0", + "dedent": "0.7.0", + "detect-indent": "6.1.0", + "find-node-modules": "^2.1.2", + "find-root": "1.1.0", + "fs-extra": "9.1.0", + "glob": "7.2.3", + "inquirer": "8.2.5", + "is-utf8": "^0.2.1", + "lodash": "4.17.21", + "minimist": "1.2.7", + "strip-bom": "4.0.0", + "strip-json-comments": "3.1.1" + }, + "dependencies": { "strip-bom": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", "dev": true - }, - "strip-json-comments": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", - "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true } } }, @@ -13740,12 +12086,6 @@ "dot-prop": "^5.1.0" } }, - "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true - }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -14383,12 +12723,6 @@ "integrity": "sha512-rcQ1bsQO9799wq24uE5AM2tAILy4gXGIK/njFWcVQkGNZ96edlpY+A7bjwvzjYvLDyzmG1MmMLZhpcsb+klNMQ==", "dev": true }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true - }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -14698,12 +13032,6 @@ } } }, - "decode-uri-component": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", - "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", - "dev": true - }, "dedent": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", @@ -14739,6 +13067,15 @@ } } }, + "defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "requires": { + "clone": "^1.0.2" + } + }, "define-lazy-prop": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", @@ -14754,47 +13091,6 @@ "object-keys": "^1.0.12" } }, - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, "del": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/del/-/del-7.0.0.tgz", @@ -14835,13 +13131,13 @@ "detect-file": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", - "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", + "integrity": "sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==", "dev": true }, "detect-indent": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.0.0.tgz", - "integrity": "sha512-oSyFlqaTHCItVRGK5RmrmjB+CmaMOW7IaNA/kdxqhoa6d17j/5ce9O9eWXmV/KEdRwqpQA+Vqe8a8Bsybu4YnA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", + "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", "dev": true }, "detect-newline": { @@ -15083,12 +13379,6 @@ "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", "dev": true - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true } } }, @@ -15418,95 +13708,15 @@ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, "expand-tilde": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", + "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==", "dev": true, "requires": { "homedir-polyfill": "^1.0.1" } }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - } - } - }, "external-editor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", @@ -15529,71 +13739,6 @@ } } }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -15725,13 +13870,13 @@ } }, "find-node-modules": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/find-node-modules/-/find-node-modules-2.0.0.tgz", - "integrity": "sha512-8MWIBRgJi/WpjjfVXumjPKCtmQ10B+fjx6zmSA+770GMJirLhWIzg8l763rhjl9xaeaHbnxPNRQKq2mgMhr+aw==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/find-node-modules/-/find-node-modules-2.1.3.tgz", + "integrity": "sha512-UC2I2+nx1ZuOBclWVNdcnbDR5dlrOdVb7xNjmT/lHE+LsgztWks3dG7boJ37yTS/venXw84B/mAW9uHVoC5QRg==", "dev": true, "requires": { - "findup-sync": "^3.0.0", - "merge": "^1.2.1" + "findup-sync": "^4.0.0", + "merge": "^2.1.1" } }, "find-root": { @@ -15751,120 +13896,15 @@ } }, "findup-sync": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", - "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-4.0.0.tgz", + "integrity": "sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ==", "dev": true, "requires": { "detect-file": "^1.0.0", "is-glob": "^4.0.0", - "micromatch": "^3.0.4", + "micromatch": "^4.0.2", "resolve-dir": "^1.0.1" - }, - "dependencies": { - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } - } } }, "flat-cache": { @@ -15883,29 +13923,14 @@ "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", "dev": true }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true - }, "foreground-child": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", - "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.0", - "signal-exit": "^3.0.2" - } - }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", "dev": true, "requires": { - "map-cache": "^0.2.2" + "cross-spawn": "^7.0.0", + "signal-exit": "^3.0.2" } }, "fromentries": { @@ -16218,12 +14243,6 @@ "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", "dev": true }, - "get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", - "dev": true - }, "gh-pages": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/gh-pages/-/gh-pages-3.1.0.tgz", @@ -16500,26 +14519,18 @@ "dev": true, "requires": { "ini": "^1.3.2" - }, - "dependencies": { - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - } } }, "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } @@ -16547,7 +14558,7 @@ "global-prefix": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", - "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", + "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==", "dev": true, "requires": { "expand-tilde": "^2.0.2", @@ -16555,14 +14566,6 @@ "ini": "^1.3.4", "is-windows": "^1.0.1", "which": "^1.2.14" - }, - "dependencies": { - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - } } }, "globals": { @@ -16654,58 +14657,6 @@ "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", "dev": true }, - "has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "dev": true, - "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - } - }, - "has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, "hasha": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", @@ -16892,176 +14843,33 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, "inquirer": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", - "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.5.tgz", + "integrity": "sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==", "dev": true, "requires": { - "ansi-escapes": "^3.2.0", - "chalk": "^2.4.2", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", "external-editor": "^3.0.3", - "figures": "^2.0.0", - "lodash": "^4.17.12", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rxjs": "^6.4.0", - "string-width": "^2.1.0", - "strip-ansi": "^5.1.0", - "through": "^2.3.6" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "dev": true, - "requires": { - "restore-cursor": "^2.0.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "dev": true - }, - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "dev": true, - "requires": { - "mimic-fn": "^1.0.0" - } - }, - "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", - "dev": true, - "requires": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - } - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "dependencies": { - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - } - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^7.0.0" } }, "interpret": { @@ -17076,26 +14884,6 @@ "integrity": "sha512-YXxECO/W6N9aMBVKMKKZ8TXESgq7EFrp3emCGGUcrYY1cgJIeZjoB75MTu8qi+NAKntS9NwPU8VdcQ3r6E6aWQ==", "dev": true }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -17126,12 +14914,6 @@ "call-bind": "^1.0.0" } }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, "is-callable": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", @@ -17147,51 +14929,12 @@ "has": "^1.0.3" } }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, "is-date-object": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", "dev": true }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, "is-docker": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", @@ -17204,12 +14947,6 @@ "integrity": "sha512-IOQqts/aHWbiisY5DuPJQ0gcbvaLFCa7fBa9xoLfxBZvQ+ZI/Zh9xoI7Gk+G64N0FdK4AbibytHht2tWgpJWLg==", "dev": true }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true - }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -17237,6 +14974,12 @@ "is-extglob": "^2.1.1" } }, + "is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true + }, "is-negative-zero": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", @@ -17376,12 +15119,6 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, "istanbul-lib-coverage": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", @@ -17653,6 +15390,24 @@ "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", "dev": true }, + "log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "dependencies": { + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true + } + } + }, "longest": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/longest/-/longest-2.0.1.tgz", @@ -17716,27 +15471,12 @@ "p-defer": "^1.0.0" } }, - "map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true - }, "map-obj": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.2.1.tgz", "integrity": "sha512-+WA2/1sPmDj1dlvvJmB5G6JKfY9dpn7EVBUL06+y6PoljPkh+6V1QihwxNkbcGxCRjt2b0F9K0taiCuo7MbdFQ==", "dev": true }, - "map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "dev": true, - "requires": { - "object-visit": "^1.0.0" - } - }, "marked": { "version": "1.2.9", "resolved": "https://registry.npmjs.org/marked/-/marked-1.2.9.tgz", @@ -17954,9 +15694,9 @@ } }, "merge": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/merge/-/merge-1.2.1.tgz", - "integrity": "sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/merge/-/merge-2.1.1.tgz", + "integrity": "sha512-jz+Cfrg9GWOZbQAnDQ4hlVnQky+341Yk5ru8bZSe6sIDTCIg8n9i/u7hSQGSVOF3C7lH6mGtqjkiT9G4wFLL0w==", "dev": true }, "merge2": { @@ -17997,9 +15737,9 @@ } }, "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", "dev": true }, "minimist-options": { @@ -18021,36 +15761,6 @@ } } }, - "mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "dev": true, - "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - } - } - }, "modify-values": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz", @@ -18063,31 +15773,12 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", - "dev": true - }, - "nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - } - }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -18450,37 +16141,6 @@ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true }, - "object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "dev": true, - "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, "object-inspect": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz", @@ -18493,15 +16153,6 @@ "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true }, - "object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "dev": true, - "requires": { - "isobject": "^3.0.0" - } - }, "object.assign": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", @@ -18526,15 +16177,6 @@ "has": "^1.0.3" } }, - "object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, "object.values": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.3.tgz", @@ -18556,6 +16198,23 @@ "wrappy": "1" } }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + }, + "dependencies": { + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + } + } + }, "open": { "version": "8.4.0", "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", @@ -18602,10 +16261,35 @@ "word-wrap": "^1.2.3" } }, + "ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "requires": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "dependencies": { + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true + } + } + }, "os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", "dev": true }, "p-defer": { @@ -18735,13 +16419,7 @@ "parse-passwd": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", - "dev": true - }, - "pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", "dev": true }, "path-exists": { @@ -18886,12 +16564,6 @@ "irregular-plurals": "^3.3.0" } }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "dev": true - }, "prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -19156,16 +16828,6 @@ "strip-indent": "^3.0.0" } }, - "regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "dev": true, - "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - } - }, "regexpp": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", @@ -19181,12 +16843,6 @@ "es6-error": "^4.0.1" } }, - "repeat-element": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", - "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", - "dev": true - }, "repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", @@ -19242,7 +16898,7 @@ "resolve-dir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", - "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", + "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==", "dev": true, "requires": { "expand-tilde": "^2.0.0", @@ -19272,26 +16928,18 @@ "requires": { "ini": "^1.3.4" } - }, - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true } } }, - "resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", - "dev": true - }, - "ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } }, "reusify": { "version": "1.0.4", @@ -19324,12 +16972,20 @@ } }, "rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.0.tgz", + "integrity": "sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==", "dev": true, "requires": { - "tslib": "^1.9.0" + "tslib": "^2.1.0" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "dev": true + } } }, "safe-buffer": { @@ -19338,15 +16994,6 @@ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, - "safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "dev": true, - "requires": { - "ret": "~0.1.10" - } - }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -19377,38 +17024,6 @@ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true }, - "set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - } - } - }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -19471,134 +17086,6 @@ } } }, - "snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "dev": true, - "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "dev": true, - "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "dev": true, - "requires": { - "kind-of": "^3.2.0" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, "sort-keys": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", @@ -19614,19 +17101,6 @@ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true }, - "source-map-resolve": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", - "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", - "dev": true, - "requires": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, "source-map-support": { "version": "0.5.19", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", @@ -19637,12 +17111,6 @@ "source-map": "^0.6.0" } }, - "source-map-url": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", - "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", - "dev": true - }, "spawn-wrap": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", @@ -19709,15 +17177,6 @@ "through": "2" } }, - "split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "dev": true, - "requires": { - "extend-shallow": "^3.0.0" - } - }, "split2": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", @@ -19868,27 +17327,6 @@ } } }, - "static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "dev": true, - "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, "stream-events": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/stream-events/-/stream-events-1.0.5.tgz", @@ -20010,6 +17448,12 @@ "min-indent": "^1.0.0" } }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, "strip-outer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz", @@ -20280,38 +17724,6 @@ "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", "dev": true }, - "to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "dev": true, - "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - } - }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -20390,14 +17802,6 @@ "json5": "^1.0.1", "minimist": "^1.2.6", "strip-bom": "^3.0.0" - }, - "dependencies": { - "minimist": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", - "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", - "dev": true - } } }, "tslib": { @@ -20495,18 +17899,6 @@ "which-boxed-primitive": "^1.0.2" } }, - "union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" - } - }, "unique-string": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", @@ -20522,46 +17914,6 @@ "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", "dev": true }, - "unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "dev": true, - "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true - } - } - }, "uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -20571,24 +17923,12 @@ "punycode": "^2.1.0" } }, - "urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "dev": true - }, "urlgrey": { "version": "0.4.4", "resolved": "https://registry.npmjs.org/urlgrey/-/urlgrey-0.4.4.tgz", "integrity": "sha1-iS/pWWCAXoVRnxzUOJ8stMu3ZS8=", "dev": true }, - "use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", - "dev": true - }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -20623,6 +17963,15 @@ "integrity": "sha512-jkjy6pjU1fxUvI51P+gCsxg1u2n8LSt0W6KrCNQceaziKzff74GoWmjVG46KieVzybO1sttPQmYfrwSHey7GUA==", "dev": true }, + "wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "requires": { + "defaults": "^1.0.3" + } + }, "webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", diff --git a/packages/noco-docs/content/en/developer-resources/rest-apis.md b/packages/noco-docs/content/en/developer-resources/rest-apis.md index 738645d7de..328932159d 100644 --- a/packages/noco-docs/content/en/developer-resources/rest-apis.md +++ b/packages/noco-docs/content/en/developer-resources/rest-apis.md @@ -120,14 +120,20 @@ Currently, the default value for {orgs} is noco. Users will be able to ch | Meta | Patch | dbView | update | /api/v1/db/meta/tables/{tableId} | | Meta | Delete| dbView | delete | /api/v1/db/meta/tables/{tableId} | | Meta | Post | dbView | reorder | /api/v1/db/meta/tables/{tableId}/reorder | -| Meta | Post | dbView | formCreate | /api/v1/db/meta/forms | -| Meta | Patch | dbView | formUpdate | /api/v1/db/meta/forms/{formId} | -| Meta | Get | dbView | formRead | /api/v1/db/meta/forms/{formId} | +| Meta | Post | dbView | formCreate | /api/v1/db/meta/tables/{tableId}/forms | +| Meta | Patch | dbView | formUpdate | /api/v1/db/meta/forms/{formViewId} | +| Meta | Get | dbView | formRead | /api/v1/db/meta/forms/{formViewId} | | Meta | Patch | dbView | formColumnUpdate | /api/v1/db/meta/form-columns/{formViewColumnId} | -| Meta | Post | dbView | galleryCreate | /api/v1/db/meta/galleries | -| Meta | Patch | dbView | galleryUpdate | /api/v1/db/meta/galleries/{galleriesId} | -| Meta | Get | dbView | galleryRead | /api/v1/db/meta/galleries/{galleriesId} | -| Meta | Post | dbView | gridCreate | /api/v1/db/meta/tables/${tableId}/grids | +| Meta | Post | dbView | galleryCreate | /api/v1/db/meta/tables/{tableId}/galleries | +| Meta | Patch | dbView | galleryUpdate | /api/v1/db/meta/galleries/{galleryViewId} | +| Meta | Get | dbView | galleryRead | /api/v1/db/meta/galleries/{galleryViewId} | +| Meta | Post | dbView | kanbanCreate | /api/v1/db/meta/tables/{tableId}/kanbans | +| Meta | Patch | dbView | kanbanUpdate | /api/v1/db/meta/kanban/{kanbanViewId} | +| Meta | Get | dbView | kanbanRead | /api/v1/db/meta/kanbans/{kanbanViewId} | +| Meta | Post | dbView | mapCreate | /api/v1/db/meta/tables/{tableId}/maps | +| Meta | Patch | dbView | mapUpdate | /api/v1/db/meta/maps/{mapViewId} | +| Meta | Get | dbView | mapRead | /api/v1/db/meta/maps/{mapViewId} | +| Meta | Post | dbView | gridCreate | /api/v1/db/meta/tables/{tableId}/grids | | Meta | Get | dbView | gridColumnsList | /api/v1/db/meta/grids/{gridId}/grid-columns | | Meta | Patch | dbView | gridColumnUpdate | /api/v1/db/meta/grid-columns/{columnId} | | Meta | Patch | dbView | update | /api/v1/db/meta/views/{viewId} | @@ -221,11 +227,42 @@ Currently, the default value for {orgs} is noco. Users will be able to ch | btw | between | (colName,btw,val1,val2) | | nbtw | not between | (colName,nbtw,val1,val2) | | like | like | (colName,like,%name) | +| isWithin | is Within (Available in `Date` and `DateTime` only) | (colName,isWithin,sub_op) | | allof | includes all of | (colName,allof,val1,val2,...) | | anyof | includes any of | (colName,anyof,val1,val2,...) | | nallof | does not include all of (includes none or some, but not all of) | (colName,nallof,val1,val2,...) | | nanyof | does not include any of (includes none of) | (colName,nanyof,val1,val2,...) | +## Comparison Sub-Operators + +The following sub-operators are available in `Date` and `DateTime` columns. + +| Operation | Meaning | Example | +|-----------------|-------------------------|-----------------------------------| +| today | today | (colName,eq,today) | +| tomorrow | tomorrow | (colName,eq,tomorrow) | +| yesterday | yesterday | (colName,eq,yesterday) | +| oneWeekAgo | one week ago | (colName,eq,oneWeekAgo) | +| oneWeekFromNow | one week from now | (colName,eq,oneWeekFromNow) | +| oneMonthAgo | one month ago | (colName,eq,oneMonthAgo) | +| oneMonthFromNow | one month from now | (colName,eq,oneMonthFromNow) | +| daysAgo | number of days ago | (colName,eq,daysAgo,10) | +| daysFromNow | number of days from now | (colName,eq,daysFromNow,10) | +| exactDate | exact date | (colName,eq,exactDate,2022-02-02) | + +For `isWithin` in `Date` and `DateTime` columns, the different set of sub-operators are used. + +| Operation | Meaning | Example | +|------------------|-------------------------|-----------------------------------------| +| pastWeek | the past week | (colName,isWithin,pastWeek) | +| pastMonth | the past month | (colName,isWithin,pastMonth) | +| pastYear | the past year | (colName,isWithin,pastYear) | +| nextWeek | the next week | (colName,isWithin,nextWeek) | +| nextMonth | the next month | (colName,isWithin,nextMonth) | +| nextYear | the next year | (colName,isWithin,nextYear) | +| nextNumberOfDays | the next number of days | (colName,isWithin,nextNumberOfDays,10) | +| pastNumberOfDays | the past number of days | (colName,isWithin,pastNumberOfDays,10) | + ## Logical Operators | Operation | Example | diff --git a/packages/noco-docs/content/en/setup-and-usages/table-operations.md b/packages/noco-docs/content/en/setup-and-usages/table-operations.md index 2aeeae8c43..e6245bdea3 100644 --- a/packages/noco-docs/content/en/setup-and-usages/table-operations.md +++ b/packages/noco-docs/content/en/setup-and-usages/table-operations.md @@ -70,7 +70,8 @@ After the click, it will show a menu and you can enter the column name and choos You can also click `Show more` for additional menu options. - +![Screenshot 2023-03-03 at 8 13 07 PM](https://user-images.githubusercontent.com/86527202/222749857-0e793db2-a5d2-4b54-8d23-2a0cbbec8f5d.png) + Click `Save` button to create the new column. @@ -86,6 +87,11 @@ You will be able to edit column name & associated datatype using pop-up modal. +Prior to v0.104.3, Advanced menu by default displayed developer specific database configuration options. To avoid unintended tweaks from user, these are now hidden under an easter egg menu. To enable, double click on `show all`/`hide all` button in column edit modal. + +![Screenshot 2023-03-06 at 10 45 26 AM](https://user-images.githubusercontent.com/86527202/223024810-85dac1c6-87ef-4193-90cb-3a05be8ccc1d.png) + + ### Column Delete To delete a column, click the down arrow, select `Delete` from the menu. diff --git a/packages/nocodb-sdk/src/lib/Api.ts b/packages/nocodb-sdk/src/lib/Api.ts index a2358937bb..33a759b62c 100644 --- a/packages/nocodb-sdk/src/lib/Api.ts +++ b/packages/nocodb-sdk/src/lib/Api.ts @@ -9,921 +9,2293 @@ * --------------------------------------------------------------- */ -export interface UserType { - /** Unique identifier for the given user. */ - id: string; - firstname: string; - lastname: string; - /** @format email */ - email: string; - roles?: string; +/** + * Model for API Token + */ +export interface ApiTokenType { + /** Unique API Token ID */ + id?: IdType; + /** Foreign Key to User */ + fk_user_id?: IdType; /** - * @format date - * @example 1997-10-31 + * API Token Description + * @example This API Token is for ABC application */ - date_of_birth?: string; - /** Set to true if the user's email has been verified. */ - email_verified: boolean; + description?: string; /** - * The date that the user was created. - * @format date + * API Token + * @example DYh540o8hbWpUGdarekECKLdN5OhlgCUWutVJYX2 */ - createDate?: string; + token?: string; } -export interface PageReqQueryParamsType { - offset?: number; - limit?: number; - query?: string; +/** + * Model for API Token Request + */ +export interface ApiTokenReqType { + /** + * Description of the API token + * @example This API Token is for ABC application + */ + description?: string; } -export interface UserListType { - users: { - list: UserType; - pageInfo: PaginatedType; - }; +/** + * Model for Attachment + */ +export interface AttachmentType { + /** Data for uploading */ + data?: any; + /** The mimetype of the attachment */ + mimetype?: string; + /** File Path */ + path?: string; + /** Attachment Size */ + size?: number; + /** The title of the attachment. Used in UI. */ + title?: string; + /** Attachment URL */ + url?: string; } -export interface ProjectReqType { - title: string; - description?: string; - color?: string; - bases?: BaseReqType[]; +/** + * Model for Attachment Request + */ +export interface AttachmentReqType { + /** The mimetype of the attachment */ + mimetype?: string; + /** The file path of the attachment */ + path?: string; + /** The size of the attachment */ + size?: number; + /** The title of the attachment used in UI */ + title?: string; + /** Attachment URL to be uploaded via upload-by-url */ + url?: string; } -export interface ProjectType { - id?: string; - title?: string; +/** + * Model for Audit + */ +export interface AuditType { + /** Unique ID */ + id?: IdType; + /** + * The user name performing the action + * @example w@nocodb.com + */ + user?: string; + /** + * IP address from the user + * @example ::ffff:127.0.0.1 + */ + ip?: string; + /** + * Base ID in where action is performed + * @example ds_3l9qx8xqksenrl + */ + base_id?: string; + /** + * Project ID in where action is performed + * @example p_9sx43moxhqtjm3 + */ + project_id?: string; + /** + * Model ID in where action is performed + * @example md_ehn5izr99m7d45 + */ + fk_model_id?: string; + /** + * Row ID + * @example rec0Adp9PMG9o7uJy + */ + row_id?: string; + /** + * Operation Type + * @example AUTHENTICATION + */ + op_type?: + | 'COMMENT' + | 'DATA' + | 'PROJECT' + | 'VIRTUAL_RELATION' + | 'RELATION' + | 'TABLE_VIEW' + | 'TABLE' + | 'VIEW' + | 'META' + | 'WEBHOOKS' + | 'AUTHENTICATION' + | 'TABLE_COLUMN' + | 'ORG_USER'; + /** + * Operation Sub Type + * @example UPDATE + */ + op_sub_type?: + | 'UPDATE' + | 'INSERT' + | 'BULK_INSERT' + | 'BULK_UPDATE' + | 'BULK_DELETE' + | 'LINK_RECORD' + | 'UNLINK_RECORD' + | 'DELETE' + | 'CREATED' + | 'DELETED' + | 'RENAMED' + | 'IMPORT_FROM_ZIP' + | 'EXPORT_TO_FS' + | 'EXPORT_TO_ZIP' + | 'UPDATED' + | 'SIGNIN' + | 'SIGNUP' + | 'PASSWORD_RESET' + | 'PASSWORD_FORGOT' + | 'PASSWORD_CHANGE' + | 'EMAIL_VERIFICATION' + | 'ROLES_MANAGEMENT' + | 'INVITE' + | 'RESEND_INVITE'; + /** Audit Status */ status?: string; + /** + * Description of the action + * @example Table nc_snms___Table_1 : field Date got changed from 2023-03-12 to + */ description?: string; - meta?: MetaType; - color?: string; - deleted?: BoolType; - order?: number; - bases?: BaseType[]; - is_meta?: BoolType; - prefix?: string; - created_at?: any; - updated_at?: any; - slug?: string; + /** + * Detail + * @example Date : 2023-03-12 + */ + details?: string; } -export interface ProjectListType { - list?: ProjectType[]; - pageInfo?: PaginatedType; +/** + * Model for Audit Row Update Request + */ +export interface AuditRowUpdateReqType { + /** + * Column Name + * @example baz + */ + column_name?: string; + /** + * Foreign Key to Model + * @example md_ehn5izr99m7d45 + */ + fk_model_id?: string; + /** + * Row ID + * @example rec0Adp9PMG9o7uJy + */ + row_id?: string; + /** The previous value before the action */ + prev_value?: any; + /** The current value after the action */ + value?: any; } +/** + * Model for Base + */ export interface BaseType { - id?: string; - project_id?: string; - alias?: string; - type?: string; - is_meta?: BoolType; + /** Base Name - Default BASE will be null by default */ + alias?: StringOrNullType; + /** Base Configuration */ config?: any; - created_at?: any; - updated_at?: any; - inflection_column?: string; - inflection_table?: string; - order?: number; + /** Is this base enabled */ enabled?: BoolType; -} - -export interface BaseReqType { + /** Unique Base ID */ id?: string; - project_id?: string; - alias?: string; - type?: string; - is_meta?: boolean; - config?: any; + /** + * Inflection for columns + * @example camelize + */ inflection_column?: string; + /** + * Inflection for tables + * @example camelize + */ inflection_table?: string; + /** Is the data source connected externally */ + is_meta?: BoolType; + /** + * The order of the list of bases + * @example 1 + */ + order?: number; + /** The project ID that this base belongs to */ + project_id?: string; + /** + * DB Type + * @example mysql2 + */ + type?: + | 'mssql' + | 'mysql' + | 'mysql2' + | 'oracledb' + | 'pg' + | 'snowflake' + | 'sqlite3'; } +/** + * Model for Base List + */ export interface BaseListType { bases: { list: BaseType[]; + /** Model for Paginated */ pageInfo: PaginatedType; }; } -export interface TableType { - id?: string; - project_id?: string; - base_id?: string; - table_name: string; - title: string; - type?: string; - enabled?: BoolType; - parent_id?: string; - show_as?: string; - tags?: string; - pinned?: BoolType; - deleted?: BoolType; - order?: number; - columns?: ColumnType[]; - columnsById?: object; - slug?: string; - mm?: BoolType; - meta?: MetaType; +/** + * Model for Base Request + */ +export interface BaseReqType { + /** + * Base Name - Default BASE will be null by default + * @example My Base + */ + alias?: string; + /** Base Configuration */ + config?: any; + /** + * Inflection for columns + * @example camelize + */ + inflection_column?: string; + /** + * Inflection for tables + * @example camelize + */ + inflection_table?: string; + /** Is the data source connected externally */ + is_meta?: boolean; + /** DB Type */ + type?: + | 'mssql' + | 'mysql' + | 'mysql2' + | 'oracledb' + | 'pg' + | 'snowflake' + | 'sqlite3'; } -export interface ViewType { - id?: string; - title: string; +/** + * Model for Bool + */ +export type BoolType = number | boolean | null; + +/** + * Model for Column + */ +export interface ColumnType { + /** Is Auto-Increment? */ + ai?: BoolType; + /** Auto Update Timestamp */ + au?: BoolType; + /** + * Base ID that this column belongs to + * @example ds_krsappzu9f8vmo + */ + base_id?: string; + /** Column Comment */ + cc?: string; + /** Column Default */ + cdf?: StringOrNullType; + /** Character Maximum Length */ + clen?: number | null | string; + /** Column Options */ + colOptions?: + | FormulaType + | LinkToAnotherRecordType + | LookupType + | RollupType + | SelectOptionsType + | object + | (FormulaType & + LinkToAnotherRecordType & + LookupType & + RollupType & + SelectOptionsType & + object); + /** + * Column Name + * @example title + */ + column_name?: string; + /** Column Ordinal Position */ + cop?: string; + /** Character Set Name */ + csn?: StringOrNullType; + /** + * Column Type + * @example varchar(45) + */ + ct?: string; + /** Is Deleted? */ deleted?: BoolType; - order?: number; + /** + * Data Type in DB + * @example varchar + */ + dt?: string; + /** + * Data Type X + * @example specificType + */ + dtx?: string; + /** Data Type X Precision */ + dtxp?: null | number | string; + /** Data Type X Scale */ + dtxs?: null | number | string; + /** + * Model ID that this column belongs to + * @example md_yvwvbt2i78rgcm + */ fk_model_id?: string; - slug?: string; - uuid?: string; + /** Unique ID */ + id?: IdType; + /** Meta Info */ meta?: MetaType; - show_system_fields?: BoolType; - lock_type?: 'collaborative' | 'locked' | 'personal'; - type?: number; - view?: - | FormType - | GridType - | GalleryType - | KanbanType - | MapType - | (FormType & GridType & GalleryType & KanbanType & MapType); -} - -export interface TableInfoType { - id?: string; - fk_project_id?: string; - fk_base_id?: string; - title: string; - table_name: string; - type?: string; - enabled?: string; - parent_id?: string; - show_as?: string; - tags?: string; - pinned?: BoolType; - deleted?: BoolType; - order?: number; - column?: ColumnType[]; - filters?: FilterType[]; - sort?: SortType[]; -} - -export interface TableReqType { - id?: string; - fk_project_id?: string; - fk_base_id?: string; - table_name: string; - title: string; - type?: string; - enabled?: string; - parent_id?: string; - show_as?: string; - tags?: string; - pinned?: BoolType; - deleted?: BoolType; + /** Numeric Precision */ + np?: number | null | string; + /** Numeric Scale */ + ns?: number | null | string; + /** The order of the list of columns */ order?: number; - mm?: BoolType; - columns: NormalColumnRequestType[]; - meta?: MetaType; -} - -export interface TableListType { - list?: TableType[]; - pageInfo?: PaginatedType; -} - -export interface FilterType { - id?: string; - fk_model_id?: string; - fk_column_id?: string; - logical_op?: string; - comparison_op?: string; - value?: any; - is_group?: boolean | number | null; - children?: FilterType[]; - project_id?: string; - base_id?: string; - fk_parent_id?: string; - fk_view_id?: StringOrNullType; - fk_hook_id?: StringOrNullType; -} + /** Is Primary Key? */ + pk?: BoolType; + /** Is Primary Value? */ + pv?: BoolType; + /** Is Required? */ + rqd?: BoolType; + /** Is System Column? */ + system?: BoolType; + /** + * Column Title + * @example Title + */ + title?: string; + /** + * The data type in UI + * @example SingleLineText + */ + uidt?: + | 'Attachment' + | 'AutoNumber' + | 'Barcode' + | 'Button' + | 'Checkbox' + | 'Collaborator' + | 'Count' + | 'CreateTime' + | 'Currency' + | 'Date' + | 'DateTime' + | 'Decimal' + | 'Duration' + | 'Email' + | 'Formula' + | 'ForeignKey' + | 'GeoData' + | 'Geometry' + | 'ID' + | 'JSON' + | 'LastModifiedTime' + | 'LongText' + | 'LinkToAnotherRecord' + | 'Lookup' + | 'MultiSelect' + | 'Number' + | 'Percent' + | 'PhoneNumber' + | 'Rating' + | 'Rollup' + | 'SingleLineText' + | 'SingleSelect' + | 'SpecificDBType' + | 'Time' + | 'URL' + | 'Year' + | 'QrCode'; + /** Is Unsigned? */ + un?: BoolType; + /** Is unique? */ + unique?: BoolType; + /** Is Visible? */ + visible?: BoolType; +} -export interface FilterReqType { - id?: string; - fk_model_id?: string; - fk_column_id?: string; - logical_op?: string; - comparison_op?: string; - value?: any; - is_group?: boolean | number | null; - children?: FilterType[]; - project_id?: string; +/** + * Model for Column List + */ +export interface ColumnListType { + columns: { + list: ColumnType[]; + }; +} + +/** + * Model for Column Request + */ +export type ColumnReqType = ( + | FormulaColumnReqType + | LinkToAnotherColumnReqType + | LookupColumnReqType + | NormalColumnRequestType + | RollupColumnReqType + | (FormulaColumnReqType & + LinkToAnotherColumnReqType & + LookupColumnReqType & + NormalColumnRequestType & + RollupColumnReqType) +) & { + column_name?: string; + /** Column order in a specific view */ + column_order?: { + order?: number; + view_id?: string; + }; + title: string; +}; + +/** + * Model for Comment Request + */ +export interface CommentReqType { + /** + * Description for the target row + * @example This is the comment for the row + */ + description?: string; + /** + * Foreign Key to Model + * @example md_ehn5izr99m7d45 + */ + fk_model_id: string; + /** + * Row ID + * @example 3 + */ + row_id: string; +} + +/** + * Model for Filter + */ +export interface FilterType { + /** Unqiue Base ID */ base_id?: string; - fk_parent_id?: string; - fk_view_id?: StringOrNullType; + /** Children filters. Available when the filter is grouped. */ + children?: FilterType[]; + /** Comparison Operator */ + comparison_op?: + | 'allof' + | 'anyof' + | 'blank' + | 'btw' + | 'checked' + | 'empty' + | 'eq' + | 'ge' + | 'gt' + | 'gte' + | 'in' + | 'is' + | 'isWithin' + | 'isnot' + | 'le' + | 'like' + | 'lt' + | 'lte' + | 'nallof' + | 'nanyof' + | 'nbtw' + | 'neq' + | 'nlike' + | 'not' + | 'notblank' + | 'notchecked' + | 'notempty' + | 'notnull' + | 'null'; + /** Comparison Sub-Operator */ + comparison_sub_op?: + | 'daysAgo' + | 'daysFromNow' + | 'exactDate' + | 'nextMonth' + | 'nextNumberOfDays' + | 'nextWeek' + | 'nextYear' + | 'oneMonthAgo' + | 'oneMonthFromNow' + | 'oneWeekAgo' + | 'oneWeekFromNow' + | 'pastMonth' + | 'pastNumberOfDays' + | 'pastWeek' + | 'pastYear' + | 'today' + | 'tomorrow' + | 'yesterday' + | null + | ( + | 'daysAgo' + | 'daysFromNow' + | 'exactDate' + | 'nextMonth' + | 'nextNumberOfDays' + | 'nextWeek' + | 'nextYear' + | 'oneMonthAgo' + | 'oneMonthFromNow' + | 'oneWeekAgo' + | 'oneWeekFromNow' + | 'pastMonth' + | 'pastNumberOfDays' + | 'pastWeek' + | 'pastYear' + | 'today' + | 'tomorrow' + | ('yesterday' & null) + ); + /** Foreign Key to Column */ + fk_column_id?: IdType; + /** Foreign Key to Hook */ fk_hook_id?: StringOrNullType; + /** Foreign Key to Model */ + fk_model_id?: IdType; + /** Foreign Key to parent group. */ + fk_parent_id?: StringOrNullType; + /** Foreign Key to View */ + fk_view_id?: StringOrNullType; + /** Unique ID */ + id?: IdType; + /** Is this filter grouped? */ + is_group?: boolean | number | null; + /** Logical Operator */ + logical_op?: 'and' | 'not' | 'or'; + /** Unique Project ID */ + project_id?: string; + /** The filter value. Can be NULL for some operators. */ + value?: any; } +/** + * Model for Filter List + */ export interface FilterListType { filters: { list: FilterType[]; }; } -export interface SortType { - id?: string; +/** + * Model for Filter Request + */ +export interface FilterReqType { + /** Comparison Operator */ + comparison_op?: + | 'allof' + | 'anyof' + | 'blank' + | 'btw' + | 'checked' + | 'empty' + | 'eq' + | 'ge' + | 'gt' + | 'gte' + | 'in' + | 'is' + | 'isWithin' + | 'isnot' + | 'le' + | 'like' + | 'lt' + | 'lte' + | 'nallof' + | 'nanyof' + | 'nbtw' + | 'neq' + | 'nlike' + | 'not' + | 'notblank' + | 'notchecked' + | 'notempty' + | 'notnull' + | 'null'; + /** Comparison Sub-Operator */ + comparison_sub_op?: + | 'daysAgo' + | 'daysFromNow' + | 'exactDate' + | 'nextMonth' + | 'nextNumberOfDays' + | 'nextWeek' + | 'nextYear' + | 'oneMonthAgo' + | 'oneMonthFromNow' + | 'oneWeekAgo' + | 'oneWeekFromNow' + | 'pastMonth' + | 'pastNumberOfDays' + | 'pastWeek' + | 'pastYear' + | 'today' + | 'tomorrow' + | 'yesterday' + | null + | ( + | 'daysAgo' + | 'daysFromNow' + | 'exactDate' + | 'nextMonth' + | 'nextNumberOfDays' + | 'nextWeek' + | 'nextYear' + | 'oneMonthAgo' + | 'oneMonthFromNow' + | 'oneWeekAgo' + | 'oneWeekFromNow' + | 'pastMonth' + | 'pastNumberOfDays' + | 'pastWeek' + | 'pastYear' + | 'today' + | 'tomorrow' + | ('yesterday' & null) + ); + /** Foreign Key to Column */ + fk_column_id?: IdType; + /** Belong to which filter ID */ + fk_parent_id?: IdType; + /** Is this filter grouped? */ + is_group?: BoolType; + /** Logical Operator */ + logical_op?: 'and' | 'not' | 'or'; + /** The filter value. Can be NULL for some operators. */ + value?: any; +} + +/** + * Model for Form + */ +export interface FormType { + /** Unique ID */ + id?: IdType; + /** Banner Image URL. Not in use currently. */ + banner_image_url?: StringOrNullType; + /** Form Columns */ + columns?: FormColumnType[]; + /** Email to sned after form is submitted */ + email?: StringOrNullType; + /** + * Foreign Key to Model + * @example md_rsu68aqjsbyqtl + */ fk_model_id?: string; - fk_column_id?: string; - direction?: string; - order?: number; - project_id?: string; + /** + * Base ID + * @example md_rsu68aqjsbyqtl + */ base_id?: string; + /** + * The heading of the form + * @example My Form + */ + heading?: string; + /** + * Lock Type of this view + * @example collaborative + */ + lock_type?: 'collaborative' | 'locked' | 'personal'; + /** Logo URL. Not in use currently. */ + logo_url?: StringOrNullType; + /** Meta Info for this view */ + meta?: MetaType; + /** The numbers of seconds to redirect after form submission */ + redirect_after_secs?: StringOrNullType; + /** URL to redirect after submission */ + redirect_url?: StringOrNullType; + /** Show `Blank Form` after 5 seconds */ + show_blank_form?: BoolType; + /** + * The subheading of the form + * @example My Form Subheading + */ + subheading?: string; + /** Show `Submit Another Form` button */ + submit_another_form?: BoolType; + /** Custom message after the form is successfully submitted */ + success_msg?: StringOrNullType; + /** + * Form View Title + * @example Form View 1 + */ + title?: string; } -export interface SortReqType { - fk_column_id?: string; - direction?: string; +/** + * Model for Form Request + */ +export interface FormReqType { + /** Banner Image URL. Not in use currently. */ + banner_image_url?: StringOrNullType; + /** Email to sned after form is submitted */ + email?: StringOrNullType; + /** + * The heading of the form + * @example My Form + */ + heading?: string; + /** + * Lock Type of this view + * @example collaborative + */ + lock_type?: 'collaborative' | 'locked' | 'personal'; + /** Logo URL. Not in use currently. */ + logo_url?: StringOrNullType; + /** Meta Info for this view */ + meta?: MetaType; + /** The numbers of seconds to redirect after form submission */ + redirect_after_secs?: StringOrNullType; + /** URL to redirect after submission */ + redirect_url?: StringOrNullType; + /** Show `Blank Form` after 5 seconds */ + show_blank_form?: BoolType; + /** + * The subheading of the form + * @example My Form Subheading + */ + subheading?: string; + /** Show `Submit Another Form` button */ + submit_another_form?: BoolType; + /** Custom message after the form is successfully submitted */ + success_msg?: StringOrNullType; + /** + * The title of the form + * @example My Form + */ + title?: string; } -export interface SortListType { - sorts: { - list: SharedViewType[]; - }; +/** + * Model for Form Column + */ +export interface FormColumnType { + /** Unique ID */ + id?: IdType; + /** Form Column Description (Not in use) */ + description?: StringOrNullType; + /** Foreign Key to Column */ + fk_column_id?: IdType; + /** Foreign Key to View */ + fk_view_id?: IdType; + /** Form Column Help Text */ + help?: StringOrNullType; + /** Form Column Label */ + label?: StringOrNullType; + /** Meta Info */ + meta?: MetaType; + /** + * The order among all the columns in the form + * @example 1 + */ + order?: number; + /** Is this form column required in submission? */ + required?: BoolType; + /** Is this column shown in Form? */ + show?: BoolType; + /** Form Column UUID (Not in use) */ + uuid?: StringOrNullType; } -export interface ColumnType { - id?: string; - base_id?: string; - fk_model_id?: string; +/** + * Model for Form Column Request + */ +export interface FormColumnReqType { + /** Form Column Description (Not in use) */ + description?: StringOrNullType; + /** Form Column Help Text */ + help?: StringOrNullType; + /** Form Column Label */ + label?: StringOrNullType; + /** Meta Info */ + meta?: MetaType; + /** The order among all the columns in the form */ + order?: number; + /** Is this form column required in submission? */ + required?: BoolType; + /** Is this column shown in Form? */ + show?: BoolType; +} + +/** + * Model for Formula + */ +export interface FormulaType { + /** Unique ID */ + id?: IdType; + /** Foreign Key to Column */ + fk_column_id?: IdType; + /** + * Formula with column ID replaced + * @example CONCAT("FOO", {{cl_c5knoi4xs4sfpt}}) + */ + formula?: string; + /** + * Original Formula inputted in UI + * @example CONCAT("FOO", {Title}) + */ + formula_raw?: string; + /** Error Message */ + error?: string; +} + +/** + * Model for Formula Column Request + */ +export interface FormulaColumnReqType { + /** Formula with column ID replaced */ + formula?: string; + /** Original Formula inputted in UI */ + formula_raw?: string; + /** Formula Title */ title?: string; - uidt?: string; - dt?: string; - np?: string | number | null; - ns?: string | number | null; - clen?: string | number | null; - cop?: string; - pk?: BoolType; - pv?: BoolType; - rqd?: BoolType; - column_name?: string; - un?: BoolType; - ct?: string; - ai?: BoolType; - unique?: BoolType; - cdf?: string; - cc?: string; - csn?: string; - dtx?: string; - dtxp?: string | number | null; - dtxs?: string | number | null; - au?: BoolType; + /** UI Data Type */ + uidt?: 'Formula'; +} + +/** + * Model for Gallery + */ +export interface GalleryType { + alias?: string; + columns?: GalleryColumnType[]; + cover_image?: string; + cover_image_idx?: number; + /** Model for Bool */ deleted?: BoolType; - visible?: BoolType; + /** Foreign Key to Cover Image Column */ + fk_cover_image_col_id?: string; + /** Foreign Key to Model */ + fk_model_id?: string; + /** Foreign Key to View */ + fk_view_id?: string; + lock_type?: 'collaborative' | 'locked' | 'personal'; + /** Model for Bool */ + next_enabled?: BoolType; + /** Order of Gallery */ order?: number; - system?: BoolType; + /** Model for Bool */ + prev_enabled?: BoolType; + restrict_number?: string; + restrict_size?: string; + restrict_types?: string; + title?: string; +} + +/** + * Model for Gallery Column + */ +export interface GalleryColumnType { + fk_col_id?: string; + fk_gallery_id?: string; + help?: string; + /** Unique ID */ + id?: IdType; + label?: string; +} + +/** + * Model for Gallery Request + */ +export interface GalleryReqType { + cover_image?: string; + /** @min 0 */ + cover_image_idx?: number; + /** The id of the column that contains the cover image */ + fk_cover_image_col_id?: string; + /** The lock type of gallery */ + lock_type?: 'collaborative' | 'locked' | 'personal'; + /** Model for Bool */ + next_enabled?: BoolType; + /** Model for Bool */ + prev_enabled?: BoolType; + restrict_number?: string; + restrict_size?: string; + restrict_types?: string; + /** + * The title of the gallery + * @example My Gallery + */ + title: string; +} + +/** + * Model for Geo Location + */ +export interface GeoLocationType { + /** + * The latitude of the location + * @format double + * @example 18.52139 + */ + latitude?: number; + /** + * The longitude of the location + * @format double + * @example 179.87295 + */ + longitude?: number; +} + +/** + * Model for Grid + */ +export interface GridType { + /** Unique ID */ + id?: IdType; + /** Project ID */ + project_id?: IdType; + /** Base ID */ + base_id?: IdType; + /** Foreign Key to View */ + fk_view_id?: IdType; + /** + * Row Height + * @example 1 + */ + row_height?: number; + /** Meta info for Grid Model */ meta?: MetaType; - colOptions?: - | LinkToAnotherRecordType - | FormulaType - | RollupType - | LookupType - | SelectOptionsType - | object - | (LinkToAnotherRecordType & - FormulaType & - RollupType & - LookupType & - SelectOptionsType & - object); + /** Grid View Columns */ + columns?: GridColumnType[]; } -export interface ColumnListType { - columns: { - list: ColumnType[]; - }; +/** + * Model for Grid Column + */ +export interface GridColumnType { + /** Unique ID */ + id?: IdType; + /** Foreign Key to View */ + fk_view_id?: IdType; + /** Foreign Key to Column */ + fk_column_id?: IdType; + /** Project ID */ + project_id?: IdType; + /** Base ID */ + base_id?: IdType; + /** Model for Bool */ + show?: BoolType; + /** + * Grid Column Order + * @example 1 + */ + order?: number; + /** + * Column Width + * @example 200px + */ + width?: string; + /** Column Help Text */ + help?: StringOrNullType; } -export interface LinkToAnotherRecordType { - id?: string; - type?: string; - virtual?: BoolType; - fk_column_id?: string; - fk_child_column_id?: string; - fk_parent_column_id?: string; - fk_mm_model_id?: string; - fk_related_model_id?: string; - fk_mm_child_column_id?: string; - fk_mm_parent_column_id?: string; - ur?: string; - dr?: string; - fk_index_name?: string; - deleted?: string; - order?: string; +/** + * Model for Grid Column Request + */ +export interface GridColumnReqType { + /** Foreign Key to Column */ + fk_column_id?: IdType; + help?: string; + /** + * The label of the column + * @example My Column + */ + label?: string; + /** + * The width of the column + * @pattern ^[0-9]+(px|%)$ + * @example 200px + */ + width?: string; +} + +/** + * Model for Grid Request + */ +export interface GridReqType { + /** The lock type of the grid */ + lock_type?: 'collaborative' | 'locked' | 'personal'; + /** + * The order of the grid + * @example 1 + */ + order?: number; + /** + * The height of the grid rows + * @min 1 + * @example 1 + */ + row_height?: number; + /** + * The title of the grid + * @example My Grid + */ + title: string; +} + +/** + * Model for Hook + */ +export interface HookType { + /** Is the hook active? */ + active?: BoolType; + /** Is the hook aysnc? */ + async?: BoolType; + /** + * Hook Description + * @example This is my hook description + */ + description?: string; + /** + * Environment for the hook + * @example all + */ + env?: string; + /** + * Event Type for the operation + * @example after + */ + event?: 'after' | 'before'; + /** + * Foreign Key to Model + * @example md_rsu68aqjsbyqtl + */ + fk_model_id?: string; + /** Unique ID */ + id?: IdType; + /** Hook Notification including info such as type, payload, method, body, and etc */ + notification?: object | string; + /** + * Hook Operation + * @example insert + */ + operation?: 'delete' | 'insert' | 'update'; + /** + * Retry Count + * @example 10 + */ + retries?: number; + /** + * Retry Interval + * @example 60000 + */ + retry_interval?: number; + /** + * Timeout + * @example 60000 + */ + timeout?: number; + /** + * Hook Title + * @example My Webhook + */ + title?: string; + /** Hook Type */ + type?: string; } -export interface LookupType { - id?: string; - type?: string; - virtual?: BoolType; - fk_column_id?: string; - fk_relation_column_id?: string; - fk_lookup_column_id?: string; - deleted?: string; - order?: string; +/** + * Model for Hook + */ +export interface HookReqType { + /** Is the hook active? */ + active?: BoolType; + /** Is the hook aysnc? */ + async?: BoolType; + /** Hook Description */ + description?: StringOrNullType; + /** + * Environment for the hook + * @example all + */ + env?: string; + /** + * Event Type for the operation + * @example after + */ + event: 'after' | 'before'; + /** + * Foreign Key to Model + * @example md_rsu68aqjsbyqtl + */ + fk_model_id?: string; + /** Unique ID */ + id?: IdType; + /** Hook Notification including info such as type, payload, method, body, and etc */ + notification: object | string; + /** + * Hook Operation + * @example insert + */ + operation: 'delete' | 'insert' | 'update'; + /** + * Retry Count + * @example 10 + */ + retries?: number; + /** + * Retry Interval + * @example 60000 + */ + retry_interval?: number; + /** + * Timeout + * @example 60000 + */ + timeout?: number; + /** + * Hook Title + * @example My Webhook + */ + title: string; + /** Hook Type */ + type?: string | null; } -export interface RollupType { - id?: string; - type?: string; - virtual?: BoolType; - fk_column_id?: string; - fk_relation_column_id?: string; - fk_rollup_column_id?: string; - rollup_function?: string; - deleted?: string; - order?: string; +/** + * Model for Hook List + */ +export interface HookListType { + list?: HookType[]; + /** Model for Paginated */ + pageInfo?: PaginatedType; } -export interface FormulaType { - id?: string; +/** + * Model for Hook Log + */ +export interface HookLogType { + base_id?: string; + conditions?: string; + error?: string; + error_code?: string; + error_message?: string; + event?: string; + execution_time?: string; + /** Model for StringOrNull */ + fk_hook_id?: StringOrNullType; + /** Unique ID */ + id?: IdType; + notifications?: string; + operation?: string; + payload?: any; + project_id?: string; + response?: string; + /** Model for Bool */ + test_call?: BoolType; + triggered_by?: string; type?: string; - virtual?: BoolType; - fk_column_id?: string; - formula?: string; - formula_raw?: string; - deleted?: string; - order?: string; } -export interface SelectOptionsType { - options: SelectOptionType[]; +/** + * Model for Hook Test Request + */ +export interface HookTestReqType { + /** Model for Hook */ + hook: HookReqType; + /** Payload to be sent */ + payload: any; } -export interface SelectOptionType { - id?: string; - fk_column_id?: string; - title?: string; - color?: string; - order?: number; -} +/** + * Model for ID + */ +export type IdType = string; -export interface GridType { - id?: string; +/** + * Model for Kanban + */ +export interface KanbanType { + /** Unique ID */ + id?: IdType; + /** Grouping Field Column ID */ + fk_grp_col_id?: StringOrNullType; + /** View ID */ + fk_view_id?: IdType; + /** Cover Image Column ID */ + fk_cover_image_col_id?: IdType; + /** Kanban Columns */ + columns?: KanbanColumnType[]; + /** Meta Info for Kanban */ + meta?: MetaType; + /** + * Kanban Title + * @example My Kanban + */ title?: string; - alias?: string; - deleted?: BoolType; - order?: number; - lock_type?: 'collaborative' | 'locked' | 'personal'; - row_height?: number; -} - -export interface GridReqType { - title: string; - order?: number; - lock_type?: 'collaborative' | 'locked' | 'personal'; - row_height?: number; } -export interface GalleryType { - fk_view_id?: string; +/** + * Model for Kanban Column + */ +export interface KanbanColumnType { + /** Unique ID */ + id?: IdType; + /** Foreign Key to Column */ + fk_column_id?: IdType; + /** Foreign Key to View */ + fk_view_id?: IdType; + /** + * Baes ID + * + */ + base_id?: IdType; + /** Project ID */ + project_id?: IdType; + /** Project ID */ title?: string; - alias?: string; - deleted?: BoolType; + /** Is this column shown? */ + show?: BoolType; + /** + * Column Order + * @example 1 + */ order?: number; - next_enabled?: BoolType; - prev_enabled?: BoolType; - cover_image_idx?: number; - cover_image?: string; - restrict_types?: string; - restrict_size?: string; - restrict_number?: string; - columns?: GalleryColumnType[]; - fk_model_id?: string; - fk_cover_image_col_id?: string; - lock_type?: 'collaborative' | 'locked' | 'personal'; } -export interface GalleryReqType { +/** + * Model for Kanban Request + */ +export interface KanbanReqType { + /** Grouping Column ID */ + fk_grp_col_id?: StringOrNullType; + /** + * The title of the kanban + * @example My Kanban + */ title: string; - next_enabled?: BoolType; - prev_enabled?: BoolType; - cover_image_idx?: number; - cover_image?: string; - restrict_types?: string; - restrict_size?: string; - restrict_number?: string; - fk_cover_image_col_id?: string; - lock_type?: 'collaborative' | 'locked' | 'personal'; } -export interface GalleryColumnType { - id?: string; - label?: string; - help?: string; - fk_col_id?: string; - fk_gallery_id?: string; +/** + * Model for Kanban Update Request + */ +export interface KanbanUpdateReqType { + /** Model for StringOrNull */ + fk_grp_col_id?: StringOrNullType; } -export interface GridColumnReqType { - label?: string; - help?: string; - fk_column_id?: string; - fk_gallery_id?: string; - width?: string; +/** + * Model for Kanban Request + */ +export interface LicenseReqType { + /** + * The license key + * @example 1234567890 + */ + key?: string; } -export interface GridColumnType { - id?: string; - label?: string; - help?: string; - fk_column_id?: string; - fk_gallery_id?: string; - width?: string; +/** + * Model for LinkToAnotherColumn Request + */ +export interface LinkToAnotherColumnReqType { + /** Foreign Key to chhild column */ + childId: IdType; + /** Foreign Key to parent column */ + parentId: IdType; + /** The title of the virtual column */ + title: string; + /** The type of the relationship */ + type: 'bt' | 'hm' | 'mm'; + /** Abstract type of the relationship */ + uidt: 'LinkToAnotherRecord'; + /** Is this relationship virtual? */ + virtual?: BoolType; } -export interface KanbanColumnType { - id?: string; - label?: string; - help?: string; - fk_column_id?: string; - fk_kanban_id?: string; +/** + * Model for LinkToAnotherRecord + */ +export interface LinkToAnotherRecordType { + deleted?: string; + dr?: string; + fk_child_column_id?: string; + /** Foreign Key to Column */ + fk_column_id?: IdType; + fk_index_name?: string; + fk_mm_child_column_id?: string; + fk_mm_model_id?: string; + fk_mm_parent_column_id?: string; + fk_parent_column_id?: string; + fk_related_model_id?: string; + /** Unique ID */ + id?: IdType; + order?: string; + type?: string; + ur?: string; + /** Model for Bool */ + virtual?: BoolType; } -export interface KanbanType { - id?: string; - title?: string; - alias?: string; - columns?: KanbanColumnType[]; - fk_model_id?: string; - fk_grp_col_id?: StringOrNullType; - fk_cover_image_col_id?: string; - meta?: MetaType; +/** + * Model for Lookup + */ +export interface LookupType { + /** Unique ID */ + id?: IdType; + /** Foreign Key to Column */ + fk_column_id?: IdType; + /** Foreign Key to Lookup Column */ + fk_lookup_column_id?: IdType; + /** Foreign Key to Relation Column */ + fk_relation_column_id?: IdType; + /** + * The order among the list + * @example 1 + */ + order?: number; } -export interface GeoLocationType { - /** @format double */ - latitude?: number; - /** @format double */ - longitude?: number; +/** + * Model for Lookup Column Request + */ +export interface LookupColumnReqType { + /** Foreign Key to Lookup Column */ + fk_lookup_column_id?: IdType; + /** Foreign Key to Relation Column */ + fk_relation_column_id?: IdType; + /** + * Lookup Title + * @example My Lookup + */ + title?: string; + /** UI DataType */ + uidt?: 'Lookup'; } +/** + * Model for Map + */ export interface MapType { - id?: string; - title?: string; - alias?: string; - initial_geo_position?: GeoLocationType; - fk_model_id?: string; + /** + * The ID of the base that this view belongs to + * @example ds_g4ccx6e77h1dmi + */ + base_id?: string; + /** Columns in this view */ + columns?: MapColumnType[]; + /** + * Foreign Key to GeoData Column + * @example cl_8iw2o4ejzvdyna + */ + fk_geo_data_col_id?: string; + /** + * Unique ID for Map + * @example vw_qjt7klod1p9kyv + */ fk_view_id?: string; - fk_geo_data_col_id?: StringOrNullType; - columns?: MapColumnType[]; + /** Meta data for this view */ meta?: MetaType; + /** The order of the map list */ + order?: number; + /** + * The ID of the project that this view belongs to + * @example p_xm3thidrblw4n7 + */ + project_id?: string; + /** To show this Map or not */ + show?: boolean; + /** + * Title of Map View + * @example My Map + */ + title?: string; } +/** + * Model for Map Column + */ export interface MapColumnType { + /** + * The ID of the base that this map column belongs to + * @example ds_g4ccx6e77h1dmi + */ + base_id?: string; + /** + * Foreign Key to Column + * @example cl_8iw2o4ejzvdyna + */ + fk_column_id?: string; + /** + * Foreign Key to View + * @example vw_qjt7klod1p9kyv + */ + fk_view_id?: string; + /** + * Unique ID of Map Column + * @example nc_46xcacqn4rc9xf + */ id?: string; - label?: string; - help?: string; - fk_col_id?: string; - fk_gallery_id?: string; -} - -export interface LicenseReqType { - key?: string; -} - -export interface KanbanReqType { - title: string; - fk_grp_col_id?: StringOrNullType; + /** + * the order in the list of map columns + * @example 1 + */ + order?: number; + /** + * The ID of the project that this map column belongs to + * @example p_xm3thidrblw4n7 + */ + project_id?: string; + /** + * Whether to show this column or not + * @example 1 + */ + show?: number; } -export interface KanbanUpdateReqType { - fk_grp_col_id?: StringOrNullType; -} +/** + * Model for Meta + */ +export type MetaType = null | object | string; -export interface FormType { - id?: string; - title?: string; - heading?: string; - subheading?: string; - success_msg?: string; - redirect_url?: StringOrNullType; - redirect_after_secs?: StringOrNullType; - email?: StringOrNullType; - banner_image_url?: StringOrNullType; - logo_url?: StringOrNullType; - submit_another_form?: BoolType; - show_blank_form?: BoolType; - columns?: FormColumnType[]; +/** + * Model for ModelRoleVisibility + */ +export interface ModelRoleVisibilityType { + base_id?: string; + /** Model for Bool */ + disabled?: BoolType; fk_model_id?: string; - lock_type?: 'collaborative' | 'locked' | 'personal'; - meta?: MetaType; + fk_view_id?: string; + /** Unique ID */ + id?: IdType; + project_id?: string; + role?: string; } -export interface FormReqType { +/** + * Model for Normal Column Request + */ +export interface NormalColumnRequestType { + /** Is this column auto-incremented? */ + ai?: BoolType; + /** Is this column auto-updated datetime field? */ + au?: BoolType; + /** Column Comment */ + cc?: StringOrNullType; + /** Column Default Value */ + cdf?: StringOrNullType; + /** Column Name */ + column_name: string; + /** Model for StringOrNull */ + csn?: StringOrNullType; + /** Data Type */ + dt?: string; + /** Data Type Extra */ + dtx?: StringOrNullType; + /** Data Type Extra Precision */ + dtxp?: StringOrNullType | number; + /** Data Type Extra Scale */ + dtxs?: StringOrNullType | number; + /** Numeric Precision */ + np?: StringOrNullType | number; + /** Numeric Scale */ + ns?: StringOrNullType | number; + /** Is this column a primary key? */ + pk?: BoolType; + /** Is this column a primary value? */ + pv?: BoolType; + /** Is this column required? */ + rqd?: BoolType; + /** Column Title */ title?: string; - heading?: string; - subheading?: string; - success_msg?: string; - redirect_url?: StringOrNullType; - redirect_after_secs?: StringOrNullType; - email?: StringOrNullType; - banner_image_url?: StringOrNullType; - logo_url?: StringOrNullType; - submit_another_form?: BoolType; - show_blank_form?: BoolType; - lock_type?: 'collaborative' | 'locked' | 'personal'; - meta?: MetaType; -} - -export type FormCreateReqType = FormReqType; - -export interface FormColumnType { - fk_column_id?: string; - id?: string; - fk_view_id?: string; - uuid?: any; - label?: string; - help?: any; - required?: BoolType; - show?: BoolType; - order?: number; - created_at?: string; - updated_at?: string; - description?: string; - meta?: MetaType; + /** UI Data Type */ + uidt?: + | 'Attachment' + | 'AutoNumber' + | 'Barcode' + | 'Button' + | 'Checkbox' + | 'Collaborator' + | 'Count' + | 'CreateTime' + | 'Currency' + | 'Date' + | 'DateTime' + | 'Decimal' + | 'Duration' + | 'Email' + | 'Formula' + | 'ForeignKey' + | 'GeoData' + | 'Geometry' + | 'ID' + | 'JSON' + | 'LastModifiedTime' + | 'LongText' + | 'LinkToAnotherRecord' + | 'Lookup' + | 'MultiSelect' + | 'Number' + | 'Percent' + | 'PhoneNumber' + | 'Rating' + | 'Rollup' + | 'SingleLineText' + | 'SingleSelect' + | 'SpecificDBType' + | 'Time' + | 'URL' + | 'Year' + | 'QrCode'; + /** Is this column unique? */ + un?: BoolType; + /** Is this column unique? */ + unique?: BoolType; } -export interface FormColumnReqType { - uuid?: any; - label?: string; - help?: any; - required?: BoolType; - show?: BoolType; - order?: number; - description?: string; - meta?: MetaType; +/** + * Model for Organisation User Update Request + */ +export interface OrgUserReqType { + /** @format email */ + email?: string; + /** Roles for the project user */ + roles?: 'org-level-creator' | 'org-level-viewer'; } +/** + * Model for Paginated + */ export interface PaginatedType { - pageSize?: number; - totalRows?: number; - sort?: string | SortType[]; + /** Is the current page the first page */ isFirstPage?: boolean; + /** Is the current page the last page */ isLastPage?: boolean; + /** + * The current page + * @example 1 + */ page?: number; + /** + * The number of pages + * @example 10 + */ + pageSize?: number; + /** + * The number of rows in the given result + * @example 1 + */ + totalRows?: number; } -export interface HookListType { - list?: object[]; - pageInfo?: PaginatedType; -} +/** + * Model for Password + * @example password123456789 + */ +export type PasswordType = string; -export interface SharedViewType { - id?: string; - fk_view_id?: string; - password?: string; - deleted?: string; +/** + * Model for Password Change Request + */ +export interface PasswordChangeReqType { + currentPassword: string; + newPassword: string; } -export interface SharedViewListType { - list?: SharedViewType[]; - pageInfo?: PaginatedType; +/** + * Model for Password Forgot Request + */ +export interface PasswordForgotReqType { + /** + * Email address of the user + * @format email + */ + email: string; } -export interface ViewListType { - list?: ViewType[]; - pageInfo?: PaginatedType; +/** + * Model for Password Reset Request + */ +export interface PasswordResetReqType { + /** + * New password + * @example newpassword + */ + password: string; } -export interface AttachmentType { - url?: string; - title?: string; - mimetype?: string; - size?: string; +/** + * Model for Plugin + */ +export interface PluginType { + /** Is plguin active? */ + active?: BoolType; + /** + * Plugin Category + * @example Storage + */ + category?: string; + /** Plugin Creator (Not in use) */ + creator?: string; + /** Plugin Creator website (Not in use) */ + creator_website?: string; + /** + * Plugin Description + * @example Amazon Simple Storage Service (Amazon S3) is an object storage service that offers industry-leading scalability, data availability, security, and performance. + */ + description?: string; + /** Documentation of plugin (Not in use) */ + docs?: string; + /** Plugin Icon (Not in use) */ icon?: string; - path?: string; - data?: any; + /** Unique ID */ + id?: IdType; + /** Plugin Input */ + input?: StringOrNullType | number; + /** + * Plugin Input Schema + * + */ + input_schema?: string; + /** + * Plugin logo + * @example plugins/s3.png + */ + logo?: string; + /** Plugin Price (Not in use) */ + price?: string; + /** Plugin Rating (Not in use) */ + rating?: number; + /** + * Plugin Status + * @example install + */ + status?: string; + /** Not in use */ + status_details?: string; + /** + * Plugin tags + * @example Storage + */ + tags?: string; + /** Plugin Title */ + title?: string; + /** + * Plugin Version + * @example 0.0.1 + */ + version?: string; +} + +/** + * Model for Plugin Request + */ +export interface PluginReqType { + /** Is Plugin Active? */ + active?: BoolType; + /** Plugin Input */ + input?: string; +} + +/** + * Model for Plugin Test Request + */ +export interface PluginTestReqType { + /** Plugin Title */ + title: string; + /** Plugin Input as JSON string */ + input: string; } -export interface WebhookType { +/** + * Model for Project + */ +export interface ProjectType { + /** List of base models */ + bases?: BaseType[]; + /** + * Primary Theme Color + * @example #24716E + */ + color?: string; + /** Is the project deleted */ + deleted?: BoolType; + /** + * Project Description + * @example This is my project description + */ + description?: string; + /** + * Unique Project ID + * @example p_124hhlkbeasewh + */ id?: string; + /** Model for Bool */ + is_meta?: BoolType; + /** Meta Info such as theme colors */ + meta?: MetaType; + /** The order in project list */ + order?: number; + /** + * Project prefix. Used in XCDB only. + * @example nc_vm5q__ + */ + prefix?: string; + status?: string; + /** + * Project Title + * @example my-project + */ title?: string; - type?: string; } -export interface AuditType { - id?: string; - user?: string; - ip?: string; - base_id?: string; - project_id?: string; - fk_model_id?: string; - row_id?: string; - op_type?: string; - op_sub_type?: string; - status?: string; - description?: string; - details?: string; +/** + * Model for Project List + */ +export interface ProjectListType { + /** List of Project Models */ + list?: ProjectType[]; + /** Pagination Info */ + pageInfo?: PaginatedType; } -export interface HookType { - id?: string; - fk_model_id?: string; - title?: string; +/** + * Model for Project Request + */ +export interface ProjectReqType { + /** Array of Bases */ + bases?: BaseReqType[]; + /** + * Primary Theme Color + * @example #24716E + */ + color?: string; + /** + * Project Description + * @example This is my project description + */ description?: string; - env?: string; - type?: string; - event?: 'after' | 'before'; - operation?: 'insert' | 'delete' | 'update'; - async?: BoolType; - notification?: string; - retries?: number; - retry_interval?: number; - timeout?: number; - active?: BoolType; -} - -export interface HookReqType { - id?: string; - fk_model_id?: string; + /** + * Project Title + * @example My Project + */ title: string; - description?: StringOrNullType; - env?: string; - event: 'after' | 'before'; - operation: 'insert' | 'delete' | 'update'; - async?: string | number | null; - notification: object; - retries?: number; - retry_interval?: number; - timeout?: number; - active?: BoolType; } -export interface HookTestReqType { - payload: any; - hook: HookReqType; +/** + * Model for Project User Request + */ +export interface ProjectUserReqType { + /** + * Project User Email + * @format email + */ + email: string; + /** Project User Role */ + roles: 'commenter' | 'editor' | 'guest' | 'owner' | 'viewer' | 'creator'; } -export interface SignUpReqType { - email: string; - password: string; +/** + * Model for Rollup + */ +export interface RollupType { + /** Unique ID */ + id?: IdType; + /** Foreign Key to Column */ + fk_column_id?: IdType; + /** Foreign to Relation Column */ + fk_relation_column_id?: IdType; + /** Foreign to Rollup Column */ + fk_rollup_column_id?: IdType; + /** + * Rollup Function + * @example count + */ + rollup_function?: + | 'count' + | 'min' + | 'max' + | 'avg' + | 'countDistinct' + | 'sumDistinct' + | 'avgDistinct'; } -export interface SignInReqType { - email: string; - password: string; +/** + * Model for Rollup Column Request + */ +export interface RollupColumnReqType { + /** Foreign Key to Relation Column */ + fk_relation_column_id?: IdType; + /** Foreign Key to Rollup Column */ + fk_rollup_column_id?: IdType; + /** Rollup Column Title */ + title?: string; + /** Rollup Function */ + rollup_function?: + | 'avg' + | 'avgDistinct' + | 'count' + | 'countDistinct' + | 'max' + | 'min' + | 'sum' + | 'sumDistinct'; + /** UI DataType */ + uidt?: 'Rollup'; } -export interface PasswordForgotReqType { - email: string; +/** + * Model for SelectOption + */ +export interface SelectOptionType { + /** Unique ID */ + id?: IdType; + /** + * Option Title + * + * @example Option A + */ + title?: string; + /** Foreign Key to Column */ + fk_column_id?: IdType; + /** + * Option Color + * @example #cfdffe + */ + color?: string; + /** + * The order among the options + * @example 1 + */ + order?: number; } -export interface PasswordResetReqType { - password: string; +/** + * Model for SelectOptions + */ +export interface SelectOptionsType { + /** Array of select options */ + options: SelectOptionType[]; } -export interface PasswordChangeReqType { - currentPassword: string; - newPassword: string; +/** + * Model for Shared Base Request + */ +export interface SharedBaseReqType { + /** + * Password to protect the base + * @example password123 + */ + password?: string; + /** + * The role given the target user + * @example editor + */ + roles?: 'commenter' | 'editor' | 'viewer'; } -export interface ApiTokenReqType { - description?: StringOrNullType; +/** + * Model for Shared View + */ +export type SharedViewType = ViewType; + +/** + * Model for Shared View List + */ +export interface SharedViewListType { + list?: SharedViewType[]; + /** Model for Paginated */ + pageInfo?: PaginatedType; } -export interface PluginType { - id?: string; - title?: string; - description?: string; - active?: BoolType; - rating?: number; - version?: string; - docs?: string; - status?: string; - status_details?: string; - logo?: string; - icon?: string; - tags?: string; - category?: string; - input_schema?: string; - input?: number | StringOrNullType; - creator?: string; - creator_website?: string; - price?: string; +/** + * Model for Shared View Request + */ +export interface SharedViewReqType { + /** Meta data passing to Shared View such as if download is allowed or not. */ + meta?: MetaType; + /** Password to restrict access */ + password?: StringOrNullType; } -export interface ModelRoleVisibilityType { - id?: string; - project_id?: string; - base_id?: string; - fk_model_id?: string; - fk_view_id?: string; - role?: string; - disabled?: BoolType; +/** + * Model for Signin Request + */ +export interface SignInReqType { + /** + * Email address of the user + * @format email + */ + email: string; + /** Password of the user */ + password: string; } -export interface ApiTokenType { - id?: string; - token?: string; - description?: string; - fk_user_id?: string; - created_at?: any; - updated_at?: any; +/** + * Model for Signup Request + */ +export interface SignUpReqType { + /** + * Email address of the user + * @format email + * @example user@example.com + */ + email: string; + /** + * Password of the user + * @example password123456789 + */ + password: string; + /** Model for StringOrNull */ + firstname?: StringOrNullType; + /** Model for StringOrNull */ + lastname?: StringOrNullType; + /** Sign Up Token. Used for invitation. */ + token?: StringOrNullType; + /** Ignore Subscription */ + ignore_subscribe?: BoolType; } -export interface HookLogType { - id?: string; +/** + * Model for Sort + */ +export interface SortType { + /** Unique ID */ + id?: IdType; + /** Model for ID */ + fk_column_id?: IdType; + /** Model for ID */ + fk_model_id?: IdType; + /** + * Base ID + * @example ds_3l9qx8xqksenrl + */ base_id?: string; + /** + * Sort direction + * @example desc + */ + direction?: 'asc' | 'desc'; + /** @example 1 */ + order?: number; + /** + * Project ID + * @example p_9sx43moxhqtjm3 + */ project_id?: string; - fk_hook_id?: StringOrNullType; - type?: string; - event?: string; - operation?: string; - test_call?: BoolType; - payload?: any; - conditions?: string; - notifications?: string; - error_code?: string; - error_message?: string; - error?: string; - execution_time?: string; - response?: string; - triggered_by?: string; - created_at?: string; - updated_at?: string; } -export interface NormalColumnRequestType { - uidt?: - | 'ID' - | 'SingleLineText' - | 'LongText' - | 'Attachment' - | 'Checkbox' - | 'MultiSelect' - | 'SingleSelect' - | 'Collaborator' - | 'Date' - | 'Year' - | 'GeoData' - | 'Time' - | 'PhoneNumber' - | 'Email' - | 'URL' - | 'Number' - | 'Decimal' - | 'Currency' - | 'Percent' - | 'Duration' - | 'Rating' - | 'Count' - | 'DateTime' - | 'CreateTime' - | 'LastModifiedTime' - | 'AutoNumber' - | 'Geometry' - | 'JSON' - | 'SpecificDBType' - | 'Barcode' - | 'Button'; - id?: string; - base_id?: string; - fk_model_id?: string; - title?: string; - dt?: string; - np?: number | StringOrNullType; - ns?: number | StringOrNullType; - pk?: BoolType; - pv?: BoolType; - rqd?: BoolType; - column_name?: string; - un?: BoolType; - ct?: string; - ai?: BoolType; - unique?: BoolType; - cdf?: StringOrNullType; - cc?: string; - csn?: string; - dtx?: string; - dtxp?: number | StringOrNullType; - dtxs?: number | StringOrNullType; - au?: BoolType; +/** + * Model for Sort List + */ +export interface SortListType { + sorts: { + list: SortType[]; + }; } -export interface LinkToAnotherColumnReqType { - uidt: 'LinkToAnotherRecord'; - title: string; - virtual?: BoolType; - parentId: string; - childId: string; - type: 'hm' | 'bt' | 'mm'; +/** + * Model for Sort Request + */ +export interface SortReqType { + /** Foreign Key to Column */ + fk_column_id?: IdType; + /** Sort direction */ + direction?: 'asc' | 'desc'; } -export interface RollupColumnReqType { - uidt?: 'Rollup'; - title?: string; - fk_relation_column_id?: string; - fk_rollup_column_id?: string; - rollup_function?: string; +/** + * Model for StringOrNull + */ +export type StringOrNullType = string | null; + +/** + * Model for Table + */ +export interface TableType { + /** Unique Base ID */ + base_id?: string; + /** The columns included in this table */ + columns?: ColumnType[]; + /** Column Models grouped by IDs */ + columnsById?: object; + /** Model for Bool */ + deleted?: BoolType; + /** Is this table enabled? */ + enabled?: BoolType; + /** Unique Table ID */ + id?: string; + /** Meta Data */ + meta?: MetaType; + /** Is this table used for M2M */ + mm?: BoolType; + /** The order of the list of tables */ + order?: number; + /** Currently not in use */ + pinned?: BoolType; + /** Unique Project ID */ + project_id?: string; + /** Table Name. Prefix will be added for XCDB projects. */ + table_name: string; + /** Currently not in use */ + tags?: StringOrNullType; + /** Table Title */ + title: string; + /** Table Type */ + type?: string; } -export interface LookupColumnReqType { - uidt?: 'Lookup'; - title?: string; - fk_relation_column_id?: string; - fk_lookup_column_id?: string; +/** + * Model for Table List + */ +export interface TableListType { + list?: TableType[]; + /** Model for Paginated */ + pageInfo?: PaginatedType; } -export interface FormulaColumnReqType { - uidt?: string; - formula_raw?: string; - formula?: string; +/** + * Model for Table Request + */ +export interface TableReqType { + /** The column models in this table */ + columns: NormalColumnRequestType[]; + /** the meta data for this table */ + meta?: MetaType; + /** + * The order of table list + * @example 1 + */ + order?: number; + /** + * Table name + * @example my_table + */ + table_name: string; + /** + * Table title + * @example My Table + */ title?: string; } -export type ColumnReqType = ( - | LinkToAnotherColumnReqType - | RollupColumnReqType - | FormulaColumnReqType - | LookupColumnReqType - | NormalColumnRequestType - | (LinkToAnotherColumnReqType & - RollupColumnReqType & - FormulaColumnReqType & - LookupColumnReqType & - NormalColumnRequestType) -) & { - column_name?: string; - title?: string; - column_order?: { - view_id?: string; - order?: number; - }; -}; +/** + * Model for User + */ +export interface UserType { + /** + * The email of the user + * @format email + * @example user@example.com + */ + email: string; + /** Set to true if the user's email has been verified. */ + email_verified: boolean; + /** + * The first name of the user + * @example Alice + */ + firstname: string; + /** + * Unique identifier for the given user. + * @example us_8kugj628ebjngs + */ + id: string; + /** + * The last name of the user + * @example Smith + */ + lastname: string; + /** + * The roles of the user + * @example org-level-viewer + */ + roles?: string; +} +/** + * Model for User Info + */ export interface UserInfoType { - id?: string; + /** + * User Email + * @format email + */ email?: string; - email_verified?: string; + /** Set to true if the user's email has been verified. */ + email_verified?: boolean; + /** The firstname of the user */ firstname?: string; + /** User ID */ + id?: string; + /** The lastname of the user */ lastname?: string; + /** The roles of the user */ roles?: any; } -export type VisibilityRuleReqType = { - disabled?: { - commenter?: BoolType; - creator?: BoolType; - editor?: BoolType; - guest?: BoolType; - owner?: BoolType; - viewer?: BoolType; +/** + * Model for User List + */ +export interface UserListType { + /** users includes `list` and `pageInfo` */ + users: { + /** List of User objects */ + list: UserType; + /** Pagination info */ + pageInfo: PaginatedType; }; -}[]; - -export type BoolType = boolean | number | null; - -export type StringOrNullType = string | null; - -export type MetaType = object | string | null; - -export interface CommentReqType { - row_id: string; - fk_model_id: string; - description?: string; } -export interface AuditRowUpdateReqType { - fk_model_id?: string; - column_name?: string; - row_id?: string; - value?: any; - prev_value?: any; +/** + * Model for View + */ +export interface ViewType { + /** Unique Base ID */ + base_id?: IdType; + /** Unique Model ID */ + fk_model_id: IdType; + /** Unique ID for View */ + id?: IdType; + /** Lock Type of the view */ + lock_type?: 'collaborative' | 'locked' | 'personal'; + /** Meta data for this view */ + meta?: MetaType; + /** The rder of the list of views */ + order?: number; + /** Password for protecting the view */ + password?: string; + /** Unique Project ID */ + project_id?: IdType; + /** If this view is shown? */ + show: BoolType; + /** Should show system fields in this view? */ + show_system_fields?: BoolType; + /** View Title */ + title: string; + /** View Type */ + type: number; + /** UUID of the view */ + uuid?: StringOrNullType; + /** Associated View Model */ + view?: + | FormType + | GalleryType + | GridType + | KanbanType + | MapType + | (FormType & GalleryType & GridType & KanbanType & MapType); } -export interface OrgUserReqType { - email?: string; - roles?: string; +/** + * Model for View List + */ +export interface ViewListType { + list?: ViewType[]; + /** Model for Paginated */ + pageInfo?: PaginatedType; } -export interface ProjectUserReqType { - email?: string; - roles?: string; +/** + * Model for View Request + */ +export interface ViewReqType { + /** + * View Title + * @example Grid View 1 + */ + title?: string; + /** + * View UUID. Used in Shared View. + * @example e2457bbf-e29c-4fec-866e-fe3b01dba57f + */ + uuid?: string; + /** + * View Password. Used in Shared View. + * @example password123 + */ + password?: string; + /** + * Lock type of View. + * @example collaborative + */ + lock_type?: 'collaborative' | 'locked' | 'personal'; + /** Meta info used in View. */ + meta?: MetaType; + /** + * The order of the list of views. + * @min 0 + * @example 1 + */ + order?: number; + /** Should this view show system fields? */ + show_system_fields?: BoolType; } -export interface SharedBaseReqType { - uuid?: StringOrNullType; - roles?: StringOrNullType; +/** + * Model for View Column Update Request + */ +export interface ViewColumnUpdateReqType { + /** View Title */ + show?: BoolType; + /** + * The order of the list of views. + * @min 0 + * @example 1 + */ + order?: number; } -export interface PluginTestReqType { - title?: string; - input?: any; +/** + * Model for View Column Request + */ +export interface ViewColumnReqType { + /** Foreign Key to Column */ + fk_column_id?: IdType; + /** View Title */ + show?: BoolType; + /** + * The order of the list of views. + * @min 0 + * @example 1 + */ + order?: number; } -export interface PluginReqType { - active?: BoolType; - input?: any; -} +/** + * Model for Visibility Rule Request + */ +export type VisibilityRuleReqType = { + id?: string | null; + disabled?: { + /** Model for Bool */ + commenter?: BoolType; + /** Model for Bool */ + creator?: BoolType; + /** Model for Bool */ + editor?: BoolType; + /** Model for Bool */ + guest?: BoolType; + /** Model for Bool */ + owner?: BoolType; + /** Model for Bool */ + viewer?: BoolType; + }; +}[]; import axios, { AxiosInstance, AxiosRequestConfig, ResponseType } from 'axios'; @@ -1087,6 +2459,8 @@ export class HttpClient { * @title nocodb * @version 1.0 * @baseUrl http://localhost:8080 + * + * NocoDB API Documentation */ export class Api< SecurityDataType extends unknown @@ -1100,6 +2474,7 @@ export class Api< * @summary Signup * @request POST:/api/v1/auth/user/signup * @response `200` `{ + \** The signed JWT token for information exchange *\ token?: string, }` OK @@ -1107,21 +2482,21 @@ export class Api< msg?: string, }` Bad Request - * @response `401` `void` Unauthorized - * @response `403` `void` Forbidden */ signup: (data: SignUpReqType, params: RequestParams = {}) => this.request< { + /** The signed JWT token for information exchange */ token?: string; }, { msg?: string; - } | void + } >({ path: `/api/v1/auth/user/signup`, method: 'POST', body: data, + type: ContentType.Json, format: 'json', ...params, }), @@ -1134,6 +2509,7 @@ export class Api< * @summary Signout * @request POST:/api/v1/auth/user/signout * @response `200` `{ + \** Success Message *\ msg?: string, }` OK @@ -1141,6 +2517,7 @@ export class Api< signout: (params: RequestParams = {}) => this.request< { + /** Success Message */ msg?: string; }, any @@ -1159,10 +2536,12 @@ export class Api< * @summary Signin * @request POST:/api/v1/auth/user/signin * @response `200` `{ + \** The signed JWT token for information exchange *\ token?: string, }` OK * @response `400` `{ + \** Error Message *\ msg?: string, }` Bad Request @@ -1170,9 +2549,11 @@ export class Api< signin: (data: SignInReqType, params: RequestParams = {}) => this.request< { + /** The signed JWT token for information exchange */ token?: string; }, { + /** Error Message */ msg?: string; } >({ @@ -1189,14 +2570,14 @@ export class Api< * * @tags Auth * @name Me - * @summary User info + * @summary Get User Info * @request GET:/api/v1/auth/user/me * @response `200` `UserInfoType` OK */ me: ( query?: { /** Pass project id to get project specific roles along with user info */ - project_id?: string; + project_id?: IdType; }, params: RequestParams = {} ) => @@ -1213,7 +2594,7 @@ export class Api< * * @tags Auth * @name PasswordForgot - * @summary Password forgot + * @summary Forget Password * @request POST:/api/v1/auth/password/forgot * @response `200` `void` OK * @response `401` `void` Unauthorized @@ -1232,13 +2613,15 @@ export class Api< * * @tags Auth * @name PasswordChange - * @summary Password change + * @summary Change Password * @request POST:/api/v1/auth/password/change * @response `200` `{ + \** Success Message *\ msg?: string, }` OK * @response `400` `{ + \** Error Message *\ msg?: string, }` Bad request @@ -1246,9 +2629,11 @@ export class Api< passwordChange: (data: PasswordChangeReqType, params: RequestParams = {}) => this.request< { + /** Success Message */ msg?: string; }, { + /** Error Message */ msg?: string; } >({ @@ -1261,11 +2646,11 @@ export class Api< }), /** - * @description Validtae password reset url token. + * @description Validate password reset url token. * * @tags Auth * @name PasswordResetTokenValidate - * @summary Reset token verify + * @summary Verify Reset Token * @request POST:/api/v1/auth/token/validate/{token} * @response `200` `void` OK */ @@ -1281,7 +2666,7 @@ export class Api< * * @tags Auth * @name EmailValidate - * @summary Verify email + * @summary Verify Email * @request POST:/api/v1/auth/email/validate/{token} * @response `200` `void` OK */ @@ -1297,7 +2682,7 @@ export class Api< * * @tags Auth * @name PasswordReset - * @summary Password reset + * @summary Reset Password * @request POST:/api/v1/auth/password/reset/{token} * @response `200` `void` OK */ @@ -1315,42 +2700,55 @@ export class Api< }), /** - * No description - * - * @tags Auth - * @name TokenRefresh - * @summary Refresh token - * @request POST:/api/v1/auth/token/refresh - * @response `200` `void` OK - */ + * @description Regenerate user refresh token + * + * @tags Auth + * @name TokenRefresh + * @summary Refresh Token + * @request POST:/api/v1/auth/token/refresh + * @response `200` `{ + \** New access token for user *\ + token?: string, + +}` OK + */ tokenRefresh: (params: RequestParams = {}) => - this.request({ + this.request< + { + /** New access token for user */ + token?: string; + }, + any + >({ path: `/api/v1/auth/token/refresh`, method: 'POST', + format: 'json', ...params, }), /** - * No description + * @description List all users in the given project. * * @tags Auth * @name ProjectUserList - * @summary Project users + * @summary List Project Users * @request GET:/api/v1/db/meta/projects/{projectId}/users * @response `200` `{ users?: { list: (UserType)[], + \** Model for Paginated *\ pageInfo: PaginatedType, }, }` OK */ - projectUserList: (projectId: string, params: RequestParams = {}) => + projectUserList: (projectId: IdType, params: RequestParams = {}) => this.request< { users?: { list: UserType[]; + /** Model for Paginated */ pageInfo: PaginatedType; }; }, @@ -1363,16 +2761,16 @@ export class Api< }), /** - * No description + * @description Create a user and add it to the given project * * @tags Auth * @name ProjectUserAdd - * @summary Project User Add + * @summary Create Project User * @request POST:/api/v1/db/meta/projects/{projectId}/users * @response `200` `any` OK */ projectUserAdd: ( - projectId: string, + projectId: IdType, data: ProjectUserReqType, params: RequestParams = {} ) => @@ -1386,17 +2784,17 @@ export class Api< }), /** - * No description + * @description Update a given user in a given project. Exclusive for Super Admin. Access with API Tokens will be blocked. * * @tags Auth * @name ProjectUserUpdate - * @summary Project user update + * @summary Update Project User * @request PATCH:/api/v1/db/meta/projects/{projectId}/users/{userId} * @response `200` `any` OK */ projectUserUpdate: ( - projectId: string, - userId: string, + projectId: IdType, + userId: IdType, data: ProjectUserReqType, params: RequestParams = {} ) => @@ -1410,17 +2808,17 @@ export class Api< }), /** - * No description + * @description Delete a given user in a given project. Exclusive for Super Admin. Access with API Tokens will be blocked. * * @tags Auth * @name ProjectUserRemove - * @summary Project user remove + * @summary Delete Project User * @request DELETE:/api/v1/db/meta/projects/{projectId}/users/{userId} * @response `200` `any` OK */ projectUserRemove: ( - projectId: string, - userId: string, + projectId: IdType, + userId: IdType, params: RequestParams = {} ) => this.request({ @@ -1435,12 +2833,13 @@ export class Api< * * @tags Auth * @name ProjectUserResendInvite + * @summary Resend User Invitation * @request POST:/api/v1/db/meta/projects/{projectId}/users/{userId}/resend-invite * @response `200` `any` OK */ projectUserResendInvite: ( - projectId: string, - userId: string, + projectId: IdType, + userId: IdType, params: RequestParams = {} ) => this.request({ @@ -1452,11 +2851,11 @@ export class Api< }; orgTokens = { /** - * No description + * @description List all organisation API tokens. Access with API tokens will be blocked. * - * @tags Org tokens + * @tags Org Tokens * @name List - * @summary Organisation API Tokens List + * @summary List Organisation API Tokens * @request GET:/api/v1/tokens * @response `200` `{ users?: { @@ -1464,6 +2863,7 @@ export class Api< created_by?: string, }))[], + \** Model for Paginated *\ pageInfo: PaginatedType, }, @@ -1477,6 +2877,7 @@ export class Api< list: (ApiTokenType & { created_by?: string; })[]; + /** Model for Paginated */ pageInfo: PaginatedType; }; }, @@ -1489,10 +2890,11 @@ export class Api< }), /** - * No description + * @description Creat an organisation API token. Access with API tokens will be blocked. * - * @tags Org tokens + * @tags Org Tokens * @name Create + * @summary Create Organisation API Token * @request POST:/api/v1/tokens * @response `200` `void` OK */ @@ -1506,10 +2908,11 @@ export class Api< }), /** - * No description + * @description Delete an organisation API token. Access with API tokens will be blocked. * - * @tags Org tokens + * @tags Org Tokens * @name Delete + * @summary Delete Organisation API Tokens * @request DELETE:/api/v1/tokens/{token} * @response `200` `void` OK */ @@ -1522,13 +2925,14 @@ export class Api< }; orgLicense = { /** - * No description + * @description Get the application license key. Exclusive for super admin. * - * @tags Org license + * @tags Org License * @name Get - * @summary App license get + * @summary Get App License * @request GET:/api/v1/license * @response `200` `{ + \** Application license key *\ key?: string, }` OK @@ -1536,6 +2940,7 @@ export class Api< get: (params: RequestParams = {}) => this.request< { + /** Application license key */ key?: string; }, any @@ -1547,11 +2952,11 @@ export class Api< }), /** - * No description + * @description Set the application license key. Exclusive for super admin. * - * @tags Org license + * @tags Org License * @name Set - * @summary App license get + * @summary Create App License * @request POST:/api/v1/license * @response `200` `void` OK */ @@ -1566,13 +2971,17 @@ export class Api< }; orgAppSettings = { /** - * No description + * @description Get the application settings. Exclusive for super admin. * - * @tags Org app settings + * @tags Org App Settings * @name Get - * @summary App settings get + * @summary Get App Settings * @request GET:/api/v1/app-settings * @response `200` `{ + \** + * Status of invite only signup + * @example true + *\ invite_only_signup?: boolean, }` OK @@ -1580,6 +2989,10 @@ export class Api< get: (params: RequestParams = {}) => this.request< { + /** + * Status of invite only signup + * @example true + */ invite_only_signup?: boolean; }, any @@ -1591,16 +3004,20 @@ export class Api< }), /** - * No description + * @description Update the application settings. Exclusive for super admin. * - * @tags Org app settings + * @tags Org App Settings * @name Set - * @summary App app settings get + * @summary Create App Settings * @request POST:/api/v1/app-settings * @response `200` `void` OK */ set: ( data: { + /** + * Status of invite only signup + * @example true + */ invite_only_signup?: boolean; }, params: RequestParams = {} @@ -1615,15 +3032,16 @@ export class Api< }; orgUsers = { /** - * No description + * @description List all organisation users. Exclusive for Super Admin. Access with API Tokens will be blocked. * - * @tags Org users + * @tags Org Users * @name List - * @summary Organisation Users + * @summary List Organisation Users * @request GET:/api/v1/users * @response `200` `{ users?: { list: (UserType)[], + \** Model for Paginated *\ pageInfo: PaginatedType, }, @@ -1635,6 +3053,7 @@ export class Api< { users?: { list: UserType[]; + /** Model for Paginated */ pageInfo: PaginatedType; }; }, @@ -1647,15 +3066,15 @@ export class Api< }), /** - * No description + * @description Create an organisation user. Exclusive for Super Admin. Access with API Tokens will be blocked. * - * @tags Org users + * @tags Org Users * @name Add - * @summary Organisation User Add + * @summary Create Organisation User * @request POST:/api/v1/users * @response `200` `any` OK */ - add: (data: UserType, params: RequestParams = {}) => + add: (data: OrgUserReqType, params: RequestParams = {}) => this.request({ path: `/api/v1/users`, method: 'POST', @@ -1666,16 +3085,16 @@ export class Api< }), /** - * No description + * @description Update an organisation user by User ID. Exclusive for Super Admin. Access with API Tokens will be blocked. * - * @tags Org users + * @tags Org Users * @name Update - * @summary Organisation User Update + * @summary Update Organisation User * @request PATCH:/api/v1/users/{userId} * @response `200` `void` OK */ update: ( - userId: string, + userId: IdType, data: OrgUserReqType, params: RequestParams = {} ) => @@ -1688,15 +3107,15 @@ export class Api< }), /** - * No description + * @description Delete an organisation user by User ID. Exclusive for Super Admin. Access with API Tokens will be blocked. * - * @tags Org users + * @tags Org Users * @name Delete - * @summary Organisation User Delete + * @summary Delete Organisation User * @request DELETE:/api/v1/users/{userId} * @response `200` `void` OK */ - delete: (userId: string, params: RequestParams = {}) => + delete: (userId: IdType, params: RequestParams = {}) => this.request({ path: `/api/v1/users/${userId}`, method: 'DELETE', @@ -1704,15 +3123,15 @@ export class Api< }), /** - * No description + * @description Resend Invitation to a specific user. Exclusive for Super Admin. Access with API Tokens will be blocked. * - * @tags Org users + * @tags Org Users * @name ResendInvite - * @summary Organisation User Invite + * @summary Invite Organisation User * @request POST:/api/v1/users/{userId}/resend-invite * @response `200` `void` OK */ - resendInvite: (userId: string, params: RequestParams = {}) => + resendInvite: (userId: IdType, params: RequestParams = {}) => this.request({ path: `/api/v1/users/${userId}/resend-invite`, method: 'POST', @@ -1720,22 +3139,26 @@ export class Api< }), /** - * No description + * @description Generate Password Reset Token for Organisation User. Exclusive for Super Admin. Access with API Tokens will be blocked. * - * @tags Org users + * @tags Org Users * @name GeneratePasswordResetToken - * @summary Organisation User Generate Password Reset Token + * @summary Generate Organisation User Password Reset Token * @request POST:/api/v1/users/{userId}/generate-reset-url * @response `200` `{ + \** Password Reset Token for the user *\ reset_password_token?: string, + \** Password Reset URL for the user *\ reset_password_url?: string, }` OK */ - generatePasswordResetToken: (userId: string, params: RequestParams = {}) => + generatePasswordResetToken: (userId: IdType, params: RequestParams = {}) => this.request< { + /** Password Reset Token for the user */ reset_password_token?: string; + /** Password Reset URL for the user */ reset_password_url?: string; }, any @@ -1748,56 +3171,119 @@ export class Api< }; project = { /** - * No description + * @description Get info such as node version, arch, platform, is docker, rootdb and package version of a given project * * @tags Project * @name MetaGet - * @summary Project info + * @summary Get Project info * @request GET:/api/v1/db/meta/projects/{projectId}/info * @response `200` `{ + \** + * Node version + * @example v12.16.1 + *\ Node?: string, + \** + * Architecture type + * @example x64 + *\ Arch?: string, + \** + * Platform type + * @example linux + *\ Platform?: string, + \** + * Is docker + * @example false + *\ Docker?: boolean, + \** + * Database type + * @example postgres + *\ Database?: string, - ProjectOnRootDB?: string, + \** + * Is project on rootdb + * @example false + *\ + ProjectOnRootDB?: boolean, + \** + * Root database type + * @example postgres + *\ RootDB?: string, + \** + * Package version + * @example 1.0.0 + *\ PackageVersion?: string, }` OK */ - metaGet: (projectId: string, params: RequestParams = {}, query: object) => + metaGet: (projectId: IdType, params: RequestParams = {}) => this.request< { + /** + * Node version + * @example v12.16.1 + */ Node?: string; + /** + * Architecture type + * @example x64 + */ Arch?: string; + /** + * Platform type + * @example linux + */ Platform?: string; + /** + * Is docker + * @example false + */ Docker?: boolean; + /** + * Database type + * @example postgres + */ Database?: string; - ProjectOnRootDB?: string; + /** + * Is project on rootdb + * @example false + */ + ProjectOnRootDB?: boolean; + /** + * Root database type + * @example postgres + */ RootDB?: string; + /** + * Package version + * @example 1.0.0 + */ PackageVersion?: string; }, any >({ path: `/api/v1/db/meta/projects/${projectId}/info`, method: 'GET', - query: query, format: 'json', ...params, }), /** - * No description + * @description Hide / show views based on user role * * @tags Project * @name ModelVisibilityList - * @summary UI ACL + * @summary Get UI ACL * @request GET:/api/v1/db/meta/projects/{projectId}/visibility-rules * @response `200` `(any)[]` OK */ modelVisibilityList: ( - projectId: string, + projectId: IdType, query?: { includeM2M?: boolean; }, @@ -1812,15 +3298,16 @@ export class Api< }), /** - * No description + * @description Hide / show views based on user role * * @tags Project * @name ModelVisibilitySet + * @summary Create UI ACL * @request POST:/api/v1/db/meta/projects/{projectId}/visibility-rules * @response `200` `VisibilityRuleReqType` OK */ modelVisibilitySet: ( - projectId: string, + projectId: IdType, data: any, params: RequestParams = {} ) => @@ -1834,45 +3321,38 @@ export class Api< }), /** - * @description Read project details + * @description List all project meta data * * @tags Project * @name List - * @summary Project list + * @summary List Projects * @request GET:/api/v1/db/meta/projects/ * @response `201` `ProjectListType` */ - list: ( - query?: { - page?: number; - pageSize?: number; - sort?: string; - }, - params: RequestParams = {} - ) => + list: (params: RequestParams = {}) => this.request({ path: `/api/v1/db/meta/projects/`, method: 'GET', - query: query, ...params, }), /** - * No description + * @description Create a new project * * @tags Project * @name Create - * @summary Project create + * @summary Create Project * @request POST:/api/v1/db/meta/projects/ - * @response `200` `ProjectType` OK + * @response `200` `ProjectReqType` OK */ create: ( data: ProjectType & { + /** If true, the project will us an external database else it will use the root database */ external?: boolean; }, params: RequestParams = {} ) => - this.request({ + this.request({ path: `/api/v1/db/meta/projects/`, method: 'POST', body: data, @@ -1882,16 +3362,16 @@ export class Api< }), /** - * @description Read project details + * @description Get the info of a given projecct * * @tags Project * @name Read - * @summary Project read + * @summary Get Project * @request GET:/api/v1/db/meta/projects/{projectId} - * @response `200` `object` OK + * @response `200` `ProjectType` OK */ - read: (projectId: string, params: RequestParams = {}) => - this.request({ + read: (projectId: IdType, params: RequestParams = {}) => + this.request({ path: `/api/v1/db/meta/projects/${projectId}`, method: 'GET', format: 'json', @@ -1899,15 +3379,15 @@ export class Api< }), /** - * No description + * @description Delete the given project * * @tags Project * @name Delete - * @summary Project delete + * @summary Delete Project * @request DELETE:/api/v1/db/meta/projects/{projectId} * @response `200` `void` OK */ - delete: (projectId: string, params: RequestParams = {}) => + delete: (projectId: IdType, params: RequestParams = {}) => this.request({ path: `/api/v1/db/meta/projects/${projectId}`, method: 'DELETE', @@ -1915,15 +3395,15 @@ export class Api< }), /** - * No description + * @description Update the given project * * @tags Project * @name Update - * @summary Project update + * @summary Update Project * @request PATCH:/api/v1/db/meta/projects/{projectId} * @response `200` `void` OK */ - update: (projectId: string, data: any, params: RequestParams = {}) => + update: (projectId: IdType, data: any, params: RequestParams = {}) => this.request({ path: `/api/v1/db/meta/projects/${projectId}`, method: 'PATCH', @@ -1933,23 +3413,36 @@ export class Api< }), /** - * @description Read project details + * @description Get Project Shared Base * * @tags Project * @name SharedBaseGet + * @summary Get Project Shared Base * @request GET:/api/v1/db/meta/projects/{projectId}/shared * @response `200` `{ + \** + * @format uuid + * @example a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11 + *\ uuid?: string, + \** @format uri *\ url?: string, + \** @example viewer *\ roles?: string, }` OK */ - sharedBaseGet: (projectId: string, params: RequestParams = {}) => + sharedBaseGet: (projectId: IdType, params: RequestParams = {}) => this.request< { + /** + * @format uuid + * @example a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11 + */ uuid?: string; + /** @format uri */ url?: string; + /** @example viewer */ roles?: string; }, any @@ -1961,14 +3454,15 @@ export class Api< }), /** - * No description + * @description Delete Project Shared Base * * @tags Project * @name SharedBaseDisable + * @summary Delete Project Shared Base * @request DELETE:/api/v1/db/meta/projects/{projectId}/shared * @response `200` `void` OK */ - sharedBaseDisable: (projectId: string, params: RequestParams = {}) => + sharedBaseDisable: (projectId: IdType, params: RequestParams = {}) => this.request({ path: `/api/v1/db/meta/projects/${projectId}/shared`, method: 'DELETE', @@ -1976,22 +3470,34 @@ export class Api< }), /** - * No description - * - * @tags Project - * @name SharedBaseCreate - * @request POST:/api/v1/db/meta/projects/{projectId}/shared - * @response `200` `SharedBaseReqType` OK - */ + * @description Create Project Shared Base + * + * @tags Project + * @name SharedBaseCreate + * @summary Create Project Shared Base + * @request POST:/api/v1/db/meta/projects/{projectId}/shared + * @response `200` `{ + \** Model for StringOrNull *\ + uuid?: StringOrNullType, + \** Model for StringOrNull *\ + roles?: StringOrNullType, + +}` OK + */ sharedBaseCreate: ( - projectId: string, - data: { - roles?: string; - password?: string; - }, + projectId: IdType, + data: SharedBaseReqType, params: RequestParams = {} ) => - this.request({ + this.request< + { + /** Model for StringOrNull */ + uuid?: StringOrNullType; + /** Model for StringOrNull */ + roles?: StringOrNullType; + }, + any + >({ path: `/api/v1/db/meta/projects/${projectId}/shared`, method: 'POST', body: data, @@ -2001,30 +3507,40 @@ export class Api< }), /** - * No description + * @description Update Project Shared Base * * @tags Project * @name SharedBaseUpdate + * @summary Update Project Shared Base * @request PATCH:/api/v1/db/meta/projects/{projectId}/shared * @response `200` `{ + \** + * @format uuid + * @example a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11 + *\ uuid?: string, + \** @format uri *\ url?: string, + \** @example viewer *\ roles?: string, }` OK */ sharedBaseUpdate: ( - projectId: string, - data: { - roles?: string; - password?: string; - }, + projectId: IdType, + data: SharedBaseReqType, params: RequestParams = {} ) => this.request< { + /** + * @format uuid + * @example a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11 + */ uuid?: string; + /** @format uri */ url?: string; + /** @example viewer */ roles?: string; }, any @@ -2038,15 +3554,15 @@ export class Api< }), /** - * @description Project compare cost + * @description Calculate the Project Cost * * @tags Project * @name Cost - * @summary Project compare cost + * @summary Project Cost * @request GET:/api/v1/db/meta/projects/{projectId}/cost * @response `200` `object` OK */ - cost: (projectId: string, params: RequestParams = {}) => + cost: (projectId: IdType, params: RequestParams = {}) => this.request({ path: `/api/v1/db/meta/projects/${projectId}/cost`, method: 'GET', @@ -2055,14 +3571,15 @@ export class Api< }), /** - * No description + * @description Synchronise the meta data difference between NC_DB and external data sources * * @tags Project * @name MetaDiffSync + * @summary Sync Meta * @request POST:/api/v1/db/meta/projects/{projectId}/meta-diff * @response `200` `any` OK */ - metaDiffSync: (projectId: string, params: RequestParams = {}) => + metaDiffSync: (projectId: IdType, params: RequestParams = {}) => this.request({ path: `/api/v1/db/meta/projects/${projectId}/meta-diff`, method: 'POST', @@ -2071,14 +3588,15 @@ export class Api< }), /** - * No description + * @description Get the meta data difference between NC_DB and external data sources * * @tags Project * @name MetaDiffGet + * @summary Meta Diff * @request GET:/api/v1/db/meta/projects/{projectId}/meta-diff * @response `200` `any` OK */ - metaDiffGet: (projectId: string, params: RequestParams = {}) => + metaDiffGet: (projectId: IdType, params: RequestParams = {}) => this.request({ path: `/api/v1/db/meta/projects/${projectId}/meta-diff`, method: 'GET', @@ -2087,14 +3605,15 @@ export class Api< }), /** - * No description + * @description Check if a project contains empty and null filters. Used in `Show NULL and EMPTY in Filter` in Project Setting. * * @tags Project * @name HasEmptyOrNullFilters + * @summary List Empty & Null Filter * @request GET:/api/v1/db/meta/projects/{projectId}/has-empty-or-null-filters * @response `200` `any` OK */ - hasEmptyOrNullFilters: (projectId: string, params: RequestParams = {}) => + hasEmptyOrNullFilters: (projectId: IdType, params: RequestParams = {}) => this.request({ path: `/api/v1/db/meta/projects/${projectId}/has-empty-or-null-filters`, method: 'GET', @@ -2103,28 +3622,33 @@ export class Api< }), /** - * No description + * @description List all audit data in the given project * * @tags Project * @name AuditList + * @summary List Audits in Project * @request GET:/api/v1/db/meta/projects/{projectId}/audits * @response `200` `{ list: (AuditType)[], + \** Model for Paginated *\ pageInfo: PaginatedType, }` OK */ auditList: ( - projectId: string, + projectId: IdType, query?: { - offset?: string; - limit?: string; + /** @min 0 */ + offset?: number; + /** @max 1 */ + limit?: number; }, params: RequestParams = {} ) => this.request< { list: AuditType[]; + /** Model for Paginated */ pageInfo: PaginatedType; }, any @@ -2138,16 +3662,16 @@ export class Api< }; base = { /** - * @description Read project base details + * @description Get the base details of a given project * * @tags Base * @name Read - * @summary Base read + * @summary Get Base * @request GET:/api/v1/db/meta/projects/{projectId}/bases/{baseId} - * @response `200` `object` OK + * @response `200` `BaseType` OK */ - read: (projectId: string, baseId: string, params: RequestParams = {}) => - this.request({ + read: (projectId: IdType, baseId: string, params: RequestParams = {}) => + this.request({ path: `/api/v1/db/meta/projects/${projectId}/bases/${baseId}`, method: 'GET', format: 'json', @@ -2155,15 +3679,15 @@ export class Api< }), /** - * No description + * @description Delete the base details of a given project * * @tags Base * @name Delete - * @summary Base delete + * @summary Delete Base * @request DELETE:/api/v1/db/meta/projects/{projectId}/bases/{baseId} * @response `200` `void` OK */ - delete: (projectId: string, baseId: string, params: RequestParams = {}) => + delete: (projectId: IdType, baseId: string, params: RequestParams = {}) => this.request({ path: `/api/v1/db/meta/projects/${projectId}/bases/${baseId}`, method: 'DELETE', @@ -2171,16 +3695,16 @@ export class Api< }), /** - * No description + * @description Update the base details of a given project * * @tags Base * @name Update - * @summary Base update + * @summary Update Base * @request PATCH:/api/v1/db/meta/projects/{projectId}/bases/{baseId} * @response `200` `void` OK */ update: ( - projectId: string, + projectId: IdType, baseId: string, data: any, params: RequestParams = {} @@ -2198,12 +3722,12 @@ export class Api< * * @tags Base * @name List - * @summary Base list + * @summary List Bases * @request GET:/api/v1/db/meta/projects/{projectId}/bases/ - * @response `200` `object` OK + * @response `200` `BaseListType` OK */ - list: (projectId: string, params: RequestParams = {}) => - this.request({ + list: (projectId: IdType, params: RequestParams = {}) => + this.request({ path: `/api/v1/db/meta/projects/${projectId}/bases/`, method: 'GET', format: 'json', @@ -2211,16 +3735,16 @@ export class Api< }), /** - * No description + * @description Create a new base on a given project * * @tags Base * @name Create - * @summary Base create + * @summary Create Base * @request POST:/api/v1/db/meta/projects/{projectId}/bases/ * @response `200` `BaseType` OK */ create: ( - projectId: string, + projectId: IdType, data: BaseType & { external?: boolean; }, @@ -2236,15 +3760,16 @@ export class Api< }), /** - * No description + * @description List all tables in a given Project and Base * * @tags Base * @name TableList + * @summary List Tables * @request GET:/api/v1/db/meta/projects/{projectId}/{baseId}/tables * @response `200` `TableListType` */ tableList: ( - projectId: string, + projectId: IdType, baseId: string, query?: { page?: number; @@ -2262,15 +3787,16 @@ export class Api< }), /** - * No description + * @description Create a new table in a given Project and Base * * @tags Base * @name TableCreate + * @summary Create Table * @request POST:/api/v1/db/meta/projects/{projectId}/{baseId}/tables * @response `200` `TableType` OK */ tableCreate: ( - projectId: string, + projectId: IdType, baseId: string, data: TableReqType, params: RequestParams = {} @@ -2285,15 +3811,16 @@ export class Api< }), /** - * No description + * @description Synchronise the meta data difference between NC_DB and external data sources in a given Base * * @tags Base * @name MetaDiffSync + * @summary Synchronise Base Meta * @request POST:/api/v1/db/meta/projects/{projectId}/meta-diff/{baseId} * @response `200` `any` OK */ metaDiffSync: ( - projectId: string, + projectId: IdType, baseId: string, params: RequestParams = {} ) => @@ -2305,15 +3832,16 @@ export class Api< }), /** - * No description + * @description Get the meta data difference between NC_DB and external data sources in a given Base * * @tags Base * @name MetaDiffGet + * @summary Base Meta Diff * @request GET:/api/v1/db/meta/projects/{projectId}/meta-diff/{baseId} * @response `200` `any` OK */ metaDiffGet: ( - projectId: string, + projectId: IdType, baseId: string, params: RequestParams = {} ) => @@ -2326,15 +3854,16 @@ export class Api< }; dbTable = { /** - * No description + * @description Create a new table in a given project * - * @tags DB table + * @tags DB Table * @name Create + * @summary Create Table * @request POST:/api/v1/db/meta/projects/{projectId}/tables * @response `200` `TableType` OK */ create: ( - projectId: string, + projectId: IdType, data: TableReqType, params: RequestParams = {} ) => @@ -2348,15 +3877,16 @@ export class Api< }), /** - * No description + * @description List all tables in a given project * - * @tags DB table + * @tags DB Table * @name List + * @summary List Tables * @request GET:/api/v1/db/meta/projects/{projectId}/tables * @response `200` `TableListType` */ list: ( - projectId: string, + projectId: IdType, query?: { page?: number; pageSize?: number; @@ -2373,15 +3903,16 @@ export class Api< }), /** - * No description + * @description Read the table meta data by the given table ID * - * @tags DB table + * @tags DB Table * @name Read + * @summary Read Table * @request GET:/api/v1/db/meta/tables/{tableId} - * @response `200` `TableInfoType` OK + * @response `200` `TableType` OK */ - read: (tableId: string, params: RequestParams = {}) => - this.request({ + read: (tableId: IdType, params: RequestParams = {}) => + this.request({ path: `/api/v1/db/meta/tables/${tableId}`, method: 'GET', format: 'json', @@ -2389,19 +3920,33 @@ export class Api< }), /** - * No description + * @description Update the table meta data by the given table ID * - * @tags DB table + * @tags DB Table * @name Update + * @summary Update Table * @request PATCH:/api/v1/db/meta/tables/{tableId} * @response `200` `any` OK */ update: ( - tableId: string, + tableId: IdType, data: { + /** + * Table name + * @example users + */ table_name?: string; + /** + * Table title + * @example Users + */ title?: string; + /** + * Project ID + * @example p_124hhlkbeasewh + */ project_id?: string; + /** Model for Meta */ meta?: MetaType; }, params: RequestParams = {} @@ -2416,14 +3961,15 @@ export class Api< }), /** - * No description + * @description Delete the table meta data by the given table ID * - * @tags DB table + * @tags DB Table * @name Delete + * @summary Delete Table * @request DELETE:/api/v1/db/meta/tables/{tableId} * @response `200` `void` OK */ - delete: (tableId: string, params: RequestParams = {}) => + delete: (tableId: IdType, params: RequestParams = {}) => this.request({ path: `/api/v1/db/meta/tables/${tableId}`, method: 'DELETE', @@ -2431,15 +3977,16 @@ export class Api< }), /** - * No description + * @description Update the order of the given Table * - * @tags DB table + * @tags DB Table * @name Reorder + * @summary Reorder Table * @request POST:/api/v1/db/meta/tables/{tableId}/reorder * @response `200` `void` OK */ reorder: ( - tableId: string, + tableId: IdType, data: { order?: number; }, @@ -2455,16 +4002,16 @@ export class Api< }; dbTableColumn = { /** - * No description + * @description Create a new column in a given Table * - * @tags DB table column + * @tags DB Table Column * @name Create - * @summary Column create + * @summary Create Column * @request POST:/api/v1/db/meta/tables/{tableId}/columns * @response `200` `void` OK */ create: ( - tableId: string, + tableId: IdType, data: ColumnReqType, params: RequestParams = {} ) => @@ -2477,11 +4024,11 @@ export class Api< }), /** - * No description + * @description Update the existing column by the given column ID * - * @tags DB table column + * @tags DB Table Column * @name Update - * @summary Column Update + * @summary Update Column * @request PATCH:/api/v1/db/meta/columns/{columnId} * @response `200` `ColumnType` OK */ @@ -2500,11 +4047,11 @@ export class Api< }), /** - * No description + * @description Delete the existing column by the given column ID * - * @tags DB table column + * @tags DB Table Column * @name Delete - * @summary Column Delete + * @summary Delete Column * @request DELETE:/api/v1/db/meta/columns/{columnId} * @response `200` `void` OK */ @@ -2516,11 +4063,11 @@ export class Api< }), /** - * No description + * @description Get the existing column by the given column ID * * @tags DB Table Column * @name Get - * @summary Column Get + * @summary Get Column * @request GET:/api/v1/db/meta/columns/{columnId} * @response `200` `void` OK */ @@ -2532,10 +4079,11 @@ export class Api< }), /** - * No description + * @description Set a primary value on a given column * - * @tags DB table column + * @tags DB Table Column * @name PrimaryColumnSet + * @summary Create Primary Value * @request POST:/api/v1/db/meta/columns/{columnId}/primary * @response `200` `void` OK */ @@ -2548,14 +4096,15 @@ export class Api< }; dbView = { /** - * No description + * @description List all views in a given Table. * - * @tags DB view + * @tags DB View * @name List + * @summary List views * @request GET:/api/v1/db/meta/tables/{tableId}/views * @response `200` `ViewListType` */ - list: (tableId: string, params: RequestParams = {}) => + list: (tableId: IdType, params: RequestParams = {}) => this.request({ path: `/api/v1/db/meta/tables/${tableId}/views`, method: 'GET', @@ -2563,24 +4112,15 @@ export class Api< }), /** - * No description + * @description Update the view with the given view Id. * - * @tags DB view + * @tags DB View * @name Update + * @summary Update View * @request PATCH:/api/v1/db/meta/views/{viewId} * @response `200` `void` OK */ - update: ( - viewId: string, - data: { - order?: number; - meta?: MetaType; - title?: string; - show_system_fields?: boolean; - lock_type?: 'collaborative' | 'locked' | 'personal'; - }, - params: RequestParams = {} - ) => + update: (viewId: IdType, data: ViewReqType, params: RequestParams = {}) => this.request({ path: `/api/v1/db/meta/views/${viewId}`, method: 'PATCH', @@ -2590,14 +4130,15 @@ export class Api< }), /** - * No description + * @description Delete the view with the given view Id. * - * @tags DB view + * @tags DB View * @name Delete + * @summary Delete View * @request DELETE:/api/v1/db/meta/views/{viewId} * @response `200` `void` OK */ - delete: (viewId: string, params: RequestParams = {}) => + delete: (viewId: IdType, params: RequestParams = {}) => this.request({ path: `/api/v1/db/meta/views/${viewId}`, method: 'DELETE', @@ -2605,15 +4146,16 @@ export class Api< }), /** - * No description + * @description Show All Columns in a given View * - * @tags DB view + * @tags DB View * @name ShowAllColumn + * @summary Show All Columns In View * @request POST:/api/v1/db/meta/views/{viewId}/show-all * @response `200` `void` OK */ showAllColumn: ( - viewId: string, + viewId: IdType, query?: { ignoreIds?: any[]; }, @@ -2627,15 +4169,16 @@ export class Api< }), /** - * No description + * @description Hide All Columns in a given View * - * @tags DB view + * @tags DB View * @name HideAllColumn + * @summary Hide All Columns In View * @request POST:/api/v1/db/meta/views/{viewId}/hide-all * @response `200` `void` OK */ hideAllColumn: ( - viewId: string, + viewId: IdType, query?: { ignoreIds?: any[]; }, @@ -2649,15 +4192,16 @@ export class Api< }), /** - * No description + * @description Create a new grid view in a given Table * - * @tags DB view + * @tags DB View * @name GridCreate + * @summary Create Grid View * @request POST:/api/v1/db/meta/tables/{tableId}/grids * @response `200` `GridType` OK */ gridCreate: ( - tableId: string, + tableId: IdType, data: GridReqType, params: RequestParams = {} ) => @@ -2671,16 +4215,17 @@ export class Api< }), /** - * No description + * @description Create a new form view in a given Table * - * @tags DB view + * @tags DB View * @name FormCreate + * @summary Create Form View * @request POST:/api/v1/db/meta/tables/{tableId}/forms * @response `200` `FormType` OK */ formCreate: ( - tableId: string, - data: FormCreateReqType, + tableId: IdType, + data: FormReqType, params: RequestParams = {} ) => this.request({ @@ -2693,20 +4238,21 @@ export class Api< }), /** - * No description + * @description Update the form data by Form ID * - * @tags DB view + * @tags DB View * @name FormUpdate - * @request PATCH:/api/v1/db/meta/forms/{formId} + * @summary Update Form + * @request PATCH:/api/v1/db/meta/forms/{formViewId} * @response `200` `void` OK */ formUpdate: ( - formId: string, + formViewId: IdType, data: FormReqType, params: RequestParams = {} ) => this.request({ - path: `/api/v1/db/meta/forms/${formId}`, + path: `/api/v1/db/meta/forms/${formViewId}`, method: 'PATCH', body: data, type: ContentType.Json, @@ -2714,35 +4260,37 @@ export class Api< }), /** - * No description + * @description Get the form data by Form ID * - * @tags DB view + * @tags DB View * @name FormRead - * @request GET:/api/v1/db/meta/forms/{formId} + * @summary Get Form + * @request GET:/api/v1/db/meta/forms/{formViewId} * @response `200` `FormType` OK */ - formRead: (formId: string, params: RequestParams = {}) => + formRead: (formViewId: IdType, params: RequestParams = {}) => this.request({ - path: `/api/v1/db/meta/forms/${formId}`, + path: `/api/v1/db/meta/forms/${formViewId}`, method: 'GET', format: 'json', ...params, }), /** - * No description + * @description Update the form column(s) by Form View Column ID * - * @tags DB view + * @tags DB View * @name FormColumnUpdate + * @summary Update Form Column * @request PATCH:/api/v1/db/meta/form-columns/{formViewColumnId} - * @response `200` `any` OK + * @response `200` `FormColumnReqType` OK */ formColumnUpdate: ( - formViewColumnId: string, + formViewColumnId: IdType, data: FormColumnReqType, params: RequestParams = {} ) => - this.request({ + this.request({ path: `/api/v1/db/meta/form-columns/${formViewColumnId}`, method: 'PATCH', body: data, @@ -2752,10 +4300,11 @@ export class Api< }), /** - * No description + * @description Update Grid View * - * @tags DB view + * @tags DB View * @name GridUpdate + * @summary Update Grid View * @request PATCH:/api/v1/db/meta/grids/{viewId} * @response `200` `any` OK */ @@ -2770,10 +4319,11 @@ export class Api< }), /** - * No description + * @description List all columns in the given Grid * - * @tags DB view + * @tags DB View * @name GridColumnsList + * @summary List Grid Columns * @request GET:/api/v1/db/meta/grids/{gridId}/grid-columns * @response `200` `(GridColumnType)[]` OK */ @@ -2786,15 +4336,16 @@ export class Api< }), /** - * No description + * @description Update grid column(s) in the given Grid * - * @tags DB view + * @tags DB View * @name GridColumnUpdate + * @summary Update Grid Column * @request PATCH:/api/v1/db/meta/grid-columns/{columnId} * @response `200` `any` OK */ gridColumnUpdate: ( - columnId: string, + columnId: IdType, data: GridColumnReqType, params: RequestParams = {} ) => @@ -2810,13 +4361,14 @@ export class Api< /** * No description * - * @tags DB view + * @tags DB View * @name GalleryCreate + * @summary Gallery View * @request POST:/api/v1/db/meta/tables/{tableId}/galleries * @response `200` `object` OK */ galleryCreate: ( - tableId: string, + tableId: IdType, data: GalleryReqType, params: RequestParams = {} ) => @@ -2830,20 +4382,21 @@ export class Api< }), /** - * No description + * @description Update the Gallery View data with Gallery ID * - * @tags DB view + * @tags DB View * @name GalleryUpdate - * @request PATCH:/api/v1/db/meta/galleries/{galleryId} + * @summary Update Gallery View + * @request PATCH:/api/v1/db/meta/galleries/{galleryViewId} * @response `200` `void` OK */ galleryUpdate: ( - galleryId: string, + galleryViewId: string, data: GalleryReqType, params: RequestParams = {} ) => this.request({ - path: `/api/v1/db/meta/galleries/${galleryId}`, + path: `/api/v1/db/meta/galleries/${galleryViewId}`, method: 'PATCH', body: data, type: ContentType.Json, @@ -2851,31 +4404,33 @@ export class Api< }), /** - * No description + * @description Get the Gallery View data with Gallery ID * - * @tags DB view + * @tags DB View * @name GalleryRead - * @request GET:/api/v1/db/meta/galleries/{galleryId} + * @summary Get Gallery View + * @request GET:/api/v1/db/meta/galleries/{galleryViewId} * @response `200` `GalleryType` OK */ - galleryRead: (galleryId: string, params: RequestParams = {}) => + galleryRead: (galleryViewId: string, params: RequestParams = {}) => this.request({ - path: `/api/v1/db/meta/galleries/${galleryId}`, + path: `/api/v1/db/meta/galleries/${galleryViewId}`, method: 'GET', format: 'json', ...params, }), /** - * No description + * @description Create a new Kanban View * - * @tags DB view + * @tags DB View * @name KanbanCreate + * @summary Create Kanban View * @request POST:/api/v1/db/meta/tables/{tableId}/kanbans * @response `200` `object` OK */ kanbanCreate: ( - tableId: string, + tableId: IdType, data: KanbanReqType, params: RequestParams = {} ) => @@ -2889,20 +4444,21 @@ export class Api< }), /** - * No description + * @description Update the Kanban View data with Kanban ID * - * @tags DB view + * @tags DB View * @name KanbanUpdate - * @request PATCH:/api/v1/db/meta/kanbans/{kanbanId} + * @summary Update Kanban View + * @request PATCH:/api/v1/db/meta/kanbans/{kanbanViewId} * @response `200` `void` OK */ kanbanUpdate: ( - kanbanId: string, + kanbanViewId: string, data: KanbanUpdateReqType, params: RequestParams = {} ) => this.request({ - path: `/api/v1/db/meta/kanbans/${kanbanId}`, + path: `/api/v1/db/meta/kanbans/${kanbanViewId}`, method: 'PATCH', body: data, type: ContentType.Json, @@ -2910,30 +4466,32 @@ export class Api< }), /** - * No description + * @description Get the Kanban View data by Kanban ID * - * @tags DB view + * @tags DB View * @name KanbanRead - * @request GET:/api/v1/db/meta/kanbans/{kanbanId} + * @summary Get Kanban View + * @request GET:/api/v1/db/meta/kanbans/{kanbanViewId} * @response `200` `KanbanType` OK */ - kanbanRead: (kanbanId: string, params: RequestParams = {}) => + kanbanRead: (kanbanViewId: string, params: RequestParams = {}) => this.request({ - path: `/api/v1/db/meta/kanbans/${kanbanId}`, + path: `/api/v1/db/meta/kanbans/${kanbanViewId}`, method: 'GET', format: 'json', ...params, }), /** - * No description + * @description Create a new Map View * - * @tags DB view + * @tags DB View * @name MapCreate + * @summary Create Map View * @request POST:/api/v1/db/meta/tables/{tableId}/maps * @response `200` `object` OK */ - mapCreate: (tableId: string, data: MapType, params: RequestParams = {}) => + mapCreate: (tableId: IdType, data: MapType, params: RequestParams = {}) => this.request({ path: `/api/v1/db/meta/tables/${tableId}/maps`, method: 'POST', @@ -2944,16 +4502,17 @@ export class Api< }), /** - * No description + * @description Update the Map View data by Map ID * - * @tags DB view + * @tags DB View * @name MapUpdate - * @request PATCH:/api/v1/db/meta/maps/{mapId} + * @summary Update Map View + * @request PATCH:/api/v1/db/meta/maps/{mapViewId} * @response `200` `void` OK */ - mapUpdate: (mapId: string, data: MapType, params: RequestParams = {}) => + mapUpdate: (mapViewId: string, data: MapType, params: RequestParams = {}) => this.request({ - path: `/api/v1/db/meta/maps/${mapId}`, + path: `/api/v1/db/meta/maps/${mapViewId}`, method: 'PATCH', body: data, type: ContentType.Json, @@ -2961,16 +4520,17 @@ export class Api< }), /** - * No description + * @description Get the Map View data by Map ID * - * @tags DB view + * @tags DB View * @name MapRead - * @request GET:/api/v1/db/meta/maps/{mapId} + * @summary Get Map View + * @request GET:/api/v1/db/meta/maps/{mapViewId} * @response `200` `MapType` OK */ - mapRead: (mapId: string, params: RequestParams = {}) => + mapRead: (mapViewId: string, params: RequestParams = {}) => this.request({ - path: `/api/v1/db/meta/maps/${mapId}`, + path: `/api/v1/db/meta/maps/${mapViewId}`, method: 'GET', format: 'json', ...params, @@ -2978,16 +4538,16 @@ export class Api< }; dbViewShare = { /** - * No description + * @description List all shared views in a given Table * - * @tags DB view share + * @tags DB View Share * @name List - * @summary Shared view list + * @summary List Shared Views * @request GET:/api/v1/db/meta/tables/{tableId}/share - * @response `200` `(any)[]` OK + * @response `200` `SharedViewListType` OK */ - list: (tableId: string, params: RequestParams = {}) => - this.request({ + list: (tableId: IdType, params: RequestParams = {}) => + this.request({ path: `/api/v1/db/meta/tables/${tableId}/share`, method: 'GET', format: 'json', @@ -2995,23 +4555,16 @@ export class Api< }), /** - * No description - * - * @tags DB view share - * @name Create - * @request POST:/api/v1/db/meta/views/{viewId}/share - * @response `200` `{ - uuid?: string, - -}` OK - */ + * @description Create a shared view in a given View.. + * + * @tags DB View Share + * @name Create + * @summary Create Shared View + * @request POST:/api/v1/db/meta/views/{viewId}/share + * @response `200` `SharedViewReqType` OK + */ create: (viewId: string, params: RequestParams = {}) => - this.request< - { - uuid?: string; - }, - any - >({ + this.request({ path: `/api/v1/db/meta/views/${viewId}/share`, method: 'POST', format: 'json', @@ -3019,19 +4572,17 @@ export class Api< }), /** - * No description + * @description Update a shared view in a given View.. * - * @tags DB view share + * @tags DB View Share * @name Update + * @summary Update Shared View * @request PATCH:/api/v1/db/meta/views/{viewId}/share * @response `200` `SharedViewType` OK */ update: ( viewId: string, - data: { - password?: string; - meta?: MetaType; - }, + data: SharedViewReqType, params: RequestParams = {} ) => this.request({ @@ -3044,10 +4595,11 @@ export class Api< }), /** - * No description + * @description Delete a shared view in a given View. * - * @tags DB view share + * @tags DB View Share * @name Delete + * @summary Delete Shared View * @request DELETE:/api/v1/db/meta/views/{viewId}/share * @response `200` `void` OK */ @@ -3060,10 +4612,11 @@ export class Api< }; dbViewColumn = { /** - * No description + * @description List all columns by ViewID * - * @tags DB view column + * @tags DB View Column * @name List + * @summary List Columns In View * @request GET:/api/v1/db/meta/views/{viewId}/columns */ list: (viewId: string, params: RequestParams = {}) => @@ -3074,14 +4627,19 @@ export class Api< }), /** - * No description + * @description Create a new column in a given View * - * @tags DB view column + * @tags DB View Column * @name Create + * @summary Create Column in View * @request POST:/api/v1/db/meta/views/{viewId}/columns * @response `200` `void` OK */ - create: (viewId: string, data: any, params: RequestParams = {}) => + create: ( + viewId: string, + data: ViewColumnReqType, + params: RequestParams = {} + ) => this.request({ path: `/api/v1/db/meta/views/${viewId}/columns`, method: 'POST', @@ -3091,17 +4649,18 @@ export class Api< }), /** - * No description + * @description Update a column in a View * - * @tags DB view column + * @tags DB View Column * @name Update + * @summary Update View Column * @request PATCH:/api/v1/db/meta/views/{viewId}/columns/{columnId} * @response `200` `void` OK */ update: ( - viewId: string, - columnId: string, - data: any, + viewId: IdType, + columnId: IdType, + data: ViewColumnUpdateReqType, params: RequestParams = {} ) => this.request({ @@ -3114,10 +4673,11 @@ export class Api< }; dbTableSort = { /** - * No description + * @description List all the sort data in a given View * - * @tags DB table sort + * @tags DB Table Sort * @name List + * @summary List View Sorts * @request GET:/api/v1/db/meta/views/{viewId}/sorts * @response `200` `{ sorts?: { @@ -3143,16 +4703,21 @@ export class Api< }), /** - * No description + * @description Update the sort data in a given View * - * @tags DB table sort + * @tags DB Table Sort * @name Create + * @summary Update View Sort * @request POST:/api/v1/db/meta/views/{viewId}/sorts * @response `200` `void` OK */ create: ( viewId: string, - data: SortType & { + data: SortReqType & { + /** + * Push the sort to the top of the list + * @example true + */ push_to_top?: boolean; }, params: RequestParams = {} @@ -3166,10 +4731,11 @@ export class Api< }), /** - * No description + * @description Get the sort data by Sort ID * - * @tags DB table sort + * @tags DB Table Sort * @name Get + * @summary Get Sort * @request GET:/api/v1/db/meta/sorts/{sortId} * @response `200` `SortType` OK */ @@ -3182,14 +4748,15 @@ export class Api< }), /** - * No description + * @description Update the sort data by Sort ID * - * @tags DB table sort + * @tags DB Table Sort * @name Update + * @summary Update Sort * @request PATCH:/api/v1/db/meta/sorts/{sortId} * @response `200` `void` OK */ - update: (sortId: string, data: SortType, params: RequestParams = {}) => + update: (sortId: string, data: SortReqType, params: RequestParams = {}) => this.request({ path: `/api/v1/db/meta/sorts/${sortId}`, method: 'PATCH', @@ -3199,10 +4766,11 @@ export class Api< }), /** - * No description + * @description Delete the sort data by Sort ID * - * @tags DB table sort + * @tags DB Table Sort * @name Delete + * @summary Delete Sort * @request DELETE:/api/v1/db/meta/sorts/{sortId} * @response `200` `void` OK */ @@ -3215,10 +4783,11 @@ export class Api< }; dbTableFilter = { /** - * No description + * @description Get the filter data in a given View * - * @tags DB table filter + * @tags DB Table Filter * @name Read + * @summary Get View Filter * @request GET:/api/v1/db/meta/views/{viewId}/filters * @response `200` `(FilterType)[]` OK */ @@ -3231,10 +4800,11 @@ export class Api< }), /** - * No description + * @description Update the filter data in a given View * - * @tags DB table filter + * @tags DB Table Filter * @name Create + * @summary Create View Filter * @request POST:/api/v1/db/meta/views/{viewId}/filters * @response `200` `FilterType` OK */ @@ -3249,14 +4819,15 @@ export class Api< }), /** - * No description + * @description Get the filter data with a given Filter ID * - * @tags DB table filter + * @tags DB Table Filter * @name Get + * @summary Get Filter * @request GET:/api/v1/db/meta/filters/{filterId} * @response `200` `FilterType` OK */ - get: (filterId: string, params: RequestParams = {}) => + get: (filterId: IdType, params: RequestParams = {}) => this.request({ path: `/api/v1/db/meta/filters/${filterId}`, method: 'GET', @@ -3265,15 +4836,16 @@ export class Api< }), /** - * No description + * @description Update the filter data with a given Filter ID * - * @tags DB table filter + * @tags DB Table Filter * @name Update + * @summary Update Filter * @request PATCH:/api/v1/db/meta/filters/{filterId} * @response `200` `void` OK */ update: ( - filterId: string, + filterId: IdType, data: FilterReqType, params: RequestParams = {} ) => @@ -3286,14 +4858,15 @@ export class Api< }), /** - * No description + * @description Delete the filter data with a given Filter ID * - * @tags DB table filter + * @tags DB Table Filter * @name Delete + * @summary Delete Filter * @request DELETE:/api/v1/db/meta/filters/{filterId} * @response `200` `void` OK */ - delete: (filterId: string, params: RequestParams = {}) => + delete: (filterId: IdType, params: RequestParams = {}) => this.request({ path: `/api/v1/db/meta/filters/${filterId}`, method: 'DELETE', @@ -3301,14 +4874,15 @@ export class Api< }), /** - * No description + * @description Get Filter Group Children of a given group ID * - * @tags DB table filter + * @tags DB Table Filter * @name ChildrenRead + * @summary Get Filter Group Children * @request GET:/api/v1/db/meta/filters/{filterGroupId}/children * @response `200` `(FilterType)[]` OK */ - childrenRead: (filterGroupId: string, params: RequestParams = {}) => + childrenRead: (filterGroupId: IdType, params: RequestParams = {}) => this.request({ path: `/api/v1/db/meta/filters/${filterGroupId}/children`, method: 'GET', @@ -3318,14 +4892,15 @@ export class Api< }; dbTableWebhookFilter = { /** - * No description + * @description Get the filter data in a given Hook * - * @tags DB table webhook filter + * @tags DB Table Webhook Filter * @name Read + * @summary Get Hook Filter * @request GET:/api/v1/db/meta/hooks/{hookId}/filters * @response `200` `FilterListType` */ - read: (hookId: string, params: RequestParams = {}) => + read: (hookId: IdType, params: RequestParams = {}) => this.request({ path: `/api/v1/db/meta/hooks/${hookId}/filters`, method: 'GET', @@ -3333,14 +4908,15 @@ export class Api< }), /** - * No description + * @description Create filter(s) in a given Hook * - * @tags DB table webhook filter + * @tags DB Table Webhook Filter * @name Create + * @summary Create Hook Filter * @request POST:/api/v1/db/meta/hooks/{hookId}/filters * @response `200` `void` OK */ - create: (hookId: string, data: FilterReqType, params: RequestParams = {}) => + create: (hookId: IdType, data: FilterReqType, params: RequestParams = {}) => this.request({ path: `/api/v1/db/meta/hooks/${hookId}/filters`, method: 'POST', @@ -3351,11 +4927,11 @@ export class Api< }; dbTableRow = { /** - * No description + * @description List all table rows in a given table and project * - * @tags DB table row + * @tags DB Table Row * @name List - * @summary Table row list + * @summary List Table Rows * @request GET:/api/v1/db/data/{orgs}/{projectName}/{tableName} * @response `200` `any` OK */ @@ -3364,11 +4940,26 @@ export class Api< projectName: string, tableName: string, query?: { + /** Which fields to be shown */ fields?: any[]; - sort?: any[]; + /** The result will be sorted based on `sort` query */ + sort?: string[] | string; + /** Extra filtering */ where?: string; - offset?: string; - limit?: string; + /** + * Offset in rows + * @min 0 + */ + offset?: number; + /** + * Limit in rows + * @min 1 + */ + limit?: number; + /** Used for multiple sort queries */ + sortArrJson?: string; + /** Used for multiple filter queries */ + filterArrJson?: string; }, params: RequestParams = {} ) => @@ -3381,11 +4972,11 @@ export class Api< }), /** - * No description + * @description Create a new row in a given table and project. * - * @tags DB table row + * @tags DB Table Row * @name Create - * @summary Table row create + * @summary Create Table Row * @request POST:/api/v1/db/data/{orgs}/{projectName}/{tableName} * @response `200` `any` OK */ @@ -3406,11 +4997,11 @@ export class Api< }), /** - * No description + * @description Return the first result of the target Table Row * - * @tags DB table row + * @tags DB Table Row * @name FindOne - * @summary Table row FindOne + * @summary Find One Table Row * @request GET:/api/v1/db/data/{orgs}/{projectName}/{tableName}/find-one * @response `200` `any` OK */ @@ -3434,11 +5025,11 @@ export class Api< }), /** - * No description + * @description Get the result grouped by the given query * - * @tags DB table row + * @tags DB Table Row * @name GroupBy - * @summary Table row Group by + * @summary Group By Table Row * @request GET:/api/v1/db/data/{orgs}/{projectName}/{tableName}/groupby * @response `200` `any` OK */ @@ -3451,7 +5042,9 @@ export class Api< column_name?: string; sort?: any[]; where?: string; + /** @min 1 */ limit?: number; + /** @min 0 */ offset?: number; }, params: RequestParams = {} @@ -3465,9 +5058,9 @@ export class Api< }), /** - * No description + * @description Get the grouped data By Column ID. Used in Kanban View. * - * @tags DB table row + * @tags DB Table Row * @name GroupedDataList * @summary Table Group by Column * @request GET:/api/v1/db/data/{orgs}/{projectName}/{tableName}/group/{columnId} @@ -3477,7 +5070,7 @@ export class Api< orgs: string, projectName: string, tableName: string, - columnId: string, + columnId: IdType, query?: { fields?: any[]; sort?: any[]; @@ -3496,11 +5089,11 @@ export class Api< }), /** - * No description + * @description Get the Table Row * - * @tags DB table row + * @tags DB Table Row * @name Read - * @summary Table row read + * @summary Get Table Row * @request GET:/api/v1/db/data/{orgs}/{projectName}/{tableName}/{rowId} * @response `201` `any` Created */ @@ -3508,7 +5101,7 @@ export class Api< orgs: string, projectName: string, tableName: string, - rowId: string, + rowId: any, params: RequestParams = {} ) => this.request({ @@ -3519,11 +5112,11 @@ export class Api< }), /** - * No description + * @description Update the Table Row * - * @tags DB table row + * @tags DB Table Row * @name Update - * @summary Table row update + * @summary Update Table Row * @request PATCH:/api/v1/db/data/{orgs}/{projectName}/{tableName}/{rowId} * @response `200` `any` OK */ @@ -3531,7 +5124,7 @@ export class Api< orgs: string, projectName: string, tableName: string, - rowId: string, + rowId: any, data: any, params: RequestParams = {} ) => @@ -3545,11 +5138,11 @@ export class Api< }), /** - * No description + * @description Delete the Table Row * - * @tags DB table row + * @tags DB Table Row * @name Delete - * @summary Table row delete + * @summary Delete Table Row * @request DELETE:/api/v1/db/data/{orgs}/{projectName}/{tableName}/{rowId} * @response `200` `any` OK */ @@ -3557,7 +5150,7 @@ export class Api< orgs: string, projectName: string, tableName: string, - rowId: string, + rowId: any, params: RequestParams = {} ) => this.request({ @@ -3570,9 +5163,9 @@ export class Api< /** * @description check row with provided primary key exists or not * - * @tags DB table row + * @tags DB Table Row * @name Exist - * @summary Table row exist + * @summary Does Table Row Exist * @request GET:/api/v1/db/data/{orgs}/{projectName}/{tableName}/{rowId}/exist * @response `201` `any` Created */ @@ -3580,7 +5173,7 @@ export class Api< orgs: string, projectName: string, tableName: string, - rowId: string, + rowId: any, params: RequestParams = {} ) => this.request({ @@ -3591,11 +5184,11 @@ export class Api< }), /** - * No description + * @description Bulk insert table rows in one go. * - * @tags DB table row + * @tags DB Table Row * @name BulkCreate - * @summary Bulk insert table rows + * @summary Bulk Insert Table Rows * @request POST:/api/v1/db/data/bulk/{orgs}/{projectName}/{tableName} * @response `200` `any` OK */ @@ -3616,11 +5209,11 @@ export class Api< }), /** - * No description + * @description Bulk Update Table Rows by given IDs * - * @tags DB table row + * @tags DB Table Row * @name BulkUpdate - * @summary Bulk update all table rows by IDs + * @summary Bulk Update Table Rows by IDs * @request PATCH:/api/v1/db/data/bulk/{orgs}/{projectName}/{tableName} * @response `200` `any` OK */ @@ -3641,11 +5234,11 @@ export class Api< }), /** - * No description + * @description Bulk Delete Table Rows by given IDs * - * @tags DB table row + * @tags DB Table Row * @name BulkDelete - * @summary Bulk delete all table rows by IDs + * @summary Bulk Delete Table Rows by IDs * @request DELETE:/api/v1/db/data/bulk/{orgs}/{projectName}/{tableName} * @response `200` `any` OK */ @@ -3666,11 +5259,11 @@ export class Api< }), /** - * No description + * @description Bulk Update all Table Rows if the condition is true * - * @tags DB table row + * @tags DB Table Row * @name BulkUpdateAll - * @summary Bulk update all table rows with conditions + * @summary Bulk Update Table Rows with Conditions * @request PATCH:/api/v1/db/data/bulk/{orgs}/{projectName}/{tableName}/all * @response `200` `any` OK */ @@ -3695,11 +5288,11 @@ export class Api< }), /** - * No description + * @description Bulk Delete all Table Rows if the condition is true * - * @tags DB table row + * @tags DB Table Row * @name BulkDeleteAll - * @summary Bulk delete all table rows with conditions + * @summary Bulk Delete Table Rows with Conditions * @request DELETE:/api/v1/db/data/bulk/{orgs}/{projectName}/{tableName}/all * @response `200` `any` OK */ @@ -3724,11 +5317,11 @@ export class Api< }), /** - * @description CSV or Excel export + * @description Export Table View Rows by CSV or Excel * - * @tags DB table row + * @tags DB Table Row * @name CsvExport - * @summary Tablerows export + * @summary Export Table View Rows * @request GET:/api/v1/db/data/{orgs}/{projectName}/{tableName}/export/{type} * @response `200` `any` OK */ @@ -3747,11 +5340,11 @@ export class Api< }), /** - * No description + * @description List all nested relations rows * - * @tags DB table row + * @tags DB Table Row * @name NestedList - * @summary Nested relations row list + * @summary List Nested Relations Rows * @request GET:/api/v1/db/data/{orgs}/{projectName}/{tableName}/{rowId}/{relationType}/{columnName} * @response `200` `any` OK */ @@ -3759,12 +5352,14 @@ export class Api< orgs: string, projectName: string, tableName: string, - rowId: string, + rowId: any, relationType: 'mm' | 'hm' | 'bt', columnName: string, query?: { - limit?: string | number; - offset?: string | number; + /** @min 1 */ + limit?: number; + /** @min 0 */ + offset?: number; where?: string; }, params: RequestParams = {} @@ -3778,11 +5373,11 @@ export class Api< }), /** - * No description + * @description Create a new nested relations row * - * @tags DB table row + * @tags DB Table Row * @name NestedAdd - * @summary Nested relations row add + * @summary Create Nested Relations Row * @request POST:/api/v1/db/data/{orgs}/{projectName}/{tableName}/{rowId}/{relationType}/{columnName}/{refRowId} * @response `200` `any` OK */ @@ -3790,13 +5385,31 @@ export class Api< orgs: string, projectName: string, tableName: string, - rowId: string, + rowId: any, relationType: 'mm' | 'hm' | 'bt', columnName: string, refRowId: string, query?: { - limit?: string; - offset?: string; + /** Which fields to be shown */ + fields?: any[]; + /** The result will be sorted based on `sort` query */ + sort?: string[] | string; + /** Extra filtering */ + where?: string; + /** + * Offset in rows + * @min 0 + */ + offset?: number; + /** + * Limit in rows + * @min 1 + */ + limit?: number; + /** Used for multiple sort queries */ + sortArrJson?: string; + /** Used for multiple filter queries */ + filterArrJson?: string; }, params: RequestParams = {} ) => @@ -3809,11 +5422,11 @@ export class Api< }), /** - * No description + * @description Delete a new nested relations row * - * @tags DB table row + * @tags DB Table Row * @name NestedRemove - * @summary Nested relations row remove + * @summary Delete Nested Relations Row * @request DELETE:/api/v1/db/data/{orgs}/{projectName}/{tableName}/{rowId}/{relationType}/{columnName}/{refRowId} * @response `200` `any` OK */ @@ -3821,7 +5434,7 @@ export class Api< orgs: string, projectName: string, tableName: string, - rowId: string, + rowId: any, relationType: 'mm' | 'hm' | 'bt', columnName: string, refRowId: string, @@ -3835,11 +5448,11 @@ export class Api< }), /** - * No description + * @description Get the table rows but exculding the current record's children and parent * - * @tags DB table row + * @tags DB Table Row * @name NestedChildrenExcludedList - * @summary Referenced tables rows excluding current records children/parent + * @summary Referenced Table Rows Excluding Current Record's Children / Parent * @request GET:/api/v1/db/data/{orgs}/{projectName}/{tableName}/{rowId}/{relationType}/{columnName}/exclude * @response `200` `any` OK */ @@ -3847,12 +5460,14 @@ export class Api< orgs: string, projectName: string, tableName: string, - rowId: string, + rowId: any, relationType: 'mm' | 'hm' | 'bt', columnName: string, query?: { - limit?: string | number; - offset?: string | number; + /** @min 1 */ + limit?: number; + /** @min 0 */ + offset?: number; where?: string; }, params: RequestParams = {} @@ -3867,20 +5482,20 @@ export class Api< }; dbViewRow = { /** - * No description + * @description Get the grouped data By Column ID. Used in Kanban View. * - * @tags DB view row + * @tags DB View Row * @name GroupedDataList * @summary Table Group by Column * @request GET:/api/v1/db/data/{orgs}/{projectName}/{tableName}/views/{viewName}/group/{columnId} * @response `200` `any` OK */ groupedDataList: ( - orgs: string, + orgs: IdType, projectName: string, tableName: string, viewName: string, - columnId: string, + columnId: IdType, query?: { fields?: any[]; sort?: any[]; @@ -3899,11 +5514,11 @@ export class Api< }), /** - * No description + * @description List all table view rows * - * @tags DB view row + * @tags DB View Row * @name List - * @summary Table view row list + * @summary List Table View Rows * @request GET:/api/v1/db/data/{orgs}/{projectName}/{tableName}/views/{viewName} * @response `200` `any` OK */ @@ -3931,11 +5546,11 @@ export class Api< }), /** - * No description + * @description Create a new row in the given Table View * - * @tags DB view row + * @tags DB View Row * @name Create - * @summary Table view row create + * @summary Create Table View Row * @request POST:/api/v1/db/data/{orgs}/{projectName}/{tableName}/views/{viewName} * @response `200` `any` OK */ @@ -3957,11 +5572,11 @@ export class Api< }), /** - * No description + * @description Return the first result of table view rows with the given query * - * @tags DB view row + * @tags DB View Row * @name FindOne - * @summary Table view row FindOne + * @summary Find One Table View Row * @request GET:/api/v1/db/data/{orgs}/{projectName}/{tableName}/views/{viewName}/find-one * @response `200` `any` OK */ @@ -3988,11 +5603,11 @@ export class Api< }), /** - * No description + * @description Get the table view rows groupe by the given query * - * @tags DB view row + * @tags DB View Row * @name GroupBy - * @summary Table view row Group by + * @summary Group By Table View Row * @request GET:/api/v1/db/data/{orgs}/{projectName}/{tableName}/views/{viewName}/groupby * @response `200` `any` OK */ @@ -4006,7 +5621,9 @@ export class Api< column_name?: string; sort?: any[]; where?: string; + /** @min 1 */ limit?: number; + /** @min 0 */ offset?: number; }, params: RequestParams = {} @@ -4020,11 +5637,11 @@ export class Api< }), /** - * No description + * @description Count how many rows in the given Table View * - * @tags DB view row + * @tags DB View Row * @name Count - * @summary Table view rows count + * @summary Count Table View Rows * @request GET:/api/v1/db/data/{orgs}/{projectName}/{tableName}/views/{viewName}/count * @response `200` `any` OK */ @@ -4049,11 +5666,11 @@ export class Api< }), /** - * No description + * @description Get the target Table View Row * - * @tags DB view row + * @tags DB View Row * @name Read - * @summary Table view row read + * @summary Get Table View Row * @request GET:/api/v1/db/data/{orgs}/{projectName}/{tableName}/views/{viewName}/{rowId} * @response `201` `any` Created */ @@ -4062,7 +5679,7 @@ export class Api< projectName: string, tableName: string, viewName: string, - rowId: string, + rowId: any, params: RequestParams = {} ) => this.request({ @@ -4073,11 +5690,11 @@ export class Api< }), /** - * No description + * @description Update the target Table View Row * - * @tags DB view row + * @tags DB View Row * @name Update - * @summary Table view row update + * @summary Update Table View Row * @request PATCH:/api/v1/db/data/{orgs}/{projectName}/{tableName}/views/{viewName}/{rowId} * @response `200` `any` OK */ @@ -4086,7 +5703,7 @@ export class Api< projectName: string, tableName: string, viewName: string, - rowId: string, + rowId: any, data: any, params: RequestParams = {} ) => @@ -4100,11 +5717,11 @@ export class Api< }), /** - * No description + * @description Delete the target Table View Row * - * @tags DB view row + * @tags DB View Row * @name Delete - * @summary Table view row delete + * @summary Delete Table View Row * @request DELETE:/api/v1/db/data/{orgs}/{projectName}/{tableName}/views/{viewName}/{rowId} * @response `200` `void` OK */ @@ -4113,7 +5730,7 @@ export class Api< projectName: string, tableName: string, viewName: string, - rowId: string, + rowId: any, params: RequestParams = {} ) => this.request({ @@ -4123,11 +5740,11 @@ export class Api< }), /** - * @description check row with provided primary key exists or not + * @description Check row with provided primary key exists or not * - * @tags DB view row + * @tags DB View Row * @name Exist - * @summary Table view row exist + * @summary Does Table View Row Exist * @request GET:/api/v1/db/data/{orgs}/{projectName}/{tableName}/views/{viewName}/{rowId}/exist * @response `201` `any` Created */ @@ -4136,7 +5753,7 @@ export class Api< projectName: string, tableName: string, viewName: string, - rowId: string, + rowId: any, params: RequestParams = {} ) => this.request({ @@ -4147,11 +5764,11 @@ export class Api< }), /** - * @description CSV or Excel export + * @description Export Table View Rows by CSV or Excel * - * @tags DB view row + * @tags DB View Row * @name Export - * @summary Table view rows export + * @summary Export Table View Rows * @request GET:/api/v1/db/data/{orgs}/{projectName}/{tableName}/views/{viewName}/export/{type} * @response `200` `any` OK */ @@ -4172,19 +5789,38 @@ export class Api< }; public = { /** - * No description + * @description List Shared View Grouped Data * * @tags Public * @name GroupedDataList + * @summary List Shared View Grouped Data * @request GET:/api/v1/db/public/shared-view/{sharedViewUuid}/group/{columnId} * @response `200` `any` OK */ groupedDataList: ( sharedViewUuid: string, - columnId: string, + columnId: IdType, query?: { - limit?: string; - offset?: string; + /** Which fields to be shown */ + fields?: any[]; + /** The result will be sorted based on `sort` query */ + sort?: string[] | string; + /** Extra filtering */ + where?: string; + /** + * Offset in rows + * @min 0 + */ + offset?: number; + /** + * Limit in rows + * @min 1 + */ + limit?: number; + /** Used for multiple sort queries */ + sortArrJson?: string; + /** Used for multiple filter queries */ + filterArrJson?: string; }, params: RequestParams = {} ) => @@ -4197,18 +5833,37 @@ export class Api< }), /** - * No description + * @description List all shared view rows * * @tags Public * @name DataList + * @summary List Shared View Rows * @request GET:/api/v1/db/public/shared-view/{sharedViewUuid}/rows * @response `200` `any` OK */ dataList: ( sharedViewUuid: string, query?: { - limit?: string; - offset?: string; + /** Which fields to be shown */ + fields?: any[]; + /** The result will be sorted based on `sort` query */ + sort?: string[] | string; + /** Extra filtering */ + where?: string; + /** + * Offset in rows + * @min 0 + */ + offset?: number; + /** + * Limit in rows + * @min 1 + */ + limit?: number; + /** Used for multiple sort queries */ + sortArrJson?: string; + /** Used for multiple filter queries */ + filterArrJson?: string; }, params: RequestParams = {} ) => @@ -4221,10 +5876,11 @@ export class Api< }), /** - * No description + * @description Create a new row for the target shared view * * @tags Public * @name DataCreate + * @summary Create Share View Row * @request POST:/api/v1/db/public/shared-view/{sharedViewUuid}/rows * @response `200` `any` OK */ @@ -4243,21 +5899,40 @@ export class Api< }), /** - * No description + * @description List all nested list data in a given shared view * * @tags Public * @name DataNestedList + * @summary List Nested List Data * @request GET:/api/v1/db/public/shared-view/{sharedViewUuid}/rows/{rowId}/{relationType}/{columnName} * @response `200` `any` OK */ dataNestedList: ( sharedViewUuid: string, - rowId: string, + rowId: any, relationType: 'mm' | 'hm' | 'bt', columnName: string, query?: { - limit?: string; - offset?: string; + /** Which fields to be shown */ + fields?: any[]; + /** The result will be sorted based on `sort` query */ + sort?: string[] | string; + /** Extra filtering */ + where?: string; + /** + * Offset in rows + * @min 0 + */ + offset?: number; + /** + * Limit in rows + * @min 1 + */ + limit?: number; + /** Used for multiple sort queries */ + sortArrJson?: string; + /** Used for multiple filter queries */ + filterArrJson?: string; }, params: RequestParams = {} ) => @@ -4270,10 +5945,11 @@ export class Api< }), /** - * No description + * @description Export all rows in Share View in a CSV / Excel Format * * @tags Public * @name CsvExport + * @summary Export Rows in Share View * @request GET:/api/v1/db/public/shared-view/{sharedViewUuid}/rows/export/{type} * @response `200` `any` OK */ @@ -4290,10 +5966,11 @@ export class Api< }), /** - * No description + * @description List Nested Data Relation * * @tags Public * @name DataRelationList + * @summary List Nested Data Relation * @request GET:/api/v1/db/public/shared-view/{sharedViewUuid}/nested/{columnName} * @response `200` `any` OK */ @@ -4301,8 +5978,26 @@ export class Api< sharedViewUuid: string, columnName: string, query?: { - limit?: string; - offset?: string; + /** Which fields to be shown */ + fields?: any[]; + /** The result will be sorted based on `sort` query */ + sort?: string[] | string; + /** Extra filtering */ + where?: string; + /** + * Offset in rows + * @min 0 + */ + offset?: number; + /** + * Limit in rows + * @min 1 + */ + limit?: number; + /** Used for multiple sort queries */ + sortArrJson?: string; + /** Used for multiple filter queries */ + filterArrJson?: string; }, params: RequestParams = {} ) => @@ -4315,10 +6010,11 @@ export class Api< }), /** - * @description Read project details + * @description Get Share Base Meta * * @tags Public * @name SharedBaseGet + * @summary Get Share Base Meta * @request GET:/api/v1/db/public/shared-base/{sharedBaseUuid}/meta * @response `200` `{ project_id?: string, @@ -4339,16 +6035,18 @@ export class Api< }), /** - * No description + * @description Get Share View Meta * * @tags Public * @name SharedViewMetaGet + * @summary Get Share View Meta * @request GET:/api/v1/db/public/shared-view/{sharedViewUuid}/meta * @response `200` `(ViewType & { relatedMetas?: any, client?: string, base_id?: string, columns?: ((GridColumnType | FormColumnType | GalleryColumnType | (GridColumnType & FormColumnType & GalleryColumnType)) & ColumnType), + \** Model for Table *\ model?: TableType, } & { @@ -4369,6 +6067,7 @@ export class Api< | (GridColumnType & FormColumnType & GalleryColumnType) ) & ColumnType; + /** Model for Table */ model?: TableType; } & { view?: @@ -4387,17 +6086,30 @@ export class Api< }; utils = { /** - * No description + * @description List all comments * * @tags Utils * @name CommentList + * @summary List Comments in Audit * @request GET:/api/v1/db/meta/audits/comments * @response `201` `any` Created */ commentList: ( query: { + /** + * Row ID + * @example 10 + */ row_id: string; - fk_model_id: string; + /** + * Foreign Key to Model + * @example md_c6csq89tl37jm5 + */ + fk_model_id: IdType; + /** + * Is showing comments only? + * @example true + */ comments_only?: boolean; }, params: RequestParams = {} @@ -4411,10 +6123,11 @@ export class Api< }), /** - * No description + * @description Create a new comment in a row. Logged in Audit. * * @tags Utils * @name CommentRow + * @summary Comment Rows * @request POST:/api/v1/db/meta/audits/comments * @response `200` `void` OK */ @@ -4428,17 +6141,19 @@ export class Api< }), /** - * No description + * @description Return the number of comments in the given query. * * @tags Utils * @name CommentCount + * @summary Count Comments * @request GET:/api/v1/db/meta/audits/comments/count * @response `201` `any` Created */ commentCount: ( query: { ids: any; - fk_model_id: string; + /** Model for ID */ + fk_model_id: IdType; }, params: RequestParams = {} ) => @@ -4451,15 +6166,16 @@ export class Api< }), /** - * No description + * @description Update Audit Row * * @tags Utils * @name AuditRowUpdate + * @summary Update Audit Row * @request POST:/api/v1/db/meta/audits/rows/{rowId}/update * @response `200` `void` OK */ auditRowUpdate: ( - rowId: string, + rowId: any, data: AuditRowUpdateReqType, params: RequestParams = {} ) => @@ -4472,10 +6188,11 @@ export class Api< }), /** - * No description + * @description Test the DB Connection * * @tags Utils * @name TestConnection + * @summary Test DB Connection * @request POST:/api/v1/db/meta/connection/test * @response `200` `{ code?: number, @@ -4500,11 +6217,13 @@ export class Api< }), /** - * No description + * @description Extract XC URL From JDBC and parse to connection config * * @tags Utils * @name UrlToConfig + * @summary Convert JDBC URL to Config * @request POST:/api/v1/url_to_config + * @response `200` `any` OK */ urlToConfig: (data: any, params: RequestParams = {}) => this.request({ @@ -4512,14 +6231,16 @@ export class Api< method: 'POST', body: data, type: ContentType.Json, + format: 'json', ...params, }), /** - * No description + * @description Get the application info such as authType, defaultLimit, version and etc. * * @tags Utils * @name AppInfo + * @summary Get App Info * @request GET:/api/v1/db/meta/nocodb/info * @response `200` `any` OK */ @@ -4536,6 +6257,7 @@ export class Api< * * @tags Utils * @name AxiosRequestMake + * @summary Axios Request * @request POST:/api/v1/db/meta/axiosRequestMake * @response `200` `object` OK */ @@ -4550,10 +6272,11 @@ export class Api< }), /** - * No description + * @description Get the application version * * @tags Utils * @name AppVersion + * @summary Get App Version * @request GET:/api/v1/version * @response `200` `any` OK */ @@ -4566,10 +6289,11 @@ export class Api< }), /** - * No description + * @description Get Application Health Status * * @tags Utils * @name AppHealth + * @summary Get Application Health Status * @request GET:/api/v1/health * @response `200` `any` OK */ @@ -4582,45 +6306,67 @@ export class Api< }), /** - * No description + * @description Get Aggregated Meta Info such as tableCount, dbViewCount, viewCount and etc. * * @tags Utils * @name AggregatedMetaInfo + * @summary Get Aggregated Meta Info * @request GET:/api/v1/aggregated-meta-info * @response `200` `{ projectCount?: number, projects?: ({ tableCount?: { + \** Table Count *\ table?: number, + \** View Count *\ view?: number, }, + \** External Project *\ external?: boolean, viewCount?: { + \** Form Count *\ formCount?: number, + \** Grid Count *\ gridCount?: number, + \** Gallery Count *\ galleryCount?: number, + \** Kanban Count *\ kanbanCount?: number, + \** Total View Count *\ total?: number, + \** Shared Form Count *\ sharedFormCount?: number, + \** Shared Grid Count *\ sharedGridCount?: number, + \** Shared Gallery Count *\ sharedGalleryCount?: number, + \** Shared Kanban Count *\ sharedKanbanCount?: number, + \** Shared Total View Count *\ sharedTotal?: number, + \** Shared Locked View Count *\ sharedLockedCount?: number, }, + \** Webhook Count *\ webhookCount?: number, + \** Filter Count *\ filterCount?: number, + \** Sort Count *\ sortCount?: number, + \** Row Count *\ rowCount?: ({ TotalRecords?: string, })[], + \** Total project user Count *\ userCount?: number, })[], + \** Total user Count *\ userCount?: number, + \** Total shared base Count *\ sharedBaseCount?: number, }` OK @@ -4631,32 +6377,53 @@ export class Api< projectCount?: number; projects?: { tableCount?: { + /** Table Count */ table?: number; + /** View Count */ view?: number; }; + /** External Project */ external?: boolean; viewCount?: { + /** Form Count */ formCount?: number; + /** Grid Count */ gridCount?: number; + /** Gallery Count */ galleryCount?: number; + /** Kanban Count */ kanbanCount?: number; + /** Total View Count */ total?: number; + /** Shared Form Count */ sharedFormCount?: number; + /** Shared Grid Count */ sharedGridCount?: number; + /** Shared Gallery Count */ sharedGalleryCount?: number; + /** Shared Kanban Count */ sharedKanbanCount?: number; + /** Shared Total View Count */ sharedTotal?: number; + /** Shared Locked View Count */ sharedLockedCount?: number; }; + /** Webhook Count */ webhookCount?: number; + /** Filter Count */ filterCount?: number; + /** Sort Count */ sortCount?: number; + /** Row Count */ rowCount?: { TotalRecords?: string; }[]; + /** Total project user Count */ userCount?: number; }[]; + /** Total user Count */ userCount?: number; + /** Total shared base Count */ sharedBaseCount?: number; }, any @@ -4672,7 +6439,7 @@ export class Api< * * @tags Utils * @name CacheGet - * @summary Your GET endpoint + * @summary Get Cache * @request GET:/api/v1/db/meta/cache */ cacheGet: (params: RequestParams = {}) => @@ -4687,6 +6454,7 @@ export class Api< * * @tags Utils * @name CacheDelete + * @summary Delete Cache * @request DELETE:/api/v1/db/meta/cache * @response `200` `void` OK */ @@ -4699,21 +6467,24 @@ export class Api< }; dbTableWebhook = { /** - * No description + * @description List all hook records in the given Table * - * @tags DB table webhook + * @tags DB Table Webhook * @name List + * @summary List Table Hooks * @request GET:/api/v1/db/meta/tables/{tableId}/hooks * @response `200` `{ list: (HookType)[], + \** Model for Paginated *\ pageInfo: PaginatedType, }` OK */ - list: (tableId: string, params: RequestParams = {}) => + list: (tableId: IdType, params: RequestParams = {}) => this.request< { list: HookType[]; + /** Model for Paginated */ pageInfo: PaginatedType; }, any @@ -4725,15 +6496,16 @@ export class Api< }), /** - * No description + * @description Create a hook in the given table * - * @tags DB table webhook + * @tags DB Table Webhook * @name Create + * @summary Create Table Hook * @request POST:/api/v1/db/meta/tables/{tableId}/hooks - * @response `200` `AuditType` OK + * @response `200` `HookReqType` OK */ - create: (tableId: string, data: AuditType, params: RequestParams = {}) => - this.request({ + create: (tableId: IdType, data: AuditType, params: RequestParams = {}) => + this.request({ path: `/api/v1/db/meta/tables/${tableId}/hooks`, method: 'POST', body: data, @@ -4743,15 +6515,16 @@ export class Api< }), /** - * No description + * @description Test the hook in the given Table * - * @tags DB table webhook + * @tags DB Table Webhook * @name Test + * @summary Test Hook * @request POST:/api/v1/db/meta/tables/{tableId}/hooks/test * @response `200` `any` OK */ test: ( - tableId: string, + tableId: IdType, data: HookTestReqType, params: RequestParams = {} ) => @@ -4765,14 +6538,16 @@ export class Api< }), /** - * No description + * @description Get the sample hook payload * - * @tags DB table webhook + * @tags DB Table Webhook * @name SamplePayloadGet + * @summary Get Sample Hook Payload * @request GET:/api/v1/db/meta/tables/{tableId}/hooks/samplePayload/{operation} * @response `200` `{ plugins?: { list: (PluginType)[], + \** Model for Paginated *\ pageInfo: PaginatedType, }, @@ -4780,7 +6555,7 @@ export class Api< }` OK */ samplePayloadGet: ( - tableId: string, + tableId: IdType, operation: 'update' | 'delete' | 'insert', params: RequestParams = {} ) => @@ -4788,6 +6563,7 @@ export class Api< { plugins?: { list: PluginType[]; + /** Model for Paginated */ pageInfo: PaginatedType; }; }, @@ -4800,10 +6576,11 @@ export class Api< }), /** - * No description + * @description Update the exsiting hook by its ID * - * @tags DB table webhook + * @tags DB Table Webhook * @name Update + * @summary Update Hook * @request PATCH:/api/v1/db/meta/hooks/{hookId} * @response `200` `HookType` OK */ @@ -4818,10 +6595,11 @@ export class Api< }), /** - * No description + * @description Delete the exsiting hook by its ID * - * @tags DB table webhook + * @tags DB Table Webhook * @name Delete + * @summary Delete Hook * @request DELETE:/api/v1/db/meta/hooks/{hookId} * @response `200` `void` OK */ @@ -4834,13 +6612,15 @@ export class Api< }; plugin = { /** - * No description + * @description List all plugins * * @tags Plugin * @name List + * @summary List Plugins * @request GET:/api/v1/db/meta/plugins * @response `200` `{ list?: (PluginType)[], + \** Model for Paginated *\ pageInfo?: PaginatedType, }` OK @@ -4849,6 +6629,7 @@ export class Api< this.request< { list?: PluginType[]; + /** Model for Paginated */ pageInfo?: PaginatedType; }, any @@ -4864,6 +6645,7 @@ export class Api< * * @tags Plugin * @name Status + * @summary Get Plugin Status * @request GET:/api/v1/db/meta/plugins/{pluginTitle}/status * @response `200` `boolean` OK */ @@ -4876,10 +6658,11 @@ export class Api< }), /** - * No description + * @description Test if the plugin is working with the given configurations * * @tags Plugin * @name Test + * @summary Test Plugin * @request POST:/api/v1/db/meta/plugins/test * @response `200` `any` OK * @response `400` `void` Bad Request @@ -4896,15 +6679,20 @@ export class Api< }), /** - * No description + * @description Update the plugin data by ID * * @tags Plugin * @name Update + * @summary Update Plugin * @request PATCH:/api/v1/db/meta/plugins/{pluginId} - * @response `200` `PluginReqType` OK + * @response `200` `any` OK */ - update: (pluginId: string, data: PluginType, params: RequestParams = {}) => - this.request({ + update: ( + pluginId: string, + data: PluginReqType, + params: RequestParams = {} + ) => + this.request({ path: `/api/v1/db/meta/plugins/${pluginId}`, method: 'PATCH', body: data, @@ -4914,10 +6702,11 @@ export class Api< }), /** - * No description + * @description Get the plugin data by ID * * @tags Plugin * @name Read + * @summary Get Plugin * @request GET:/api/v1/db/meta/plugins/{pluginId} * @response `200` `PluginType` OK */ @@ -4931,16 +6720,30 @@ export class Api< }; apiToken = { /** - * No description - * - * @tags Api token - * @name List - * @summary Your GET endpoint - * @request GET:/api/v1/db/meta/projects/{projectId}/api-tokens - * @response `200` `(ApiTokenType)[]` OK - */ - list: (projectId: string, params: RequestParams = {}) => - this.request({ + * @description List API Tokens in the given project + * + * @tags API Token + * @name List + * @summary List API Tokens in Project + * @request GET:/api/v1/db/meta/projects/{projectId}/api-tokens + * @response `200` `{ + \** List of API Token Models *\ + list: (ApiTokenType)[], + \** Pagination Info *\ + pageInfo: PaginatedType, + +}` OK + */ + list: (projectId: IdType, params: RequestParams = {}) => + this.request< + { + /** List of API Token Models */ + list: ApiTokenType[]; + /** Pagination Info */ + pageInfo: PaginatedType; + }, + any + >({ path: `/api/v1/db/meta/projects/${projectId}/api-tokens`, method: 'GET', format: 'json', @@ -4948,19 +6751,18 @@ export class Api< }), /** - * No description + * @description Create API Token in a project * - * @tags Api token + * @tags API Token * @name Create + * @summary Create API Token * @request POST:/api/v1/db/meta/projects/{projectId}/api-tokens * @response `200` `void` OK - * @response `201` `ApiTokenReqType` Created + * @response `201` `any` Created */ create: ( - projectId: string, - data: { - description?: string; - }, + projectId: IdType, + data: ApiTokenReqType, params: RequestParams = {} ) => this.request({ @@ -4972,14 +6774,15 @@ export class Api< }), /** - * No description + * @description Delete the given API Token in project * - * @tags Api token + * @tags API Token * @name Delete + * @summary Delete API Token * @request DELETE:/api/v1/db/meta/projects/{projectId}/api-tokens/{token} * @response `200` `void` OK */ - delete: (projectId: string, token: string, params: RequestParams = {}) => + delete: (projectId: IdType, token: string, params: RequestParams = {}) => this.request({ path: `/api/v1/db/meta/projects/${projectId}/api-tokens/${token}`, method: 'DELETE', @@ -4988,21 +6791,22 @@ export class Api< }; storage = { /** - * No description + * @description Upload attachment * * @tags Storage * @name Upload - * @summary Attachment + * @summary Attachment Upload * @request POST:/api/v1/db/storage/upload */ upload: ( query: { + /** + * Target File Path + * @example download/noco/jango_fett/Table1/attachment/uVbjPVQxC_SSfs8Ctx.jpg + */ path: string; }, - data: { - files?: any; - json?: string; - }, + data: AttachmentReqType, params: RequestParams = {} ) => this.request({ @@ -5015,23 +6819,22 @@ export class Api< }), /** - * No description + * @description Upload attachment by URL. Used in Airtable Migration. * * @tags Storage * @name UploadByUrl - * @summary Attachment + * @summary Attachment Upload by URL * @request POST:/api/v1/db/storage/upload-by-url */ uploadByUrl: ( query: { + /** + * Target File Path + * @example download/noco/jango_fett/Table1/attachment/c7z_UF8sZBgJUxMjpN.jpg + */ path: string; }, - data: { - url?: string; - fileName?: string; - mimetype?: string; - size?: string; - }[], + data: AttachmentReqType[], params: RequestParams = {} ) => this.request({ diff --git a/packages/nocodb-sdk/src/lib/globals.ts b/packages/nocodb-sdk/src/lib/globals.ts index 0e069f9760..fd64f2d2a8 100644 --- a/packages/nocodb-sdk/src/lib/globals.ts +++ b/packages/nocodb-sdk/src/lib/globals.ts @@ -55,7 +55,7 @@ export enum AuditOperationSubTypes { EXPORT_TO_ZIP = 'EXPORT_TO_ZIP', UPDATED = 'UPDATED', SIGNIN = 'SIGNIN', - SIGN = 'SIGN', + SIGNUP = 'SIGNUP', PASSWORD_RESET = 'PASSWORD_RESET', PASSWORD_FORGOT = 'PASSWORD_FORGOT', PASSWORD_CHANGE = 'PASSWORD_CHANGE', diff --git a/packages/nocodb-sdk/src/lib/sqlUi/OracleUi.ts b/packages/nocodb-sdk/src/lib/sqlUi/OracleUi.ts index aa157d07d5..3498a0835e 100644 --- a/packages/nocodb-sdk/src/lib/sqlUi/OracleUi.ts +++ b/packages/nocodb-sdk/src/lib/sqlUi/OracleUi.ts @@ -1,3 +1,4 @@ +import { NormalColumnRequestType } from '../Api' import UITypes from '../UITypes'; import { IDType } from './index'; @@ -794,7 +795,10 @@ export class OracleUi { } } - static getDataTypeForUiType(col: { uidt: UITypes }, idType?: IDType) { + static getDataTypeForUiType( + col: { uidt: UITypes | NormalColumnRequestType['uidt'] }, + idType?: IDType + ) { const colProp: any = {}; switch (col.uidt) { case 'ID': diff --git a/packages/nocodb-sdk/src/lib/sqlUi/SqlUiFactory.ts b/packages/nocodb-sdk/src/lib/sqlUi/SqlUiFactory.ts index 6e79066cad..3eef12622a 100644 --- a/packages/nocodb-sdk/src/lib/sqlUi/SqlUiFactory.ts +++ b/packages/nocodb-sdk/src/lib/sqlUi/SqlUiFactory.ts @@ -1,3 +1,4 @@ +import { BoolType } from '../Api' import UITypes from '../UITypes'; import { MssqlUi } from './MssqlUi'; @@ -56,12 +57,12 @@ export type SqlUIColumn = { dt?: string; dtx?: string; ct?: string; - nrqd?: boolean; - rqd?: boolean; + nrqd?: BoolType; + rqd?: BoolType; ck?: string; - pk?: boolean; - un?: boolean; - ai?: boolean; + pk?: BoolType; + un?: BoolType; + ai?: BoolType; cdf?: string | any; clen?: number | any; np?: string; diff --git a/packages/nocodb/.eslintrc.json b/packages/nocodb/.eslintrc.json index 9e367810c2..6570091b22 100644 --- a/packages/nocodb/.eslintrc.json +++ b/packages/nocodb/.eslintrc.json @@ -7,18 +7,8 @@ "env": { "es6": true }, - "ignorePatterns": [ - "node_modules", - "build", - "coverage", - "dist", - "nc" - ], - "plugins": [ - "import", - "eslint-comments", - "functional" - ], + "ignorePatterns": ["node_modules", "build", "coverage", "dist", "nc"], + "plugins": ["import", "eslint-comments", "functional"], "extends": [ "eslint:recommended", "plugin:eslint-comments/recommended", @@ -47,6 +37,21 @@ "ignoreCase": true } ], + "import/order": [ + "error", + { + "groups": [ + "builtin", + "external", + "internal", + "parent", + "sibling", + "index", + "object", + "type" + ] + } + ], "@typescript-eslint/no-this-alias": "off", // todo: enable @@ -57,46 +62,6 @@ "no-useless-catch": "off", "no-empty": "off", "@typescript-eslint/no-empty-function": "off", - "import/order": "off" - - -// "@typescript-eslint/member-ordering": [ -// "warn" , -// { -// "default": { -// "memberTypes": [ "static-field", -// "public-field", -// "instance-field", -// "protected-field", -// "private-field", -// "abstract-field", -// -// "public-static-field", -// "protected-static-field", -// "private-static-field", -// "public-instance-field", -// "public-decorated-field", -// "public-abstract-field", -// "protected-instance-field", -// "protected-decorated-field", -// "protected-abstract-field", -// "private-instance-field", -// "private-decorated-field", -// "private-abstract-field", -// -// -// -// "constructor", -// -// "public-static-method", -// "protected-static-method", -// "private-static-method", -// "public-method", -// "protected-method", -// "private-method" -// ] -// } -// } -// ] + "@typescript-eslint/consistent-type-imports": "warn" } } diff --git a/packages/nocodb/package-lock.json b/packages/nocodb/package-lock.json index 1f94426e0a..20e22da694 100644 --- a/packages/nocodb/package-lock.json +++ b/packages/nocodb/package-lock.json @@ -14,6 +14,7 @@ "@sentry/node": "^6.3.5", "airtable": "^0.11.3", "ajv": "^8.12.0", + "ajv-formats": "^2.1.1", "archiver": "^5.0.2", "auto-bind": "^4.0.0", "aws-sdk": "^2.829.0", @@ -65,7 +66,7 @@ "multer": "^1.4.2", "mysql2": "^2.2.5", "nanoid": "^3.1.20", - "nc-help": "0.2.85", + "nc-help": "0.2.87", "nc-lib-gui": "0.105.3", "nc-plugin": "0.1.2", "ncp": "^2.0.0", @@ -120,7 +121,7 @@ "eslint-config-prettier": "^6.15.0", "eslint-plugin-eslint-comments": "^3.2.0", "eslint-plugin-functional": "^3.0.2", - "eslint-plugin-import": "^2.22.0", + "eslint-plugin-import": "^2.25.2", "eslint-plugin-prettier": "^4.0.0", "mocha": "^10.1.0", "nodemon": "^2.0.7", @@ -2261,6 +2262,22 @@ "ajv": ">=5.0.0" } }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, "node_modules/amdefine": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", @@ -11294,9 +11311,9 @@ } }, "node_modules/nc-help": { - "version": "0.2.85", - "resolved": "https://registry.npmjs.org/nc-help/-/nc-help-0.2.85.tgz", - "integrity": "sha512-EOyrc2PuRUJzv73jHNHmUR6YhC0TlJG0DTY/sug7BF4MJAVPJgyavJnrqkRC7g0NS4xociki9gs5MbLRjlRwtQ==", + "version": "0.2.87", + "resolved": "https://registry.npmjs.org/nc-help/-/nc-help-0.2.87.tgz", + "integrity": "sha512-Zlg06ialvylBEE1qtvjlNKxZrPShzXwvy3WG7nfw+8GngOkQBCTlKguejT2Kq4Gfb5378WPX1APXtsetMKBrRA==", "dependencies": { "@rudderstack/rudder-sdk-node": "^1.1.3", "axios": "^0.21.1", @@ -20919,6 +20936,14 @@ "dev": true, "requires": {} }, + "ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "requires": { + "ajv": "^8.0.0" + } + }, "amdefine": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", @@ -28004,9 +28029,9 @@ "integrity": "sha512-3AryS9uwa5NfISLxMciUonrH7YfXp+nlahB9T7girXIsLQrmwX4MdnuKs32akduCOGpKmjTJSWmATULbuMkbfw==" }, "nc-help": { - "version": "0.2.85", - "resolved": "https://registry.npmjs.org/nc-help/-/nc-help-0.2.85.tgz", - "integrity": "sha512-EOyrc2PuRUJzv73jHNHmUR6YhC0TlJG0DTY/sug7BF4MJAVPJgyavJnrqkRC7g0NS4xociki9gs5MbLRjlRwtQ==", + "version": "0.2.87", + "resolved": "https://registry.npmjs.org/nc-help/-/nc-help-0.2.87.tgz", + "integrity": "sha512-Zlg06ialvylBEE1qtvjlNKxZrPShzXwvy3WG7nfw+8GngOkQBCTlKguejT2Kq4Gfb5378WPX1APXtsetMKBrRA==", "requires": { "@rudderstack/rudder-sdk-node": "^1.1.3", "axios": "^0.21.1", diff --git a/packages/nocodb/package.json b/packages/nocodb/package.json index 0b77966f58..d171658307 100644 --- a/packages/nocodb/package.json +++ b/packages/nocodb/package.json @@ -25,7 +25,7 @@ "obfuscate:build:publish": "npm run build:obfuscate && npm publish .", "fix": "run-s fix:*", "fix:prettier": "prettier \"src/**/*.ts\" --write", - "lint": "eslint src --ext .ts", + "lint": "eslint src --ext .ts --fix", "test": "cross-env TS_NODE_PROJECT=tsconfig.json mocha -r ts-node/register src/__tests__/**/*.test.ts --recursive", "unit-test": "cross-env TS_NODE_PROJECT=tsconfig.json mocha --require ts-node/register 'src/__tests__/unit/**/*.test.ts' --recursive --check-leaks --exit", "local:test:unit": "cross-env TS_NODE_PROJECT=./tests/unit/tsconfig.json mocha -r ts-node/register tests/unit/index.test.ts --recursive --timeout 300000 --exit --delay", @@ -43,7 +43,8 @@ "watch:run:pg": "cross-env NC_DISABLE_TELE=true EE=true nodemon -e ts,js -w ./src -x \"ts-node src/run/dockerRunPG --log-error --project tsconfig.json\"", "run": "ts-node src/run/docker", "watch:try": "nodemon -e ts,js -w ./src -x \"ts-node src/run/try --log-error --project tsconfig.json\"", - "example:docker": "ts-node src/run/docker.ts" + "example:docker": "ts-node src/run/docker.ts", + "redoc": "nodemon -e ts,json -w ./src/schema -x \"ts-node src/run/redoc --log-error --project tsconfig.json\"" }, "engines": { "node": ">=8.9" @@ -54,6 +55,7 @@ "@sentry/node": "^6.3.5", "airtable": "^0.11.3", "ajv": "^8.12.0", + "ajv-formats": "^2.1.1", "archiver": "^5.0.2", "auto-bind": "^4.0.0", "aws-sdk": "^2.829.0", @@ -105,7 +107,7 @@ "multer": "^1.4.2", "mysql2": "^2.2.5", "nanoid": "^3.1.20", - "nc-help": "0.2.85", + "nc-help": "0.2.87", "nc-lib-gui": "0.105.3", "nc-plugin": "0.1.2", "ncp": "^2.0.0", @@ -160,7 +162,7 @@ "eslint-config-prettier": "^6.15.0", "eslint-plugin-eslint-comments": "^3.2.0", "eslint-plugin-functional": "^3.0.2", - "eslint-plugin-import": "^2.22.0", + "eslint-plugin-import": "^2.25.2", "eslint-plugin-prettier": "^4.0.0", "mocha": "^10.1.0", "nodemon": "^2.0.7", diff --git a/packages/nocodb/src/interface/config.ts b/packages/nocodb/src/interface/config.ts index 4789208021..61ae8c67ec 100644 --- a/packages/nocodb/src/interface/config.ts +++ b/packages/nocodb/src/interface/config.ts @@ -1,6 +1,6 @@ -import { Handler } from 'express'; -import * as e from 'express'; -import { Knex } from 'knex'; +import type { Handler } from 'express'; +import type * as e from 'express'; +import type { Knex } from 'knex'; export interface Route { path: string; diff --git a/packages/nocodb/src/lib/Noco.ts b/packages/nocodb/src/lib/Noco.ts index b66287a446..4b7f9ca900 100644 --- a/packages/nocodb/src/lib/Noco.ts +++ b/packages/nocodb/src/lib/Noco.ts @@ -9,43 +9,43 @@ import clear from 'clear'; import cookieParser from 'cookie-parser'; import debug from 'debug'; import * as express from 'express'; -import { Router } from 'express'; import importFresh from 'import-fresh'; import morgan from 'morgan'; import NcToolGui from 'nc-lib-gui'; import requestIp from 'request-ip'; import { v4 as uuidv4 } from 'uuid'; -import { NcConfig } from '../interface/config'; +import { T } from 'nc-help'; +import mkdirp from 'mkdirp'; import { NC_LICENSE_KEY } from './constants'; import Migrator from './db/sql-migrator/lib/KnexMigrator'; import Store from './models/Store'; import NcConfigFactory from './utils/NcConfigFactory'; -import { Tele } from 'nc-help'; import NcProjectBuilderCE from './v1-legacy/NcProjectBuilder'; import NcProjectBuilderEE from './v1-legacy/NcProjectBuilderEE'; -import { GqlApiBuilder } from './v1-legacy/gql/GqlApiBuilder'; -import NcMetaIO from './meta/NcMetaIO'; import NcMetaImplCE from './meta/NcMetaIOImpl'; import NcMetaImplEE from './meta/NcMetaIOImplEE'; -import NcMetaMgrCE from './meta/NcMetaMgr'; -import NcMetaMgrEE from './meta/NcMetaMgrEE'; -import { RestApiBuilder } from './v1-legacy/rest/RestApiBuilder'; import RestAuthCtrlCE from './v1-legacy/rest/RestAuthCtrl'; import RestAuthCtrlEE from './v1-legacy/rest/RestAuthCtrlEE'; -import mkdirp from 'mkdirp'; import MetaAPILogger from './meta/MetaAPILogger'; import NcUpgrader from './version-upgrader/NcUpgrader'; -import NcMetaMgrv2 from './meta/NcMetaMgrv2'; import NocoCache from './cache/NocoCache'; import registerMetaApis from './meta/api'; import NcPluginMgrv2 from './meta/helpers/NcPluginMgrv2'; import User from './models/User'; -import * as http from 'http'; import weAreHiring from './utils/weAreHiring'; import getInstance from './utils/getInstance'; -import initAdminFromEnv from './meta/api/userApi/initAdminFromEnv'; +import initAdminFromEnv from './services/user/initAdminFromEnv'; +import type * as http from 'http'; +import type NcMetaMgrv2 from './meta/NcMetaMgrv2'; +import type { RestApiBuilder } from './v1-legacy/rest/RestApiBuilder'; +import type NcMetaMgrEE from './meta/NcMetaMgrEE'; +import type NcMetaMgrCE from './meta/NcMetaMgr'; +import type NcMetaIO from './meta/NcMetaIO'; +import type { GqlApiBuilder } from './v1-legacy/gql/GqlApiBuilder'; +import type { NcConfig } from '../interface/config'; +import type { Router } from 'express'; const log = debug('nc:app'); require('dotenv').config(); @@ -105,7 +105,7 @@ export default class Noco { constructor() { process.env.PORT = process.env.PORT || '8080'; // todo: move - process.env.NC_VERSION = '0105002'; + process.env.NC_VERSION = '0105003'; // if env variable NC_MINIMAL_DBS is set, then disable project creation with external sources if (process.env.NC_MINIMAL_DBS) { @@ -275,10 +275,10 @@ export default class Noco { } next(); }); - Tele.init({ + T.init({ instance: getInstance, }); - Tele.emit('evt_app_started', await User.count()); + T.emit('evt_app_started', await User.count()); console.log(`App started successfully.\nVisit -> ${Noco.dashboardUrl}`); weAreHiring(); return this.router; @@ -531,7 +531,7 @@ export default class Noco { if (!serverId) { await Noco._ncMeta.metaInsert('', '', 'nc_store', { key: 'nc_server_id', - value: (serverId = Tele.id), + value: (serverId = T.id), }); } process.env.NC_SERVER_UUID = serverId; diff --git a/packages/nocodb/src/lib/cache/NocoCache.ts b/packages/nocodb/src/lib/cache/NocoCache.ts index 7896ebca37..381760fef0 100644 --- a/packages/nocodb/src/lib/cache/NocoCache.ts +++ b/packages/nocodb/src/lib/cache/NocoCache.ts @@ -1,7 +1,7 @@ -import CacheMgr from './CacheMgr'; +import { CacheGetType } from '../utils/globals'; import RedisCacheMgr from './RedisCacheMgr'; import RedisMockCacheMgr from './RedisMockCacheMgr'; -import { CacheGetType } from '../utils/globals'; +import type CacheMgr from './CacheMgr'; export default class NocoCache { private static client: CacheMgr; diff --git a/packages/nocodb/src/lib/cache/RedisCacheMgr.ts b/packages/nocodb/src/lib/cache/RedisCacheMgr.ts index d970f6b716..b8deaae118 100644 --- a/packages/nocodb/src/lib/cache/RedisCacheMgr.ts +++ b/packages/nocodb/src/lib/cache/RedisCacheMgr.ts @@ -1,7 +1,7 @@ import debug from 'debug'; -import CacheMgr from './CacheMgr'; import Redis from 'ioredis'; import { CacheDelDirection, CacheGetType, CacheScope } from '../utils/globals'; +import CacheMgr from './CacheMgr'; const log = debug('nc:cache'); diff --git a/packages/nocodb/src/lib/cache/RedisMockCacheMgr.ts b/packages/nocodb/src/lib/cache/RedisMockCacheMgr.ts index 902b728bb2..a06ddd9fe5 100644 --- a/packages/nocodb/src/lib/cache/RedisMockCacheMgr.ts +++ b/packages/nocodb/src/lib/cache/RedisMockCacheMgr.ts @@ -1,7 +1,7 @@ import debug from 'debug'; -import CacheMgr from './CacheMgr'; import Redis from 'ioredis-mock'; import { CacheDelDirection, CacheGetType, CacheScope } from '../utils/globals'; +import CacheMgr from './CacheMgr'; const log = debug('nc:cache'); export default class RedisMockCacheMgr extends CacheMgr { diff --git a/packages/nocodb/src/lib/controllers/apiDocs/index.ts b/packages/nocodb/src/lib/controllers/apiDocs/index.ts new file mode 100644 index 0000000000..7f83ad686b --- /dev/null +++ b/packages/nocodb/src/lib/controllers/apiDocs/index.ts @@ -0,0 +1,36 @@ +import { Router } from 'express'; +import ncMetaAclMw from '../../meta/helpers/ncMetaAclMw'; +import { swaggerService } from '../../services'; +import getSwaggerHtml from './swaggerHtml'; +import getRedocHtml from './redocHtml'; + +async function swaggerJson(req, res) { + const swagger = await swaggerService.swaggerJson({ + projectId: req.params.projectId, + siteUrl: req.ncSiteUrl, + }); + + res.json(swagger); +} + +function swaggerHtml(_, res) { + res.send(getSwaggerHtml({ ncSiteUrl: process.env.NC_PUBLIC_URL || '' })); +} + +function redocHtml(_, res) { + res.send(getRedocHtml({ ncSiteUrl: process.env.NC_PUBLIC_URL || '' })); +} + +const router = Router({ mergeParams: true }); + +// todo: auth +router.get( + '/api/v1/db/meta/projects/:projectId/swagger.json', + ncMetaAclMw(swaggerJson, 'swaggerJson') +); + +router.get('/api/v1/db/meta/projects/:projectId/swagger', swaggerHtml); + +router.get('/api/v1/db/meta/projects/:projectId/redoc', redocHtml); + +export default router; diff --git a/packages/nocodb/src/lib/meta/api/swagger/redocHtml.ts b/packages/nocodb/src/lib/controllers/apiDocs/redocHtml.ts similarity index 100% rename from packages/nocodb/src/lib/meta/api/swagger/redocHtml.ts rename to packages/nocodb/src/lib/controllers/apiDocs/redocHtml.ts diff --git a/packages/nocodb/src/lib/meta/api/swagger/swaggerHtml.ts b/packages/nocodb/src/lib/controllers/apiDocs/swaggerHtml.ts similarity index 100% rename from packages/nocodb/src/lib/meta/api/swagger/swaggerHtml.ts rename to packages/nocodb/src/lib/controllers/apiDocs/swaggerHtml.ts diff --git a/packages/nocodb/src/lib/controllers/apiToken.ctl.ts b/packages/nocodb/src/lib/controllers/apiToken.ctl.ts new file mode 100644 index 0000000000..0110afef29 --- /dev/null +++ b/packages/nocodb/src/lib/controllers/apiToken.ctl.ts @@ -0,0 +1,50 @@ +import { Router } from 'express'; +import ncMetaAclMw from '../meta/helpers/ncMetaAclMw'; +import { metaApiMetrics } from '../meta/helpers/apiMetrics'; +import { apiTokenService } from '../services'; +import type { Request, Response } from 'express'; + +export async function apiTokenList(req: Request, res: Response) { + res.json(await apiTokenService.apiTokenList({ userId: req['user'].id })); +} + +export async function apiTokenCreate(req: Request, res: Response) { + res.json( + await apiTokenService.apiTokenCreate({ + tokenBody: req.body, + userId: req['user'].id, + }) + ); +} + +export async function apiTokenDelete(req: Request, res: Response) { + res.json( + await apiTokenService.apiTokenDelete({ + token: req.params.token, + user: req['user'], + }) + ); +} + +// todo: add reset token api to regenerate token + +// deprecated apis +const router = Router({ mergeParams: true }); + +router.get( + '/api/v1/db/meta/projects/:projectId/api-tokens', + metaApiMetrics, + ncMetaAclMw(apiTokenList, 'apiTokenList') +); +router.post( + '/api/v1/db/meta/projects/:projectId/api-tokens', + metaApiMetrics, + ncMetaAclMw(apiTokenCreate, 'apiTokenCreate') +); +router.delete( + '/api/v1/db/meta/projects/:projectId/api-tokens/:token', + metaApiMetrics, + ncMetaAclMw(apiTokenDelete, 'apiTokenDelete') +); + +export default router; diff --git a/packages/nocodb/src/lib/controllers/attachment.ctl.ts b/packages/nocodb/src/lib/controllers/attachment.ctl.ts new file mode 100644 index 0000000000..437539d7cb --- /dev/null +++ b/packages/nocodb/src/lib/controllers/attachment.ctl.ts @@ -0,0 +1,128 @@ +import path from 'path'; +import { Router } from 'express'; +import multer from 'multer'; +import { OrgUserRoles, ProjectRoles } from 'nocodb-sdk'; +import Noco from '../Noco'; +import { MetaTable } from '../utils/globals'; +import extractProjectIdAndAuthenticate from '../meta/helpers/extractProjectIdAndAuthenticate'; +import catchError, { NcError } from '../meta/helpers/catchError'; +import { NC_ATTACHMENT_FIELD_SIZE } from '../constants'; +import { getCacheMiddleware } from '../meta/api/helpers'; +import { attachmentService } from '../services'; +import type { Request, Response } from 'express'; + +const isUploadAllowedMw = async (req: Request, _res: Response, next: any) => { + if (!req['user']?.id) { + if (!req['user']?.isPublicBase) { + NcError.unauthorized('Unauthorized'); + } + } + + try { + // check user is super admin or creator + if ( + req['user'].roles?.includes(OrgUserRoles.SUPER_ADMIN) || + req['user'].roles?.includes(OrgUserRoles.CREATOR) || + req['user'].roles?.includes(ProjectRoles.EDITOR) || + // if viewer then check at-least one project have editor or higher role + // todo: cache + !!(await Noco.ncMeta + .knex(MetaTable.PROJECT_USERS) + .where(function () { + this.where('roles', ProjectRoles.OWNER); + this.orWhere('roles', ProjectRoles.CREATOR); + this.orWhere('roles', ProjectRoles.EDITOR); + }) + .andWhere('fk_user_id', req['user'].id) + .first()) + ) + return next(); + } catch {} + NcError.badRequest('Upload not allowed'); +}; + +export async function upload(req: Request, res: Response) { + const attachments = await attachmentService.upload({ + files: (req as any).files, + path: req.query?.path as string, + }); + + res.json(attachments); +} + +export async function uploadViaURL(req: Request, res: Response) { + const attachments = await attachmentService.uploadViaURL({ + urls: req.body, + path: req.query?.path as string, + }); + + res.json(attachments); +} + +export async function fileRead(req, res) { + try { + const { img, type } = await attachmentService.fileRead({ + path: path.join('nc', 'uploads', req.params?.[0]), + }); + + res.writeHead(200, { 'Content-Type': type }); + res.end(img, 'binary'); + } catch (e) { + console.log(e); + res.status(404).send('Not found'); + } +} + +const router = Router({ mergeParams: true }); + +router.get( + /^\/dl\/([^/]+)\/([^/]+)\/(.+)$/, + getCacheMiddleware(), + async (req, res) => { + try { + const { img, type } = await attachmentService.fileRead({ + path: path.join( + 'nc', + req.params[0], + req.params[1], + 'uploads', + ...req.params[2].split('/') + ), + }); + + res.writeHead(200, { 'Content-Type': type }); + res.end(img, 'binary'); + } catch (e) { + res.status(404).send('Not found'); + } + } +); + +router.post( + '/api/v1/db/storage/upload', + multer({ + storage: multer.diskStorage({}), + limits: { + fieldSize: NC_ATTACHMENT_FIELD_SIZE, + }, + }).any(), + [ + extractProjectIdAndAuthenticate, + catchError(isUploadAllowedMw), + catchError(upload), + ] +); + +router.post( + '/api/v1/db/storage/upload-by-url', + + [ + extractProjectIdAndAuthenticate, + catchError(isUploadAllowedMw), + catchError(uploadViaURL), + ] +); + +router.get(/^\/download\/(.+)$/, getCacheMiddleware(), catchError(fileRead)); + +export default router; diff --git a/packages/nocodb/src/lib/controllers/audit.ctl.ts b/packages/nocodb/src/lib/controllers/audit.ctl.ts new file mode 100644 index 0000000000..35939e6d50 --- /dev/null +++ b/packages/nocodb/src/lib/controllers/audit.ctl.ts @@ -0,0 +1,73 @@ +import { Router } from 'express'; +import Audit from '../models/Audit'; +import { PagedResponseImpl } from '../meta/helpers/PagedResponse'; +import ncMetaAclMw from '../meta/helpers/ncMetaAclMw'; +import { auditService } from '../services'; +import type { Request, Response } from 'express'; + +export async function commentRow(req: Request, res) { + res.json( + await auditService.commentRow({ + rowId: req.params.rowId, + user: (req as any).user, + body: req.body, + }) + ); +} + +export async function auditRowUpdate(req: Request, res) { + res.json( + await auditService.auditRowUpdate({ + rowId: req.params.rowId, + body: req.body, + }) + ); +} + +export async function commentList(req: Request, res) { + res.json(await Audit.commentsList(req.query)); +} + +export async function auditList(req: Request, res: Response) { + res.json( + new PagedResponseImpl( + await Audit.projectAuditList(req.params.projectId, req.query), + { + count: await Audit.projectAuditCount(req.params.projectId), + ...req.query, + } + ) + ); +} + +export async function commentsCount(req: Request, res) { + res.json( + await Audit.commentsCount({ + fk_model_id: req.query.fk_model_id as string, + ids: req.query.ids as string[], + }) + ); +} + +const router = Router({ mergeParams: true }); +router.get( + '/api/v1/db/meta/audits/comments', + ncMetaAclMw(commentList, 'commentList') +); +router.post( + '/api/v1/db/meta/audits/comments', + ncMetaAclMw(commentRow, 'commentRow') +); +router.post( + '/api/v1/db/meta/audits/rows/:rowId/update', + ncMetaAclMw(auditRowUpdate, 'auditRowUpdate') +); +router.get( + '/api/v1/db/meta/audits/comments/count', + ncMetaAclMw(commentsCount, 'commentsCount') +); +router.get( + '/api/v1/db/meta/projects/:projectId/audits', + ncMetaAclMw(auditList, 'auditList') +); +export default router; diff --git a/packages/nocodb/src/lib/controllers/base.ctl.ts b/packages/nocodb/src/lib/controllers/base.ctl.ts new file mode 100644 index 0000000000..ad3e459bd0 --- /dev/null +++ b/packages/nocodb/src/lib/controllers/base.ctl.ts @@ -0,0 +1,91 @@ +import { PagedResponseImpl } from '../meta/helpers/PagedResponse'; +import ncMetaAclMw from '../meta/helpers/ncMetaAclMw'; +import { metaApiMetrics } from '../meta/helpers/apiMetrics'; + +import { baseService } from '../services'; +import type Base from '../models/Base'; +import type { BaseListType } from 'nocodb-sdk'; +import type { Request, Response } from 'express'; + +async function baseGet(req: Request, res: Response) { + const base = await baseService.baseGetWithConfig({ + baseId: req.params.baseId, + }); + + res.json(base); +} + +async function baseUpdate(req: Request, res: Response) { + const base = await baseService.baseUpdate({ + baseId: req.params.baseId, + base: req.body, + projectId: req.params.projectId, + }); + res.json(base); +} + +async function baseList( + req: Request, + res: Response +) { + const bases = await baseService.baseList({ + projectId: req.params.projectId, + }); + + res // todo: pagination + .json({ + bases: new PagedResponseImpl(bases, { + count: bases.length, + limit: bases.length, + }), + }); +} + +export async function baseDelete( + req: Request, + res: Response +) { + const result = await baseService.baseDelete({ + baseId: req.params.baseId, + }); + res.json(result); +} + +async function baseCreate(req: Request, res) { + const base = await baseService.baseCreate({ + projectId: req.params.projectId, + base: req.body, + }); + + res.json(base); +} + +const initRoutes = (router) => { + router.get( + '/api/v1/db/meta/projects/:projectId/bases/:baseId', + metaApiMetrics, + ncMetaAclMw(baseGet, 'baseGet') + ); + router.patch( + '/api/v1/db/meta/projects/:projectId/bases/:baseId', + metaApiMetrics, + ncMetaAclMw(baseUpdate, 'baseUpdate') + ); + router.delete( + '/api/v1/db/meta/projects/:projectId/bases/:baseId', + metaApiMetrics, + ncMetaAclMw(baseDelete, 'baseDelete') + ); + router.post( + '/api/v1/db/meta/projects/:projectId/bases', + metaApiMetrics, + ncMetaAclMw(baseCreate, 'baseCreate') + ); + router.get( + '/api/v1/db/meta/projects/:projectId/bases', + metaApiMetrics, + ncMetaAclMw(baseList, 'baseList') + ); +}; + +export default initRoutes; diff --git a/packages/nocodb/src/lib/meta/api/cacheApis.ts b/packages/nocodb/src/lib/controllers/cache.ctl.ts similarity index 70% rename from packages/nocodb/src/lib/meta/api/cacheApis.ts rename to packages/nocodb/src/lib/controllers/cache.ctl.ts index 8c5af7fa0d..b34f1a5ec8 100644 --- a/packages/nocodb/src/lib/meta/api/cacheApis.ts +++ b/packages/nocodb/src/lib/controllers/cache.ctl.ts @@ -1,9 +1,9 @@ -import catchError from '../helpers/catchError'; -import NocoCache from '../../cache/NocoCache'; import { Router } from 'express'; +import catchError from '../meta/helpers/catchError'; +import { cacheService } from '../services'; export async function cacheGet(_, res) { - const data = await NocoCache.export(); + const data = await cacheService.cacheGet(); res.set({ 'Content-Type': 'application/json', 'Content-Disposition': `attachment; filename="cache-export.json"`, @@ -12,7 +12,7 @@ export async function cacheGet(_, res) { } export async function cacheDelete(_, res) { - return res.json(await NocoCache.destroy()); + return res.json(await cacheService.cacheDelete()); } const router = Router(); diff --git a/packages/nocodb/src/lib/controllers/column.ctl.ts b/packages/nocodb/src/lib/controllers/column.ctl.ts new file mode 100644 index 0000000000..553008fc3f --- /dev/null +++ b/packages/nocodb/src/lib/controllers/column.ctl.ts @@ -0,0 +1,78 @@ +import { Router } from 'express'; +import { metaApiMetrics } from '../meta/helpers/apiMetrics'; +import ncMetaAclMw from '../meta/helpers/ncMetaAclMw'; +import { columnService } from '../services'; +import type { ColumnReqType, TableType, UITypes } from 'nocodb-sdk'; +import type { Request, Response } from 'express'; + +export async function columnGet(req: Request, res: Response) { + res.json(await columnService.columnGet({ columnId: req.params.columnId })); +} + +export async function columnAdd( + req: Request, + res: Response +) { + res.json( + await columnService.columnAdd({ + tableId: req.params.tableId, + column: req.body, + req, + }) + ); +} + +export async function columnSetAsPrimary(req: Request, res: Response) { + res.json( + await columnService.columnSetAsPrimary({ columnId: req.params.columnId }) + ); +} + +export async function columnUpdate(req: Request, res: Response) { + res.json( + await columnService.columnUpdate({ + columnId: req.params.columnId, + column: req.body, + req, + }) + ); +} + +export async function columnDelete(req: Request, res: Response) { + res.json( + await columnService.columnDelete({ columnId: req.params.columnId, req }) + ); +} + +const router = Router({ mergeParams: true }); + +router.post( + '/api/v1/db/meta/tables/:tableId/columns/', + metaApiMetrics, + ncMetaAclMw(columnAdd, 'columnAdd') +); + +router.patch( + '/api/v1/db/meta/columns/:columnId', + metaApiMetrics, + ncMetaAclMw(columnUpdate, 'columnUpdate') +); + +router.delete( + '/api/v1/db/meta/columns/:columnId', + metaApiMetrics, + ncMetaAclMw(columnDelete, 'columnDelete') +); + +router.get( + '/api/v1/db/meta/columns/:columnId', + metaApiMetrics, + ncMetaAclMw(columnGet, 'columnGet') +); + +router.post( + '/api/v1/db/meta/columns/:columnId/primary', + metaApiMetrics, + ncMetaAclMw(columnSetAsPrimary, 'columnSetAsPrimary') +); +export default router; diff --git a/packages/nocodb/src/lib/controllers/dbData/bulkDataAlias.ctl.ts b/packages/nocodb/src/lib/controllers/dbData/bulkDataAlias.ctl.ts new file mode 100644 index 0000000000..3ec7bed6a7 --- /dev/null +++ b/packages/nocodb/src/lib/controllers/dbData/bulkDataAlias.ctl.ts @@ -0,0 +1,93 @@ +import { Router } from 'express'; +import { bulkDataService } from '../../services'; +import ncMetaAclMw from '../../meta/helpers/ncMetaAclMw'; +import apiMetrics from '../../meta/helpers/apiMetrics'; +import type { Request, Response } from 'express'; + +async function bulkDataInsert(req: Request, res: Response) { + res.json( + await bulkDataService.bulkDataInsert({ + body: req.body, + cookie: req, + projectName: req.params.projectName, + tableName: req.params.tableName, + }) + ); +} + +async function bulkDataUpdate(req: Request, res: Response) { + res.json( + await bulkDataService.bulkDataUpdate({ + body: req.body, + cookie: req, + projectName: req.params.projectName, + tableName: req.params.tableName, + }) + ); +} + +// todo: Integrate with filterArrJson bulkDataUpdateAll +async function bulkDataUpdateAll(req: Request, res: Response) { + res.json( + await bulkDataService.bulkDataUpdateAll({ + body: req.body, + cookie: req, + projectName: req.params.projectName, + tableName: req.params.tableName, + query: req.query, + }) + ); +} + +async function bulkDataDelete(req: Request, res: Response) { + res.json( + await bulkDataService.bulkDataDelete({ + body: req.body, + cookie: req, + projectName: req.params.projectName, + tableName: req.params.tableName, + }) + ); +} + +// todo: Integrate with filterArrJson bulkDataDeleteAll +async function bulkDataDeleteAll(req: Request, res: Response) { + res.json( + await bulkDataService.bulkDataDeleteAll({ + // cookie: req, + projectName: req.params.projectName, + tableName: req.params.tableName, + query: req.query, + }) + ); +} + +const router = Router({ mergeParams: true }); + +router.post( + '/api/v1/db/data/bulk/:orgs/:projectName/:tableName', + apiMetrics, + ncMetaAclMw(bulkDataInsert, 'bulkDataInsert') +); +router.patch( + '/api/v1/db/data/bulk/:orgs/:projectName/:tableName', + apiMetrics, + ncMetaAclMw(bulkDataUpdate, 'bulkDataUpdate') +); +router.patch( + '/api/v1/db/data/bulk/:orgs/:projectName/:tableName/all', + apiMetrics, + ncMetaAclMw(bulkDataUpdateAll, 'bulkDataUpdateAll') +); +router.delete( + '/api/v1/db/data/bulk/:orgs/:projectName/:tableName', + apiMetrics, + ncMetaAclMw(bulkDataDelete, 'bulkDataDelete') +); +router.delete( + '/api/v1/db/data/bulk/:orgs/:projectName/:tableName/all', + apiMetrics, + ncMetaAclMw(bulkDataDeleteAll, 'bulkDataDeleteAll') +); + +export default router; diff --git a/packages/nocodb/src/lib/controllers/dbData/data.ctl.ts b/packages/nocodb/src/lib/controllers/dbData/data.ctl.ts new file mode 100644 index 0000000000..882e6c7bec --- /dev/null +++ b/packages/nocodb/src/lib/controllers/dbData/data.ctl.ts @@ -0,0 +1,193 @@ +import { Router } from 'express'; +import { dataService } from '../../services'; +import ncMetaAclMw from '../../meta/helpers/ncMetaAclMw'; +import apiMetrics from '../../meta/helpers/apiMetrics'; +import type { Request, Response } from 'express'; + +export async function dataList(req: Request, res: Response) { + res.json( + await dataService.dataListByViewId({ + viewId: req.params.viewId, + query: req.query, + }) + ); +} + +export async function mmList(req: Request, res: Response) { + res.json( + await dataService.mmList({ + viewId: req.params.viewId, + colId: req.params.colId, + rowId: req.params.rowId, + query: req.query, + }) + ); +} + +export async function mmExcludedList(req: Request, res: Response) { + res.json( + await dataService.mmExcludedList({ + viewId: req.params.viewId, + colId: req.params.colId, + rowId: req.params.rowId, + query: req.query, + }) + ); +} + +export async function hmExcludedList(req: Request, res: Response) { + res.json( + await dataService.hmExcludedList({ + viewId: req.params.viewId, + colId: req.params.colId, + rowId: req.params.rowId, + query: req.query, + }) + ); +} + +export async function btExcludedList(req: Request, res: Response) { + res.json( + await dataService.btExcludedList({ + viewId: req.params.viewId, + colId: req.params.colId, + rowId: req.params.rowId, + query: req.query, + }) + ); +} + +export async function hmList(req: Request, res: Response) { + res.json( + await dataService.hmList({ + viewId: req.params.viewId, + colId: req.params.colId, + rowId: req.params.rowId, + query: req.query, + }) + ); +} + +async function dataRead(req: Request, res: Response) { + res.json( + await dataService.dataReadByViewId({ + viewId: req.params.viewId, + rowId: req.params.rowId, + query: req.query, + }) + ); +} + +async function dataInsert(req: Request, res: Response) { + res.json( + await dataService.dataInsertByViewId({ + viewId: req.params.viewId, + body: req.body, + cookie: req, + }) + ); +} + +async function dataUpdate(req: Request, res: Response) { + res.json( + await dataService.dataUpdateByViewId({ + viewId: req.params.viewId, + rowId: req.params.rowId, + body: req.body, + cookie: req, + }) + ); +} + +async function dataDelete(req: Request, res: Response) { + res.json( + await dataService.dataDeleteByViewId({ + viewId: req.params.viewId, + rowId: req.params.rowId, + cookie: req, + }) + ); +} + +async function relationDataDelete(req, res) { + await dataService.relationDataDelete({ + viewId: req.params.viewId, + colId: req.params.colId, + childId: req.params.childId, + rowId: req.params.rowId, + cookie: req, + }); + + res.json({ msg: 'success' }); +} + +//@ts-ignore +async function relationDataAdd(req, res) { + await dataService.relationDataAdd({ + viewId: req.params.viewId, + colId: req.params.colId, + childId: req.params.childId, + rowId: req.params.rowId, + cookie: req, + }); + + res.json({ msg: 'success' }); +} + +const router = Router({ mergeParams: true }); + +router.get('/data/:viewId/', apiMetrics, ncMetaAclMw(dataList, 'dataList')); +router.post( + '/data/:viewId/', + apiMetrics, + ncMetaAclMw(dataInsert, 'dataInsert') +); +router.get( + '/data/:viewId/:rowId', + apiMetrics, + ncMetaAclMw(dataRead, 'dataRead') +); +router.patch( + '/data/:viewId/:rowId', + apiMetrics, + ncMetaAclMw(dataUpdate, 'dataUpdate') +); +router.delete( + '/data/:viewId/:rowId', + apiMetrics, + ncMetaAclMw(dataDelete, 'dataDelete') +); + +router.get( + '/data/:viewId/:rowId/mm/:colId', + apiMetrics, + ncMetaAclMw(mmList, 'mmList') +); +router.get( + '/data/:viewId/:rowId/hm/:colId', + apiMetrics, + ncMetaAclMw(hmList, 'hmList') +); + +router.get( + '/data/:viewId/:rowId/mm/:colId/exclude', + ncMetaAclMw(mmExcludedList, 'mmExcludedList') +); +router.get( + '/data/:viewId/:rowId/hm/:colId/exclude', + ncMetaAclMw(hmExcludedList, 'hmExcludedList') +); +router.get( + '/data/:viewId/:rowId/bt/:colId/exclude', + ncMetaAclMw(btExcludedList, 'btExcludedList') +); + +router.post( + '/data/:viewId/:rowId/:relationType/:colId/:childId', + ncMetaAclMw(relationDataAdd, 'relationDataAdd') +); +router.delete( + '/data/:viewId/:rowId/:relationType/:colId/:childId', + ncMetaAclMw(relationDataDelete, 'relationDataDelete') +); +export default router; diff --git a/packages/nocodb/src/lib/controllers/dbData/dataAlias.ctl.ts b/packages/nocodb/src/lib/controllers/dbData/dataAlias.ctl.ts new file mode 100644 index 0000000000..ff18681ea8 --- /dev/null +++ b/packages/nocodb/src/lib/controllers/dbData/dataAlias.ctl.ts @@ -0,0 +1,260 @@ +import { Router } from 'express'; +import { dataService } from '../../services'; +import ncMetaAclMw from '../../meta/helpers/ncMetaAclMw'; +import apiMetrics from '../../meta/helpers/apiMetrics'; +import { parseHrtimeToSeconds } from '../../meta/api/helpers'; +import type { Request, Response } from 'express'; + +// todo: Handle the error case where view doesnt belong to model +async function dataList(req: Request, res: Response) { + const startTime = process.hrtime(); + const responseData = await dataService.dataList({ + query: req.query, + projectName: req.params.projectName, + tableName: req.params.tableName, + viewName: req.params.viewName, + }); + const elapsedSeconds = parseHrtimeToSeconds(process.hrtime(startTime)); + res.setHeader('xc-db-response', elapsedSeconds); + res.json(responseData); +} + +async function dataFindOne(req: Request, res: Response) { + res.json( + await dataService.dataFindOne({ + query: req.query, + projectName: req.params.projectName, + tableName: req.params.tableName, + viewName: req.params.viewName, + }) + ); +} + +async function dataGroupBy(req: Request, res: Response) { + res.json( + await dataService.dataGroupBy({ + query: req.query, + projectName: req.params.projectName, + tableName: req.params.tableName, + viewName: req.params.viewName, + }) + ); +} + +async function dataCount(req: Request, res: Response) { + const countResult = await dataService.dataCount({ + query: req.query, + projectName: req.params.projectName, + tableName: req.params.tableName, + viewName: req.params.viewName, + }); + + res.json(countResult); +} + +async function dataInsert(req: Request, res: Response) { + res.json( + await dataService.dataInsert({ + projectName: req.params.projectName, + tableName: req.params.tableName, + viewName: req.params.viewName, + body: req.body, + cookie: req, + }) + ); +} + +async function dataUpdate(req: Request, res: Response) { + res.json( + await dataService.dataUpdate({ + projectName: req.params.projectName, + tableName: req.params.tableName, + viewName: req.params.viewName, + body: req.body, + cookie: req, + rowId: req.params.rowId, + }) + ); +} + +async function dataDelete(req: Request, res: Response) { + res.json( + await dataService.dataDelete({ + projectName: req.params.projectName, + tableName: req.params.tableName, + viewName: req.params.viewName, + cookie: req, + rowId: req.params.rowId, + }) + ); +} + +async function dataRead(req: Request, res: Response) { + res.json( + await dataService.dataRead({ + projectName: req.params.projectName, + tableName: req.params.tableName, + viewName: req.params.viewName, + rowId: req.params.rowId, + query: req.query, + }) + ); +} + +async function dataExist(req: Request, res: Response) { + res.json( + await dataService.dataExist({ + projectName: req.params.projectName, + tableName: req.params.tableName, + viewName: req.params.viewName, + rowId: req.params.rowId, + query: req.query, + }) + ); +} + +// todo: Handle the error case where view doesnt belong to model +async function groupedDataList(req: Request, res: Response) { + const startTime = process.hrtime(); + const groupedData = await dataService.groupedDataList({ + projectName: req.params.projectName, + tableName: req.params.tableName, + viewName: req.params.viewName, + query: req.query, + columnId: req.params.columnId, + }); + const elapsedSeconds = parseHrtimeToSeconds(process.hrtime(startTime)); + res.setHeader('xc-db-response', elapsedSeconds); + res.json(groupedData); +} +const router = Router({ mergeParams: true }); + +// table data crud apis +router.get( + '/api/v1/db/data/:orgs/:projectName/:tableName', + apiMetrics, + ncMetaAclMw(dataList, 'dataList') +); + +router.get( + '/api/v1/db/data/:orgs/:projectName/:tableName/find-one', + apiMetrics, + ncMetaAclMw(dataFindOne, 'dataFindOne') +); + +router.get( + '/api/v1/db/data/:orgs/:projectName/:tableName/groupby', + apiMetrics, + ncMetaAclMw(dataGroupBy, 'dataGroupBy') +); + +router.get( + '/api/v1/db/data/:orgs/:projectName/:tableName/group/:columnId', + apiMetrics, + ncMetaAclMw(groupedDataList, 'groupedDataList') +); + +router.get( + '/api/v1/db/data/:orgs/:projectName/:tableName/:rowId/exist', + apiMetrics, + ncMetaAclMw(dataExist, 'dataExist') +); + +router.get( + '/api/v1/db/data/:orgs/:projectName/:tableName/count', + apiMetrics, + ncMetaAclMw(dataCount, 'dataCount') +); + +router.get( + '/api/v1/db/data/:orgs/:projectName/:tableName/views/:viewName/count', + apiMetrics, + ncMetaAclMw(dataCount, 'dataCount') +); + +router.get( + '/api/v1/db/data/:orgs/:projectName/:tableName/:rowId', + apiMetrics, + ncMetaAclMw(dataRead, 'dataRead') +); + +router.patch( + '/api/v1/db/data/:orgs/:projectName/:tableName/:rowId', + apiMetrics, + ncMetaAclMw(dataUpdate, 'dataUpdate') +); + +router.delete( + '/api/v1/db/data/:orgs/:projectName/:tableName/:rowId', + apiMetrics, + ncMetaAclMw(dataDelete, 'dataDelete') +); + +router.get( + '/api/v1/db/data/:orgs/:projectName/:tableName', + apiMetrics, + ncMetaAclMw(dataList, 'dataList') +); + +// table view data crud apis +router.get( + '/api/v1/db/data/:orgs/:projectName/:tableName/views/:viewName', + apiMetrics, + ncMetaAclMw(dataList, 'dataList') +); + +router.get( + '/api/v1/db/data/:orgs/:projectName/:tableName/views/:viewName/find-one', + apiMetrics, + ncMetaAclMw(dataFindOne, 'dataFindOne') +); + +router.get( + '/api/v1/db/data/:orgs/:projectName/:tableName/views/:viewName/groupby', + apiMetrics, + ncMetaAclMw(dataGroupBy, 'dataGroupBy') +); + +router.get( + '/api/v1/db/data/:orgs/:projectName/:tableName/views/:viewName/group/:columnId', + apiMetrics, + ncMetaAclMw(groupedDataList, 'groupedDataList') +); + +router.get( + '/api/v1/db/data/:orgs/:projectName/:tableName/views/:viewName/:rowId/exist', + apiMetrics, + ncMetaAclMw(dataExist, 'dataExist') +); + +router.post( + '/api/v1/db/data/:orgs/:projectName/:tableName', + apiMetrics, + ncMetaAclMw(dataInsert, 'dataInsert') +); + +router.post( + '/api/v1/db/data/:orgs/:projectName/:tableName/views/:viewName', + apiMetrics, + ncMetaAclMw(dataInsert, 'dataInsert') +); + +router.patch( + '/api/v1/db/data/:orgs/:projectName/:tableName/views/:viewName/:rowId', + apiMetrics, + ncMetaAclMw(dataUpdate, 'dataUpdate') +); + +router.get( + '/api/v1/db/data/:orgs/:projectName/:tableName/views/:viewName/:rowId', + apiMetrics, + ncMetaAclMw(dataRead, 'dataRead') +); + +router.delete( + '/api/v1/db/data/:orgs/:projectName/:tableName/views/:viewName/:rowId', + apiMetrics, + ncMetaAclMw(dataDelete, 'dataDelete') +); + +export default router; diff --git a/packages/nocodb/src/lib/meta/api/dataApis/dataAliasExportApis.ts b/packages/nocodb/src/lib/controllers/dbData/dataAliasExport.ctl.ts similarity index 84% rename from packages/nocodb/src/lib/meta/api/dataApis/dataAliasExportApis.ts rename to packages/nocodb/src/lib/controllers/dbData/dataAliasExport.ctl.ts index 8c6cf38bea..0b4b46e91b 100644 --- a/packages/nocodb/src/lib/meta/api/dataApis/dataAliasExportApis.ts +++ b/packages/nocodb/src/lib/controllers/dbData/dataAliasExport.ctl.ts @@ -1,13 +1,11 @@ -import { Request, Response, Router } from 'express'; +import { Router } from 'express'; import * as XLSX from 'xlsx'; -import ncMetaAclMw from '../../helpers/ncMetaAclMw'; -import { - extractCsvData, - extractXlsxData, - getViewAndModelFromRequestByAliasOrId, -} from './helpers'; -import apiMetrics from '../../helpers/apiMetrics'; -import View from '../../../models/View'; +import apiMetrics from '../../meta/helpers/apiMetrics'; +import ncMetaAclMw from '../../meta/helpers/ncMetaAclMw'; +import { View } from '../../models'; +import { extractCsvData, extractXlsxData } from '../../services/dbData/helpers'; +import { getViewAndModelFromRequestByAliasOrId } from './helpers'; +import type { Request, Response } from 'express'; async function excelDataExport(req: Request, res: Response) { const { model, view } = await getViewAndModelFromRequestByAliasOrId(req); diff --git a/packages/nocodb/src/lib/controllers/dbData/dataAliasNested.ctl.ts b/packages/nocodb/src/lib/controllers/dbData/dataAliasNested.ctl.ts new file mode 100644 index 0000000000..9b4660d31d --- /dev/null +++ b/packages/nocodb/src/lib/controllers/dbData/dataAliasNested.ctl.ts @@ -0,0 +1,138 @@ +import { Router } from 'express'; +import ncMetaAclMw from '../../meta/helpers/ncMetaAclMw'; +import apiMetrics from '../../meta/helpers/apiMetrics'; +import { dataAliasNestedService } from '../../services'; +import type { Request, Response } from 'express'; + +// todo: handle case where the given column is not ltar +export async function mmList(req: Request, res: Response) { + res.json( + await dataAliasNestedService.mmList({ + query: req.query, + columnName: req.params.columnName, + rowId: req.params.rowId, + projectName: req.params.projectName, + tableName: req.params.tableName, + }) + ); +} + +export async function mmExcludedList(req: Request, res: Response) { + res.json( + await dataAliasNestedService.mmExcludedList({ + query: req.query, + columnName: req.params.columnName, + rowId: req.params.rowId, + projectName: req.params.projectName, + tableName: req.params.tableName, + }) + ); +} + +export async function hmExcludedList(req: Request, res: Response) { + res.json( + await dataAliasNestedService.hmExcludedList({ + query: req.query, + columnName: req.params.columnName, + rowId: req.params.rowId, + projectName: req.params.projectName, + tableName: req.params.tableName, + }) + ); +} + +export async function btExcludedList(req: Request, res: Response) { + res.json( + await dataAliasNestedService.btExcludedList({ + query: req.query, + columnName: req.params.columnName, + rowId: req.params.rowId, + projectName: req.params.projectName, + tableName: req.params.tableName, + }) + ); +} + +// todo: handle case where the given column is not ltar +export async function hmList(req: Request, res: Response) { + res.json( + await dataAliasNestedService.hmList({ + query: req.query, + columnName: req.params.columnName, + rowId: req.params.rowId, + projectName: req.params.projectName, + tableName: req.params.tableName, + }) + ); +} + +//@ts-ignore +async function relationDataRemove(req, res) { + await dataAliasNestedService.relationDataRemove({ + columnName: req.params.columnName, + rowId: req.params.rowId, + projectName: req.params.projectName, + tableName: req.params.tableName, + cookie: req, + refRowId: req.params.refRowId, + }); + + res.json({ msg: 'success' }); +} + +//@ts-ignore +// todo: Give proper error message when reference row is already related and handle duplicate ref row id in hm +async function relationDataAdd(req, res) { + await dataAliasNestedService.relationDataAdd({ + columnName: req.params.columnName, + rowId: req.params.rowId, + projectName: req.params.projectName, + tableName: req.params.tableName, + cookie: req, + refRowId: req.params.refRowId, + }); + + res.json({ msg: 'success' }); +} + +const router = Router({ mergeParams: true }); + +router.get( + '/api/v1/db/data/:orgs/:projectName/:tableName/:rowId/mm/:columnName/exclude', + apiMetrics, + ncMetaAclMw(mmExcludedList, 'mmExcludedList') +); +router.get( + '/api/v1/db/data/:orgs/:projectName/:tableName/:rowId/hm/:columnName/exclude', + apiMetrics, + ncMetaAclMw(hmExcludedList, 'hmExcludedList') +); +router.get( + '/api/v1/db/data/:orgs/:projectName/:tableName/:rowId/bt/:columnName/exclude', + apiMetrics, + ncMetaAclMw(btExcludedList, 'btExcludedList') +); + +router.post( + '/api/v1/db/data/:orgs/:projectName/:tableName/:rowId/:relationType/:columnName/:refRowId', + apiMetrics, + ncMetaAclMw(relationDataAdd, 'relationDataAdd') +); +router.delete( + '/api/v1/db/data/:orgs/:projectName/:tableName/:rowId/:relationType/:columnName/:refRowId', + apiMetrics, + ncMetaAclMw(relationDataRemove, 'relationDataRemove') +); + +router.get( + '/api/v1/db/data/:orgs/:projectName/:tableName/:rowId/mm/:columnName', + apiMetrics, + ncMetaAclMw(mmList, 'mmList') +); +router.get( + '/api/v1/db/data/:orgs/:projectName/:tableName/:rowId/hm/:columnName', + apiMetrics, + ncMetaAclMw(hmList, 'hmList') +); + +export default router; diff --git a/packages/nocodb/src/lib/controllers/dbData/helpers.ts b/packages/nocodb/src/lib/controllers/dbData/helpers.ts new file mode 100644 index 0000000000..1004947829 --- /dev/null +++ b/packages/nocodb/src/lib/controllers/dbData/helpers.ts @@ -0,0 +1,270 @@ +import { isSystemColumn, UITypes } from 'nocodb-sdk'; +import * as XLSX from 'xlsx'; +import papaparse from 'papaparse'; +import { NcError } from '../../meta/helpers/catchError'; +import Project from '../../models/Project'; +import Model from '../../models/Model'; +import View from '../../models/View'; +import Base from '../../models/Base'; +import NcConnectionMgrv2 from '../../utils/common/NcConnectionMgrv2'; + +import Column from '../../models/Column'; +import { dataService } from '../../services'; +import type LookupColumn from '../../models/LookupColumn'; +import type LinkToAnotherRecordColumn from '../../models/LinkToAnotherRecordColumn'; + +import type { Request } from 'express'; +export async function getViewAndModelFromRequestByAliasOrId( + req: + | Request<{ projectName: string; tableName: string; viewName?: string }> + | Request +) { + const project = await Project.getWithInfoByTitleOrId(req.params.projectName); + + const model = await Model.getByAliasOrId({ + project_id: project.id, + aliasOrId: req.params.tableName, + }); + const view = + req.params.viewName && + (await View.getByTitleOrId({ + titleOrId: req.params.viewName, + fk_model_id: model.id, + })); + if (!model) NcError.notFound('Table not found'); + return { model, view }; +} + +export async function extractXlsxData(param: { + view: View; + query: any; + siteUrl: string; +}) { + const { view, query, siteUrl } = param; + const base = await Base.get(view.base_id); + + await view.getModelWithInfo(); + await view.getColumns(); + + view.model.columns = view.columns + .filter((c) => c.show) + .map( + (c) => + new Column({ ...c, ...view.model.columnsById[c.fk_column_id] } as any) + ) + .filter((column) => !isSystemColumn(column) || view.show_system_fields); + + const baseModel = await Model.getBaseModelSQL({ + id: view.model.id, + viewId: view?.id, + dbDriver: await NcConnectionMgrv2.get(base), + }); + + const { offset, dbRows, elapsed } = await dataService.getDbRows({ + baseModel, + view, + query, + siteUrl, + }); + + const fields = query.fields as string[]; + + const data = XLSX.utils.json_to_sheet(dbRows, { header: fields }); + + return { offset, dbRows, elapsed, data }; +} + +export async function extractCsvData(view: View, req: Request) { + const base = await Base.get(view.base_id); + const fields = req.query.fields; + + await view.getModelWithInfo(); + await view.getColumns(); + + view.model.columns = view.columns + .filter((c) => c.show) + .map( + (c) => + new Column({ ...c, ...view.model.columnsById[c.fk_column_id] } as any) + ) + .filter((column) => !isSystemColumn(column) || view.show_system_fields); + + const baseModel = await Model.getBaseModelSQL({ + id: view.model.id, + viewId: view?.id, + dbDriver: await NcConnectionMgrv2.get(base), + }); + + const { offset, dbRows, elapsed } = await dataService.getDbRows({ + baseModel, + view, + query: req.query, + siteUrl: (req as any).ncSiteUrl, + }); + + const data = papaparse.unparse( + { + fields: view.model.columns + .sort((c1, c2) => + Array.isArray(fields) + ? fields.indexOf(c1.title as any) - fields.indexOf(c2.title as any) + : 0 + ) + .filter( + (c) => + !fields || !Array.isArray(fields) || fields.includes(c.title as any) + ) + .map((c) => c.title), + data: dbRows, + }, + { + escapeFormulae: true, + } + ); + + return { offset, dbRows, elapsed, data }; +} +// +// async function getDbRows(baseModel, view: View, req: Request) { +// let offset = +req.query.offset || 0; +// const limit = 100; +// // const size = +process.env.NC_EXPORT_MAX_SIZE || 1024; +// const timeout = +process.env.NC_EXPORT_MAX_TIMEOUT || 5000; +// const dbRows = []; +// const startTime = process.hrtime(); +// let elapsed, temp; +// +// const listArgs: any = { ...req.query }; +// try { +// listArgs.filterArr = JSON.parse(listArgs.filterArrJson); +// } catch (e) {} +// try { +// listArgs.sortArr = JSON.parse(listArgs.sortArrJson); +// } catch (e) {} +// +// for ( +// elapsed = 0; +// elapsed < timeout; +// offset += limit, +// temp = process.hrtime(startTime), +// elapsed = temp[0] * 1000 + temp[1] / 1000000 +// ) { +// const rows = await nocoExecute( +// await getAst({ +// query: req.query, +// includePkByDefault: false, +// model: view.model, +// view, +// }), +// await baseModel.list({ ...listArgs, offset, limit }), +// {}, +// req.query +// ); +// +// if (!rows?.length) { +// offset = -1; +// break; +// } +// +// for (const row of rows) { +// const dbRow = { ...row }; +// +// for (const column of view.model.columns) { +// if (isSystemColumn(column) && !view.show_system_fields) continue; +// dbRow[column.title] = await serializeCellValue({ +// value: row[column.title], +// column, +// siteUrl: req['ncSiteUrl'], +// }); +// } +// dbRows.push(dbRow); +// } +// } +// return { offset, dbRows, elapsed }; +// } + +export async function serializeCellValue({ + value, + column, + siteUrl, +}: { + column?: Column; + value: any; + siteUrl: string; +}) { + if (!column) { + return value; + } + + if (!value) return value; + + switch (column?.uidt) { + case UITypes.Attachment: { + let data = value; + try { + if (typeof value === 'string') { + data = JSON.parse(value); + } + } catch {} + + return (data || []).map( + (attachment) => + `${encodeURI(attachment.title)}(${encodeURI( + attachment.path ? `${siteUrl}/${attachment.path}` : attachment.url + )})` + ); + } + case UITypes.Lookup: + { + const colOptions = await column.getColOptions(); + const lookupColumn = await colOptions.getLookupColumn(); + return ( + await Promise.all( + [...(Array.isArray(value) ? value : [value])].map(async (v) => + serializeCellValue({ + value: v, + column: lookupColumn, + siteUrl, + }) + ) + ) + ).join(', '); + } + break; + case UITypes.LinkToAnotherRecord: + { + const colOptions = + await column.getColOptions(); + const relatedModel = await colOptions.getRelatedTable(); + await relatedModel.getColumns(); + return [...(Array.isArray(value) ? value : [value])] + .map((v) => { + return v[relatedModel.displayValue?.title]; + }) + .join(', '); + } + break; + default: + if (value && typeof value === 'object') { + return JSON.stringify(value); + } + return value; + } +} + +export async function getColumnByIdOrName( + columnNameOrId: string, + model: Model +) { + const column = (await model.getColumns()).find( + (c) => + c.title === columnNameOrId || + c.id === columnNameOrId || + c.column_name === columnNameOrId + ); + + if (!column) + NcError.notFound(`Column with id/name '${columnNameOrId}' is not found`); + + return column; +} diff --git a/packages/nocodb/src/lib/controllers/dbData/index.ts b/packages/nocodb/src/lib/controllers/dbData/index.ts new file mode 100644 index 0000000000..f4a9eea143 --- /dev/null +++ b/packages/nocodb/src/lib/controllers/dbData/index.ts @@ -0,0 +1,15 @@ +import dataController from './data.ctl'; +import oldDataController from './oldData.ctl'; +import dataAliasController from './dataAlias.ctl'; +import bulkDataAliasController from './bulkDataAlias.ctl'; +import dataAliasNestedController from './dataAliasNested.ctl'; +import dataAliasExportController from './dataAliasExport.ctl'; + +export { + dataController, + oldDataController, + dataAliasController, + bulkDataAliasController, + dataAliasNestedController, + dataAliasExportController, +}; diff --git a/packages/nocodb/src/lib/meta/api/dataApis/oldDataApis.ts b/packages/nocodb/src/lib/controllers/dbData/oldData.ctl.ts similarity index 82% rename from packages/nocodb/src/lib/meta/api/dataApis/oldDataApis.ts rename to packages/nocodb/src/lib/controllers/dbData/oldData.ctl.ts index 5df008eb8a..d5a573b013 100644 --- a/packages/nocodb/src/lib/meta/api/dataApis/oldDataApis.ts +++ b/packages/nocodb/src/lib/controllers/dbData/oldData.ctl.ts @@ -1,14 +1,15 @@ -import { Request, Response, Router } from 'express'; -import Model from '../../../models/Model'; +import { Router } from 'express'; import { nocoExecute } from 'nc-help'; -import Base from '../../../models/Base'; -import NcConnectionMgrv2 from '../../../utils/common/NcConnectionMgrv2'; -import View from '../../../models/View'; -import ncMetaAclMw from '../../helpers/ncMetaAclMw'; -import Project from '../../../models/Project'; -import { NcError } from '../../helpers/catchError'; -import apiMetrics from '../../helpers/apiMetrics'; -import getAst from '../../../db/sql-data-mapper/lib/sql/helpers/getAst'; +import Model from '../../models/Model'; +import Base from '../../models/Base'; +import NcConnectionMgrv2 from '../../utils/common/NcConnectionMgrv2'; +import View from '../../models/View'; +import ncMetaAclMw from '../../meta/helpers/ncMetaAclMw'; +import Project from '../../models/Project'; +import { NcError } from '../../meta/helpers/catchError'; +import apiMetrics from '../../meta/helpers/apiMetrics'; +import getAst from '../../db/sql-data-mapper/lib/sql/helpers/getAst'; +import type { Request, Response } from 'express'; export async function dataList(req: Request, res: Response) { const { model, view } = await getViewAndModelFromRequest(req); @@ -17,7 +18,7 @@ export async function dataList(req: Request, res: Response) { const baseModel = await Model.getBaseModelSQL({ id: model.id, viewId: view?.id, - dbDriver: NcConnectionMgrv2.get(base), + dbDriver: await NcConnectionMgrv2.get(base), }); const requestObj = await getAst({ @@ -50,7 +51,7 @@ export async function dataCount(req: Request, res: Response) { const baseModel = await Model.getBaseModelSQL({ id: model.id, viewId: view?.id, - dbDriver: NcConnectionMgrv2.get(base), + dbDriver: await NcConnectionMgrv2.get(base), }); const listArgs: any = { ...req.query }; @@ -73,7 +74,7 @@ async function dataInsert(req: Request, res: Response) { const baseModel = await Model.getBaseModelSQL({ id: model.id, viewId: view?.id, - dbDriver: NcConnectionMgrv2.get(base), + dbDriver: await NcConnectionMgrv2.get(base), }); res.json(await baseModel.insert(req.body, null, req)); @@ -86,7 +87,7 @@ async function dataUpdate(req: Request, res: Response) { const baseModel = await Model.getBaseModelSQL({ id: model.id, viewId: view.id, - dbDriver: NcConnectionMgrv2.get(base), + dbDriver: await NcConnectionMgrv2.get(base), }); res.json(await baseModel.updateByPk(req.params.rowId, req.body, null, req)); @@ -98,7 +99,7 @@ async function dataDelete(req: Request, res: Response) { const baseModel = await Model.getBaseModelSQL({ id: model.id, viewId: view.id, - dbDriver: NcConnectionMgrv2.get(base), + dbDriver: await NcConnectionMgrv2.get(base), }); res.json(await baseModel.delByPk(req.params.rowId, null, req)); @@ -128,7 +129,7 @@ async function dataRead(req: Request, res: Response) { const baseModel = await Model.getBaseModelSQL({ id: model.id, viewId: view?.id, - dbDriver: NcConnectionMgrv2.get(base), + dbDriver: await NcConnectionMgrv2.get(base), }); res.json( diff --git a/packages/nocodb/src/lib/meta/api/exportApis.ts b/packages/nocodb/src/lib/controllers/export.ctl.ts similarity index 72% rename from packages/nocodb/src/lib/meta/api/exportApis.ts rename to packages/nocodb/src/lib/controllers/export.ctl.ts index 7c0a5e013e..f3353ef45f 100644 --- a/packages/nocodb/src/lib/meta/api/exportApis.ts +++ b/packages/nocodb/src/lib/controllers/export.ctl.ts @@ -1,7 +1,8 @@ -import { Request, Response, Router } from 'express'; -import View from '../../models/View'; -import ncMetaAclMw from '../helpers/ncMetaAclMw'; -import { extractCsvData } from './dataApis/helpers'; +import { Router } from 'express'; +import View from '../models/View'; +import ncMetaAclMw from '../meta/helpers/ncMetaAclMw'; +import { extractCsvData } from './dbData/helpers'; +import type { Request, Response } from 'express'; async function exportCsv(req: Request, res: Response) { const view = await View.get(req.params.viewId); diff --git a/packages/nocodb/src/lib/controllers/filter.ctl.ts b/packages/nocodb/src/lib/controllers/filter.ctl.ts new file mode 100644 index 0000000000..0423904649 --- /dev/null +++ b/packages/nocodb/src/lib/controllers/filter.ctl.ts @@ -0,0 +1,116 @@ +import { Router } from 'express'; +import ncMetaAclMw from '../meta/helpers/ncMetaAclMw'; +import { metaApiMetrics } from '../meta/helpers/apiMetrics'; + +import { filterService } from '../services'; +import type { FilterReqType } from 'nocodb-sdk'; +import type { Request, Response } from 'express'; + +// @ts-ignore +export async function filterGet(req: Request, res: Response) { + res.json(await filterService.filterGet({ filterId: req.params.filterId })); +} + +// @ts-ignore +export async function filterList(req: Request, res: Response) { + res.json( + await filterService.filterList({ + viewId: req.params.viewId, + }) + ); +} + +// @ts-ignore +export async function filterChildrenRead(req: Request, res: Response) { + const filter = await filterService.filterChildrenList({ + filterId: req.params.filterParentId, + }); + + res.json(filter); +} + +export async function filterCreate(req: Request, res) { + const filter = await filterService.filterCreate({ + filter: req.body, + viewId: req.params.viewId, + }); + res.json(filter); +} + +export async function filterUpdate(req, res) { + const filter = await filterService.filterUpdate({ + filterId: req.params.filterId, + filter: req.body, + }); + res.json(filter); +} + +export async function filterDelete(req: Request, res: Response) { + const filter = await filterService.filterDelete({ + filterId: req.params.filterId, + }); + res.json(filter); +} + +export async function hookFilterList(req: Request, res: Response) { + res.json( + await filterService.hookFilterList({ + hookId: req.params.hookId, + }) + ); +} + +export async function hookFilterCreate( + req: Request, + res +) { + const filter = await filterService.hookFilterCreate({ + filter: req.body, + hookId: req.params.hookId, + }); + res.json(filter); +} + +const router = Router({ mergeParams: true }); +router.get( + '/api/v1/db/meta/views/:viewId/filters', + metaApiMetrics, + ncMetaAclMw(filterList, 'filterList') +); +router.post( + '/api/v1/db/meta/views/:viewId/filters', + metaApiMetrics, + ncMetaAclMw(filterCreate, 'filterCreate') +); + +router.get( + '/api/v1/db/meta/hooks/:hookId/filters', + ncMetaAclMw(hookFilterList, 'filterList') +); +router.post( + '/api/v1/db/meta/hooks/:hookId/filters', + metaApiMetrics, + ncMetaAclMw(hookFilterCreate, 'filterCreate') +); + +router.get( + '/api/v1/db/meta/filters/:filterId', + metaApiMetrics, + ncMetaAclMw(filterGet, 'filterGet') +); +router.patch( + '/api/v1/db/meta/filters/:filterId', + metaApiMetrics, + ncMetaAclMw(filterUpdate, 'filterUpdate') +); +router.delete( + '/api/v1/db/meta/filters/:filterId', + metaApiMetrics, + ncMetaAclMw(filterDelete, 'filterDelete') +); +router.get( + '/api/v1/db/meta/filters/:filterParentId/children', + metaApiMetrics, + ncMetaAclMw(filterChildrenRead, 'filterChildrenRead') +); +export default router; diff --git a/packages/nocodb/src/lib/controllers/hook.ctl.ts b/packages/nocodb/src/lib/controllers/hook.ctl.ts new file mode 100644 index 0000000000..ddbcf0bc81 --- /dev/null +++ b/packages/nocodb/src/lib/controllers/hook.ctl.ts @@ -0,0 +1,99 @@ +import { Router } from 'express'; +import catchError from '../meta/helpers/catchError'; +import { PagedResponseImpl } from '../meta/helpers/PagedResponse'; +import ncMetaAclMw from '../meta/helpers/ncMetaAclMw'; +import { metaApiMetrics } from '../meta/helpers/apiMetrics'; +import { hookService } from '../services'; +import type { HookListType, HookType } from 'nocodb-sdk'; +import type { Request, Response } from 'express'; + +export async function hookList( + req: Request, + res: Response +) { + // todo: pagination + res.json( + new PagedResponseImpl( + await hookService.hookList({ tableId: req.params.tableId }) + ) + ); +} + +export async function hookCreate( + req: Request, + res: Response +) { + const hook = await hookService.hookCreate({ + hook: req.body, + tableId: req.params.tableId, + }); + res.json(hook); +} + +export async function hookDelete( + req: Request, + res: Response +) { + res.json(await hookService.hookDelete({ hookId: req.params.hookId })); +} + +export async function hookUpdate( + req: Request, + res: Response +) { + res.json( + await hookService.hookUpdate({ hookId: req.params.hookId, hook: req.body }) + ); +} + +export async function hookTest(req: Request, res: Response) { + await hookService.hookTest({ + hookTest: req.body, + tableId: req.params.tableId, + }); + res.json({ msg: 'Success' }); +} + +export async function tableSampleData(req: Request, res: Response) { + res // todo: pagination + .json( + await hookService.tableSampleData({ + tableId: req.params.tableId, + // todo: replace any with type + operation: req.params.operation as any, + }) + ); +} + +const router = Router({ mergeParams: true }); +router.get( + '/api/v1/db/meta/tables/:tableId/hooks', + metaApiMetrics, + ncMetaAclMw(hookList, 'hookList') +); +router.post( + '/api/v1/db/meta/tables/:tableId/hooks/test', + metaApiMetrics, + ncMetaAclMw(hookTest, 'hookTest') +); +router.post( + '/api/v1/db/meta/tables/:tableId/hooks', + metaApiMetrics, + ncMetaAclMw(hookCreate, 'hookCreate') +); +router.delete( + '/api/v1/db/meta/hooks/:hookId', + metaApiMetrics, + ncMetaAclMw(hookDelete, 'hookDelete') +); +router.patch( + '/api/v1/db/meta/hooks/:hookId', + metaApiMetrics, + ncMetaAclMw(hookUpdate, 'hookUpdate') +); +router.get( + '/api/v1/db/meta/tables/:tableId/hooks/samplePayload/:operation', + metaApiMetrics, + catchError(tableSampleData) +); +export default router; diff --git a/packages/nocodb/src/lib/controllers/hookFilter.ctl.ts b/packages/nocodb/src/lib/controllers/hookFilter.ctl.ts new file mode 100644 index 0000000000..d479a2b264 --- /dev/null +++ b/packages/nocodb/src/lib/controllers/hookFilter.ctl.ts @@ -0,0 +1,91 @@ +import { Router } from 'express'; +import { T } from 'nc-help'; +import ncMetaAclMw from '../meta/helpers/ncMetaAclMw'; +import { metaApiMetrics } from '../meta/helpers/apiMetrics'; +import { hookFilterService } from '../services'; +import type { Request, Response } from 'express'; + +export async function filterGet(req: Request, res: Response) { + const filter = await hookFilterService.filterGet({ + hookId: req.params.hookId, + }); + + res.json(filter); +} + +export async function filterList(req: Request, res: Response) { + const filter = await hookFilterService.filterList({ + hookId: req.params.hookId, + }); + + res.json(filter); +} + +export async function filterChildrenRead(req: Request, res: Response) { + const filter = await hookFilterService.filterChildrenRead({ + hookId: req.params.hookId, + filterParentId: req.params.filterParentId, + }); + + res.json(filter); +} + +export async function filterCreate(req: Request, res) { + const filter = await hookFilterService.filterCreate({ + filter: req.body, + hookId: req.params.hookId, + }); + + res.json(filter); +} + +export async function filterUpdate(req, res) { + const filter = await hookFilterService.filterUpdate({ + filterId: req.params.filterId, + filter: req.body, + hookId: req.params.hookId, + }); + + res.json(filter); +} + +export async function filterDelete(req: Request, res: Response) { + const filter = await hookFilterService.filterDelete({ + filterId: req.params.filterId, + }); + T.emit('evt', { evt_type: 'hookFilter:deleted' }); + res.json(filter); +} + +const router = Router({ mergeParams: true }); +router.get( + '/hooks/:hookId/filters/', + metaApiMetrics, + ncMetaAclMw(filterList, 'filterList') +); +router.post( + '/hooks/:hookId/filters/', + metaApiMetrics, + ncMetaAclMw(filterCreate, 'filterCreate') +); +router.get( + '/hooks/:hookId/filters/:filterId', + metaApiMetrics, + ncMetaAclMw(filterGet, 'filterGet') +); +router.patch( + '/hooks/:hookId/filters/:filterId', + metaApiMetrics, + ncMetaAclMw(filterUpdate, 'filterUpdate') +); +router.delete( + '/hooks/:hookId/filters/:filterId', + metaApiMetrics, + ncMetaAclMw(filterDelete, 'filterDelete') +); +router.get( + '/hooks/:hookId/filters/:filterParentId/children', + metaApiMetrics, + ncMetaAclMw(filterChildrenRead, 'filterChildrenRead') +); +export default router; diff --git a/packages/nocodb/src/lib/controllers/metaDiff.ctl.ts b/packages/nocodb/src/lib/controllers/metaDiff.ctl.ts new file mode 100644 index 0000000000..144a19d3f3 --- /dev/null +++ b/packages/nocodb/src/lib/controllers/metaDiff.ctl.ts @@ -0,0 +1,54 @@ +import { Router } from 'express'; +import ncMetaAclMw from '../meta/helpers/ncMetaAclMw'; +import { metaApiMetrics } from '../meta/helpers/apiMetrics'; +import { metaDiffService } from '../services'; + +export async function metaDiff(req, res) { + res.json(await metaDiffService.metaDiff({ projectId: req.params.projectId })); +} + +export async function baseMetaDiff(req, res) { + res.json( + await metaDiffService.baseMetaDiff({ + baseId: req.params.baseId, + projectId: req.params.projectId, + }) + ); +} + +export async function metaDiffSync(req, res) { + await metaDiffService.metaDiffSync({ projectId: req.params.projectId }); + res.json({ msg: 'success' }); +} + +export async function baseMetaDiffSync(req, res) { + await metaDiffService.baseMetaDiffSync({ + projectId: req.params.projectId, + baseId: req.params.baseId, + }); + + res.json({ msg: 'success' }); +} + +const router = Router(); +router.get( + '/api/v1/db/meta/projects/:projectId/meta-diff', + metaApiMetrics, + ncMetaAclMw(metaDiff, 'metaDiff') +); +router.post( + '/api/v1/db/meta/projects/:projectId/meta-diff', + metaApiMetrics, + ncMetaAclMw(metaDiffSync, 'metaDiffSync') +); +router.get( + '/api/v1/db/meta/projects/:projectId/meta-diff/:baseId', + metaApiMetrics, + ncMetaAclMw(baseMetaDiff, 'baseMetaDiff') +); +router.post( + '/api/v1/db/meta/projects/:projectId/meta-diff/:baseId', + metaApiMetrics, + ncMetaAclMw(baseMetaDiffSync, 'baseMetaDiffSync') +); +export default router; diff --git a/packages/nocodb/src/lib/controllers/modelVisibility.ctl.ts b/packages/nocodb/src/lib/controllers/modelVisibility.ctl.ts new file mode 100644 index 0000000000..6af9a71506 --- /dev/null +++ b/packages/nocodb/src/lib/controllers/modelVisibility.ctl.ts @@ -0,0 +1,34 @@ +import { Router } from 'express'; +import ncMetaAclMw from '../meta/helpers/ncMetaAclMw'; +import { metaApiMetrics } from '../meta/helpers/apiMetrics'; +import { modelVisibilityService } from '../services'; + +async function xcVisibilityMetaSetAll(req, res) { + await modelVisibilityService.xcVisibilityMetaSetAll({ + visibilityRule: req.body, + projectId: req.params.projectId, + }); + + res.json({ msg: 'success' }); +} + +const router = Router({ mergeParams: true }); +router.get( + '/api/v1/db/meta/projects/:projectId/visibility-rules', + metaApiMetrics, + ncMetaAclMw(async (req, res) => { + res.json( + await modelVisibilityService.xcVisibilityMetaGet({ + projectId: req.params.projectId, + includeM2M: + req.query.includeM2M === true || req.query.includeM2M === 'true', + }) + ); + }, 'modelVisibilityList') +); +router.post( + '/api/v1/db/meta/projects/:projectId/visibility-rules', + metaApiMetrics, + ncMetaAclMw(xcVisibilityMetaSetAll, 'modelVisibilitySet') +); +export default router; diff --git a/packages/nocodb/src/lib/meta/api/orgLicenseApis.ts b/packages/nocodb/src/lib/controllers/orgLicense.ctl.ts similarity index 54% rename from packages/nocodb/src/lib/meta/api/orgLicenseApis.ts rename to packages/nocodb/src/lib/controllers/orgLicense.ctl.ts index ec13f4f9e7..23e5948ba1 100644 --- a/packages/nocodb/src/lib/meta/api/orgLicenseApis.ts +++ b/packages/nocodb/src/lib/controllers/orgLicense.ctl.ts @@ -1,21 +1,15 @@ import { Router } from 'express'; import { OrgUserRoles } from 'nocodb-sdk'; -import { NC_LICENSE_KEY } from '../../constants'; -import Store from '../../models/Store'; -import Noco from '../../Noco'; -import { metaApiMetrics } from '../helpers/apiMetrics'; -import ncMetaAclMw from '../helpers/ncMetaAclMw'; -import { getAjvValidatorMw } from './helpers'; +import { metaApiMetrics } from '../meta/helpers/apiMetrics'; +import ncMetaAclMw from '../meta/helpers/ncMetaAclMw'; +import { orgLicenseService } from '../services'; async function licenseGet(_req, res) { - const license = await Store.get(NC_LICENSE_KEY); - - res.json({ key: license?.value }); + res.json(await orgLicenseService.licenseGet()); } async function licenseSet(req, res) { - await Store.saveOrUpdate({ value: req.body.key, key: NC_LICENSE_KEY }); - await Noco.loadEEState(); + await orgLicenseService.licenseSet({ key: req.body.key }); res.json({ msg: 'License key saved' }); } @@ -31,7 +25,6 @@ router.get( router.post( '/api/v1/license', metaApiMetrics, - getAjvValidatorMw('swagger.json#/components/schemas/LicenseReq'), ncMetaAclMw(licenseSet, 'licenseSet', { allowedRoles: [OrgUserRoles.SUPER_ADMIN], blockApiTokenAccess: true, diff --git a/packages/nocodb/src/lib/controllers/orgToken.ctl.ts b/packages/nocodb/src/lib/controllers/orgToken.ctl.ts new file mode 100644 index 0000000000..4dea4dec21 --- /dev/null +++ b/packages/nocodb/src/lib/controllers/orgToken.ctl.ts @@ -0,0 +1,64 @@ +import { Router } from 'express'; +import { metaApiMetrics } from '../meta/helpers/apiMetrics'; +import { getConditionalHandler } from '../meta/helpers/getHandler'; +import ncMetaAclMw from '../meta/helpers/ncMetaAclMw'; +import { orgTokenService, orgTokenServiceEE } from '../services'; +import type { Request, Response } from 'express'; + +async function apiTokenList(req, res) { + res.json( + await getConditionalHandler( + orgTokenService.apiTokenList, + orgTokenServiceEE.apiTokenListEE + )({ + query: req.query, + user: req['user'], + }) + ); +} + +export async function apiTokenCreate(req: Request, res: Response) { + res.json( + await orgTokenService.apiTokenCreate({ + apiToken: req.body, + user: req['user'], + }) + ); +} + +export async function apiTokenDelete(req: Request, res: Response) { + res.json( + await orgTokenService.apiTokenDelete({ + token: req.params.token, + user: req['user'], + }) + ); +} + +const router = Router({ mergeParams: true }); + +router.get( + '/api/v1/tokens', + metaApiMetrics, + ncMetaAclMw(apiTokenList, 'apiTokenList', { + // allowedRoles: [OrgUserRoles.SUPER], + blockApiTokenAccess: true, + }) +); +router.post( + '/api/v1/tokens', + metaApiMetrics, + ncMetaAclMw(apiTokenCreate, 'apiTokenCreate', { + // allowedRoles: [OrgUserRoles.SUPER], + blockApiTokenAccess: true, + }) +); +router.delete( + '/api/v1/tokens/:token', + metaApiMetrics, + ncMetaAclMw(apiTokenDelete, 'apiTokenDelete', { + // allowedRoles: [OrgUserRoles.SUPER], + blockApiTokenAccess: true, + }) +); +export default router; diff --git a/packages/nocodb/src/lib/controllers/orgUser.ctl.ts b/packages/nocodb/src/lib/controllers/orgUser.ctl.ts new file mode 100644 index 0000000000..e2e6df488a --- /dev/null +++ b/packages/nocodb/src/lib/controllers/orgUser.ctl.ts @@ -0,0 +1,154 @@ +import { Router } from 'express'; +import { OrgUserRoles } from 'nocodb-sdk'; +import { metaApiMetrics } from '../meta/helpers/apiMetrics'; +import ncMetaAclMw from '../meta/helpers/ncMetaAclMw'; +import { orgUserService } from '../services'; + +async function userList(req, res) { + res.json( + await orgUserService.userList({ + query: req.query, + }) + ); +} + +async function userUpdate(req, res) { + res.json( + await orgUserService.userUpdate({ + user: req.body, + userId: req.params.userId, + }) + ); +} + +async function userDelete(req, res) { + await orgUserService.userDelete({ + userId: req.params.userId, + }); + res.json({ msg: 'success' }); +} + +async function userAdd(req, res) { + const result = await orgUserService.userAdd({ + user: req.body, + req, + projectId: req.params.projectId, + }); + + res.json(result); +} + +async function userSettings(_req, res): Promise { + await orgUserService.userSettings({}); + res.json({}); +} + +async function userInviteResend(req, res): Promise { + await orgUserService.userInviteResend({ + userId: req.params.userId, + req, + }); + + res.json({ msg: 'success' }); +} + +async function generateResetUrl(req, res) { + const result = await orgUserService.generateResetUrl({ + siteUrl: req.ncSiteUrl, + userId: req.params.userId, + }); + + res.json(result); +} + +async function appSettingsGet(_req, res) { + const settings = await orgUserService.appSettingsGet(); + res.json(settings); +} + +async function appSettingsSet(req, res) { + await orgUserService.appSettingsSet({ + settings: req.body, + }); + + res.json({ msg: 'Settings saved' }); +} + +const router = Router({ mergeParams: true }); +router.get( + '/api/v1/users', + metaApiMetrics, + ncMetaAclMw(userList, 'userList', { + allowedRoles: [OrgUserRoles.SUPER_ADMIN], + blockApiTokenAccess: true, + }) +); +router.patch( + '/api/v1/users/:userId', + metaApiMetrics, + ncMetaAclMw(userUpdate, 'userUpdate', { + allowedRoles: [OrgUserRoles.SUPER_ADMIN], + blockApiTokenAccess: true, + }) +); +router.delete( + '/api/v1/users/:userId', + metaApiMetrics, + ncMetaAclMw(userDelete, 'userDelete', { + allowedRoles: [OrgUserRoles.SUPER_ADMIN], + blockApiTokenAccess: true, + }) +); +router.post( + '/api/v1/users', + metaApiMetrics, + ncMetaAclMw(userAdd, 'userAdd', { + allowedRoles: [OrgUserRoles.SUPER_ADMIN], + blockApiTokenAccess: true, + }) +); +router.post( + '/api/v1/users/settings', + metaApiMetrics, + ncMetaAclMw(userSettings, 'userSettings', { + allowedRoles: [OrgUserRoles.SUPER_ADMIN], + blockApiTokenAccess: true, + }) +); +router.post( + '/api/v1/users/:userId/resend-invite', + metaApiMetrics, + ncMetaAclMw(userInviteResend, 'userInviteResend', { + allowedRoles: [OrgUserRoles.SUPER_ADMIN], + blockApiTokenAccess: true, + }) +); + +router.post( + '/api/v1/users/:userId/generate-reset-url', + metaApiMetrics, + ncMetaAclMw(generateResetUrl, 'generateResetUrl', { + allowedRoles: [OrgUserRoles.SUPER_ADMIN], + blockApiTokenAccess: true, + }) +); + +router.get( + '/api/v1/app-settings', + metaApiMetrics, + ncMetaAclMw(appSettingsGet, 'appSettingsGet', { + allowedRoles: [OrgUserRoles.SUPER_ADMIN], + blockApiTokenAccess: true, + }) +); + +router.post( + '/api/v1/app-settings', + metaApiMetrics, + ncMetaAclMw(appSettingsSet, 'appSettingsSet', { + allowedRoles: [OrgUserRoles.SUPER_ADMIN], + blockApiTokenAccess: true, + }) +); + +export default router; diff --git a/packages/nocodb/src/lib/meta/api/pluginApis.ts b/packages/nocodb/src/lib/controllers/plugin.ctl.ts similarity index 50% rename from packages/nocodb/src/lib/meta/api/pluginApis.ts rename to packages/nocodb/src/lib/controllers/plugin.ctl.ts index 6934e17b41..fb3ed46341 100644 --- a/packages/nocodb/src/lib/meta/api/pluginApis.ts +++ b/packages/nocodb/src/lib/controllers/plugin.ctl.ts @@ -1,38 +1,36 @@ -import { Request, Response, Router } from 'express'; -import { Tele } from 'nc-help'; -import { PagedResponseImpl } from '../helpers/PagedResponse'; -import Plugin from '../../models/Plugin'; -import { PluginType } from 'nocodb-sdk'; -import NcPluginMgrv2 from '../helpers/NcPluginMgrv2'; -import ncMetaAclMw from '../helpers/ncMetaAclMw'; -import { metaApiMetrics } from '../helpers/apiMetrics'; -import { getAjvValidatorMw } from './helpers'; +import { Router } from 'express'; +import { PagedResponseImpl } from '../meta/helpers/PagedResponse'; +import ncMetaAclMw from '../meta/helpers/ncMetaAclMw'; +import { metaApiMetrics } from '../meta/helpers/apiMetrics'; +import { pluginService } from '../services'; +import type { PluginType } from 'nocodb-sdk'; +import type { Request, Response } from 'express'; export async function pluginList(_req: Request, res: Response) { - res.json(new PagedResponseImpl(await Plugin.list())); + res.json(new PagedResponseImpl(await pluginService.pluginList())); } export async function pluginTest(req: Request, res: Response) { - Tele.emit('evt', { evt_type: 'plugin:tested' }); - res.json(await NcPluginMgrv2.test(req.body)); + res.json(await pluginService.pluginTest({ body: req.body })); } export async function pluginRead(req: Request, res: Response) { - res.json(await Plugin.get(req.params.pluginId)); + res.json(await pluginService.pluginRead({ pluginId: req.params.pluginId })); } export async function pluginUpdate( req: Request, res: Response ) { - const plugin = await Plugin.update(req.params.pluginId, req.body); - Tele.emit('evt', { - evt_type: plugin.active ? 'plugin:installed' : 'plugin:uninstalled', - title: plugin.title, + const plugin = await pluginService.pluginUpdate({ + pluginId: req.params.pluginId, + plugin: req.body, }); res.json(plugin); } export async function isPluginActive(req: Request, res: Response) { - res.json(await Plugin.isPluginActive(req.params.pluginTitle)); + res.json( + await pluginService.isPluginActive({ pluginTitle: req.params.pluginTitle }) + ); } const router = Router({ mergeParams: true }); @@ -44,8 +42,6 @@ router.get( router.post( '/api/v1/db/meta/plugins/test', metaApiMetrics, - getAjvValidatorMw('swagger.json#/components/schemas/PluginTestReq'), - ncMetaAclMw(pluginTest, 'pluginTest') ); router.get( @@ -56,7 +52,6 @@ router.get( router.patch( '/api/v1/db/meta/plugins/:pluginId', metaApiMetrics, - getAjvValidatorMw('swagger.json#/components/schemas/PluginReq'), ncMetaAclMw(pluginUpdate, 'pluginUpdate') ); router.get( diff --git a/packages/nocodb/src/lib/controllers/project.ctl.ts b/packages/nocodb/src/lib/controllers/project.ctl.ts new file mode 100644 index 0000000000..da626329c3 --- /dev/null +++ b/packages/nocodb/src/lib/controllers/project.ctl.ts @@ -0,0 +1,169 @@ +import { T } from 'nc-help'; +import isDocker from 'is-docker'; +import { packageVersion } from '../utils/packageVersion'; +import { PagedResponseImpl } from '../meta/helpers/PagedResponse'; +import NcConnectionMgrv2 from '../utils/common/NcConnectionMgrv2'; +import ncMetaAclMw from '../meta/helpers/ncMetaAclMw'; +import ProjectUser from '../models/ProjectUser'; +import Noco from '../Noco'; +import Project from '../models/Project'; +import { metaApiMetrics } from '../meta/helpers/apiMetrics'; +import Filter from '../models/Filter'; + +import { projectService } from '../services'; +import type { ProjectListType } from 'nocodb-sdk'; +import type { ProjectType } from 'nocodb-sdk'; +import type { Request, Response } from 'express'; + +// // Project CRUD + +export async function projectGet( + req: Request, + res: Response +) { + const project = await projectService.getProjectWithInfo({ + projectId: req.params.projectId, + }); + + projectService.sanitizeProject(project); + + res.json(project); +} + +export async function projectUpdate( + req: Request, + res: Response +) { + const project = await projectService.projectUpdate({ + projectId: req.params.projectId, + project: req.body, + }); + + res.json(project); +} + +export async function projectList( + req: Request & { user: { id: string; roles: string } }, + res: Response +) { + const projects = await projectService.projectList({ + user: req.user, + query: req.query, + }); + + res.json( + new PagedResponseImpl(projects as ProjectType[], { + count: projects.length, + limit: projects.length, + }) + ); +} + +export async function projectDelete(req: Request, res: Response) { + const deleted = await projectService.projectSoftDelete({ + projectId: req.params.projectId, + }); + + res.json(deleted); +} + +async function projectCreate(req: Request, res) { + const project = await projectService.projectCreate({ + project: req.body, + user: req['user'], + }); + + res.json(project); +} + +export async function projectInfoGet(_req, res) { + res.json({ + Node: process.version, + Arch: process.arch, + Platform: process.platform, + Docker: isDocker(), + RootDB: Noco.getConfig()?.meta?.db?.client, + PackageVersion: packageVersion, + }); +} + +export async function projectCost(req, res) { + let cost = 0; + const project = await Project.getWithInfo(req.params.projectId); + + for (const base of project.bases) { + const sqlClient = await NcConnectionMgrv2.getSqlClient(base); + const userCount = await ProjectUser.getUsersCount(req.query); + const recordCount = (await sqlClient.totalRecords())?.data.TotalRecords; + + if (recordCount > 100000) { + // 36,000 or $79/user/month + cost = Math.max(36000, 948 * userCount); + } else if (recordCount > 50000) { + // $36,000 or $50/user/month + cost = Math.max(36000, 600 * userCount); + } else if (recordCount > 10000) { + // $240/user/yr + cost = Math.min(240 * userCount, 36000); + } else if (recordCount > 1000) { + // $120/user/yr + cost = Math.min(120 * userCount, 36000); + } + } + + T.event({ + event: 'a:project:cost', + data: { + cost, + }, + }); + + res.json({ cost }); +} + +export async function hasEmptyOrNullFilters(req, res) { + res.json(await Filter.hasEmptyOrNullFilters(req.params.projectId)); +} + +export default (router) => { + router.get( + '/api/v1/db/meta/projects/:projectId/info', + metaApiMetrics, + ncMetaAclMw(projectInfoGet, 'projectInfoGet') + ); + router.get( + '/api/v1/db/meta/projects/:projectId', + metaApiMetrics, + ncMetaAclMw(projectGet, 'projectGet') + ); + router.patch( + '/api/v1/db/meta/projects/:projectId', + metaApiMetrics, + ncMetaAclMw(projectUpdate, 'projectUpdate') + ); + router.get( + '/api/v1/db/meta/projects/:projectId/cost', + metaApiMetrics, + ncMetaAclMw(projectCost, 'projectCost') + ); + router.delete( + '/api/v1/db/meta/projects/:projectId', + metaApiMetrics, + ncMetaAclMw(projectDelete, 'projectDelete') + ); + router.post( + '/api/v1/db/meta/projects', + metaApiMetrics, + ncMetaAclMw(projectCreate, 'projectCreate') + ); + router.get( + '/api/v1/db/meta/projects', + metaApiMetrics, + ncMetaAclMw(projectList, 'projectList') + ); + router.get( + '/api/v1/db/meta/projects/:projectId/has-empty-or-null-filters', + metaApiMetrics, + ncMetaAclMw(hasEmptyOrNullFilters, 'hasEmptyOrNullFilters') + ); +}; diff --git a/packages/nocodb/src/lib/controllers/projectUser.ctl.ts b/packages/nocodb/src/lib/controllers/projectUser.ctl.ts new file mode 100644 index 0000000000..cc3beca1f5 --- /dev/null +++ b/packages/nocodb/src/lib/controllers/projectUser.ctl.ts @@ -0,0 +1,85 @@ +import { Router } from 'express'; +import ncMetaAclMw from '../meta/helpers/ncMetaAclMw'; +import { metaApiMetrics } from '../meta/helpers/apiMetrics'; +import { projectUserService } from '../services'; + +async function userList(req, res) { + res.json({ + users: await projectUserService.userList({ + projectId: req.params.projectId, + query: req.query, + }), + }); +} + +async function userInvite(req, res): Promise { + res.json( + await projectUserService.userInvite({ + projectId: req.params.projectId, + projectUser: req.body, + req, + }) + ); +} + +// @ts-ignore +async function projectUserUpdate(req, res, next): Promise { + res.json( + await projectUserService.projectUserUpdate({ + projectUser: req.body, + projectId: req.params.projectId, + userId: req.params.userId, + req, + }) + ); +} + +async function projectUserDelete(req, res): Promise { + await projectUserService.projectUserDelete({ + projectId: req.params.projectId, + userId: req.params.userId, + req, + }); + res.json({ + msg: 'success', + }); +} + +async function projectUserInviteResend(req, res): Promise { + res.json( + await projectUserService.projectUserInviteResend({ + projectId: req.params.projectId, + userId: req.params.userId, + projectUser: req.body, + req, + }) + ); +} + +const router = Router({ mergeParams: true }); +router.get( + '/api/v1/db/meta/projects/:projectId/users', + metaApiMetrics, + ncMetaAclMw(userList, 'userList') +); +router.post( + '/api/v1/db/meta/projects/:projectId/users', + metaApiMetrics, + ncMetaAclMw(userInvite, 'userInvite') +); +router.patch( + '/api/v1/db/meta/projects/:projectId/users/:userId', + metaApiMetrics, + ncMetaAclMw(projectUserUpdate, 'projectUserUpdate') +); +router.delete( + '/api/v1/db/meta/projects/:projectId/users/:userId', + metaApiMetrics, + ncMetaAclMw(projectUserDelete, 'projectUserDelete') +); +router.post( + '/api/v1/db/meta/projects/:projectId/users/:userId/resend-invite', + metaApiMetrics, + ncMetaAclMw(projectUserInviteResend, 'projectUserInviteResend') +); +export default router; diff --git a/packages/nocodb/src/lib/controllers/publicControllers/index.ts b/packages/nocodb/src/lib/controllers/publicControllers/index.ts new file mode 100644 index 0000000000..dc7196a8c5 --- /dev/null +++ b/packages/nocodb/src/lib/controllers/publicControllers/index.ts @@ -0,0 +1,9 @@ +import publicDataController from './publicData.ctl'; +import publicDataExportController from './publicDataExport.ctl'; +import publicMetaController from './publicMeta.ctl'; + +export { + publicDataController, + publicDataExportController, + publicMetaController, +}; diff --git a/packages/nocodb/src/lib/controllers/publicControllers/publicData.ctl.ts b/packages/nocodb/src/lib/controllers/publicControllers/publicData.ctl.ts new file mode 100644 index 0000000000..8117760fe5 --- /dev/null +++ b/packages/nocodb/src/lib/controllers/publicControllers/publicData.ctl.ts @@ -0,0 +1,106 @@ +import { Router } from 'express'; +import multer from 'multer'; +import { NC_ATTACHMENT_FIELD_SIZE } from '../../constants'; +import catchError from '../../meta/helpers/catchError'; +import { publicDataService } from '../../services'; +import type { Request, Response } from 'express'; + +export async function dataList(req: Request, res: Response) { + const pagedResponse = await publicDataService.dataList({ + query: req.query, + password: req.headers?.['xc-password'] as string, + sharedViewUuid: req.params.sharedViewUuid, + }); + res.json({ data: pagedResponse }); +} + +// todo: Handle the error case where view doesnt belong to model +async function groupedDataList(req: Request, res: Response) { + const groupedData = await publicDataService.groupedDataList({ + query: req.query, + password: req.headers?.['xc-password'] as string, + sharedViewUuid: req.params.sharedViewUuid, + groupColumnId: req.params.columnId, + }); + res.json(groupedData); +} + +async function dataInsert(req: Request & { files: any[] }, res: Response) { + const insertResult = await publicDataService.dataInsert({ + sharedViewUuid: req.params.sharedViewUuid, + password: req.headers?.['xc-password'] as string, + body: req.body?.data, + siteUrl: (req as any).ncSiteUrl, + files: req.files, + }); + + res.json(insertResult); +} + +async function relDataList(req, res) { + const pagedResponse = await publicDataService.relDataList({ + query: req.query, + password: req.headers?.['xc-password'] as string, + sharedViewUuid: req.params.sharedViewUuid, + columnId: req.params.columnId, + }); + + res.json(pagedResponse); +} + +export async function publicMmList(req: Request, res: Response) { + const paginatedResponse = await publicDataService.publicMmList({ + query: req.query, + password: req.headers?.['xc-password'] as string, + sharedViewUuid: req.params.sharedViewUuid, + columnId: req.params.columnId, + rowId: req.params.rowId, + }); + res.json(paginatedResponse); +} + +export async function publicHmList(req: Request, res: Response) { + const paginatedResponse = await publicDataService.publicHmList({ + query: req.query, + password: req.headers?.['xc-password'] as string, + sharedViewUuid: req.params.sharedViewUuid, + columnId: req.params.columnId, + rowId: req.params.rowId, + }); + res.json(paginatedResponse); +} + +const router = Router({ mergeParams: true }); +router.get( + '/api/v1/db/public/shared-view/:sharedViewUuid/rows', + catchError(dataList) +); +router.get( + '/api/v1/db/public/shared-view/:sharedViewUuid/group/:columnId', + catchError(groupedDataList) +); +router.get( + '/api/v1/db/public/shared-view/:sharedViewUuid/nested/:columnId', + catchError(relDataList) +); +router.post( + '/api/v1/db/public/shared-view/:sharedViewUuid/rows', + multer({ + storage: multer.diskStorage({}), + limits: { + fieldSize: NC_ATTACHMENT_FIELD_SIZE, + }, + }).any(), + catchError(dataInsert) +); + +router.get( + '/api/v1/db/public/shared-view/:sharedViewUuid/rows/:rowId/mm/:colId', + catchError(publicMmList) +); +router.get( + '/api/v1/db/public/shared-view/:sharedViewUuid/rows/:rowId/hm/:colId', + catchError(publicHmList) +); + +export default router; diff --git a/packages/nocodb/src/lib/meta/api/publicApis/publicDataExportApis.ts b/packages/nocodb/src/lib/controllers/publicControllers/publicDataExport.ctl.ts similarity index 91% rename from packages/nocodb/src/lib/meta/api/publicApis/publicDataExportApis.ts rename to packages/nocodb/src/lib/controllers/publicControllers/publicDataExport.ctl.ts index 936cc68c9b..9ab36afdc7 100644 --- a/packages/nocodb/src/lib/meta/api/publicApis/publicDataExportApis.ts +++ b/packages/nocodb/src/lib/controllers/publicControllers/publicDataExport.ctl.ts @@ -1,17 +1,14 @@ -import { Request, Response, Router } from 'express'; +import { Router } from 'express'; import * as XLSX from 'xlsx'; -import View from '../../../models/View'; -import Model from '../../../models/Model'; -import Base from '../../../models/Base'; -import NcConnectionMgrv2 from '../../../utils/common/NcConnectionMgrv2'; import { nocoExecute } from 'nc-help'; import papaparse from 'papaparse'; import { ErrorMessages, isSystemColumn, UITypes, ViewTypes } from 'nocodb-sdk'; -import Column from '../../../models/Column'; -import LinkToAnotherRecordColumn from '../../../models/LinkToAnotherRecordColumn'; -import LookupColumn from '../../../models/LookupColumn'; -import catchError, { NcError } from '../../helpers/catchError'; -import getAst from '../../../db/sql-data-mapper/lib/sql/helpers/getAst'; +import getAst from '../../db/sql-data-mapper/lib/sql/helpers/getAst'; +import catchError, { NcError } from '../../meta/helpers/catchError'; +import { Base, Column, Model, View } from '../../models'; +import NcConnectionMgrv2 from '../../utils/common/NcConnectionMgrv2'; +import type { LinkToAnotherRecordColumn, LookupColumn } from '../../models'; +import type { Request, Response } from 'express'; async function exportExcel(req: Request, res: Response) { const view = await View.getByUUID(req.params.publicDataUuid); @@ -136,7 +133,7 @@ async function getDbRows(model, view: View, req: Request) { const baseModel = await Model.getBaseModelSQL({ id: model.id, viewId: view?.id, - dbDriver: NcConnectionMgrv2.get(base), + dbDriver: await NcConnectionMgrv2.get(base), }); const requestObj = await getAst({ diff --git a/packages/nocodb/src/lib/controllers/publicControllers/publicMeta.ctl.ts b/packages/nocodb/src/lib/controllers/publicControllers/publicMeta.ctl.ts new file mode 100644 index 0000000000..3517527884 --- /dev/null +++ b/packages/nocodb/src/lib/controllers/publicControllers/publicMeta.ctl.ts @@ -0,0 +1,32 @@ +import { Router } from 'express'; +import catchError from '../../meta/helpers/catchError'; +import { publicMetaService } from '../../services'; +import type { Request, Response } from 'express'; + +export async function viewMetaGet(req: Request, res: Response) { + res.json( + await publicMetaService.viewMetaGet({ + password: req.headers?.['xc-password'] as string, + sharedViewUuid: req.params.sharedViewUuid, + }) + ); +} +async function publicSharedBaseGet(req, res): Promise { + res.json( + await publicMetaService.publicSharedBaseGet({ + sharedBaseUuid: req.params.sharedBaseUuid, + }) + ); +} + +const router = Router({ mergeParams: true }); +router.get( + '/api/v1/db/public/shared-view/:sharedViewUuid/meta', + catchError(viewMetaGet) +); + +router.get( + '/api/v1/db/public/shared-base/:sharedBaseUuid/meta', + catchError(publicSharedBaseGet) +); +export default router; diff --git a/packages/nocodb/src/lib/controllers/sharedBase.ctl.ts b/packages/nocodb/src/lib/controllers/sharedBase.ctl.ts new file mode 100644 index 0000000000..1fd9fb27cd --- /dev/null +++ b/packages/nocodb/src/lib/controllers/sharedBase.ctl.ts @@ -0,0 +1,61 @@ +import { Router } from 'express'; +import ncMetaAclMw from '../meta/helpers/ncMetaAclMw'; +import { sharedBaseService } from '../services'; + +async function createSharedBaseLink(req, res): Promise { + const sharedBase = await sharedBaseService.createSharedBaseLink({ + projectId: req.params.projectId, + roles: req.body?.roles, + password: req.body?.password, + siteUrl: req.ncSiteUrl, + }); + + res.json(sharedBase); +} + +async function updateSharedBaseLink(req, res): Promise { + const sharedBase = await sharedBaseService.updateSharedBaseLink({ + projectId: req.params.projectId, + roles: req.body?.roles, + password: req.body?.password, + siteUrl: req.ncSiteUrl, + }); + + res.json(sharedBase); +} + +async function disableSharedBaseLink(req, res): Promise { + const sharedBase = await sharedBaseService.disableSharedBaseLink({ + projectId: req.params.projectId, + }); + + res.json(sharedBase); +} + +async function getSharedBaseLink(req, res): Promise { + const sharedBase = await sharedBaseService.getSharedBaseLink({ + projectId: req.params.projectId, + siteUrl: req.ncSiteUrl, + }); + + res.json(sharedBase); +} + +const router = Router({ mergeParams: true }); +router.get( + '/api/v1/db/meta/projects/:projectId/shared', + ncMetaAclMw(getSharedBaseLink, 'getSharedBaseLink') +); +router.post( + '/api/v1/db/meta/projects/:projectId/shared', + ncMetaAclMw(createSharedBaseLink, 'createSharedBaseLink') +); +router.patch( + '/api/v1/db/meta/projects/:projectId/shared', + ncMetaAclMw(updateSharedBaseLink, 'updateSharedBaseLink') +); +router.delete( + '/api/v1/db/meta/projects/:projectId/shared', + ncMetaAclMw(disableSharedBaseLink, 'disableSharedBaseLink') +); +export default router; diff --git a/packages/nocodb/src/lib/controllers/sort.ctl.ts b/packages/nocodb/src/lib/controllers/sort.ctl.ts new file mode 100644 index 0000000000..24d071aa0d --- /dev/null +++ b/packages/nocodb/src/lib/controllers/sort.ctl.ts @@ -0,0 +1,81 @@ +import { Router } from 'express'; +import { PagedResponseImpl } from '../meta/helpers/PagedResponse'; +import ncMetaAclMw from '../meta/helpers/ncMetaAclMw'; +import { metaApiMetrics } from '../meta/helpers/apiMetrics'; + +import { sortService } from '../services'; +import type { SortListType, SortReqType } from 'nocodb-sdk'; +import type { Request, Response } from 'express'; + +// @ts-ignore +export async function sortList( + req: Request, + res: Response +) { + const sortList = await sortService.sortList({ + viewId: req.params.viewId, + }); + res.json({ + sorts: new PagedResponseImpl(sortList), + }); +} + +// @ts-ignore +export async function sortCreate(req: Request, res) { + const sort = await sortService.sortCreate({ + sort: req.body, + viewId: req.params.viewId, + }); + res.json(sort); +} + +export async function sortUpdate(req, res) { + const sort = await sortService.sortUpdate({ + sortId: req.params.sortId, + sort: req.body, + }); + res.json(sort); +} + +export async function sortDelete(req: Request, res: Response) { + const sort = await sortService.sortDelete({ + sortId: req.params.sortId, + }); + res.json(sort); +} +export async function sortGet(req: Request, res: Response) { + const sort = await sortService.sortGet({ + sortId: req.params.sortId, + }); + res.json(sort); +} + +const router = Router({ mergeParams: true }); +router.get( + '/api/v1/db/meta/views/:viewId/sorts/', + metaApiMetrics, + ncMetaAclMw(sortList, 'sortList') +); +router.post( + '/api/v1/db/meta/views/:viewId/sorts/', + metaApiMetrics, + ncMetaAclMw(sortCreate, 'sortCreate') +); + +router.get( + '/api/v1/db/meta/sorts/:sortId', + metaApiMetrics, + ncMetaAclMw(sortGet, 'sortGet') +); + +router.patch( + '/api/v1/db/meta/sorts/:sortId', + metaApiMetrics, + ncMetaAclMw(sortUpdate, 'sortUpdate') +); +router.delete( + '/api/v1/db/meta/sorts/:sortId', + metaApiMetrics, + ncMetaAclMw(sortDelete, 'sortDelete') +); +export default router; diff --git a/packages/nocodb/src/lib/meta/api/sync/importApis.ts b/packages/nocodb/src/lib/controllers/sync/import.ctl.ts similarity index 85% rename from packages/nocodb/src/lib/meta/api/sync/importApis.ts rename to packages/nocodb/src/lib/controllers/sync/import.ctl.ts index 92ab241117..d366e65b32 100644 --- a/packages/nocodb/src/lib/meta/api/sync/importApis.ts +++ b/packages/nocodb/src/lib/controllers/sync/import.ctl.ts @@ -1,13 +1,14 @@ -import { Request, Router } from 'express'; // import { Queue } from 'bullmq'; // import axios from 'axios'; -import catchError, { NcError } from '../../helpers/catchError'; -import { Server } from 'socket.io'; -import NocoJobs from '../../../jobs/NocoJobs'; -import job, { AirtableSyncConfig } from './helpers/job'; -import SyncSource from '../../../models/SyncSource'; -import Noco from '../../../Noco'; -import { genJwt } from '../userApi/helpers'; +import catchError, { NcError } from '../../meta/helpers/catchError'; +import NocoJobs from '../../jobs/NocoJobs'; +import { SyncSource } from '../../models'; +import Noco from '../../Noco'; +import { syncService, userService } from '../../services'; +import type { Server } from 'socket.io'; +import type { Request, Router } from 'express'; +import type { AirtableSyncConfig } from '../../services/sync/helpers/job'; + const AIRTABLE_IMPORT_JOB = 'AIRTABLE_IMPORT_JOB'; const AIRTABLE_PROGRESS_JOB = 'AIRTABLE_PROGRESS_JOB'; @@ -23,7 +24,10 @@ export default ( jobs: { [id: string]: { last_message: any } } ) => { // add importer job handler and progress notification job handler - NocoJobs.jobsMgr.addJobWorker(AIRTABLE_IMPORT_JOB, job); + NocoJobs.jobsMgr.addJobWorker( + AIRTABLE_IMPORT_JOB, + syncService.airtableImportJob + ); NocoJobs.jobsMgr.addJobWorker( AIRTABLE_PROGRESS_JOB, ({ payload, progress }) => { @@ -94,7 +98,7 @@ export default ( const syncSource = await SyncSource.get(req.params.syncId); const user = await syncSource.getUser(); - const token = genJwt(user, Noco.getConfig()); + const token = userService.genJwt(user, Noco.getConfig()); // Treat default baseUrl as siteUrl from req object let baseURL = (req as any).ncSiteUrl; diff --git a/packages/nocodb/src/lib/controllers/sync/index.ts b/packages/nocodb/src/lib/controllers/sync/index.ts new file mode 100644 index 0000000000..747bc7fec7 --- /dev/null +++ b/packages/nocodb/src/lib/controllers/sync/index.ts @@ -0,0 +1,4 @@ +import importController from './import.ctl'; +import syncSourceController from './sync.ctl'; + +export { importController, syncSourceController }; diff --git a/packages/nocodb/src/lib/meta/api/sync/syncSourceApis.ts b/packages/nocodb/src/lib/controllers/sync/sync.ctl.ts similarity index 50% rename from packages/nocodb/src/lib/meta/api/sync/syncSourceApis.ts rename to packages/nocodb/src/lib/controllers/sync/sync.ctl.ts index f9e761ff71..827389516d 100644 --- a/packages/nocodb/src/lib/meta/api/sync/syncSourceApis.ts +++ b/packages/nocodb/src/lib/controllers/sync/sync.ctl.ts @@ -1,42 +1,42 @@ -import { Request, Response, Router } from 'express'; - -import SyncSource from '../../../models/SyncSource'; -import { Tele } from 'nc-help'; -import { PagedResponseImpl } from '../../helpers/PagedResponse'; -import ncMetaAclMw from '../../helpers/ncMetaAclMw'; -import Project from '../../../models/Project'; +import { Router } from 'express'; +import ncMetaAclMw from '../../meta/helpers/ncMetaAclMw'; +import { syncService } from '../../services'; +import type { Request, Response } from 'express'; export async function syncSourceList(req: Request, res: Response) { - // todo: pagination res.json( - new PagedResponseImpl( - await SyncSource.list(req.params.projectId, req.params.baseId) - ) + await syncService.syncSourceList({ + projectId: req.params.projectId, + }) ); } export async function syncCreate(req: Request, res: Response) { - Tele.emit('evt', { evt_type: 'webhooks:created' }); - const project = await Project.getWithInfo(req.params.projectId); - - const sync = await SyncSource.insert({ - ...req.body, - fk_user_id: (req as any).user.id, - base_id: req.params.baseId ? req.params.baseId : project.bases[0].id, - project_id: req.params.projectId, - }); - res.json(sync); + res.json( + await syncService.syncCreate({ + projectId: req.params.projectId, + baseId: req.params.baseId, + userId: (req as any).user.id, + syncPayload: req.body, + }) + ); } export async function syncDelete(req: Request, res: Response) { - Tele.emit('evt', { evt_type: 'webhooks:deleted' }); - res.json(await SyncSource.delete(req.params.syncId)); + res.json( + await syncService.syncDelete({ + syncId: req.params.syncId, + }) + ); } export async function syncUpdate(req: Request, res: Response) { - Tele.emit('evt', { evt_type: 'webhooks:updated' }); - - res.json(await SyncSource.update(req.params.syncId, req.body)); + res.json( + await syncService.syncUpdate({ + syncId: req.params.syncId, + syncPayload: req.body, + }) + ); } const router = Router({ mergeParams: true }); diff --git a/packages/nocodb/src/lib/controllers/table.ctl.ts b/packages/nocodb/src/lib/controllers/table.ctl.ts new file mode 100644 index 0000000000..d1e3f2746f --- /dev/null +++ b/packages/nocodb/src/lib/controllers/table.ctl.ts @@ -0,0 +1,112 @@ +import { Router } from 'express'; +import { metaApiMetrics } from '../meta/helpers/apiMetrics'; +import ncMetaAclMw from '../meta/helpers/ncMetaAclMw'; +import { PagedResponseImpl } from '../meta/helpers/PagedResponse'; +import { tableService } from '../services'; +import type { TableListType, TableReqType, TableType } from 'nocodb-sdk'; +import type { Request, Response } from 'express'; + +export async function tableList(req: Request, res: Response) { + res.json( + new PagedResponseImpl( + await tableService.getAccessibleTables({ + projectId: req.params.projectId, + baseId: req.params.baseId, + includeM2M: req.query?.includeM2M === 'true', + roles: (req as any).session?.passport?.user?.roles, + }) + ) + ); +} + +export async function tableCreate(req: Request, res) { + const result = await tableService.tableCreate({ + projectId: req.params.projectId, + baseId: req.params.baseId, + table: req.body, + user: (req as any).session?.passport?.user, + }); + + res.json(result); +} + +export async function tableGet(req: Request, res: Response) { + const table = await tableService.getTableWithAccessibleViews({ + tableId: req.params.tableId, + user: (req as any).session?.passport?.user, + }); + + res.json(table); +} + +export async function tableDelete(req: Request, res: Response) { + const result = await tableService.tableDelete({ + tableId: req.params.tableId, + user: (req as any).session?.passport?.user, + req, + }); + + res.json(result); +} + +export async function tableReorder(req: Request, res: Response) { + res.json( + await tableService.reorderTable({ + tableId: req.params.tableId, + order: req.body.order, + }) + ); +} + +// todo: move to table service +export async function tableUpdate(req: Request, res) { + await tableService.tableUpdate({ + tableId: req.params.tableId, + table: req.body, + projectId: (req as any).ncProjectId, + }); + res.json({ msg: 'success' }); +} + +const router = Router({ mergeParams: true }); +router.get( + '/api/v1/db/meta/projects/:projectId/tables', + metaApiMetrics, + ncMetaAclMw(tableList, 'tableList') +); +router.get( + '/api/v1/db/meta/projects/:projectId/:baseId/tables', + metaApiMetrics, + ncMetaAclMw(tableList, 'tableList') +); +router.post( + '/api/v1/db/meta/projects/:projectId/tables', + metaApiMetrics, + ncMetaAclMw(tableCreate, 'tableCreate') +); +router.post( + '/api/v1/db/meta/projects/:projectId/:baseId/tables', + metaApiMetrics, + ncMetaAclMw(tableCreate, 'tableCreate') +); +router.get( + '/api/v1/db/meta/tables/:tableId', + metaApiMetrics, + ncMetaAclMw(tableGet, 'tableGet') +); +router.patch( + '/api/v1/db/meta/tables/:tableId', + metaApiMetrics, + ncMetaAclMw(tableUpdate, 'tableUpdate') +); +router.delete( + '/api/v1/db/meta/tables/:tableId', + metaApiMetrics, + ncMetaAclMw(tableDelete, 'tableDelete') +); +router.post( + '/api/v1/db/meta/tables/:tableId/reorder', + metaApiMetrics, + ncMetaAclMw(tableReorder, 'tableReorder') +); +export default router; diff --git a/packages/nocodb/src/lib/meta/api/testApis.ts b/packages/nocodb/src/lib/controllers/test.ctl.ts similarity index 72% rename from packages/nocodb/src/lib/meta/api/testApis.ts rename to packages/nocodb/src/lib/controllers/test.ctl.ts index 506f9d4474..a9bdce66b6 100644 --- a/packages/nocodb/src/lib/meta/api/testApis.ts +++ b/packages/nocodb/src/lib/controllers/test.ctl.ts @@ -1,5 +1,6 @@ -import { Request, Router } from 'express'; -import { TestResetService } from '../../services/test/TestResetService'; +import { Router } from 'express'; +import { TestResetService } from '../services/test/TestResetService'; +import type { Request } from 'express'; export async function reset(req: Request, res) { const service = new TestResetService({ diff --git a/packages/nocodb/src/lib/controllers/user/index.ts b/packages/nocodb/src/lib/controllers/user/index.ts new file mode 100644 index 0000000000..01668e2940 --- /dev/null +++ b/packages/nocodb/src/lib/controllers/user/index.ts @@ -0,0 +1,3 @@ +import userController from './user.ctl'; + +export { userController }; diff --git a/packages/nocodb/src/lib/meta/api/userApi/initStrategies.ts b/packages/nocodb/src/lib/controllers/user/initStrategies.ts similarity index 95% rename from packages/nocodb/src/lib/meta/api/userApi/initStrategies.ts rename to packages/nocodb/src/lib/controllers/user/initStrategies.ts index b40f2c58d1..4d9ac6466f 100644 --- a/packages/nocodb/src/lib/meta/api/userApi/initStrategies.ts +++ b/packages/nocodb/src/lib/controllers/user/initStrategies.ts @@ -1,14 +1,11 @@ -import { OrgUserRoles } from 'nocodb-sdk'; -import User from '../../../models/User'; -import ProjectUser from '../../../models/ProjectUser'; import { promisify } from 'util'; +import { OrgUserRoles } from 'nocodb-sdk'; import { Strategy as CustomStrategy } from 'passport-custom'; import passport from 'passport'; import passportJWT from 'passport-jwt'; import { Strategy as AuthTokenStrategy } from 'passport-auth-token'; import { Strategy as GoogleStrategy } from 'passport-google-oauth20'; -const PassportLocalStrategy = require('passport-local').Strategy; const ExtractJwt = passportJWT.ExtractJwt; const JwtStrategy = passportJWT.Strategy; @@ -17,13 +14,12 @@ const jwtOptions = { }; import bcrypt from 'bcryptjs'; -import Project from '../../../models/Project'; -import NocoCache from '../../../cache/NocoCache'; -import { CacheGetType, CacheScope } from '../../../utils/globals'; -import ApiToken from '../../../models/ApiToken'; -import Noco from '../../../Noco'; -import Plugin from '../../../models/Plugin'; -import { registerNewUserIfAllowed } from './userApis'; +import NocoCache from '../../cache/NocoCache'; +import { ApiToken, Plugin, Project, ProjectUser, User } from '../../models'; +import Noco from '../../Noco'; +import { CacheGetType, CacheScope } from '../../utils/globals'; +import { userService } from '../../services'; +const PassportLocalStrategy = require('passport-local').Strategy; export function initStrategies(router): void { passport.use( @@ -311,7 +307,7 @@ export function initStrategies(router): void { // or return error } else { const salt = await promisify(bcrypt.genSalt)(10); - const user = await registerNewUserIfAllowed({ + const user = await userService.registerNewUserIfAllowed({ firstname: null, lastname: null, email_verification_token: null, diff --git a/packages/nocodb/src/lib/meta/api/userApi/ui/auth/emailVerify.ts b/packages/nocodb/src/lib/controllers/user/ui/auth/emailVerify.ts similarity index 100% rename from packages/nocodb/src/lib/meta/api/userApi/ui/auth/emailVerify.ts rename to packages/nocodb/src/lib/controllers/user/ui/auth/emailVerify.ts diff --git a/packages/nocodb/src/lib/meta/api/userApi/ui/auth/resetPassword.ts b/packages/nocodb/src/lib/controllers/user/ui/auth/resetPassword.ts similarity index 100% rename from packages/nocodb/src/lib/meta/api/userApi/ui/auth/resetPassword.ts rename to packages/nocodb/src/lib/controllers/user/ui/auth/resetPassword.ts diff --git a/packages/nocodb/src/lib/meta/api/userApi/ui/emailTemplates/forgotPassword.ts b/packages/nocodb/src/lib/controllers/user/ui/emailTemplates/forgotPassword.ts similarity index 100% rename from packages/nocodb/src/lib/meta/api/userApi/ui/emailTemplates/forgotPassword.ts rename to packages/nocodb/src/lib/controllers/user/ui/emailTemplates/forgotPassword.ts diff --git a/packages/nocodb/src/lib/meta/api/userApi/ui/emailTemplates/invite.ts b/packages/nocodb/src/lib/controllers/user/ui/emailTemplates/invite.ts similarity index 100% rename from packages/nocodb/src/lib/meta/api/userApi/ui/emailTemplates/invite.ts rename to packages/nocodb/src/lib/controllers/user/ui/emailTemplates/invite.ts diff --git a/packages/nocodb/src/lib/meta/api/userApi/ui/emailTemplates/verify.ts b/packages/nocodb/src/lib/controllers/user/ui/emailTemplates/verify.ts similarity index 100% rename from packages/nocodb/src/lib/meta/api/userApi/ui/emailTemplates/verify.ts rename to packages/nocodb/src/lib/controllers/user/ui/emailTemplates/verify.ts diff --git a/packages/nocodb/src/lib/controllers/user/user.ctl.ts b/packages/nocodb/src/lib/controllers/user/user.ctl.ts new file mode 100644 index 0000000000..86b2eeeefe --- /dev/null +++ b/packages/nocodb/src/lib/controllers/user/user.ctl.ts @@ -0,0 +1,275 @@ +import { promisify } from 'util'; +import * as ejs from 'ejs'; + +import passport from 'passport'; +import catchError, { NcError } from '../../meta/helpers/catchError'; +import extractProjectIdAndAuthenticate from '../../meta/helpers/extractProjectIdAndAuthenticate'; +import ncMetaAclMw from '../../meta/helpers/ncMetaAclMw'; +import { Audit, User } from '../../models'; +import Noco from '../../Noco'; +import { userService } from '../../services'; +import { setTokenCookie } from '../../services/user/helpers'; +import type { Request } from 'express'; + +export async function signup(req: Request, res): Promise { + res.json( + await userService.signup({ + body: req.body, + req, + res, + }) + ); +} + +export async function refreshToken(req: Request, res): Promise { + res.json( + await userService.refreshToken({ + body: req.body, + req, + res, + }) + ); +} + +async function successfulSignIn({ + user, + err, + info, + req, + res, + auditDescription, +}) { + try { + if (!user || !user.email) { + if (err) { + return res.status(400).send(err); + } + if (info) { + return res.status(400).send(info); + } + return res.status(400).send({ msg: 'Your signin has failed' }); + } + + await promisify((req as any).login.bind(req))(user); + + const refreshToken = userService.randomTokenString(); + + if (!user.token_version) { + user.token_version = userService.randomTokenString(); + } + + await User.update(user.id, { + refresh_token: refreshToken, + email: user.email, + token_version: user.token_version, + }); + setTokenCookie(res, refreshToken); + + await Audit.insert({ + op_type: 'AUTHENTICATION', + op_sub_type: 'SIGNIN', + user: user.email, + ip: req.clientIp, + description: auditDescription, + }); + + res.json({ + token: userService.genJwt(user, Noco.getConfig()), + } as any); + } catch (e) { + console.log(e); + throw e; + } +} + +async function signin(req, res, next) { + passport.authenticate( + 'local', + { session: false }, + async (err, user, info): Promise => + await successfulSignIn({ + user, + err, + info, + req, + res, + auditDescription: 'signed in', + }) + )(req, res, next); +} + +async function googleSignin(req, res, next) { + passport.authenticate( + 'google', + { + session: false, + callbackURL: req.ncSiteUrl + Noco.getConfig().dashboardPath, + }, + async (err, user, info): Promise => + await successfulSignIn({ + user, + err, + info, + req, + res, + auditDescription: 'signed in using Google Auth', + }) + )(req, res, next); +} + +async function me(req, res): Promise { + res.json(req?.session?.passport?.user ?? {}); +} + +async function passwordChange(req: Request, res): Promise { + if (!(req as any).isAuthenticated()) { + NcError.forbidden('Not allowed'); + } + + await userService.passwordChange({ + user: req['user'], + req, + body: req.body, + }); + + res.json({ msg: 'Password updated successfully' }); +} + +async function passwordForgot(req: Request, res): Promise { + await userService.passwordForgot({ + siteUrl: (req as any).ncSiteUrl, + body: req.body, + req, + }); + + res.json({ msg: 'Please check your email to reset the password' }); +} + +async function tokenValidate(req, res): Promise { + await userService.tokenValidate({ + token: req.params.tokenId, + }); + res.json(true); +} + +async function passwordReset(req, res): Promise { + await userService.passwordReset({ + token: req.params.tokenId, + body: req.body, + req, + }); + + res.json({ msg: 'Password reset successful' }); +} + +async function emailVerification(req, res): Promise { + await userService.emailVerification({ + token: req.params.tokenId, + req, + }); + + res.json({ msg: 'Email verified successfully' }); +} + +async function renderPasswordReset(req, res): Promise { + try { + res.send( + ejs.render((await import('./ui/auth/resetPassword')).default, { + ncPublicUrl: process.env.NC_PUBLIC_URL || '', + token: JSON.stringify(req.params.tokenId), + baseUrl: `/`, + }) + ); + } catch (e) { + return res.status(400).json({ msg: e.message }); + } +} + +const mapRoutes = (router) => { + // todo: old api - /auth/signup?tool=1 + router.post('/auth/user/signup', catchError(signup)); + router.post('/auth/user/signin', catchError(signin)); + router.get('/auth/user/me', extractProjectIdAndAuthenticate, catchError(me)); + router.post('/auth/password/forgot', catchError(passwordForgot)); + router.post('/auth/token/validate/:tokenId', catchError(tokenValidate)); + router.post('/auth/password/reset/:tokenId', catchError(passwordReset)); + router.post('/auth/email/validate/:tokenId', catchError(emailVerification)); + router.post( + '/user/password/change', + ncMetaAclMw(passwordChange, 'passwordChange') + ); + router.post('/auth/token/refresh', catchError(refreshToken)); + + /* Google auth apis */ + + router.post(`/auth/google/genTokenByCode`, catchError(googleSignin)); + + router.get('/auth/google', (req: any, res, next) => + passport.authenticate('google', { + scope: ['profile', 'email'], + state: req.query.state, + callbackURL: req.ncSiteUrl + Noco.getConfig().dashboardPath, + })(req, res, next) + ); + + // deprecated APIs + router.post('/api/v1/db/auth/user/signup', catchError(signup)); + router.post('/api/v1/db/auth/user/signin', catchError(signin)); + router.get( + '/api/v1/db/auth/user/me', + extractProjectIdAndAuthenticate, + catchError(me) + ); + router.post('/api/v1/db/auth/password/forgot', catchError(passwordForgot)); + router.post( + '/api/v1/db/auth/token/validate/:tokenId', + catchError(tokenValidate) + ); + router.post( + '/api/v1/db/auth/password/reset/:tokenId', + catchError(passwordReset) + ); + router.post( + '/api/v1/db/auth/email/validate/:tokenId', + catchError(emailVerification) + ); + router.post( + '/api/v1/db/auth/password/change', + ncMetaAclMw(passwordChange, 'passwordChange') + ); + router.post('/api/v1/db/auth/token/refresh', catchError(refreshToken)); + router.get( + '/api/v1/db/auth/password/reset/:tokenId', + catchError(renderPasswordReset) + ); + + // new API + router.post('/api/v1/auth/user/signup', catchError(signup)); + router.post('/api/v1/auth/user/signin', catchError(signin)); + router.get( + '/api/v1/auth/user/me', + extractProjectIdAndAuthenticate, + catchError(me) + ); + router.post('/api/v1/auth/password/forgot', catchError(passwordForgot)); + router.post( + '/api/v1/auth/token/validate/:tokenId', + catchError(tokenValidate) + ); + router.post( + '/api/v1/auth/password/reset/:tokenId', + catchError(passwordReset) + ); + router.post( + '/api/v1/auth/email/validate/:tokenId', + catchError(emailVerification) + ); + router.post( + '/api/v1/auth/password/change', + ncMetaAclMw(passwordChange, 'passwordChange') + ); + router.post('/api/v1/auth/token/refresh', catchError(refreshToken)); + // respond with password reset page + router.get('/auth/password/reset/:tokenId', catchError(renderPasswordReset)); +}; +export default mapRoutes; diff --git a/packages/nocodb/src/lib/controllers/util.ctl.ts b/packages/nocodb/src/lib/controllers/util.ctl.ts new file mode 100644 index 0000000000..79fd64bebe --- /dev/null +++ b/packages/nocodb/src/lib/controllers/util.ctl.ts @@ -0,0 +1,59 @@ +// // Project CRUD +import ncMetaAclMw from '../meta/helpers/ncMetaAclMw'; +import catchError from '../meta/helpers/catchError'; +import { utilService } from '../services'; +import type { Request, Response } from 'express'; + +export async function testConnection(req: Request, res: Response) { + res.json(await utilService.testConnection({ body: req.body })); +} + +export async function appInfo(req: Request, res: Response) { + res.json( + await utilService.appInfo({ + req: { + ncSiteUrl: (req as any).ncSiteUrl, + }, + }) + ); +} + +export async function versionInfo(_req: Request, res: Response) { + res.json(await utilService.versionInfo()); +} + +export async function appHealth(_: Request, res: Response) { + res.json(await utilService.appHealth()); +} + +export async function axiosRequestMake(req: Request, res: Response) { + res.json(await utilService.axiosRequestMake({ body: req.body })); +} + +export async function aggregatedMetaInfo(_req: Request, res: Response) { + res.json(await utilService.aggregatedMetaInfo()); +} + +export async function urlToDbConfig(req: Request, res: Response) { + res.json( + await utilService.urlToDbConfig({ + body: req.body, + }) + ); +} + +export default (router) => { + router.post( + '/api/v1/db/meta/connection/test', + ncMetaAclMw(testConnection, 'testConnection') + ); + router.get('/api/v1/db/meta/nocodb/info', catchError(appInfo)); + router.post('/api/v1/db/meta/axiosRequestMake', catchError(axiosRequestMake)); + router.get('/api/v1/version', catchError(versionInfo)); + router.get('/api/v1/health', catchError(appHealth)); + router.post('/api/v1/url_to_config', catchError(urlToDbConfig)); + router.get( + '/api/v1/aggregated-meta-info', + ncMetaAclMw(aggregatedMetaInfo, 'aggregatedMetaInfo') + ); +}; diff --git a/packages/nocodb/src/lib/controllers/view.ctl.ts b/packages/nocodb/src/lib/controllers/view.ctl.ts new file mode 100644 index 0000000000..b8bdef857d --- /dev/null +++ b/packages/nocodb/src/lib/controllers/view.ctl.ts @@ -0,0 +1,134 @@ +import { Router } from 'express'; +import { PagedResponseImpl } from '../meta/helpers/PagedResponse'; +import ncMetaAclMw from '../meta/helpers/ncMetaAclMw'; +import { metaApiMetrics } from '../meta/helpers/apiMetrics'; +import { viewService } from '../services'; +import type { View } from '../models'; +import type { Request, Response } from 'express'; + +// @ts-ignore +export async function viewGet(req: Request, res: Response) {} + +// @ts-ignore +export async function viewList(req: Request, res: Response) { + const filteredViewList = await viewService.viewList({ + tableId: req.params.tableId, + user: (req as any).session?.passport?.user, + }); + + res.json(new PagedResponseImpl(filteredViewList)); +} + +// @ts-ignore +export async function shareView( + req: Request, + res: Response +) { + res.json(await viewService.shareView({ viewId: req.params.viewId })); +} + +// @ts-ignore +export async function viewCreate(req: Request, res, next) {} + +// @ts-ignore +export async function viewUpdate(req, res) { + const result = await viewService.viewUpdate({ + viewId: req.params.viewId, + view: req.body, + }); + res.json(result); +} + +// @ts-ignore +export async function viewDelete(req: Request, res: Response, next) { + const result = await viewService.viewDelete({ viewId: req.params.viewId }); + res.json(result); +} + +async function shareViewUpdate(req: Request, res) { + res.json( + await viewService.shareViewUpdate({ + viewId: req.params.viewId, + sharedView: req.body, + }) + ); +} + +async function shareViewDelete(req: Request, res) { + res.json(await viewService.shareViewDelete({ viewId: req.params.viewId })); +} + +async function showAllColumns(req: Request, res) { + res.json( + await viewService.showAllColumns({ + viewId: req.params.viewId, + ignoreIds: (req.query?.ignoreIds || []), + }) + ); +} + +async function hideAllColumns(req: Request, res) { + res.json( + await viewService.hideAllColumns({ + viewId: req.params.viewId, + ignoreIds: (req.query?.ignoreIds || []), + }) + ); +} + +async function shareViewList(req: Request, res) { + res.json( + await viewService.shareViewList({ + tableId: req.params.tableId, + }) + ); +} + +const router = Router({ mergeParams: true }); +router.get( + '/api/v1/db/meta/tables/:tableId/views', + metaApiMetrics, + ncMetaAclMw(viewList, 'viewList') +); +router.patch( + '/api/v1/db/meta/views/:viewId', + metaApiMetrics, + ncMetaAclMw(viewUpdate, 'viewUpdate') +); +router.delete( + '/api/v1/db/meta/views/:viewId', + metaApiMetrics, + ncMetaAclMw(viewDelete, 'viewDelete') +); +router.post( + '/api/v1/db/meta/views/:viewId/show-all', + metaApiMetrics, + ncMetaAclMw(showAllColumns, 'showAllColumns') +); +router.post( + '/api/v1/db/meta/views/:viewId/hide-all', + metaApiMetrics, + ncMetaAclMw(hideAllColumns, 'hideAllColumns') +); + +router.get( + '/api/v1/db/meta/tables/:tableId/share', + metaApiMetrics, + ncMetaAclMw(shareViewList, 'shareViewList') +); +router.post( + '/api/v1/db/meta/views/:viewId/share', + ncMetaAclMw(shareView, 'shareView') +); +router.patch( + '/api/v1/db/meta/views/:viewId/share', + metaApiMetrics, + ncMetaAclMw(shareViewUpdate, 'shareViewUpdate') +); +router.delete( + '/api/v1/db/meta/views/:viewId/share', + metaApiMetrics, + ncMetaAclMw(shareViewDelete, 'shareViewDelete') +); + +export default router; diff --git a/packages/nocodb/src/lib/meta/api/viewColumnApis.ts b/packages/nocodb/src/lib/controllers/viewColumn.ctl.ts similarity index 53% rename from packages/nocodb/src/lib/meta/api/viewColumnApis.ts rename to packages/nocodb/src/lib/controllers/viewColumn.ctl.ts index 2fc4df7625..5141372583 100644 --- a/packages/nocodb/src/lib/meta/api/viewColumnApis.ts +++ b/packages/nocodb/src/lib/controllers/viewColumn.ctl.ts @@ -1,33 +1,31 @@ -import { Request, Response, Router } from 'express'; -import View from '../../models/View'; -import { Tele } from 'nc-help'; -import ncMetaAclMw from '../helpers/ncMetaAclMw'; -import { metaApiMetrics } from '../helpers/apiMetrics'; +import { Router } from 'express'; +import ncMetaAclMw from '../meta/helpers/ncMetaAclMw'; +import { metaApiMetrics } from '../meta/helpers/apiMetrics'; +import { viewColumnService } from '../services'; +import type { Request, Response } from 'express'; export async function columnList(req: Request, res: Response) { - res.json(await View.getColumns(req.params.viewId)); + res.json(await viewColumnService.columnList({ viewId: req.params.viewId })); } + export async function columnAdd(req: Request, res: Response) { - const viewColumn = await View.insertOrUpdateColumn( - req.params.viewId, - req.body.fk_column_id, - { + const viewColumn = await viewColumnService.columnAdd({ + viewId: req.params.viewId, + columnId: req.body.fk_column_id, + column: { ...req.body, view_id: req.params.viewId, - } - ); - Tele.emit('evt', { evt_type: 'viewColumn:inserted' }); - + }, + }); res.json(viewColumn); } export async function columnUpdate(req: Request, res: Response) { - const result = await View.updateColumn( - req.params.viewId, - req.params.columnId, - req.body - ); - Tele.emit('evt', { evt_type: 'viewColumn:updated' }); + const result = await viewColumnService.columnUpdate({ + viewId: req.params.viewId, + columnId: req.params.columnId, + column: req.body, + }); res.json(result); } diff --git a/packages/nocodb/src/lib/controllers/views/formView.ctl.ts b/packages/nocodb/src/lib/controllers/views/formView.ctl.ts new file mode 100644 index 0000000000..851ab7cb16 --- /dev/null +++ b/packages/nocodb/src/lib/controllers/views/formView.ctl.ts @@ -0,0 +1,49 @@ +import { Router } from 'express'; +import ncMetaAclMw from '../../meta/helpers/ncMetaAclMw'; +import { metaApiMetrics } from '../../meta/helpers/apiMetrics'; +import { formViewService } from '../../services'; +import type { FormType } from 'nocodb-sdk'; +import type { Request, Response } from 'express'; + +export async function formViewGet(req: Request, res: Response) { + const formViewData = await formViewService.formViewGet({ + formViewId: req.params.formViewId, + }); + res.json(formViewData); +} + +export async function formViewCreate(req: Request, res) { + const view = await formViewService.formViewCreate({ + body: req.body, + tableId: req.params.tableId, + }); + res.json(view); +} + +export async function formViewUpdate(req, res) { + res.json( + await formViewService.formViewUpdate({ + formViewId: req.params.formViewId, + body: req.body, + }) + ); +} + +const router = Router({ mergeParams: true }); +router.post( + '/api/v1/db/meta/tables/:tableId/forms', + metaApiMetrics, + ncMetaAclMw(formViewCreate, 'formViewCreate') +); +router.get( + '/api/v1/db/meta/forms/:formViewId', + metaApiMetrics, + ncMetaAclMw(formViewGet, 'formViewGet') +); +router.patch( + '/api/v1/db/meta/forms/:formViewId', + metaApiMetrics, + ncMetaAclMw(formViewUpdate, 'formViewUpdate') +); + +export default router; diff --git a/packages/nocodb/src/lib/controllers/views/formViewColumn.ctl.ts b/packages/nocodb/src/lib/controllers/views/formViewColumn.ctl.ts new file mode 100644 index 0000000000..21596c5360 --- /dev/null +++ b/packages/nocodb/src/lib/controllers/views/formViewColumn.ctl.ts @@ -0,0 +1,22 @@ +import { Router } from 'express'; +import ncMetaAclMw from '../../meta/helpers/ncMetaAclMw'; +import { metaApiMetrics } from '../../meta/helpers/apiMetrics'; +import { formViewColumnService } from '../../services'; +import type { Request, Response } from 'express'; + +export async function columnUpdate(req: Request, res: Response) { + res.json( + await formViewColumnService.columnUpdate({ + formViewColumnId: req.params.formViewColumnId, + formViewColumn: req.body, + }) + ); +} + +const router = Router({ mergeParams: true }); +router.patch( + '/api/v1/db/meta/form-columns/:formViewColumnId', + metaApiMetrics, + ncMetaAclMw(columnUpdate, 'columnUpdate') +); +export default router; diff --git a/packages/nocodb/src/lib/controllers/views/galleryView.ctl.ts b/packages/nocodb/src/lib/controllers/views/galleryView.ctl.ts new file mode 100644 index 0000000000..a32198903b --- /dev/null +++ b/packages/nocodb/src/lib/controllers/views/galleryView.ctl.ts @@ -0,0 +1,50 @@ +import { Router } from 'express'; +import ncMetaAclMw from '../../meta/helpers/ncMetaAclMw'; +import { metaApiMetrics } from '../../meta/helpers/apiMetrics'; +import { galleryViewService } from '../../services'; +import type { GalleryType } from 'nocodb-sdk'; +import type { Request, Response } from 'express'; + +export async function galleryViewGet(req: Request, res: Response) { + res.json( + await galleryViewService.galleryViewGet({ + galleryViewId: req.params.galleryViewId, + }) + ); +} + +export async function galleryViewCreate(req: Request, res) { + const view = await galleryViewService.galleryViewCreate({ + gallery: req.body, + // todo: sanitize + tableId: req.params.tableId, + }); + res.json(view); +} + +export async function galleryViewUpdate(req, res) { + res.json( + await galleryViewService.galleryViewUpdate({ + galleryViewId: req.params.galleryViewId, + gallery: req.body, + }) + ); +} + +const router = Router({ mergeParams: true }); +router.post( + '/api/v1/db/meta/tables/:tableId/galleries', + metaApiMetrics, + ncMetaAclMw(galleryViewCreate, 'galleryViewCreate') +); +router.patch( + '/api/v1/db/meta/galleries/:galleryViewId', + metaApiMetrics, + ncMetaAclMw(galleryViewUpdate, 'galleryViewUpdate') +); +router.get( + '/api/v1/db/meta/galleries/:galleryViewId', + metaApiMetrics, + ncMetaAclMw(galleryViewGet, 'galleryViewGet') +); +export default router; diff --git a/packages/nocodb/src/lib/controllers/views/gridView.ctl.ts b/packages/nocodb/src/lib/controllers/views/gridView.ctl.ts new file mode 100644 index 0000000000..e2ab7a6ff8 --- /dev/null +++ b/packages/nocodb/src/lib/controllers/views/gridView.ctl.ts @@ -0,0 +1,35 @@ +import { Router } from 'express'; +import ncMetaAclMw from '../../meta/helpers/ncMetaAclMw'; +import { metaApiMetrics } from '../../meta/helpers/apiMetrics'; +import { gridViewService } from '../../services'; +import type { Request } from 'express'; + +export async function gridViewCreate(req: Request, res) { + const view = await gridViewService.gridViewCreate({ + grid: req.body, + tableId: req.params.tableId, + }); + res.json(view); +} + +export async function gridViewUpdate(req, res) { + res.json( + await gridViewService.gridViewUpdate({ + viewId: req.params.viewId, + grid: req.body, + }) + ); +} + +const router = Router({ mergeParams: true }); +router.post( + '/api/v1/db/meta/tables/:tableId/grids/', + metaApiMetrics, + ncMetaAclMw(gridViewCreate, 'gridViewCreate') +); +router.patch( + '/api/v1/db/meta/grids/:viewId', + metaApiMetrics, + ncMetaAclMw(gridViewUpdate, 'gridViewUpdate') +); +export default router; diff --git a/packages/nocodb/src/lib/controllers/views/gridViewColumn.ctl.ts b/packages/nocodb/src/lib/controllers/views/gridViewColumn.ctl.ts new file mode 100644 index 0000000000..89f02f6a7f --- /dev/null +++ b/packages/nocodb/src/lib/controllers/views/gridViewColumn.ctl.ts @@ -0,0 +1,35 @@ +import { Router } from 'express'; +import ncMetaAclMw from '../../meta/helpers/ncMetaAclMw'; +import { metaApiMetrics } from '../../meta/helpers/apiMetrics'; +import { gridViewColumnService } from '../../services'; +import type { Request, Response } from 'express'; + +export async function columnList(req: Request, res: Response) { + res.json( + await gridViewColumnService.columnList({ + gridViewId: req.params.gridViewId, + }) + ); +} + +export async function gridColumnUpdate(req: Request, res: Response) { + res.json( + await gridViewColumnService.gridColumnUpdate({ + gridViewColumnId: req.params.gridViewColumnId, + grid: req.body, + }) + ); +} + +const router = Router({ mergeParams: true }); +router.get( + '/api/v1/db/meta/grids/:gridViewId/grid-columns', + metaApiMetrics, + ncMetaAclMw(columnList, 'columnList') +); +router.patch( + '/api/v1/db/meta/grid-columns/:gridViewColumnId', + metaApiMetrics, + ncMetaAclMw(gridColumnUpdate, 'gridColumnUpdate') +); +export default router; diff --git a/packages/nocodb/src/lib/meta/api/kanbanViewApis.ts b/packages/nocodb/src/lib/controllers/views/kanbanView.ctl.ts similarity index 64% rename from packages/nocodb/src/lib/meta/api/kanbanViewApis.ts rename to packages/nocodb/src/lib/controllers/views/kanbanView.ctl.ts index c8d864bf82..fab14d3b1f 100644 --- a/packages/nocodb/src/lib/meta/api/kanbanViewApis.ts +++ b/packages/nocodb/src/lib/controllers/views/kanbanView.ctl.ts @@ -1,18 +1,21 @@ -import { Request, Response, Router } from 'express'; -import { KanbanType, ViewTypes } from 'nocodb-sdk'; +import { Router } from 'express'; +import { ViewTypes } from 'nocodb-sdk'; +import { T } from 'nc-help'; import View from '../../models/View'; import KanbanView from '../../models/KanbanView'; -import { Tele } from 'nc-help'; -import ncMetaAclMw from '../helpers/ncMetaAclMw'; -import { metaApiMetrics } from '../helpers/apiMetrics'; -import { getAjvValidatorMw } from './helpers'; +import ncMetaAclMw from '../../meta/helpers/ncMetaAclMw'; +import { metaApiMetrics } from '../../meta/helpers/apiMetrics'; +import type { KanbanType } from 'nocodb-sdk'; +import type { Request, Response } from 'express'; + +// todo: map to service export async function kanbanViewGet(req: Request, res: Response) { res.json(await KanbanView.get(req.params.kanbanViewId)); } export async function kanbanViewCreate(req: Request, res) { - Tele.emit('evt', { evt_type: 'vtable:created', show_as: 'kanban' }); + T.emit('evt', { evt_type: 'vtable:created', show_as: 'kanban' }); const view = await View.insert({ ...req.body, // todo: sanitize @@ -23,7 +26,7 @@ export async function kanbanViewCreate(req: Request, res) { } export async function kanbanViewUpdate(req, res) { - Tele.emit('evt', { evt_type: 'view:updated', type: 'kanban' }); + T.emit('evt', { evt_type: 'view:updated', type: 'kanban' }); res.json(await KanbanView.update(req.params.kanbanViewId, req.body)); } @@ -32,13 +35,11 @@ const router = Router({ mergeParams: true }); router.post( '/api/v1/db/meta/tables/:tableId/kanbans', metaApiMetrics, - getAjvValidatorMw('swagger.json#/components/schemas/KanbanReq'), ncMetaAclMw(kanbanViewCreate, 'kanbanViewCreate') ); router.patch( '/api/v1/db/meta/kanbans/:kanbanViewId', metaApiMetrics, - getAjvValidatorMw('swagger.json#/components/schemas/KanbanUpdateReq'), ncMetaAclMw(kanbanViewUpdate, 'kanbanViewUpdate') ); router.get( diff --git a/packages/nocodb/src/lib/controllers/views/mapView.ctl.ts b/packages/nocodb/src/lib/controllers/views/mapView.ctl.ts new file mode 100644 index 0000000000..e19cc3c353 --- /dev/null +++ b/packages/nocodb/src/lib/controllers/views/mapView.ctl.ts @@ -0,0 +1,49 @@ +import { Router } from 'express'; +import ncMetaAclMw from '../../meta/helpers/ncMetaAclMw'; +import { metaApiMetrics } from '../../meta/helpers/apiMetrics'; +import { mapViewService } from '../../services'; +import type { MapType } from 'nocodb-sdk'; +import type { Request, Response } from 'express'; + +export async function mapViewGet(req: Request, res: Response) { + res.json( + await mapViewService.mapViewGet({ mapViewId: req.params.mapViewId }) + ); +} + +export async function mapViewCreate(req: Request, res) { + const view = await mapViewService.mapViewCreate({ + tableId: req.params.tableId, + map: req.body, + }); + res.json(view); +} + +export async function mapViewUpdate(req, res) { + res.json( + await mapViewService.mapViewUpdate({ + mapViewId: req.params.mapViewId, + map: req.body, + }) + ); +} + +const router = Router({ mergeParams: true }); + +// todo: add schema in swagger and use getAjvValidatorMw +router.post( + '/api/v1/db/meta/tables/:tableId/maps', + metaApiMetrics, + ncMetaAclMw(mapViewCreate, 'mapViewCreate') +); +router.patch( + '/api/v1/db/meta/maps/:mapViewId', + metaApiMetrics, + ncMetaAclMw(mapViewUpdate, 'mapViewUpdate') +); +router.get( + '/api/v1/db/meta/maps/:mapViewId', + metaApiMetrics, + ncMetaAclMw(mapViewGet, 'mapViewGet') +); +export default router; diff --git a/packages/nocodb/src/lib/db/sql-client/lib/KnexClient.ts b/packages/nocodb/src/lib/db/sql-client/lib/KnexClient.ts index 9c47ab34ac..319885de78 100644 --- a/packages/nocodb/src/lib/db/sql-client/lib/KnexClient.ts +++ b/packages/nocodb/src/lib/db/sql-client/lib/KnexClient.ts @@ -1,19 +1,20 @@ /* eslint-disable no-constant-condition */ -import { knex, Knex } from 'knex'; -import { Tele } from 'nc-help'; -import Debug from '../../util/Debug'; -import Emit from '../../util/emit'; -import Result from '../../util/Result'; +import fs from 'fs'; +import { promisify } from 'util'; +import path from 'path'; +import { knex } from 'knex'; +import { T } from 'nc-help'; import findIndex from 'lodash/findIndex'; import find from 'lodash/find'; -import fs from 'fs'; -import { promisify } from 'util'; import jsonfile from 'jsonfile'; -import path from 'path'; import mkdirp from 'mkdirp'; +import Result from '../../util/Result'; +import Emit from '../../util/emit'; +import Debug from '../../util/Debug'; import * as dataHelp from './data.helper'; import SqlClient from './SqlClient'; +import type { Knex } from 'knex'; const evt = new Emit(); const log = new Debug('KnexClient'); @@ -620,7 +621,7 @@ class KnexClient extends SqlClient { KnexClient.___ext = await this._validateInput(); } if (!KnexClient.___ext) { - Tele.emit('evt', { + T.emit('evt', { evt_type: 'project:external', payload: null, check: true, diff --git a/packages/nocodb/src/lib/db/sql-client/lib/SqlClientFactory.ts b/packages/nocodb/src/lib/db/sql-client/lib/SqlClientFactory.ts index 09918843a6..3781b1976d 100644 --- a/packages/nocodb/src/lib/db/sql-client/lib/SqlClientFactory.ts +++ b/packages/nocodb/src/lib/db/sql-client/lib/SqlClientFactory.ts @@ -1,3 +1,5 @@ +import fs from 'fs'; +import { promisify } from 'util'; import Noco from '../../../Noco'; import SqlClientFactoryEE from './ee/SqlClientFactoryEE'; import MySqlClient from './mysql/MysqlClient'; @@ -9,9 +11,6 @@ import YugabyteClient from './pg/YugabyteClient'; import TidbClient from './mysql/TidbClient'; import VitessClient from './mysql/VitessClient'; -import fs from 'fs'; -import { promisify } from 'util'; - export class SqlClientFactory { static create(connectionConfig) { connectionConfig.meta = connectionConfig.meta || {}; diff --git a/packages/nocodb/src/lib/db/sql-client/lib/ee/SqlClientFactoryEE.ts b/packages/nocodb/src/lib/db/sql-client/lib/ee/SqlClientFactoryEE.ts index 63df3a1221..05bad304a1 100644 --- a/packages/nocodb/src/lib/db/sql-client/lib/ee/SqlClientFactoryEE.ts +++ b/packages/nocodb/src/lib/db/sql-client/lib/ee/SqlClientFactoryEE.ts @@ -1,6 +1,6 @@ +import { SnowflakeClient } from 'nc-help'; import { SqlClientFactory } from '../SqlClientFactory'; import SfClient from '../snowflake/SnowflakeClient'; -import { SnowflakeClient } from 'nc-help'; class SqlClientFactoryEE { static create(connectionConfig) { diff --git a/packages/nocodb/src/lib/db/sql-client/lib/mssql/MssqlClient.ts b/packages/nocodb/src/lib/db/sql-client/lib/mssql/MssqlClient.ts index c7f59aafc1..2b48207ca3 100644 --- a/packages/nocodb/src/lib/db/sql-client/lib/mssql/MssqlClient.ts +++ b/packages/nocodb/src/lib/db/sql-client/lib/mssql/MssqlClient.ts @@ -1,10 +1,9 @@ -import { ColumnType } from 'nocodb-sdk'; - import knex from 'knex'; +import find from 'lodash/find'; import KnexClient from '../KnexClient'; import Debug from '../../../util/Debug'; import Result from '../../../util/Result'; -import find from 'lodash/find'; +import type { ColumnType } from 'nocodb-sdk'; const log = new Debug('MssqlClient'); diff --git a/packages/nocodb/src/lib/db/sql-client/lib/mysql/MysqlClient.ts b/packages/nocodb/src/lib/db/sql-client/lib/mysql/MysqlClient.ts index da09d9d47b..1b223bd0bf 100644 --- a/packages/nocodb/src/lib/db/sql-client/lib/mysql/MysqlClient.ts +++ b/packages/nocodb/src/lib/db/sql-client/lib/mysql/MysqlClient.ts @@ -1,24 +1,23 @@ +import path from 'path'; +import { promisify } from 'util'; import knex from 'knex'; import isEmpty from 'lodash/isEmpty'; import mapKeys from 'lodash/mapKeys'; import find from 'lodash/find'; +import jsonfile from 'jsonfile'; +import mkdirp from 'mkdirp'; +import { nanoid } from 'nanoid'; +import levenshtein from 'fast-levenshtein'; import Debug from '../../../util/Debug'; import Emit from '../../../util/emit'; import Result from '../../../util/Result'; -import queries from './mysql.queries'; import KnexClient from '../KnexClient'; -import jsonfile from 'jsonfile'; -import path from 'path'; -import mkdirp from 'mkdirp'; -import { promisify } from 'util'; - -import { nanoid } from 'nanoid'; +import queries from './mysql.queries'; import fakerFunctionList from './fakerFunctionList'; import * as findDataType from './findDataTypeMapping'; -import levenshtein from 'fast-levenshtein'; const log = new Debug('MysqlClient'); const evt = new Emit(); diff --git a/packages/nocodb/src/lib/db/sql-client/lib/oracle/OracleClient.ts b/packages/nocodb/src/lib/db/sql-client/lib/oracle/OracleClient.ts index 4f01353ba0..494b378080 100644 --- a/packages/nocodb/src/lib/db/sql-client/lib/oracle/OracleClient.ts +++ b/packages/nocodb/src/lib/db/sql-client/lib/oracle/OracleClient.ts @@ -1,9 +1,9 @@ import knex from 'knex'; +import mapKeys from 'lodash/mapKeys'; +import find from 'lodash/find'; import KnexClient from '../KnexClient'; import Debug from '../../../util/Debug'; import Result from '../../../util/Result'; -import mapKeys from 'lodash/mapKeys'; -import find from 'lodash/find'; const log = new Debug('OracleClient'); diff --git a/packages/nocodb/src/lib/db/sql-client/lib/pg/PgClient.ts b/packages/nocodb/src/lib/db/sql-client/lib/pg/PgClient.ts index 90e0ec9b1d..1bc509ccbc 100644 --- a/packages/nocodb/src/lib/db/sql-client/lib/pg/PgClient.ts +++ b/packages/nocodb/src/lib/db/sql-client/lib/pg/PgClient.ts @@ -1,13 +1,13 @@ import { nanoid } from 'nanoid'; import knex from 'knex'; +import isEmpty from 'lodash/isEmpty'; +import mapKeys from 'lodash/mapKeys'; +import find from 'lodash/find'; import KnexClient from '../KnexClient'; import Debug from '../../../util/Debug'; import Result from '../../../util/Result'; import queries from './pg.queries'; -import isEmpty from 'lodash/isEmpty'; -import mapKeys from 'lodash/mapKeys'; -import find from 'lodash/find'; const log = new Debug('PGClient'); class PGClient extends KnexClient { diff --git a/packages/nocodb/src/lib/db/sql-client/lib/pg/YugabyteClient.ts b/packages/nocodb/src/lib/db/sql-client/lib/pg/YugabyteClient.ts index 3dd206007e..17630e1f72 100644 --- a/packages/nocodb/src/lib/db/sql-client/lib/pg/YugabyteClient.ts +++ b/packages/nocodb/src/lib/db/sql-client/lib/pg/YugabyteClient.ts @@ -1,6 +1,6 @@ -import PGClient from './PgClient'; import Debug from '../../../util/Debug'; import Result from '../../../util/Result'; +import PGClient from './PgClient'; const log = new Debug('YBClient'); diff --git a/packages/nocodb/src/lib/db/sql-client/lib/snowflake/SnowflakeClient.ts b/packages/nocodb/src/lib/db/sql-client/lib/snowflake/SnowflakeClient.ts index 1f3b37ff12..f364e16fcd 100644 --- a/packages/nocodb/src/lib/db/sql-client/lib/snowflake/SnowflakeClient.ts +++ b/packages/nocodb/src/lib/db/sql-client/lib/snowflake/SnowflakeClient.ts @@ -1,11 +1,11 @@ import { nanoid } from 'nanoid'; import _ from 'lodash'; +import lodash from 'lodash'; import KnexClient from '../KnexClient'; import Debug from '../../../util/Debug'; import Result from '../../../util/Result'; import queries from './snowflake.queries'; -import lodash from 'lodash'; const log = new Debug('SnowflakeClient'); const rowsToLower = (arr) => { diff --git a/packages/nocodb/src/lib/db/sql-client/lib/sqlite/SqliteClient.ts b/packages/nocodb/src/lib/db/sql-client/lib/sqlite/SqliteClient.ts index ccced13ce2..0a35494cce 100644 --- a/packages/nocodb/src/lib/db/sql-client/lib/sqlite/SqliteClient.ts +++ b/packages/nocodb/src/lib/db/sql-client/lib/sqlite/SqliteClient.ts @@ -1,14 +1,14 @@ import { promisify } from 'util'; -import knex from 'knex'; import fs from 'fs'; -import KnexClient from '../KnexClient'; -import Debug from '../../../util/Debug'; -import Result from '../../../util/Result'; -import queries from './sqlite.queries'; +import knex from 'knex'; import isEmpty from 'lodash/isEmpty'; import mapKeys from 'lodash/mapKeys'; import find from 'lodash/find'; import { customAlphabet } from 'nanoid'; +import KnexClient from '../KnexClient'; +import Debug from '../../../util/Debug'; +import Result from '../../../util/Result'; +import queries from './sqlite.queries'; const nanoid = customAlphabet('1234567890abcdefghijklmnopqrstuvwxyz_', 6); @@ -2006,7 +2006,7 @@ class SqliteClient extends KnexClient { if (change === 2) { const suffix = nanoid(); - let backupOldColumnQuery = this.genQuery( + const backupOldColumnQuery = this.genQuery( `ALTER TABLE ?? RENAME COLUMN ?? TO ??;`, [t, o.cn, `${o.cno}_nc_${suffix}`], shouldSanitize @@ -2031,13 +2031,13 @@ class SqliteClient extends KnexClient { shouldSanitize ); - let updateNewColumnQuery = this.genQuery( + const updateNewColumnQuery = this.genQuery( `UPDATE ?? SET ?? = ??;`, [t, n.cn, `${o.cno}_nc_${suffix}`], shouldSanitize ); - let dropOldColumnQuery = this.genQuery( + const dropOldColumnQuery = this.genQuery( `ALTER TABLE ?? DROP COLUMN ??;`, [t, `${o.cno}_nc_${suffix}`], shouldSanitize diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/BaseModel.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/BaseModel.ts index 8a542c3d53..1f4989c0cd 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/BaseModel.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/BaseModel.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/ban-types,prefer-const */ -import { Knex } from 'knex'; -import Filter from '../../../models/Filter'; -import Sort from '../../../models/Sort'; +import type { Knex } from 'knex'; +import type Filter from '../../../models/Filter'; +import type Sort from '../../../models/Sort'; const autoBind = require('auto-bind'); const _ = require('lodash'); diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSql.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSql.ts index 74a10ee349..34a20c4c27 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSql.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSql.ts @@ -2,10 +2,11 @@ import autoBind from 'auto-bind'; import _ from 'lodash'; import Validator from 'validator'; -import BaseModel, { XcFilter, XcFilterWithAlias } from '../BaseModel'; +import Papaparse from 'papaparse'; +import BaseModel from '../BaseModel'; import formulaQueryBuilder from './formulaQueryBuilderFromString'; import genRollupSelect from './genRollupSelect'; -import Papaparse from 'papaparse'; +import type { XcFilter, XcFilterWithAlias } from '../BaseModel'; /** * Base class for models diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts index 8934f85616..e5902ab23c 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts @@ -1,35 +1,29 @@ import autoBind from 'auto-bind'; import _ from 'lodash'; -import Model from '../../../../models/Model'; -import SelectOption from '../../../../models/SelectOption'; -import { XKnex } from '../../index'; -import LinkToAnotherRecordColumn from '../../../../models/LinkToAnotherRecordColumn'; -import RollupColumn from '../../../../models/RollupColumn'; -import LookupColumn from '../../../../models/LookupColumn'; import DataLoader from 'dataloader'; -import Column from '../../../../models/Column'; -import { XcFilter, XcFilterWithAlias } from '../BaseModel'; -import conditionV2 from './conditionV2'; -import Filter from '../../../../models/Filter'; -import sortV2 from './sortV2'; -import Sort from '../../../../models/Sort'; -import FormulaColumn from '../../../../models/FormulaColumn'; -import genRollupSelectv2 from './genRollupSelectv2'; -import formulaQueryBuilderv2 from './formulav2/formulaQueryBuilderv2'; -import { Knex } from 'knex'; -import View from '../../../../models/View'; import { AuditOperationSubTypes, AuditOperationTypes, isVirtualCol, RelationTypes, - SortType, UITypes, ViewTypes, } from 'nocodb-sdk'; -import formSubmissionEmailTemplate from '../../../../utils/common/formSubmissionEmailTemplate'; import ejs from 'ejs'; +import Validator from 'validator'; +import { customAlphabet } from 'nanoid'; +import DOMPurify from 'isomorphic-dompurify'; +import Model from '../../../../models/Model'; +import Column from '../../../../models/Column'; +import Filter, { + COMPARISON_OPS, + COMPARISON_SUB_OPS, + IS_WITHIN_COMPARISON_SUB_OPS, +} from '../../../../models/Filter'; +import Sort from '../../../../models/Sort'; +import View from '../../../../models/View'; +import formSubmissionEmailTemplate from '../../../../utils/common/formSubmissionEmailTemplate'; import Audit from '../../../../models/Audit'; import FormView from '../../../../models/FormView'; import Hook from '../../../../models/Hook'; @@ -38,14 +32,24 @@ import { _transformSubmittedFormDataForEmail, invokeWebhook, } from '../../../../meta/helpers/webhookHelpers'; -import Validator from 'validator'; -import { customValidators } from './customValidators'; import { NcError } from '../../../../meta/helpers/catchError'; -import { customAlphabet } from 'nanoid'; -import DOMPurify from 'isomorphic-dompurify'; +import { customValidators } from './customValidators'; +import formulaQueryBuilderv2 from './formulav2/formulaQueryBuilderv2'; +import genRollupSelectv2 from './genRollupSelectv2'; +import sortV2 from './sortV2'; +import conditionV2 from './conditionV2'; import { sanitize, unsanitize } from './helpers/sanitize'; -import QrCodeColumn from '../../../../models/QrCodeColumn'; -import BarcodeColumn from '../../../../models/BarcodeColumn'; +import type { SortType } from 'nocodb-sdk'; +import type { Knex } from 'knex'; +import type FormulaColumn from '../../../../models/FormulaColumn'; +import type { XcFilter, XcFilterWithAlias } from '../BaseModel'; +import type LookupColumn from '../../../../models/LookupColumn'; +import type RollupColumn from '../../../../models/RollupColumn'; +import type LinkToAnotherRecordColumn from '../../../../models/LinkToAnotherRecordColumn'; +import type { XKnex } from '../../index'; +import type SelectOption from '../../../../models/SelectOption'; +import type QrCodeColumn from '../../../../models/QrCodeColumn'; +import type BarcodeColumn from '../../../../models/BarcodeColumn'; const GROUP_COL = '__nc_group_id'; @@ -2934,6 +2938,7 @@ function extractFilterFromXwhere( if (openIndex === -1) openIndex = str.indexOf('(~'); let nextOpenIndex = openIndex; + let closingIndex = str.indexOf('))'); // if it's a simple query simply return array of conditions @@ -2986,15 +2991,54 @@ function extractFilterFromXwhere( return nestedArrayConditions; } +// mark `op` and `sub_op` any for being assignable to parameter of type +function validateFilterComparison(uidt: UITypes, op: any, sub_op?: any) { + if (!COMPARISON_OPS.includes(op)) { + NcError.badRequest(`${op} is not supported.`); + } + + if (sub_op) { + if (![UITypes.Date, UITypes.DateTime].includes(uidt)) { + NcError.badRequest(`'${sub_op}' is not supported for UI Type'${uidt}'.`); + } + if (!COMPARISON_SUB_OPS.includes(sub_op)) { + NcError.badRequest(`'${sub_op}' is not supported.`); + } + if ( + (op === 'isWithin' && !IS_WITHIN_COMPARISON_SUB_OPS.includes(sub_op)) || + (op !== 'isWithin' && IS_WITHIN_COMPARISON_SUB_OPS.includes(sub_op)) + ) { + NcError.badRequest(`'${sub_op}' is not supported for '${op}'`); + } + } +} + function extractCondition(nestedArrayConditions, aliasColObjMap) { return nestedArrayConditions?.map((str) => { // eslint-disable-next-line prefer-const let [logicOp, alias, op, value] = str.match(/(?:~(and|or|not))?\((.*?),(\w+),(.*)\)/)?.slice(1) || []; - if (op === 'in') value = value.split(','); + let sub_op = null; + + if (aliasColObjMap[alias]) { + if ( + [UITypes.Date, UITypes.DateTime].includes(aliasColObjMap[alias].uidt) + ) { + value = value.split(','); + // the first element would be sub_op + sub_op = value[0]; + // remove the first element which is sub_op + value.shift(); + } else if (op === 'in') { + value = value.split(','); + } + + validateFilterComparison(aliasColObjMap[alias].uidt, op, sub_op); + } return new Filter({ comparison_op: op, + ...(sub_op && { comparison_sub_op: sub_op }), fk_column_id: aliasColObjMap[alias]?.id, logical_op: logicOp, value, diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/CustomKnex.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/CustomKnex.ts index e12dd700e6..891e7b2675 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/CustomKnex.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/CustomKnex.ts @@ -1,14 +1,14 @@ import { Knex, knex } from 'knex'; import { SnowflakeClient } from 'nc-help'; -import { FilterType } from 'nocodb-sdk'; +import Filter from '../../../../models/Filter'; +import type { FilterType } from 'nocodb-sdk'; + +import type { BaseModelSql } from './BaseModelSql'; const types = require('pg').types; // override parsing date column to Date() types.setTypeParser(1082, (val) => val); -import { BaseModelSql } from './BaseModelSql'; -import Filter from '../../../../models/Filter'; - const opMappingGen = { eq: '=', lt: '<', diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts index ce0ec02ad8..d7abfa2911 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts @@ -1,15 +1,19 @@ +import { isNumericCol, RelationTypes, UITypes } from 'nocodb-sdk'; +import dayjs, { extend } from 'dayjs'; +import customParseFormat from 'dayjs/plugin/customParseFormat.js'; import Filter from '../../../../models/Filter'; -import LinkToAnotherRecordColumn from '../../../../models/LinkToAnotherRecordColumn'; -import { Knex } from 'knex'; -import { XKnex } from '../../index'; -import Column from '../../../../models/Column'; -import LookupColumn from '../../../../models/LookupColumn'; import genRollupSelectv2 from './genRollupSelectv2'; -import RollupColumn from '../../../../models/RollupColumn'; import formulaQueryBuilderv2 from './formulav2/formulaQueryBuilderv2'; -import FormulaColumn from '../../../../models/FormulaColumn'; -import { RelationTypes, UITypes, isNumericCol } from 'nocodb-sdk'; import { sanitize } from './helpers/sanitize'; +import type LinkToAnotherRecordColumn from '../../../../models/LinkToAnotherRecordColumn'; +import type { Knex } from 'knex'; +import type { XKnex } from '../../index'; +import type Column from '../../../../models/Column'; +import type LookupColumn from '../../../../models/LookupColumn'; +import type RollupColumn from '../../../../models/RollupColumn'; +import type FormulaColumn from '../../../../models/FormulaColumn'; + +extend(customParseFormat); export default async function conditionV2( conditionObj: Filter | Filter[], @@ -86,10 +90,20 @@ const parseConditionV2 = async ( const parentModel = await parentColumn.getModel(); await parentModel.getColumns(); if (colOptions.type === RelationTypes.HAS_MANY) { - if ( - filter.comparison_op === 'empty' || - filter.comparison_op === 'notempty' - ) { + if (['blank', 'notblank'].includes(filter.comparison_op)) { + // handle self reference + if (parentModel.id === childModel.id) { + if (filter.comparison_op === 'blank') { + return (qb) => { + qb.whereNull(childColumn.column_name); + }; + } else { + return (qb) => { + qb.whereNotNull(childColumn.column_name); + }; + } + } + const selectHmCount = knex(childModel.table_name) .count(childColumn.column_name) .where( @@ -101,7 +115,7 @@ const parseConditionV2 = async ( ); return (qb) => { - if (filter.comparison_op === 'empty') { + if (filter.comparison_op === 'blank') { qb.where(knex.raw('0'), selectHmCount); } else { qb.whereNot(knex.raw('0'), selectHmCount); @@ -132,14 +146,36 @@ const parseConditionV2 = async ( else qbP.whereIn(parentColumn.column_name, selectQb); }; } else if (colOptions.type === RelationTypes.BELONGS_TO) { - if (filter.comparison_op === 'null') { - return (qb) => { - qb.whereNull(childColumn.column_name); - }; - } - if (filter.comparison_op === 'notnull') { + if (['blank', 'notblank'].includes(filter.comparison_op)) { + // handle self reference + if (parentModel.id === childModel.id) { + if (filter.comparison_op === 'blank') { + return (qb) => { + qb.whereNull(childColumn.column_name); + }; + } else { + return (qb) => { + qb.whereNotNull(childColumn.column_name); + }; + } + } + + const selectBtCount = knex(parentModel.table_name) + .count(parentColumn.column_name) + .where( + parentColumn.column_name, + knex.raw('??.??', [ + alias || childModel.table_name, + childColumn.column_name, + ]) + ); + return (qb) => { - qb.whereNotNull(childColumn.column_name); + if (filter.comparison_op === 'blank') { + qb.where(knex.raw('0'), selectBtCount); + } else { + qb.whereNot(knex.raw('0'), selectBtCount); + } }; } @@ -171,10 +207,20 @@ const parseConditionV2 = async ( const mmParentColumn = await colOptions.getMMParentColumn(); const mmChildColumn = await colOptions.getMMChildColumn(); - if ( - filter.comparison_op === 'empty' || - filter.comparison_op === 'notempty' - ) { + if (['blank', 'notblank'].includes(filter.comparison_op)) { + // handle self reference + if (mmModel.id === childModel.id) { + if (filter.comparison_op === 'blank') { + return (qb) => { + qb.whereNull(childColumn.column_name); + }; + } else { + return (qb) => { + qb.whereNotNull(childColumn.column_name); + }; + } + } + const selectMmCount = knex(mmModel.table_name) .count(mmChildColumn.column_name) .where( @@ -186,7 +232,7 @@ const parseConditionV2 = async ( ); return (qb) => { - if (filter.comparison_op === 'empty') { + if (filter.comparison_op === 'blank') { qb.where(knex.raw('0'), selectMmCount); } else { qb.whereNot(knex.raw('0'), selectMmCount); @@ -201,6 +247,7 @@ const parseConditionV2 = async ( `${mmModel.table_name}.${mmParentColumn.column_name}`, `${parentModel.table_name}.${parentColumn.column_name}` ); + ( await parseConditionV2( new Filter({ @@ -271,14 +318,83 @@ const parseConditionV2 = async ( return (qb: Knex.QueryBuilder) => { let [field, val] = [_field, _val]; - if ( - [UITypes.Date, UITypes.DateTime].includes(column.uidt) && - !val && - ['is', 'isnot'].includes(filter.comparison_op) - ) { - // for date & datetime, - // val cannot be empty for non-is & non-isnot filters - return; + + const dateFormat = + qb?.client?.config?.client === 'mysql2' + ? 'YYYY-MM-DD HH:mm:ss' + : 'YYYY-MM-DD HH:mm:ssZ'; + + if ([UITypes.Date, UITypes.DateTime].includes(column.uidt)) { + const now = dayjs(new Date()); + // handle sub operation + switch (filter.comparison_sub_op) { + case 'today': + val = now; + break; + case 'tomorrow': + val = now.add(1, 'day'); + break; + case 'yesterday': + val = now.add(-1, 'day'); + break; + case 'oneWeekAgo': + val = now.add(-1, 'week'); + break; + case 'oneWeekFromNow': + val = now.add(1, 'week'); + break; + case 'oneMonthAgo': + val = now.add(-1, 'month'); + break; + case 'oneMonthFromNow': + val = now.add(1, 'month'); + break; + case 'daysAgo': + if (!val) return; + val = now.add(-val, 'day'); + break; + case 'daysFromNow': + if (!val) return; + val = now.add(val, 'day'); + break; + case 'exactDate': + if (!val) return; + break; + // sub-ops for `isWithin` comparison + case 'pastWeek': + val = now.add(-1, 'week'); + break; + case 'pastMonth': + val = now.add(-1, 'month'); + break; + case 'pastYear': + val = now.add(-1, 'year'); + break; + case 'nextWeek': + val = now.add(1, 'week'); + break; + case 'nextMonth': + val = now.add(1, 'month'); + break; + case 'nextYear': + val = now.add(1, 'year'); + break; + case 'pastNumberOfDays': + if (!val) return; + val = now.add(-val, 'day'); + break; + case 'nextNumberOfDays': + if (!val) return; + val = now.add(val, 'day'); + break; + } + + if (dayjs.isDayjs(val)) { + // turn `val` in dayjs object format to string + val = val.format(dateFormat).toString(); + // keep YYYY-MM-DD only for date + val = column.uidt === UITypes.Date ? val.substring(0, 10) : val; + } } if (isNumericCol(column.uidt) && typeof val === 'string') { @@ -461,23 +577,53 @@ const parseConditionV2 = async ( } break; case 'gt': - const gt_op = customWhereClause ? '<' : '>'; - qb = qb.where(field, gt_op, val); - if (column.uidt === UITypes.Rating) { - // unset rating is considered as NULL - if (gt_op === '<' && val > 0) { - qb = qb.orWhereNull(field); + { + const gt_op = customWhereClause ? '<' : '>'; + qb = qb.where(field, gt_op, val); + if (column.uidt === UITypes.Rating) { + // unset rating is considered as NULL + if (gt_op === '<' && val > 0) { + qb = qb.orWhereNull(field); + } } } break; case 'ge': case 'gte': - const ge_op = customWhereClause ? '<=' : '>='; - qb = qb.where(field, ge_op, val); - if (column.uidt === UITypes.Rating) { - // unset rating is considered as NULL - if (ge_op === '<=' || (ge_op === '>=' && val === 0)) { - qb = qb.orWhereNull(field); + { + const ge_op = customWhereClause ? '<=' : '>='; + qb = qb.where(field, ge_op, val); + if (column.uidt === UITypes.Rating) { + // unset rating is considered as NULL + if (ge_op === '<=' || (ge_op === '>=' && val === 0)) { + qb = qb.orWhereNull(field); + } + } + } + break; + case 'lt': + { + const lt_op = customWhereClause ? '>' : '<'; + qb = qb.where(field, lt_op, val); + if (column.uidt === UITypes.Rating) { + // unset number is considered as NULL + if (lt_op === '<' && val > 0) { + qb = qb.orWhereNull(field); + } + } + } + break; + + case 'le': + case 'lte': + { + const le_op = customWhereClause ? '>=' : '<='; + qb = qb.where(field, le_op, val); + if (column.uidt === UITypes.Rating) { + // unset number is considered as NULL + if (le_op === '<=' || (le_op === '>=' && val === 0)) { + qb = qb.orWhereNull(field); + } } } break; @@ -517,27 +663,6 @@ const parseConditionV2 = async ( else if (filter.value === 'false') qb = qb.whereNot(customWhereClause || field, false); break; - case 'lt': - const lt_op = customWhereClause ? '>' : '<'; - qb = qb.where(field, lt_op, val); - if (column.uidt === UITypes.Rating) { - // unset number is considered as NULL - if (lt_op === '<' && val > 0) { - qb = qb.orWhereNull(field); - } - } - break; - case 'le': - case 'lte': - const le_op = customWhereClause ? '>=' : '<='; - qb = qb.where(field, le_op, val); - if (column.uidt === UITypes.Rating) { - // unset number is considered as NULL - if (le_op === '<=' || (le_op === '>=' && val === 0)) { - qb = qb.orWhereNull(field); - } - } - break; case 'empty': if (column.uidt === UITypes.Formula) { [field, val] = [val, field]; @@ -564,7 +689,10 @@ const parseConditionV2 = async ( .orWhere(field, 'null'); } else { qb = qb.whereNull(customWhereClause || field); - if (!isNumericCol(column.uidt)) { + if ( + !isNumericCol(column.uidt) && + ![UITypes.Date, UITypes.DateTime].includes(column.uidt) + ) { qb = qb.orWhere(field, ''); } } @@ -577,7 +705,10 @@ const parseConditionV2 = async ( .whereNot(field, 'null'); } else { qb = qb.whereNotNull(customWhereClause || field); - if (!isNumericCol(column.uidt)) { + if ( + !isNumericCol(column.uidt) && + ![UITypes.Date, UITypes.DateTime].includes(column.uidt) + ) { qb = qb.whereNot(field, ''); } } @@ -598,6 +729,24 @@ const parseConditionV2 = async ( case 'nbtw': qb = qb.whereNotBetween(field, val.split(',')); break; + case 'isWithin': { + let now = dayjs(new Date()).format(dateFormat).toString(); + now = column.uidt === UITypes.Date ? now.substring(0, 10) : now; + switch (filter.comparison_sub_op) { + case 'pastWeek': + case 'pastMonth': + case 'pastYear': + case 'pastNumberOfDays': + qb = qb.whereBetween(field, [val, now]); + break; + case 'nextWeek': + case 'nextMonth': + case 'nextYear': + case 'nextNumberOfDays': + qb = qb.whereBetween(field, [now, val]); + break; + } + } } }; } diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/formulav2/formulaQueryBuilderv2.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/formulav2/formulaQueryBuilderv2.ts index c7c2b37197..74400802e2 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/formulav2/formulaQueryBuilderv2.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/formulav2/formulaQueryBuilderv2.ts @@ -1,17 +1,17 @@ import jsep from 'jsep'; +import { jsepCurlyHook, UITypes } from 'nocodb-sdk'; import mapFunctionName from '../mapFunctionName'; -import Model from '../../../../../models/Model'; -import Column from '../../../../../models/Column'; import genRollupSelectv2 from '../genRollupSelectv2'; -import RollupColumn from '../../../../../models/RollupColumn'; import FormulaColumn from '../../../../../models/FormulaColumn'; -import { XKnex } from '../../../index'; -import LinkToAnotherRecordColumn from '../../../../../models/LinkToAnotherRecordColumn'; -import LookupColumn from '../../../../../models/LookupColumn'; -import { jsepCurlyHook, UITypes } from 'nocodb-sdk'; import { validateDateWithUnknownFormat } from '../helpers/formulaFnHelper'; import { CacheGetType, CacheScope } from '../../../../../utils/globals'; import NocoCache from '../../../../../cache/NocoCache'; +import type Model from '../../../../../models/Model'; +import type Column from '../../../../../models/Column'; +import type RollupColumn from '../../../../../models/RollupColumn'; +import type { XKnex } from '../../../index'; +import type LinkToAnotherRecordColumn from '../../../../../models/LinkToAnotherRecordColumn'; +import type LookupColumn from '../../../../../models/LookupColumn'; // todo: switch function based on database @@ -753,7 +753,7 @@ async function _formulaQueryBuilder( sql = `${sql} ${colAlias}`; } } - const query = knex.raw(sql); + const query = knex.raw(sql.replace(/\?/g, '\\?')); if (prevBinaryOp && pt.operator !== prevBinaryOp) { query.wrap('(', ')'); } diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/commonFns.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/commonFns.ts index d1109ec28b..2b65d2cace 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/commonFns.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/commonFns.ts @@ -1,4 +1,4 @@ -import { MapFnArgs } from '../mapFunctionName'; +import type { MapFnArgs } from '../mapFunctionName'; export default { // todo: handle default case diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/mssql.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/mssql.ts index 58068e6c79..105311cade 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/mssql.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/mssql.ts @@ -1,8 +1,8 @@ import dayjs from 'dayjs'; -import { MapFnArgs } from '../mapFunctionName'; -import commonFns from './commonFns'; import { convertUnits } from '../helpers/convertUnits'; import { getWeekdayByText } from '../helpers/formulaFnHelper'; +import commonFns from './commonFns'; +import type { MapFnArgs } from '../mapFunctionName'; const mssql = { ...commonFns, diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/mysql.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/mysql.ts index 2512437c17..eae5c0f3f1 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/mysql.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/mysql.ts @@ -1,8 +1,8 @@ import dayjs from 'dayjs'; -import { MapFnArgs } from '../mapFunctionName'; -import commonFns from './commonFns'; import { convertUnits } from '../helpers/convertUnits'; import { getWeekdayByText } from '../helpers/formulaFnHelper'; +import commonFns from './commonFns'; +import type { MapFnArgs } from '../mapFunctionName'; const mysql2 = { ...commonFns, diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/pg.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/pg.ts index acf101a4aa..0efcfc9cb3 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/pg.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/pg.ts @@ -1,8 +1,8 @@ import dayjs from 'dayjs'; -import { MapFnArgs } from '../mapFunctionName'; -import commonFns from './commonFns'; import { convertUnits } from '../helpers/convertUnits'; import { getWeekdayByText } from '../helpers/formulaFnHelper'; +import commonFns from './commonFns'; +import type { MapFnArgs } from '../mapFunctionName'; const pg = { ...commonFns, diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/sqlite.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/sqlite.ts index 0c08dd3fa5..d4bfb56d82 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/sqlite.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/sqlite.ts @@ -1,12 +1,12 @@ import dayjs from 'dayjs'; -import { MapFnArgs } from '../mapFunctionName'; -import commonFns from './commonFns'; import { convertUnits } from '../helpers/convertUnits'; import { getWeekdayByText } from '../helpers/formulaFnHelper'; import { convertToTargetFormat, getDateFormat, } from '../../../../../utils/dateTimeUtils'; +import commonFns from './commonFns'; +import type { MapFnArgs } from '../mapFunctionName'; const sqlite3 = { ...commonFns, diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/genRollupSelect.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/genRollupSelect.ts index fe81fde763..2fc2d329d2 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/genRollupSelect.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/genRollupSelect.ts @@ -1,5 +1,5 @@ -import { Knex } from 'knex'; import { RelationTypes } from 'nocodb-sdk'; +import type { Knex } from 'knex'; export default function ({ knex, diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/genRollupSelectv2.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/genRollupSelectv2.ts index f1d52f357f..dfdb036bda 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/genRollupSelectv2.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/genRollupSelectv2.ts @@ -1,8 +1,8 @@ -import RollupColumn from '../../../../models/RollupColumn'; -import { XKnex } from '../../index'; -import LinkToAnotherRecordColumn from '../../../../models/LinkToAnotherRecordColumn'; -import { Knex } from 'knex'; import { RelationTypes } from 'nocodb-sdk'; +import type RollupColumn from '../../../../models/RollupColumn'; +import type { XKnex } from '../../index'; +import type LinkToAnotherRecordColumn from '../../../../models/LinkToAnotherRecordColumn'; +import type { Knex } from 'knex'; export default async function ({ knex, @@ -29,7 +29,7 @@ export default async function ({ case RelationTypes.HAS_MANY: return { builder: knex(`${childModel?.table_name} as ${refTableAlias}`) - [columnOptions.rollup_function]?.( + [columnOptions.rollup_function as string]?.( knex.ref(`${refTableAlias}.${rollupColumn.column_name}`) ) .where( @@ -47,7 +47,7 @@ export default async function ({ return { builder: knex(`${parentModel?.table_name} as ${refTableAlias}`) - [columnOptions.rollup_function]?.( + [columnOptions.rollup_function as string]?.( knex.ref(`${refTableAlias}.${rollupColumn.column_name}`) ) .innerJoin( diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/helpers/getAst.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/helpers/getAst.ts index 8b8c3def97..cb00298318 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/helpers/getAst.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/helpers/getAst.ts @@ -1,7 +1,7 @@ -import View from '../../../../../models/View'; import { isSystemColumn, UITypes } from 'nocodb-sdk'; -import Model from '../../../../../models/Model'; -import LinkToAnotherRecordColumn from '../../../../../models/LinkToAnotherRecordColumn'; +import View from '../../../../../models/View'; +import type Model from '../../../../../models/Model'; +import type LinkToAnotherRecordColumn from '../../../../../models/LinkToAnotherRecordColumn'; const getAst = async ({ query, diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/mapFunctionName.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/mapFunctionName.ts index 8227e273ec..49abd50ac2 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/mapFunctionName.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/mapFunctionName.ts @@ -1,9 +1,9 @@ -import { XKnex } from '../../index'; import mssql from './functionMappings/mssql'; import mysql from './functionMappings/mysql'; import pg from './functionMappings/pg'; import sqlite from './functionMappings/sqlite'; -import { Knex } from 'knex'; +import type { XKnex } from '../../index'; +import type { Knex } from 'knex'; export interface MapFnArgs { pt: any; diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/sortV2.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/sortV2.ts index 9baac9bfd7..1eb0f5c474 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/sortV2.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/sortV2.ts @@ -1,14 +1,14 @@ -import { Knex } from 'knex'; -import { XKnex } from '../../index'; +import { RelationTypes, UITypes } from 'nocodb-sdk'; import Sort from '../../../../models/Sort'; -import LinkToAnotherRecordColumn from '../../../../models/LinkToAnotherRecordColumn'; import genRollupSelectv2 from './genRollupSelectv2'; -import RollupColumn from '../../../../models/RollupColumn'; -import LookupColumn from '../../../../models/LookupColumn'; import formulaQueryBuilderv2 from './formulav2/formulaQueryBuilderv2'; -import FormulaColumn from '../../../../models/FormulaColumn'; -import { RelationTypes, UITypes } from 'nocodb-sdk'; import { sanitize } from './helpers/sanitize'; +import type { Knex } from 'knex'; +import type { XKnex } from '../../index'; +import type LinkToAnotherRecordColumn from '../../../../models/LinkToAnotherRecordColumn'; +import type RollupColumn from '../../../../models/RollupColumn'; +import type LookupColumn from '../../../../models/LookupColumn'; +import type FormulaColumn from '../../../../models/FormulaColumn'; export default async function sortV2( sortList: Sort[], diff --git a/packages/nocodb/src/lib/db/sql-mgr/SqlMgr.ts b/packages/nocodb/src/lib/db/sql-mgr/SqlMgr.ts index 3f6a85b9c2..02933d1297 100644 --- a/packages/nocodb/src/lib/db/sql-mgr/SqlMgr.ts +++ b/packages/nocodb/src/lib/db/sql-mgr/SqlMgr.ts @@ -7,14 +7,14 @@ import fsExtra from 'fs-extra'; import importFresh from 'import-fresh'; import inflection from 'inflection'; import slash from 'slash'; -import { Tele } from 'nc-help'; +import { T } from 'nc-help'; +import { customAlphabet } from 'nanoid'; import SqlClientFactory from '../sql-client/lib/SqlClientFactory'; // import debug from 'debug'; import KnexMigrator from '../sql-migrator/lib/KnexMigrator'; // import {XKnex} from "../sql-data-mapper"; import NcConnectionMgr from '../../utils/common/NcConnectionMgr'; -import { customAlphabet } from 'nanoid'; import Debug from '../util/Debug'; import Result from '../util/Result'; @@ -1047,7 +1047,7 @@ export default class SqlMgr { // t = process.hrtime(); const data = await require('axios')(...apiMeta); - Tele.emit('evt', { evt_type: 'import:excel:url' }); + T.emit('evt', { evt_type: 'import:excel:url' }); return data.data; } diff --git a/packages/nocodb/src/lib/db/sql-mgr/code/models/xc/BaseModelXcMeta.ts b/packages/nocodb/src/lib/db/sql-mgr/code/models/xc/BaseModelXcMeta.ts index 6548fa7e0c..446f6c4af8 100644 --- a/packages/nocodb/src/lib/db/sql-mgr/code/models/xc/BaseModelXcMeta.ts +++ b/packages/nocodb/src/lib/db/sql-mgr/code/models/xc/BaseModelXcMeta.ts @@ -1,6 +1,6 @@ +import { UITypes } from 'nocodb-sdk'; import BaseRender from '../../BaseRender'; import mapDefaultDisplayValue from '../../../../../meta/helpers/mapDefaultDisplayValue'; -import { UITypes } from 'nocodb-sdk'; abstract class BaseModelXcMeta extends BaseRender { protected abstract _getAbstractType(column: any): any; diff --git a/packages/nocodb/src/lib/db/sql-mgr/code/models/xc/ModelXcMetaFactory.ts b/packages/nocodb/src/lib/db/sql-mgr/code/models/xc/ModelXcMetaFactory.ts index 996a74beed..c0669dbc2a 100644 --- a/packages/nocodb/src/lib/db/sql-mgr/code/models/xc/ModelXcMetaFactory.ts +++ b/packages/nocodb/src/lib/db/sql-mgr/code/models/xc/ModelXcMetaFactory.ts @@ -1,10 +1,10 @@ -import BaseModelXcMeta from './BaseModelXcMeta'; import ModelXcMetaMssql from './ModelXcMetaMssql'; import ModelXcMetaMysql from './ModelXcMetaMysql'; import ModelXcMetaOracle from './ModelXcMetaOracle'; import ModelXcMetaPg from './ModelXcMetaPg'; import ModelXcMetaSqlite from './ModelXcMetaSqlite'; import ModelXcMetaSnowflake from './ModelXcMetaSnowflake'; +import type BaseModelXcMeta from './BaseModelXcMeta'; class ModelXcMetaFactory { public static create(connectionConfig, args): BaseModelXcMeta { diff --git a/packages/nocodb/src/lib/db/sql-mgr/code/policies/xc/ExpressXcPolicy.ts b/packages/nocodb/src/lib/db/sql-mgr/code/policies/xc/ExpressXcPolicy.ts index 9dd616cdf0..d7f867d00a 100644 --- a/packages/nocodb/src/lib/db/sql-mgr/code/policies/xc/ExpressXcPolicy.ts +++ b/packages/nocodb/src/lib/db/sql-mgr/code/policies/xc/ExpressXcPolicy.ts @@ -1,7 +1,7 @@ import lodash from 'lodash'; -import { Acl } from '../../../../../../interface/config'; import BaseRender from '../../BaseRender'; +import type { Acl } from '../../../../../../interface/config'; class ExpressXcMiddleware extends BaseRender { /** diff --git a/packages/nocodb/src/lib/db/sql-mgr/v2/ProjectMgrv2.ts b/packages/nocodb/src/lib/db/sql-mgr/v2/ProjectMgrv2.ts index 0662014e37..1574f2f78e 100644 --- a/packages/nocodb/src/lib/db/sql-mgr/v2/ProjectMgrv2.ts +++ b/packages/nocodb/src/lib/db/sql-mgr/v2/ProjectMgrv2.ts @@ -1,7 +1,7 @@ import SqlMgrv2 from './SqlMgrv2'; import SqlMgrv2Trans from './SqlMgrv2Trans'; -import NcMetaIO from '../../../meta/NcMetaIO'; -import Base from '../../../models/Base'; +import type NcMetaIO from '../../../meta/NcMetaIO'; +import type Base from '../../../models/Base'; export default class ProjectMgrv2 { private static sqlMgrMap: { diff --git a/packages/nocodb/src/lib/db/sql-mgr/v2/SqlMgrv2.ts b/packages/nocodb/src/lib/db/sql-mgr/v2/SqlMgrv2.ts index 8c7d189461..1e77c6d466 100644 --- a/packages/nocodb/src/lib/db/sql-mgr/v2/SqlMgrv2.ts +++ b/packages/nocodb/src/lib/db/sql-mgr/v2/SqlMgrv2.ts @@ -4,8 +4,8 @@ import NcConnectionMgrv2 from '../../../utils/common/NcConnectionMgrv2'; import SqlClientFactory from '../../sql-client/lib/SqlClientFactory'; import KnexMigratorv2 from '../../sql-migrator/lib/KnexMigratorv2'; -import Base from '../../../models/Base'; import Debug from '../../util/Debug'; +import type Base from '../../../models/Base'; const log = new Debug('SqlMgr'); diff --git a/packages/nocodb/src/lib/db/sql-mgr/v2/SqlMgrv2Trans.ts b/packages/nocodb/src/lib/db/sql-mgr/v2/SqlMgrv2Trans.ts index 82852fed52..a4cbe0621d 100644 --- a/packages/nocodb/src/lib/db/sql-mgr/v2/SqlMgrv2Trans.ts +++ b/packages/nocodb/src/lib/db/sql-mgr/v2/SqlMgrv2Trans.ts @@ -1,10 +1,10 @@ -import SqlMgrv2 from './SqlMgrv2'; -import Base from '../../../models/Base'; import NcConnectionMgrv2 from '../../../utils/common/NcConnectionMgrv2'; -import { Knex } from 'knex'; -import { XKnex } from '../../sql-data-mapper'; -import NcMetaIO from '../../../meta/NcMetaIO'; import KnexMigratorv2Tans from '../../sql-migrator/lib/KnexMigratorv2Tans'; +import SqlMgrv2 from './SqlMgrv2'; +import type Base from '../../../models/Base'; +import type { Knex } from 'knex'; +import type { XKnex } from '../../sql-data-mapper'; +import type NcMetaIO from '../../../meta/NcMetaIO'; export default class SqlMgrv2Trans extends SqlMgrv2 { protected trx: Knex.Transaction; @@ -34,7 +34,7 @@ export default class SqlMgrv2Trans extends SqlMgrv2 { } public async startTransaction(base: Base) { - const knex: XKnex = NcConnectionMgrv2.get(base); + const knex: XKnex = await NcConnectionMgrv2.get(base); this.trx = await knex.transaction(); } diff --git a/packages/nocodb/src/lib/db/sql-migrator/lib/KnexMigrator.ts b/packages/nocodb/src/lib/db/sql-migrator/lib/KnexMigrator.ts index 48cae09181..c1baacf17f 100644 --- a/packages/nocodb/src/lib/db/sql-migrator/lib/KnexMigrator.ts +++ b/packages/nocodb/src/lib/db/sql-migrator/lib/KnexMigrator.ts @@ -12,8 +12,8 @@ import Emit from '../../util/emit'; import Result from '../../util/Result'; import * as fileHelp from '../../util/file.help'; -import SqlMigrator from './SqlMigrator'; import NcConfigFactory from '../../../utils/NcConfigFactory'; +import SqlMigrator from './SqlMigrator'; const evt = new Emit(); const log = new Debug('KnexMigrator'); diff --git a/packages/nocodb/src/lib/db/sql-migrator/lib/KnexMigratorv2.ts b/packages/nocodb/src/lib/db/sql-migrator/lib/KnexMigratorv2.ts index d32a40d1d0..758861a093 100644 --- a/packages/nocodb/src/lib/db/sql-migrator/lib/KnexMigratorv2.ts +++ b/packages/nocodb/src/lib/db/sql-migrator/lib/KnexMigratorv2.ts @@ -1,7 +1,6 @@ import fs from 'fs'; import path from 'path'; import { promisify } from 'util'; -import { Knex } from 'knex'; import glob from 'glob'; import SqlClientFactory from '../../sql-client/lib/SqlClientFactory'; @@ -14,11 +13,12 @@ import * as fileHelp from '../../util/file.help'; // import SqlMigrator from './SqlMigrator'; // import NcConfigFactory from '../../../utils/NcConfigFactory'; import Noco from '../../../Noco'; -import { XKnex } from '../../sql-data-mapper'; import Project from '../../../models/Project'; -import Base from '../../../models/Base'; import NcConnectionMgrv2 from '../../../utils/common/NcConnectionMgrv2'; import Result from '../../util/Result'; +import type Base from '../../../models/Base'; +import type { XKnex } from '../../sql-data-mapper'; +import type { Knex } from 'knex'; const evt = new Emit(); const log = new Debug('KnexMigrator'); @@ -384,7 +384,7 @@ export default class KnexMigratorv2 { async _initDbWithSql(base: Base) { const sqlClient = await this.getSqlClient(base); - const connectionConfig = base.getConnectionConfig(); + const connectionConfig = await base.getConnectionConfig(); if (connectionConfig.client === 'oracledb') { this.emit( `${connectionConfig.client}: Creating DB if not exists ${connectionConfig.connection.user}` diff --git a/packages/nocodb/src/lib/db/sql-migrator/lib/KnexMigratorv2Tans.ts b/packages/nocodb/src/lib/db/sql-migrator/lib/KnexMigratorv2Tans.ts index 87204964a0..af3426ea69 100644 --- a/packages/nocodb/src/lib/db/sql-migrator/lib/KnexMigratorv2Tans.ts +++ b/packages/nocodb/src/lib/db/sql-migrator/lib/KnexMigratorv2Tans.ts @@ -4,12 +4,12 @@ * @class KnexMigrator * @extends {SqlMigrator} */ -import KnexMigratorv2 from './KnexMigratorv2'; -import Base from '../../../models/Base'; import NcConnectionMgrv2 from '../../../utils/common/NcConnectionMgrv2'; import Noco from '../../../Noco'; -import { XKnex } from '../../sql-data-mapper'; -import NcMetaIO from '../../../meta/NcMetaIO'; +import KnexMigratorv2 from './KnexMigratorv2'; +import type Base from '../../../models/Base'; +import type { XKnex } from '../../sql-data-mapper'; +import type NcMetaIO from '../../../meta/NcMetaIO'; import type MssqlClient from '../../sql-client/lib/mssql/MssqlClient'; import type MysqlClient from '../../sql-client/lib/mysql/MysqlClient'; diff --git a/packages/nocodb/src/lib/jobs/EmitteryJobsMgr.ts b/packages/nocodb/src/lib/jobs/EmitteryJobsMgr.ts index 38951a57e2..3323ead9c2 100644 --- a/packages/nocodb/src/lib/jobs/EmitteryJobsMgr.ts +++ b/packages/nocodb/src/lib/jobs/EmitteryJobsMgr.ts @@ -1,5 +1,5 @@ -import JobsMgr from './JobsMgr'; import Emittery from 'emittery'; +import JobsMgr from './JobsMgr'; export default class EmitteryJobsMgr extends JobsMgr { emitter: Emittery; diff --git a/packages/nocodb/src/lib/jobs/NocoJobs.ts b/packages/nocodb/src/lib/jobs/NocoJobs.ts index dd19d5c1f9..a10a36250f 100644 --- a/packages/nocodb/src/lib/jobs/NocoJobs.ts +++ b/packages/nocodb/src/lib/jobs/NocoJobs.ts @@ -1,6 +1,6 @@ -import JobsMgr from './JobsMgr'; import EmitteryJobsMgr from './EmitteryJobsMgr'; import RedisJobsMgr from './RedisJobsMgr'; +import type JobsMgr from './JobsMgr'; export default class NocoJobs { private static client: JobsMgr; diff --git a/packages/nocodb/src/lib/meta/MetaAPILogger.ts b/packages/nocodb/src/lib/meta/MetaAPILogger.ts index 88aac02eec..aea64ca26a 100644 --- a/packages/nocodb/src/lib/meta/MetaAPILogger.ts +++ b/packages/nocodb/src/lib/meta/MetaAPILogger.ts @@ -1,5 +1,5 @@ import { XKnex } from '../db/sql-data-mapper'; -import { Request } from 'express'; +import type { Request } from 'express'; export default class MetaAPILogger { static _instance: MetaAPILogger; diff --git a/packages/nocodb/src/lib/meta/NcMetaIO.ts b/packages/nocodb/src/lib/meta/NcMetaIO.ts index 305e2b0132..356b5207c4 100644 --- a/packages/nocodb/src/lib/meta/NcMetaIO.ts +++ b/packages/nocodb/src/lib/meta/NcMetaIO.ts @@ -1,6 +1,6 @@ -import { NcConfig } from '../../interface/config'; -import Noco from '../Noco'; -import { XKnex } from '../db/sql-data-mapper'; +import type { NcConfig } from '../../interface/config'; +import type Noco from '../Noco'; +import type { XKnex } from '../db/sql-data-mapper'; const META_TABLES = { graphql: [ diff --git a/packages/nocodb/src/lib/meta/NcMetaIOImpl.ts b/packages/nocodb/src/lib/meta/NcMetaIOImpl.ts index a22dc63c16..2e4e630416 100644 --- a/packages/nocodb/src/lib/meta/NcMetaIOImpl.ts +++ b/packages/nocodb/src/lib/meta/NcMetaIOImpl.ts @@ -1,15 +1,16 @@ import CryptoJS from 'crypto-js'; import { customAlphabet } from 'nanoid'; -import { NcConfig } from '../../interface/config'; -import { Knex, XKnex } from '../db/sql-data-mapper'; -import Noco from '../Noco'; +import { XKnex } from '../db/sql-data-mapper'; import XcMigrationSource from '../migrations/XcMigrationSource'; -import NcMetaIO, { META_TABLES } from './NcMetaIO'; import NcConnectionMgr from '../utils/common/NcConnectionMgr'; import { MetaTable } from '../utils/globals'; import XcMigrationSourcev2 from '../migrations/XcMigrationSourcev2'; +import NcMetaIO, { META_TABLES } from './NcMetaIO'; +import type Noco from '../Noco'; +import type { Knex } from '../db/sql-data-mapper'; +import type { NcConfig } from '../../interface/config'; // import { nanoid } from 'nanoid'; /*import { v4 as uuidv4 } from 'uuid';*/ diff --git a/packages/nocodb/src/lib/meta/NcMetaMgr.ts b/packages/nocodb/src/lib/meta/NcMetaMgr.ts index aecaff7189..2a9c166585 100644 --- a/packages/nocodb/src/lib/meta/NcMetaMgr.ts +++ b/packages/nocodb/src/lib/meta/NcMetaMgr.ts @@ -1,12 +1,13 @@ -import CryptoJS from 'crypto-js'; import fs from 'fs'; -import mkdirp from 'mkdirp'; import path from 'path'; +import { promisify } from 'util'; +import CryptoJS from 'crypto-js'; +import mkdirp from 'mkdirp'; import archiver from 'archiver'; import axios from 'axios'; import bodyParser from 'body-parser'; -import express, { Handler, Router } from 'express'; +import { Router } from 'express'; import extract from 'extract-zip'; import isDocker from 'is-docker'; import multer from 'multer'; @@ -14,10 +15,10 @@ import { customAlphabet, nanoid } from 'nanoid'; import slash from 'slash'; import { v4 as uuidv4 } from 'uuid'; import { ncp } from 'ncp'; +import { UITypes } from 'nocodb-sdk'; +import { T } from 'nc-help'; +import { Result } from '../../interface/config'; -import IEmailAdapter from '../../interface/IEmailAdapter'; -import IStorageAdapter from '../../interface/IStorageAdapter'; -import { NcConfig, Result } from '../../interface/config'; import SqlClientFactory from '../db/sql-client/lib/SqlClientFactory'; import { NcConfigFactory } from '../index'; import ProjectMgr from '../db/sql-mgr/ProjectMgr'; @@ -28,20 +29,23 @@ import NcHelp from '../utils/NcHelp'; import mimetypes, { mimeIcons } from '../utils/mimeTypes'; import { packageVersion } from '../utils/packageVersion'; import projectAcl from '../utils/projectAcl'; -import Noco from '../Noco'; -import { GqlApiBuilder } from '../v1-legacy/gql/GqlApiBuilder'; import NcPluginMgr from '../v1-legacy/plugins/NcPluginMgr'; import XcCache from '../v1-legacy/plugins/adapters/cache/XcCache'; -import { RestApiBuilder } from '../v1-legacy/rest/RestApiBuilder'; import RestAuthCtrl from '../v1-legacy/rest/RestAuthCtrlEE'; -import NcMetaIO, { META_TABLES } from './NcMetaIO'; -import { promisify } from 'util'; import NcTemplateParser from '../v1-legacy/templates/NcTemplateParser'; import { defaultConnectionConfig } from '../utils/NcConfigFactory'; -import xcMetaDiff from './handlers/xcMetaDiff'; -import { UITypes } from 'nocodb-sdk'; -import { Tele } from 'nc-help'; import { NC_ATTACHMENT_FIELD_SIZE } from '../constants'; +import xcMetaDiff from './handlers/xcMetaDiff'; +import { META_TABLES } from './NcMetaIO'; +import type NcMetaIO from './NcMetaIO'; +import type { RestApiBuilder } from '../v1-legacy/rest/RestApiBuilder'; +import type { GqlApiBuilder } from '../v1-legacy/gql/GqlApiBuilder'; +import type Noco from '../Noco'; +import type { NcConfig } from '../../interface/config'; +import type IStorageAdapter from '../../interface/IStorageAdapter'; +import type IEmailAdapter from '../../interface/IEmailAdapter'; +import type express from 'express'; +import type { Handler } from 'express'; const randomID = customAlphabet('1234567890abcdefghijklmnopqrstuvwxyz_', 10); const XC_PLUGIN_DET = 'XC_PLUGIN_DET'; @@ -953,7 +957,7 @@ export default class NcMetaMgr { ip: req.clientIp, }); - Tele.emit('evt', { evt_type: 'webhooks:deleted' }); + T.emit('evt', { evt_type: 'webhooks:deleted' }); } catch (e) { throw e; } @@ -988,7 +992,7 @@ export default class NcMetaMgr { ip: req.clientIp, }); - Tele.emit('evt', { evt_type: 'webhooks:updated' }); + T.emit('evt', { evt_type: 'webhooks:updated' }); } else { const res = await this.xcMeta.metaInsert( projectId, @@ -1009,7 +1013,7 @@ export default class NcMetaMgr { description: `created webhook ${args.args.data.title} - ${args.args.data.event} ${args.args.data.operation} - ${args.args.data.notification?.type} - of table ${args.args.tn} `, ip: req.clientIp, }); - Tele.emit('evt', { evt_type: 'webhooks:created' }); + T.emit('evt', { evt_type: 'webhooks:created' }); return res; } @@ -1269,7 +1273,7 @@ export default class NcMetaMgr { } catch (e) { throw e; } finally { - Tele.emit('evt', { evt_type: 'image:uploaded' }); + T.emit('evt', { evt_type: 'image:uploaded' }); } } @@ -1595,7 +1599,7 @@ export default class NcMetaMgr { ip: req.clientIp, }); - Tele.emit('evt', { evt_type: 'project:created' }); + T.emit('evt', { evt_type: 'project:created' }); break; case 'projectUpdateByWeb': @@ -1603,7 +1607,7 @@ export default class NcMetaMgr { this.getProjectId(args), args.args.projectJson ); - Tele.emit('evt', { evt_type: 'project:updated' }); + T.emit('evt', { evt_type: 'project:updated' }); break; case 'projectCreateByOneClick': { @@ -1635,7 +1639,7 @@ export default class NcMetaMgr { description: `created project ${config.title}(${result.id}) `, ip: req.clientIp, }); - Tele.emit('evt', { evt_type: 'project:created', oneClick: true }); + T.emit('evt', { evt_type: 'project:created', oneClick: true }); } break; case 'projectCreateByWebWithXCDB': { @@ -1689,10 +1693,10 @@ export default class NcMetaMgr { ip: req.clientIp, }); - Tele.emit('evt', { evt_type: 'project:created', xcdb: true }); + T.emit('evt', { evt_type: 'project:created', xcdb: true }); postListenerCb = async () => { if (args?.args?.template) { - Tele.emit('evt', { + T.emit('evt', { evt_type: args.args?.quickImport ? 'project:created:fromExcel' : 'project:created:fromTemplate', @@ -1730,7 +1734,7 @@ export default class NcMetaMgr { case 'projectDelete': case 'projectRestart': case 'projectStart': - Tele.emit('evt', { evt_type: 'project:' + args.api }); + T.emit('evt', { evt_type: 'project:' + args.api }); result = null; break; @@ -2145,7 +2149,7 @@ export default class NcMetaMgr { ip: req.clientIp, }); - Tele.emit('evt', { evt_type: 'acl:updated' }); + T.emit('evt', { evt_type: 'acl:updated' }); return res; } catch (e) { @@ -3485,7 +3489,7 @@ export default class NcMetaMgr { ['id', 'view_id', 'view_type'] ); res.url = `${req.ncSiteUrl}${this.config.dashboardPath}#/nc/view/${res.view_id}`; - Tele.emit('evt', { evt_type: 'sharedView:generated-link' }); + T.emit('evt', { evt_type: 'sharedView:generated-link' }); return res; } catch (e) { console.log(e); @@ -3549,7 +3553,7 @@ export default class NcMetaMgr { sharedBase.url = `${req.ncSiteUrl}${this.config.dashboardPath}#/nc/base/${sharedBase.shared_base_id}`; - Tele.emit('evt', { evt_type: 'sharedBase:generated-link' }); + T.emit('evt', { evt_type: 'sharedBase:generated-link' }); return sharedBase; } catch (e) { console.log(e); @@ -3606,7 +3610,7 @@ export default class NcMetaMgr { // await this.xcMeta.metaUpdate(this.getProjectId(args), this.getDbAlias(args), 'nc_shared_views', { // password: args.args?.password // }, args.args.id); - // Tele.emit('evt', {evt_type: 'sharedView:password-updated'}) + // T.emit('evt', {evt_type: 'sharedView:password-updated'}) // return {msg: 'Success'}; // } catch (e) { // console.log(e) @@ -3623,7 +3627,7 @@ export default class NcMetaMgr { 'nc_shared_views', args.args.id ); - Tele.emit('evt', { evt_type: 'sharedView:deleted' }); + T.emit('evt', { evt_type: 'sharedView:deleted' }); return { msg: 'Success' }; } catch (e) { console.log(e); @@ -4477,7 +4481,7 @@ export default class NcMetaMgr { }); } - Tele.emit('evt', { evt_type: 'template:imported' }); + T.emit('evt', { evt_type: 'template:imported' }); return result; } @@ -5071,7 +5075,7 @@ export default class NcMetaMgr { } catch (e) { throw e; } finally { - Tele.emit('evt', { + T.emit('evt', { evt_type: 'plugin:installed', title: args.args.title, }); @@ -5153,7 +5157,7 @@ export default class NcMetaMgr { ip: req.clientIp, }); - Tele.emit('evt', { + T.emit('evt', { evt_type: 'vtable:created', show_as: args.args.show_as, }); @@ -5270,7 +5274,7 @@ export default class NcMetaMgr { }); await RestAuthCtrl.instance.loadLatestApiTokens(); - Tele.emit('evt', { evt_type: 'apiToken:created' }); + T.emit('evt', { evt_type: 'apiToken:created' }); return { description: args.args.description, token, @@ -5282,7 +5286,7 @@ export default class NcMetaMgr { } protected async xcApiTokenDelete(args): Promise { - Tele.emit('evt', { evt_type: 'apiToken:deleted' }); + T.emit('evt', { evt_type: 'apiToken:deleted' }); const res = await this.xcMeta.metaDelete( null, null, @@ -5327,7 +5331,7 @@ export default class NcMetaMgr { ip: req.clientIp, }); - Tele.emit('evt', { + T.emit('evt', { evt_type: 'vtable:renamed', show_as: args.args.show_as, }); @@ -5335,7 +5339,7 @@ export default class NcMetaMgr { } protected async xcVirtualTableUpdate(args): Promise { - // Tele.emit('evt', {evt_type: 'vtable:updated',show_as: args.args.show_as}) + // T.emit('evt', {evt_type: 'vtable:updated',show_as: args.args.show_as}) return this.xcMeta.metaUpdate( this.getProjectId(args), this.getDbAlias(args), @@ -5482,7 +5486,7 @@ export default class NcMetaMgr { ip: req.clientIp, }); - Tele.emit('evt', { evt_type: 'vtable:deleted' }); + T.emit('evt', { evt_type: 'vtable:deleted' }); return res; } diff --git a/packages/nocodb/src/lib/meta/NcMetaMgrEE.ts b/packages/nocodb/src/lib/meta/NcMetaMgrEE.ts index dfa8dff104..c0e10ec8ab 100644 --- a/packages/nocodb/src/lib/meta/NcMetaMgrEE.ts +++ b/packages/nocodb/src/lib/meta/NcMetaMgrEE.ts @@ -1,5 +1,5 @@ import { v4 as uuidv4 } from 'uuid'; -import { Tele } from 'nc-help'; +import { T } from 'nc-help'; import NcMetaMgr from './NcMetaMgr'; @@ -104,7 +104,7 @@ export default class NcMetaMgrEE extends NcMetaMgr { ip: req.clientIp, }); - Tele.emit('evt', { evt_type: 'acl:updated' }); + T.emit('evt', { evt_type: 'acl:updated' }); return res; } catch (e) { @@ -277,7 +277,7 @@ export default class NcMetaMgrEE extends NcMetaMgr { sharedView.url = `${req.ncSiteUrl}${this.config.dashboardPath}#/nc/view/${sharedView.view_id}`; } - Tele.emit('evt', { evt_type: 'sharedView:generated-link' }); + T.emit('evt', { evt_type: 'sharedView:generated-link' }); return sharedView; } catch (e) { console.log(e); @@ -295,7 +295,7 @@ export default class NcMetaMgrEE extends NcMetaMgr { }, args.args.id ); - Tele.emit('evt', { evt_type: 'sharedView:password-updated' }); + T.emit('evt', { evt_type: 'sharedView:password-updated' }); return { msg: 'Success' }; } catch (e) { console.log(e); diff --git a/packages/nocodb/src/lib/meta/NcMetaMgrv2.ts b/packages/nocodb/src/lib/meta/NcMetaMgrv2.ts index 596249036f..2d8c228ff6 100644 --- a/packages/nocodb/src/lib/meta/NcMetaMgrv2.ts +++ b/packages/nocodb/src/lib/meta/NcMetaMgrv2.ts @@ -1,17 +1,18 @@ import bodyParser from 'body-parser'; -import { Handler, Router } from 'express'; +import { Router } from 'express'; import multer from 'multer'; -import { NcConfig } from '../../interface/config'; import ProjectMgr from '../db/sql-mgr/ProjectMgr'; import { packageVersion } from '../utils/packageVersion'; import projectAcl from '../utils/projectAcl'; -import Noco from '../Noco'; import NcPluginMgr from '../v1-legacy/plugins/NcPluginMgr'; -import NcMetaIO from './NcMetaIO'; import { defaultConnectionConfig } from '../utils/NcConfigFactory'; -import ncCreateLookup from './handlersv2/ncCreateLookup'; import { NC_ATTACHMENT_FIELD_SIZE } from '../constants'; +import ncCreateLookup from './handlersv2/ncCreateLookup'; +import type NcMetaIO from './NcMetaIO'; +import type Noco from '../Noco'; +import type { NcConfig } from '../../interface/config'; +import type { Handler } from 'express'; // import ncGetMeta from './handlersv2/ncGetMeta'; export default class NcMetaMgrv2 { diff --git a/packages/nocodb/src/lib/meta/api/apiTokenApis.ts b/packages/nocodb/src/lib/meta/api/apiTokenApis.ts deleted file mode 100644 index 5ed4c08094..0000000000 --- a/packages/nocodb/src/lib/meta/api/apiTokenApis.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { Request, Response, Router } from 'express'; -import { OrgUserRoles } from 'nocodb-sdk'; -import { Tele } from 'nc-help'; -import { NcError } from '../helpers/catchError'; -import ncMetaAclMw from '../helpers/ncMetaAclMw'; -import ApiToken from '../../models/ApiToken'; -import { metaApiMetrics } from '../helpers/apiMetrics'; -import { getAjvValidatorMw } from './helpers'; - -export async function apiTokenList(req: Request, res: Response) { - res.json(await ApiToken.list(req['user'].id)); -} -export async function apiTokenCreate(req: Request, res: Response) { - Tele.emit('evt', { evt_type: 'apiToken:created' }); - res.json(await ApiToken.insert({ ...req.body, fk_user_id: req['user'].id })); -} -export async function apiTokenDelete(req: Request, res: Response) { - const apiToken = await ApiToken.getByToken(req.params.token); - if ( - !req['user'].roles.includes(OrgUserRoles.SUPER_ADMIN) && - apiToken.fk_user_id !== req['user'].id - ) { - NcError.notFound('Token not found'); - } - Tele.emit('evt', { evt_type: 'apiToken:deleted' }); - - // todo: verify token belongs to the user - res.json(await ApiToken.delete(req.params.token)); -} - -// todo: add reset token api to regenerate token - -// deprecated apis -const router = Router({ mergeParams: true }); - -router.get( - '/api/v1/db/meta/projects/:projectId/api-tokens', - metaApiMetrics, - ncMetaAclMw(apiTokenList, 'apiTokenList') -); -router.post( - '/api/v1/db/meta/projects/:projectId/api-tokens', - metaApiMetrics, - getAjvValidatorMw('swagger.json#/components/schemas/ApiTokenReq'), - ncMetaAclMw(apiTokenCreate, 'apiTokenCreate') -); -router.delete( - '/api/v1/db/meta/projects/:projectId/api-tokens/:token', - metaApiMetrics, - ncMetaAclMw(apiTokenDelete, 'apiTokenDelete') -); - -export default router; diff --git a/packages/nocodb/src/lib/meta/api/attachmentApis.ts b/packages/nocodb/src/lib/meta/api/attachmentApis.ts deleted file mode 100644 index 88097286b4..0000000000 --- a/packages/nocodb/src/lib/meta/api/attachmentApis.ts +++ /dev/null @@ -1,227 +0,0 @@ -// @ts-ignore -import { Request, Response, Router } from 'express'; -import multer from 'multer'; -import { nanoid } from 'nanoid'; -import { OrgUserRoles, ProjectRoles } from 'nocodb-sdk'; -import path from 'path'; -import slash from 'slash'; -import Noco from '../../Noco'; -import { MetaTable } from '../../utils/globals'; -import mimetypes, { mimeIcons } from '../../utils/mimeTypes'; -import { Tele } from 'nc-help'; -import extractProjectIdAndAuthenticate from '../helpers/extractProjectIdAndAuthenticate'; -import catchError, { NcError } from '../helpers/catchError'; -import NcPluginMgrv2 from '../helpers/NcPluginMgrv2'; -import Local from '../../v1-legacy/plugins/adapters/storage/Local'; -import { NC_ATTACHMENT_FIELD_SIZE } from '../../constants'; -import { getCacheMiddleware } from './helpers'; - -const isUploadAllowed = async (req: Request, _res: Response, next: any) => { - if (!req['user']?.id) { - if (!req['user']?.isPublicBase) { - NcError.unauthorized('Unauthorized'); - } - } - - try { - // check user is super admin or creator - if ( - req['user'].roles?.includes(OrgUserRoles.SUPER_ADMIN) || - req['user'].roles?.includes(OrgUserRoles.CREATOR) || - req['user'].roles?.includes(ProjectRoles.EDITOR) || - // if viewer then check at-least one project have editor or higher role - // todo: cache - !!(await Noco.ncMeta - .knex(MetaTable.PROJECT_USERS) - .where(function () { - this.where('roles', ProjectRoles.OWNER); - this.orWhere('roles', ProjectRoles.CREATOR); - this.orWhere('roles', ProjectRoles.EDITOR); - }) - .andWhere('fk_user_id', req['user'].id) - .first()) - ) - return next(); - } catch {} - NcError.badRequest('Upload not allowed'); -}; - -export async function upload(req: Request, res: Response) { - const filePath = sanitizeUrlPath( - req.query?.path?.toString()?.split('/') || [''] - ); - const destPath = path.join('nc', 'uploads', ...filePath); - - const storageAdapter = await NcPluginMgrv2.storageAdapter(); - - const attachments = await Promise.all( - (req as any).files?.map(async (file) => { - const fileName = `${nanoid(18)}${path.extname(file.originalname)}`; - - const url = await storageAdapter.fileCreate( - slash(path.join(destPath, fileName)), - file - ); - - let attachmentPath; - - // if `url` is null, then it is local attachment - if (!url) { - // then store the attachement path only - // url will be constructued in `useAttachmentCell` - attachmentPath = `download/${filePath.join('/')}/${fileName}`; - } - - return { - ...(url ? { url } : {}), - ...(attachmentPath ? { path: attachmentPath } : {}), - title: file.originalname, - mimetype: file.mimetype, - size: file.size, - icon: mimeIcons[path.extname(file.originalname).slice(1)] || undefined, - }; - }) - ); - - Tele.emit('evt', { evt_type: 'image:uploaded' }); - - res.json(attachments); -} - -export async function uploadViaURL(req: Request, res: Response) { - const filePath = sanitizeUrlPath( - req.query?.path?.toString()?.split('/') || [''] - ); - const destPath = path.join('nc', 'uploads', ...filePath); - - const storageAdapter = await NcPluginMgrv2.storageAdapter(); - - const attachments = await Promise.all( - req.body?.map?.(async (urlMeta) => { - const { url, fileName: _fileName } = urlMeta; - - const fileName = `${nanoid(18)}${_fileName || url.split('/').pop()}`; - - const 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) { - // then store the attachement path only - // url will be constructued in `useAttachmentCell` - attachmentPath = `download/${filePath.join('/')}/${fileName}`; - } - - return { - ...(attachmentUrl ? { url: attachmentUrl } : {}), - ...(attachmentPath ? { path: attachmentPath } : {}), - title: fileName, - mimetype: urlMeta.mimetype, - size: urlMeta.size, - icon: mimeIcons[path.extname(fileName).slice(1)] || undefined, - }; - }) - ); - - Tele.emit('evt', { evt_type: 'image:uploaded' }); - - res.json(attachments); -} - -export async function fileRead(req, res) { - try { - // get the local storage adapter to display local attachments - const storageAdapter = new Local(); - const type = - mimetypes[path.extname(req.params?.[0]).split('/').pop().slice(1)] || - 'text/plain'; - - const img = await storageAdapter.fileRead( - slash( - path.join( - 'nc', - 'uploads', - req.params?.[0] - ?.split('/') - .filter((p) => p !== '..') - .join('/') - ) - ) - ); - res.writeHead(200, { 'Content-Type': type }); - res.end(img, 'binary'); - } catch (e) { - console.log(e); - res.status(404).send('Not found'); - } -} - -const router = Router({ mergeParams: true }); - -router.get( - /^\/dl\/([^/]+)\/([^/]+)\/(.+)$/, - getCacheMiddleware(), - async (req, res) => { - try { - // const type = mimetypes[path.extname(req.params.fileName).slice(1)] || 'text/plain'; - const type = - mimetypes[path.extname(req.params[2]).split('/').pop().slice(1)] || - 'text/plain'; - - const storageAdapter = await NcPluginMgrv2.storageAdapter(); - // const img = await this.storageAdapter.fileRead(slash(path.join('nc', req.params.projectId, req.params.dbAlias, 'uploads', req.params.fileName))); - const img = await storageAdapter.fileRead( - slash( - path.join( - 'nc', - req.params[0], - req.params[1], - 'uploads', - ...req.params[2].split('/') - ) - ) - ); - res.writeHead(200, { 'Content-Type': type }); - res.end(img, 'binary'); - } catch (e) { - res.status(404).send('Not found'); - } - } -); - -export function sanitizeUrlPath(paths) { - return paths.map((url) => url.replace(/[/.?#]+/g, '_')); -} - -router.post( - '/api/v1/db/storage/upload', - multer({ - storage: multer.diskStorage({}), - limits: { - fieldSize: NC_ATTACHMENT_FIELD_SIZE, - }, - }).any(), - [ - extractProjectIdAndAuthenticate, - catchError(isUploadAllowed), - catchError(upload), - ] -); - -router.post( - '/api/v1/db/storage/upload-by-url', - - [ - extractProjectIdAndAuthenticate, - catchError(isUploadAllowed), - catchError(uploadViaURL), - ] -); - -router.get(/^\/download\/(.+)$/, getCacheMiddleware(), catchError(fileRead)); - -export default router; diff --git a/packages/nocodb/src/lib/meta/api/auditApis.ts b/packages/nocodb/src/lib/meta/api/auditApis.ts deleted file mode 100644 index fdf9f70daf..0000000000 --- a/packages/nocodb/src/lib/meta/api/auditApis.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { Request, Response, Router } from 'express'; -import Audit from '../../models/Audit'; -import { AuditOperationSubTypes, AuditOperationTypes } from 'nocodb-sdk'; -import Model from '../../models/Model'; -import { PagedResponseImpl } from '../helpers/PagedResponse'; -import ncMetaAclMw from '../helpers/ncMetaAclMw'; - -import DOMPurify from 'isomorphic-dompurify'; -import { getAjvValidatorMw } from './helpers'; - -export async function commentRow(req: Request, res) { - res.json( - await Audit.insert({ - ...req.body, - user: (req as any).user?.email, - op_type: AuditOperationTypes.COMMENT, - }) - ); -} - -export async function auditRowUpdate(req: Request, res) { - const model = await Model.getByIdOrName({ id: req.body.fk_model_id }); - res.json( - await Audit.insert({ - fk_model_id: req.body.fk_model_id, - row_id: req.params.rowId, - op_type: AuditOperationTypes.DATA, - op_sub_type: AuditOperationSubTypes.UPDATE, - description: DOMPurify.sanitize( - `Table ${model.table_name} : field ${req.body.column_name} got changed from ${req.body.prev_value} to ${req.body.value}` - ), - details: DOMPurify.sanitize(`${req.body.column_name} - : ${req.body.prev_value} - ${req.body.value}`), - ip: (req as any).clientIp, - user: (req as any).user?.email, - }) - ); -} - -export async function commentList(req: Request, res) { - res.json(await Audit.commentsList(req.query)); -} - -export async function auditList(req: Request, res: Response) { - res.json( - new PagedResponseImpl( - await Audit.projectAuditList(req.params.projectId, req.query), - { - count: await Audit.projectAuditCount(req.params.projectId), - ...req.query, - } - ) - ); -} - -export async function commentsCount(req: Request, res) { - res.json( - await Audit.commentsCount({ - fk_model_id: req.query.fk_model_id as string, - ids: req.query.ids as string[], - }) - ); -} - -const router = Router({ mergeParams: true }); -router.get( - '/api/v1/db/meta/audits/comments', - ncMetaAclMw(commentList, 'commentList') -); -router.post( - '/api/v1/db/meta/audits/comments', - getAjvValidatorMw('swagger.json#/components/schemas/CommentReq'), - ncMetaAclMw(commentRow, 'commentRow') -); -router.post( - '/api/v1/db/meta/audits/rows/:rowId/update', - getAjvValidatorMw('swagger.json#/components/schemas/AuditRowUpdateReq'), - ncMetaAclMw(auditRowUpdate, 'auditRowUpdate') -); -router.get( - '/api/v1/db/meta/audits/comments/count', - ncMetaAclMw(commentsCount, 'commentsCount') -); -router.get( - '/api/v1/db/meta/projects/:projectId/audits', - ncMetaAclMw(auditList, 'auditList') -); -export default router; diff --git a/packages/nocodb/src/lib/meta/api/baseApis.ts b/packages/nocodb/src/lib/meta/api/baseApis.ts deleted file mode 100644 index c13bbd18d3..0000000000 --- a/packages/nocodb/src/lib/meta/api/baseApis.ts +++ /dev/null @@ -1,129 +0,0 @@ -import { Request, Response } from 'express'; -import Project from '../../models/Project'; -import { BaseListType } from 'nocodb-sdk'; -import { PagedResponseImpl } from '../helpers/PagedResponse'; -import { syncBaseMigration } from '../helpers/syncMigration'; -import Base from '../../models/Base'; -import ncMetaAclMw from '../helpers/ncMetaAclMw'; -import { Tele } from 'nc-help'; -import { metaApiMetrics } from '../helpers/apiMetrics'; -import { getAjvValidatorMw, populateMeta } from './helpers'; - -export async function baseGet( - req: Request, - res: Response -) { - const base = await Base.get(req.params.baseId); - - base.config = base.getConnectionConfig(); - - res.json(base); -} - -export async function baseUpdate( - req: Request, - res: Response -) { - const baseBody = req.body; - const project = await Project.getWithInfo(req.params.projectId); - const base = await Base.updateBase(req.params.baseId, { - ...baseBody, - type: baseBody.config?.client, - projectId: project.id, - id: req.params.baseId, - }); - - delete base.config; - - Tele.emit('evt', { - evt_type: 'base:updated', - }); - - res.json(base); -} - -export async function baseList( - req: Request, - res: Response, - next -) { - try { - const bases = await Base.list({ projectId: req.params.projectId }); - - res // todo: pagination - .json({ - bases: new PagedResponseImpl(bases, { - count: bases.length, - limit: bases.length, - }), - }); - } catch (e) { - console.log(e); - next(e); - } -} - -export async function baseDelete( - req: Request, - res: Response -) { - const base = await Base.get(req.params.baseId); - const result = await base.delete(); - Tele.emit('evt', { evt_type: 'base:deleted' }); - res.json(result); -} - -async function baseCreate(req: Request, res) { - // type | base | projectId - const baseBody = req.body; - const project = await Project.getWithInfo(req.params.projectId); - const base = await Base.createBase({ - ...baseBody, - type: baseBody.config?.client, - projectId: project.id, - }); - - await syncBaseMigration(project, base); - - const info = await populateMeta(base, project); - - Tele.emit('evt_api_created', info); - - delete base.config; - - Tele.emit('evt', { - evt_type: 'base:created', - }); - - res.json(base); -} - -export default (router) => { - router.get( - '/api/v1/db/meta/projects/:projectId/bases/:baseId', - metaApiMetrics, - ncMetaAclMw(baseGet, 'baseGet') - ); - router.patch( - '/api/v1/db/meta/projects/:projectId/bases/:baseId', - metaApiMetrics, - getAjvValidatorMw('swagger.json#/components/schemas/BaseReq'), - ncMetaAclMw(baseUpdate, 'baseUpdate') - ); - router.delete( - '/api/v1/db/meta/projects/:projectId/bases/:baseId', - metaApiMetrics, - ncMetaAclMw(baseDelete, 'baseDelete') - ); - router.post( - '/api/v1/db/meta/projects/:projectId/bases', - metaApiMetrics, - getAjvValidatorMw('swagger.json#/components/schemas/BaseReq'), - ncMetaAclMw(baseCreate, 'baseCreate') - ); - router.get( - '/api/v1/db/meta/projects/:projectId/bases', - metaApiMetrics, - ncMetaAclMw(baseList, 'baseList') - ); -}; diff --git a/packages/nocodb/src/lib/meta/api/dataApis/bulkDataAliasApis.ts b/packages/nocodb/src/lib/meta/api/dataApis/bulkDataAliasApis.ts deleted file mode 100644 index 739585a1c5..0000000000 --- a/packages/nocodb/src/lib/meta/api/dataApis/bulkDataAliasApis.ts +++ /dev/null @@ -1,101 +0,0 @@ -import { Request, Response, Router } from 'express'; -import { BaseModelSqlv2 } from '../../../db/sql-data-mapper/lib/sql/BaseModelSqlv2'; -import Model from '../../../models/Model'; -import Base from '../../../models/Base'; -import NcConnectionMgrv2 from '../../../utils/common/NcConnectionMgrv2'; -import ncMetaAclMw from '../../helpers/ncMetaAclMw'; -import { getViewAndModelFromRequestByAliasOrId } from './helpers'; -import apiMetrics from '../../helpers/apiMetrics'; - -type BulkOperation = - | 'bulkInsert' - | 'bulkUpdate' - | 'bulkUpdateAll' - | 'bulkDelete' - | 'bulkDeleteAll'; - -async function getModelViewBase(req: Request) { - const { model, view } = await getViewAndModelFromRequestByAliasOrId(req); - - const base = await Base.get(model.base_id); - return { model, view, base }; -} - -async function executeBulkOperation( - req: Request, - res: Response, - operation: T, - options: Parameters -) { - const { model, view, base } = await getModelViewBase(req); - const baseModel = await Model.getBaseModelSQL({ - id: model.id, - viewId: view?.id, - dbDriver: NcConnectionMgrv2.get(base), - }); - res.json(await baseModel[operation].apply(null, options)); -} - -async function bulkDataInsert(req: Request, res: Response) { - await executeBulkOperation(req, res, 'bulkInsert', [ - req.body, - { cookie: req }, - ]); -} - -async function bulkDataUpdate(req: Request, res: Response) { - await executeBulkOperation(req, res, 'bulkUpdate', [ - req.body, - { cookie: req }, - ]); -} - -// todo: Integrate with filterArrJson bulkDataUpdateAll -async function bulkDataUpdateAll(req: Request, res: Response) { - await executeBulkOperation(req, res, 'bulkUpdateAll', [ - req.query, - req.body, - { cookie: req }, - ]); -} - -async function bulkDataDelete(req: Request, res: Response) { - await executeBulkOperation(req, res, 'bulkDelete', [ - req.body, - { cookie: req }, - ]); -} - -// todo: Integrate with filterArrJson bulkDataDeleteAll -async function bulkDataDeleteAll(req: Request, res: Response) { - await executeBulkOperation(req, res, 'bulkDeleteAll', [req.query]); -} -const router = Router({ mergeParams: true }); - -router.post( - '/api/v1/db/data/bulk/:orgs/:projectName/:tableName', - apiMetrics, - ncMetaAclMw(bulkDataInsert, 'bulkDataInsert') -); -router.patch( - '/api/v1/db/data/bulk/:orgs/:projectName/:tableName', - apiMetrics, - ncMetaAclMw(bulkDataUpdate, 'bulkDataUpdate') -); -router.patch( - '/api/v1/db/data/bulk/:orgs/:projectName/:tableName/all', - apiMetrics, - ncMetaAclMw(bulkDataUpdateAll, 'bulkDataUpdateAll') -); -router.delete( - '/api/v1/db/data/bulk/:orgs/:projectName/:tableName', - apiMetrics, - ncMetaAclMw(bulkDataDelete, 'bulkDataDelete') -); -router.delete( - '/api/v1/db/data/bulk/:orgs/:projectName/:tableName/all', - apiMetrics, - ncMetaAclMw(bulkDataDeleteAll, 'bulkDataDeleteAll') -); - -export default router; diff --git a/packages/nocodb/src/lib/meta/api/dataApis/dataAliasApis.ts b/packages/nocodb/src/lib/meta/api/dataApis/dataAliasApis.ts deleted file mode 100644 index 4ef4b7ce5e..0000000000 --- a/packages/nocodb/src/lib/meta/api/dataApis/dataAliasApis.ts +++ /dev/null @@ -1,432 +0,0 @@ -import { Request, Response, Router } from 'express'; -import Model from '../../../models/Model'; -import { nocoExecute } from 'nc-help'; -import Base from '../../../models/Base'; -import NcConnectionMgrv2 from '../../../utils/common/NcConnectionMgrv2'; -import { NcError } from '../../helpers/catchError'; -import { PagedResponseImpl } from '../../helpers/PagedResponse'; -import View from '../../../models/View'; -import ncMetaAclMw from '../../helpers/ncMetaAclMw'; -import { getViewAndModelFromRequestByAliasOrId } from './helpers'; -import apiMetrics from '../../helpers/apiMetrics'; -import getAst from '../../../db/sql-data-mapper/lib/sql/helpers/getAst'; -import { parseHrtimeToSeconds } from '../helpers'; - -// todo: Handle the error case where view doesnt belong to model -async function dataList(req: Request, res: Response) { - const startTime = process.hrtime(); - const { model, view } = await getViewAndModelFromRequestByAliasOrId(req); - const responseData = await getDataList(model, view, req); - const elapsedSeconds = parseHrtimeToSeconds(process.hrtime(startTime)); - res.setHeader('xc-db-response', elapsedSeconds); - res.json(responseData); -} - -async function dataFindOne(req: Request, res: Response) { - const { model, view } = await getViewAndModelFromRequestByAliasOrId(req); - res.json(await getFindOne(model, view, req)); -} - -async function dataGroupBy(req: Request, res: Response) { - const { model, view } = await getViewAndModelFromRequestByAliasOrId(req); - res.json(await getDataGroupBy(model, view, req)); -} - -async function dataCount(req: Request, res: Response) { - const { model, view } = await getViewAndModelFromRequestByAliasOrId(req); - - const base = await Base.get(model.base_id); - - const baseModel = await Model.getBaseModelSQL({ - id: model.id, - viewId: view?.id, - dbDriver: NcConnectionMgrv2.get(base), - }); - - const countArgs: any = { ...req.query }; - try { - countArgs.filterArr = JSON.parse(countArgs.filterArrJson); - } catch (e) {} - - const count = await baseModel.count(countArgs); - - res.json({ count }); -} - -// todo: Handle the error case where view doesnt belong to model -async function dataInsert(req: Request, res: Response) { - const { model, view } = await getViewAndModelFromRequestByAliasOrId(req); - - const base = await Base.get(model.base_id); - - const baseModel = await Model.getBaseModelSQL({ - id: model.id, - viewId: view?.id, - dbDriver: NcConnectionMgrv2.get(base), - }); - - res.json(await baseModel.insert(req.body, null, req)); -} - -async function dataUpdate(req: Request, res: Response) { - const { model, view } = await getViewAndModelFromRequestByAliasOrId(req); - const base = await Base.get(model.base_id); - - const baseModel = await Model.getBaseModelSQL({ - id: model.id, - viewId: view?.id, - dbDriver: NcConnectionMgrv2.get(base), - }); - - res.json(await baseModel.updateByPk(req.params.rowId, req.body, null, req)); -} - -async function dataDelete(req: Request, res: Response) { - const { model, view } = await getViewAndModelFromRequestByAliasOrId(req); - const base = await Base.get(model.base_id); - const baseModel = await Model.getBaseModelSQL({ - id: model.id, - viewId: view?.id, - dbDriver: NcConnectionMgrv2.get(base), - }); - - // todo: Should have error http status code - const message = await baseModel.hasLTARData(req.params.rowId, model); - if (message.length) { - res.json({ message }); - return; - } - res.json(await baseModel.delByPk(req.params.rowId, null, req)); -} - -async function getDataList(model, view: View, req) { - const base = await Base.get(model.base_id); - - const baseModel = await Model.getBaseModelSQL({ - id: model.id, - viewId: view?.id, - dbDriver: NcConnectionMgrv2.get(base), - }); - - const requestObj = await getAst({ model, query: req.query, view }); - - const listArgs: any = { ...req.query }; - try { - listArgs.filterArr = JSON.parse(listArgs.filterArrJson); - } catch (e) {} - try { - listArgs.sortArr = JSON.parse(listArgs.sortArrJson); - } catch (e) {} - - let data = []; - let count = 0; - try { - data = await nocoExecute( - requestObj, - await baseModel.list(listArgs), - {}, - listArgs - ); - count = await baseModel.count(listArgs); - } catch (e) { - console.log(e); - NcError.internalServerError( - 'Internal Server Error, check server log for more details' - ); - } - - return new PagedResponseImpl(data, { - ...req.query, - count, - }); -} - -async function getFindOne(model, view: View, req) { - const base = await Base.get(model.base_id); - - const baseModel = await Model.getBaseModelSQL({ - id: model.id, - viewId: view?.id, - dbDriver: NcConnectionMgrv2.get(base), - }); - - const args: any = { ...req.query }; - try { - args.filterArr = JSON.parse(args.filterArrJson); - } catch (e) {} - try { - args.sortArr = JSON.parse(args.sortArrJson); - } catch (e) {} - - const data = await baseModel.findOne(args); - return data - ? await nocoExecute( - await getAst({ model, query: args, view }), - data, - {}, - {} - ) - : {}; -} - -async function getDataGroupBy(model, view: View, req) { - const base = await Base.get(model.base_id); - - const baseModel = await Model.getBaseModelSQL({ - id: model.id, - viewId: view?.id, - dbDriver: NcConnectionMgrv2.get(base), - }); - - const listArgs: any = { ...req.query }; - const data = await baseModel.groupBy({ ...req.query }); - const count = await baseModel.count(listArgs); - - return new PagedResponseImpl(data, { - ...req.query, - count, - }); -} - -async function dataRead(req: Request, res: Response) { - const { model, view } = await getViewAndModelFromRequestByAliasOrId(req); - - const base = await Base.get(model.base_id); - - const baseModel = await Model.getBaseModelSQL({ - id: model.id, - viewId: view?.id, - dbDriver: NcConnectionMgrv2.get(base), - }); - - const row = await baseModel.readByPk(req.params.rowId); - - if (!row) { - NcError.notFound(); - } - - res.json( - await nocoExecute( - await getAst({ model, query: req.query, view }), - row, - {}, - req.query - ) - ); -} - -async function dataExist(req: Request, res: Response) { - const { model, view } = await getViewAndModelFromRequestByAliasOrId(req); - - const base = await Base.get(model.base_id); - - const baseModel = await Model.getBaseModelSQL({ - id: model.id, - viewId: view?.id, - dbDriver: NcConnectionMgrv2.get(base), - }); - - res.json(await baseModel.exist(req.params.rowId)); -} - -// todo: Handle the error case where view doesnt belong to model -async function groupedDataList(req: Request, res: Response) { - const startTime = process.hrtime(); - const { model, view } = await getViewAndModelFromRequestByAliasOrId(req); - const groupedData = await getGroupedDataList(model, view, req); - const elapsedSeconds = parseHrtimeToSeconds(process.hrtime(startTime)); - res.setHeader('xc-db-response', elapsedSeconds); - res.json(groupedData); -} - -async function getGroupedDataList(model, view: View, req) { - const base = await Base.get(model.base_id); - - const baseModel = await Model.getBaseModelSQL({ - id: model.id, - viewId: view?.id, - dbDriver: NcConnectionMgrv2.get(base), - }); - - const requestObj = await getAst({ model, query: req.query, view }); - - const listArgs: any = { ...req.query }; - try { - listArgs.filterArr = JSON.parse(listArgs.filterArrJson); - } catch (e) {} - try { - listArgs.sortArr = JSON.parse(listArgs.sortArrJson); - } catch (e) {} - try { - listArgs.options = JSON.parse(listArgs.optionsArrJson); - } catch (e) {} - - let data = []; - // let count = 0 - try { - const groupedData = await baseModel.groupedList({ - ...listArgs, - groupColumnId: req.params.columnId, - }); - data = await nocoExecute( - { key: 1, value: requestObj }, - groupedData, - {}, - listArgs - ); - const countArr = await baseModel.groupedListCount({ - ...listArgs, - groupColumnId: req.params.columnId, - }); - data = data.map((item) => { - // todo: use map to avoid loop - const count = - countArr.find((countItem: any) => countItem.key === item.key)?.count ?? - 0; - - item.value = new PagedResponseImpl(item.value, { - ...req.query, - count: count, - }); - return item; - }); - } catch (e) { - console.log(e); - NcError.internalServerError( - 'Internal Server Error, check server log for more details' - ); - } - return data; -} - -const router = Router({ mergeParams: true }); - -// table data crud apis -router.get( - '/api/v1/db/data/:orgs/:projectName/:tableName', - apiMetrics, - ncMetaAclMw(dataList, 'dataList') -); - -router.get( - '/api/v1/db/data/:orgs/:projectName/:tableName/find-one', - apiMetrics, - ncMetaAclMw(dataFindOne, 'dataFindOne') -); - -router.get( - '/api/v1/db/data/:orgs/:projectName/:tableName/groupby', - apiMetrics, - ncMetaAclMw(dataGroupBy, 'dataGroupBy') -); - -router.get( - '/api/v1/db/data/:orgs/:projectName/:tableName/group/:columnId', - apiMetrics, - ncMetaAclMw(groupedDataList, 'groupedDataList') -); - -router.get( - '/api/v1/db/data/:orgs/:projectName/:tableName/:rowId/exist', - apiMetrics, - ncMetaAclMw(dataExist, 'dataExist') -); - -router.get( - '/api/v1/db/data/:orgs/:projectName/:tableName/count', - apiMetrics, - ncMetaAclMw(dataCount, 'dataCount') -); - -router.get( - '/api/v1/db/data/:orgs/:projectName/:tableName/views/:viewName/count', - apiMetrics, - ncMetaAclMw(dataCount, 'dataCount') -); - -router.get( - '/api/v1/db/data/:orgs/:projectName/:tableName/:rowId', - apiMetrics, - ncMetaAclMw(dataRead, 'dataRead') -); - -router.patch( - '/api/v1/db/data/:orgs/:projectName/:tableName/:rowId', - apiMetrics, - ncMetaAclMw(dataUpdate, 'dataUpdate') -); - -router.delete( - '/api/v1/db/data/:orgs/:projectName/:tableName/:rowId', - apiMetrics, - ncMetaAclMw(dataDelete, 'dataDelete') -); - -router.get( - '/api/v1/db/data/:orgs/:projectName/:tableName', - apiMetrics, - ncMetaAclMw(dataList, 'dataList') -); - -// table view data crud apis -router.get( - '/api/v1/db/data/:orgs/:projectName/:tableName/views/:viewName', - apiMetrics, - ncMetaAclMw(dataList, 'dataList') -); - -router.get( - '/api/v1/db/data/:orgs/:projectName/:tableName/views/:viewName/find-one', - apiMetrics, - ncMetaAclMw(dataFindOne, 'dataFindOne') -); - -router.get( - '/api/v1/db/data/:orgs/:projectName/:tableName/views/:viewName/groupby', - apiMetrics, - ncMetaAclMw(dataGroupBy, 'dataGroupBy') -); - -router.get( - '/api/v1/db/data/:orgs/:projectName/:tableName/views/:viewName/group/:columnId', - apiMetrics, - ncMetaAclMw(groupedDataList, 'groupedDataList') -); - -router.get( - '/api/v1/db/data/:orgs/:projectName/:tableName/views/:viewName/:rowId/exist', - apiMetrics, - ncMetaAclMw(dataExist, 'dataExist') -); - -router.post( - '/api/v1/db/data/:orgs/:projectName/:tableName', - apiMetrics, - ncMetaAclMw(dataInsert, 'dataInsert') -); - -router.post( - '/api/v1/db/data/:orgs/:projectName/:tableName/views/:viewName', - apiMetrics, - ncMetaAclMw(dataInsert, 'dataInsert') -); - -router.patch( - '/api/v1/db/data/:orgs/:projectName/:tableName/views/:viewName/:rowId', - apiMetrics, - ncMetaAclMw(dataUpdate, 'dataUpdate') -); - -router.get( - '/api/v1/db/data/:orgs/:projectName/:tableName/views/:viewName/:rowId', - apiMetrics, - ncMetaAclMw(dataRead, 'dataRead') -); - -router.delete( - '/api/v1/db/data/:orgs/:projectName/:tableName/views/:viewName/:rowId', - apiMetrics, - ncMetaAclMw(dataDelete, 'dataDelete') -); - -export default router; diff --git a/packages/nocodb/src/lib/meta/api/dataApis/dataAliasNestedApis.ts b/packages/nocodb/src/lib/meta/api/dataApis/dataAliasNestedApis.ts deleted file mode 100644 index d260694fe5..0000000000 --- a/packages/nocodb/src/lib/meta/api/dataApis/dataAliasNestedApis.ts +++ /dev/null @@ -1,291 +0,0 @@ -import { Request, Response, Router } from 'express'; -import Model from '../../../models/Model'; -import Base from '../../../models/Base'; -import NcConnectionMgrv2 from '../../../utils/common/NcConnectionMgrv2'; -import { PagedResponseImpl } from '../../helpers/PagedResponse'; -import ncMetaAclMw from '../../helpers/ncMetaAclMw'; -import { - getColumnByIdOrName, - getViewAndModelFromRequestByAliasOrId, -} from './helpers'; -import { NcError } from '../../helpers/catchError'; -import apiMetrics from '../../helpers/apiMetrics'; - -// todo: handle case where the given column is not ltar -export async function mmList(req: Request, res: Response, next) { - const { model, view } = await getViewAndModelFromRequestByAliasOrId(req); - - if (!model) return next(new Error('Table not found')); - - const base = await Base.get(model.base_id); - - const baseModel = await Model.getBaseModelSQL({ - id: model.id, - viewId: view?.id, - dbDriver: NcConnectionMgrv2.get(base), - }); - - const column = await getColumnByIdOrName(req.params.columnName, model); - - const data = await baseModel.mmList( - { - colId: column.id, - parentId: req.params.rowId, - }, - req.query as any - ); - const count: any = await baseModel.mmListCount({ - colId: column.id, - parentId: req.params.rowId, - }); - - res.json( - new PagedResponseImpl(data, { - count, - ...req.query, - }) - ); -} - -export async function mmExcludedList(req: Request, res: Response, next) { - const { model, view } = await getViewAndModelFromRequestByAliasOrId(req); - if (!model) return next(new Error('Table not found')); - - const base = await Base.get(model.base_id); - - const baseModel = await Model.getBaseModelSQL({ - id: model.id, - viewId: view?.id, - dbDriver: NcConnectionMgrv2.get(base), - }); - const column = await getColumnByIdOrName(req.params.columnName, model); - - const data = await baseModel.getMmChildrenExcludedList( - { - colId: column.id, - pid: req.params.rowId, - }, - req.query - ); - - const count = await baseModel.getMmChildrenExcludedListCount( - { - colId: column.id, - pid: req.params.rowId, - }, - req.query - ); - - res.json( - new PagedResponseImpl(data, { - count, - ...req.query, - }) - ); -} - -export async function hmExcludedList(req: Request, res: Response, next) { - const { model, view } = await getViewAndModelFromRequestByAliasOrId(req); - - if (!model) return next(new Error('Table not found')); - - const base = await Base.get(model.base_id); - - const baseModel = await Model.getBaseModelSQL({ - id: model.id, - viewId: view?.id, - dbDriver: NcConnectionMgrv2.get(base), - }); - - const column = await getColumnByIdOrName(req.params.columnName, model); - - const data = await baseModel.getHmChildrenExcludedList( - { - colId: column.id, - pid: req.params.rowId, - }, - req.query - ); - - const count = await baseModel.getHmChildrenExcludedListCount( - { - colId: column.id, - pid: req.params.rowId, - }, - req.query - ); - - res.json( - new PagedResponseImpl(data, { - count, - ...req.query, - }) - ); -} - -export async function btExcludedList(req: Request, res: Response, next) { - const { model, view } = await getViewAndModelFromRequestByAliasOrId(req); - if (!model) return next(new Error('Table not found')); - - const base = await Base.get(model.base_id); - - const baseModel = await Model.getBaseModelSQL({ - id: model.id, - viewId: view?.id, - dbDriver: NcConnectionMgrv2.get(base), - }); - - const column = await getColumnByIdOrName(req.params.columnName, model); - - const data = await baseModel.getBtChildrenExcludedList( - { - colId: column.id, - cid: req.params.rowId, - }, - req.query - ); - - const count = await baseModel.getBtChildrenExcludedListCount( - { - colId: column.id, - cid: req.params.rowId, - }, - req.query - ); - - res.json( - new PagedResponseImpl(data, { - count, - ...req.query, - }) - ); -} - -// todo: handle case where the given column is not ltar -export async function hmList(req: Request, res: Response, next) { - const { model, view } = await getViewAndModelFromRequestByAliasOrId(req); - if (!model) return next(new Error('Table not found')); - - const base = await Base.get(model.base_id); - - const baseModel = await Model.getBaseModelSQL({ - id: model.id, - viewId: view?.id, - dbDriver: NcConnectionMgrv2.get(base), - }); - - const column = await getColumnByIdOrName(req.params.columnName, model); - - const data = await baseModel.hmList( - { - colId: column.id, - id: req.params.rowId, - }, - req.query - ); - - const count = await baseModel.hmListCount({ - colId: column.id, - id: req.params.rowId, - }); - - res.json( - new PagedResponseImpl(data, { - count, - ...req.query, - } as any) - ); -} - -//@ts-ignore -async function relationDataRemove(req, res) { - const { model, view } = await getViewAndModelFromRequestByAliasOrId(req); - - if (!model) NcError.notFound('Table not found'); - - const base = await Base.get(model.base_id); - - const baseModel = await Model.getBaseModelSQL({ - id: model.id, - viewId: view?.id, - dbDriver: NcConnectionMgrv2.get(base), - }); - - const column = await getColumnByIdOrName(req.params.columnName, model); - - await baseModel.removeChild({ - colId: column.id, - childId: req.params.refRowId, - rowId: req.params.rowId, - cookie: req, - }); - - res.json({ msg: 'success' }); -} - -//@ts-ignore -// todo: Give proper error message when reference row is already related and handle duplicate ref row id in hm -async function relationDataAdd(req, res) { - const { model, view } = await getViewAndModelFromRequestByAliasOrId(req); - if (!model) NcError.notFound('Table not found'); - - const base = await Base.get(model.base_id); - - const baseModel = await Model.getBaseModelSQL({ - id: model.id, - viewId: view?.id, - dbDriver: NcConnectionMgrv2.get(base), - }); - - const column = await getColumnByIdOrName(req.params.columnName, model); - await baseModel.addChild({ - colId: column.id, - childId: req.params.refRowId, - rowId: req.params.rowId, - cookie: req, - }); - - res.json({ msg: 'success' }); -} - -const router = Router({ mergeParams: true }); - -router.get( - '/api/v1/db/data/:orgs/:projectName/:tableName/:rowId/mm/:columnName/exclude', - apiMetrics, - ncMetaAclMw(mmExcludedList, 'mmExcludedList') -); -router.get( - '/api/v1/db/data/:orgs/:projectName/:tableName/:rowId/hm/:columnName/exclude', - apiMetrics, - ncMetaAclMw(hmExcludedList, 'hmExcludedList') -); -router.get( - '/api/v1/db/data/:orgs/:projectName/:tableName/:rowId/bt/:columnName/exclude', - apiMetrics, - ncMetaAclMw(btExcludedList, 'btExcludedList') -); - -router.post( - '/api/v1/db/data/:orgs/:projectName/:tableName/:rowId/:relationType/:columnName/:refRowId', - apiMetrics, - ncMetaAclMw(relationDataAdd, 'relationDataAdd') -); -router.delete( - '/api/v1/db/data/:orgs/:projectName/:tableName/:rowId/:relationType/:columnName/:refRowId', - apiMetrics, - ncMetaAclMw(relationDataRemove, 'relationDataRemove') -); - -router.get( - '/api/v1/db/data/:orgs/:projectName/:tableName/:rowId/mm/:columnName', - apiMetrics, - ncMetaAclMw(mmList, 'mmList') -); -router.get( - '/api/v1/db/data/:orgs/:projectName/:tableName/:rowId/hm/:columnName', - apiMetrics, - ncMetaAclMw(hmList, 'hmList') -); - -export default router; diff --git a/packages/nocodb/src/lib/meta/api/dataApis/dataApis.ts b/packages/nocodb/src/lib/meta/api/dataApis/dataApis.ts deleted file mode 100644 index b8a8899b5f..0000000000 --- a/packages/nocodb/src/lib/meta/api/dataApis/dataApis.ts +++ /dev/null @@ -1,612 +0,0 @@ -import { Request, Response, Router } from 'express'; -import Model from '../../../models/Model'; -import { nocoExecute } from 'nc-help'; -import Base from '../../../models/Base'; -import NcConnectionMgrv2 from '../../../utils/common/NcConnectionMgrv2'; -import { PagedResponseImpl } from '../../helpers/PagedResponse'; -import View from '../../../models/View'; -import ncMetaAclMw from '../../helpers/ncMetaAclMw'; -import { NcError } from '../../helpers/catchError'; -import apiMetrics from '../../helpers/apiMetrics'; -import getAst from '../../../db/sql-data-mapper/lib/sql/helpers/getAst'; - -export async function dataList(req: Request, res: Response, next) { - const view = await View.get(req.params.viewId); - - const model = await Model.getByIdOrName({ - id: view?.fk_model_id || req.params.viewId, - }); - - if (!model) return next(new Error('Table not found')); - - res.json(await getDataList(model, view, req)); -} - -export async function mmList(req: Request, res: Response, next) { - const view = await View.get(req.params.viewId); - - const model = await Model.getByIdOrName({ - id: view?.fk_model_id || req.params.viewId, - }); - - if (!model) return next(new Error('Table not found')); - - const base = await Base.get(model.base_id); - - const baseModel = await Model.getBaseModelSQL({ - id: model.id, - viewId: view?.id, - dbDriver: NcConnectionMgrv2.get(base), - }); - - const key = `${model.title}List`; - const requestObj: any = { - [key]: 1, - }; - - const data = ( - await nocoExecute( - requestObj, - { - [key]: async (args) => { - return await baseModel.mmList( - { - colId: req.params.colId, - parentId: req.params.rowId, - }, - args - ); - }, - }, - {}, - - { nested: { [key]: req.query } } - ) - )?.[key]; - - const count: any = await baseModel.mmListCount({ - colId: req.params.colId, - parentId: req.params.rowId, - }); - - res.json( - new PagedResponseImpl(data, { - count, - ...req.query, - }) - ); -} - -export async function mmExcludedList(req: Request, res: Response, next) { - const view = await View.get(req.params.viewId); - - const model = await Model.getByIdOrName({ - id: view?.fk_model_id || req.params.viewId, - }); - - if (!model) return next(new Error('Table not found')); - - const base = await Base.get(model.base_id); - - const baseModel = await Model.getBaseModelSQL({ - id: model.id, - viewId: view?.id, - dbDriver: NcConnectionMgrv2.get(base), - }); - - const key = 'List'; - const requestObj: any = { - [key]: 1, - }; - - const data = ( - await nocoExecute( - requestObj, - { - [key]: async (args) => { - return await baseModel.getMmChildrenExcludedList( - { - colId: req.params.colId, - pid: req.params.rowId, - }, - args - ); - }, - }, - {}, - - { nested: { [key]: req.query } } - ) - )?.[key]; - - const count = await baseModel.getMmChildrenExcludedListCount( - { - colId: req.params.colId, - pid: req.params.rowId, - }, - req.query - ); - - res.json( - new PagedResponseImpl(data, { - count, - ...req.query, - }) - ); -} - -export async function hmExcludedList(req: Request, res: Response, next) { - const view = await View.get(req.params.viewId); - - const model = await Model.getByIdOrName({ - id: view?.fk_model_id || req.params.viewId, - }); - - if (!model) return next(new Error('Table not found')); - - const base = await Base.get(model.base_id); - - const baseModel = await Model.getBaseModelSQL({ - id: model.id, - viewId: view?.id, - dbDriver: NcConnectionMgrv2.get(base), - }); - - const key = 'List'; - const requestObj: any = { - [key]: 1, - }; - - const data = ( - await nocoExecute( - requestObj, - { - [key]: async (args) => { - return await baseModel.getHmChildrenExcludedList( - { - colId: req.params.colId, - pid: req.params.rowId, - }, - args - ); - }, - }, - {}, - - { nested: { [key]: req.query } } - ) - )?.[key]; - - const count = await baseModel.getHmChildrenExcludedListCount( - { - colId: req.params.colId, - pid: req.params.rowId, - }, - req.query - ); - - res.json( - new PagedResponseImpl(data, { - count, - ...req.query, - }) - ); -} - -export async function btExcludedList(req: Request, res: Response, next) { - const view = await View.get(req.params.viewId); - - const model = await Model.getByIdOrName({ - id: view?.fk_model_id || req.params.viewId, - }); - - if (!model) return next(new Error('Table not found')); - - const base = await Base.get(model.base_id); - - const baseModel = await Model.getBaseModelSQL({ - id: model.id, - viewId: view?.id, - dbDriver: NcConnectionMgrv2.get(base), - }); - - const key = 'List'; - const requestObj: any = { - [key]: 1, - }; - - const data = ( - await nocoExecute( - requestObj, - { - [key]: async (args) => { - return await baseModel.getBtChildrenExcludedList( - { - colId: req.params.colId, - cid: req.params.rowId, - }, - args - ); - }, - }, - {}, - - { nested: { [key]: req.query } } - ) - )?.[key]; - - const count = await baseModel.getBtChildrenExcludedListCount( - { - colId: req.params.colId, - cid: req.params.rowId, - }, - req.query - ); - - res.json( - new PagedResponseImpl(data, { - count, - ...req.query, - }) - ); -} - -export async function hmList(req: Request, res: Response, next) { - const view = await View.get(req.params.viewId); - - const model = await Model.getByIdOrName({ - id: view?.fk_model_id || req.params.viewId, - }); - - if (!model) return next(new Error('Table not found')); - - const base = await Base.get(model.base_id); - - const baseModel = await Model.getBaseModelSQL({ - id: model.id, - viewId: view?.id, - dbDriver: NcConnectionMgrv2.get(base), - }); - - const key = `${model.title}List`; - const requestObj: any = { - [key]: 1, - }; - - const data = ( - await nocoExecute( - requestObj, - { - [key]: async (args) => { - return await baseModel.hmList( - { - colId: req.params.colId, - id: req.params.rowId, - }, - args - ); - }, - }, - {}, - { nested: { [key]: req.query } } - ) - )?.[key]; - - const count = await baseModel.hmListCount({ - colId: req.params.colId, - id: req.params.rowId, - }); - - res.json( - new PagedResponseImpl(data, { - totalRows: count, - } as any) - ); -} - -async function dataRead(req: Request, res: Response, next) { - try { - const model = await Model.getByIdOrName({ - id: req.params.viewId, - }); - if (!model) return next(new Error('Table not found')); - - const base = await Base.get(model.base_id); - - const baseModel = await Model.getBaseModelSQL({ - id: model.id, - dbDriver: NcConnectionMgrv2.get(base), - }); - - res.json( - await nocoExecute( - await getAst({ model, query: req.query }), - await baseModel.readByPk(req.params.rowId), - {}, - {} - ) - ); - } catch (e) { - console.log(e); - NcError.internalServerError( - 'Internal Server Error, check server log for more details' - ); - } -} - -async function dataInsert(req: Request, res: Response, next) { - try { - const model = await Model.getByIdOrName({ - id: req.params.viewId, - }); - if (!model) return next(new Error('Table not found')); - - const base = await Base.get(model.base_id); - - const baseModel = await Model.getBaseModelSQL({ - id: model.id, - dbDriver: NcConnectionMgrv2.get(base), - }); - - res.json(await baseModel.insert(req.body, null, req)); - } catch (e) { - console.log(e); - res.status(500).json({ msg: e.message }); - } -} - -// async function dataInsertNew(req: Request, res: Response) { -// const { model, view } = await getViewAndModelFromRequest(req); -// -// const base = await Base.get(model.base_id); -// -// const baseModel = await Model.getBaseModelSQL({ -// id: model.id, -// viewId: view?.id, -// dbDriver: NcConnectionMgrv2.get(base) -// }); -// -// res.json(await baseModel.insert(req.body, null, req)); -// } - -// async function dataUpdateNew(req: Request, res: Response) { -// const { model, view } = await getViewAndModelFromRequest(req); -// const base = await Base.get(model.base_id); -// -// const baseModel = await Model.getBaseModelSQL({ -// id: model.id, -// viewId: view.id, -// dbDriver: NcConnectionMgrv2.get(base) -// }); -// -// res.json(await baseModel.updateByPk(req.params.rowId, req.body, null, req)); -// } -async function dataUpdate(req: Request, res: Response, next) { - try { - const model = await Model.getByIdOrName({ - id: req.params.viewId, - }); - if (!model) return next(new Error('Table not found')); - - const base = await Base.get(model.base_id); - - const baseModel = await Model.getBaseModelSQL({ - id: model.id, - dbDriver: NcConnectionMgrv2.get(base), - }); - - res.json(await baseModel.updateByPk(req.params.rowId, req.body, null, req)); - } catch (e) { - console.log(e); - res.status(500).json({ msg: e.message }); - } -} -// -// async function dataDeleteNew(req: Request, res: Response) { -// const { model, view } = await getViewAndModelFromRequest(req); -// const base = await Base.get(model.base_id); -// const baseModel = await Model.getBaseModelSQL({ -// id: model.id, -// viewId: view.id, -// dbDriver: NcConnectionMgrv2.get(base) -// }); -// -// res.json(await baseModel.delByPk(req.params.rowId, null, req)); -// } - -async function dataDelete(req: Request, res: Response, next) { - try { - const model = await Model.getByIdOrName({ - id: req.params.viewId, - }); - if (!model) return next(new Error('Table not found')); - - const base = await Base.get(model.base_id); - - const baseModel = await Model.getBaseModelSQL({ - id: model.id, - dbDriver: NcConnectionMgrv2.get(base), - }); - - res.json(await baseModel.delByPk(req.params.rowId, null, req)); - } catch (e) { - console.log(e); - res.status(500).json({ msg: e.message }); - } -} - -async function getDataList(model, view: View, req) { - const base = await Base.get(model.base_id); - - const baseModel = await Model.getBaseModelSQL({ - id: model.id, - viewId: view?.id, - dbDriver: NcConnectionMgrv2.get(base), - }); - - const requestObj = await getAst({ query: req.query, model, view }); - - const listArgs: any = { ...req.query }; - try { - listArgs.filterArr = JSON.parse(listArgs.filterArrJson); - } catch (e) {} - try { - listArgs.sortArr = JSON.parse(listArgs.sortArrJson); - } catch (e) {} - - let data = []; - let count = 0; - try { - data = await nocoExecute( - requestObj, - await baseModel.list(listArgs), - {}, - listArgs - ); - count = await baseModel.count(listArgs); - } catch (e) { - // show empty result instead of throwing error here - // e.g. search some text in a numeric field - console.log(e); - NcError.internalServerError( - 'Internal Server Error, check server log for more details' - ); - } - - return new PagedResponseImpl(data, { - count, - ...req.query, - }); -} -//@ts-ignore -async function relationDataDelete(req, res) { - const view = await View.get(req.params.viewId); - - const model = await Model.getByIdOrName({ - id: view?.fk_model_id || req.params.viewId, - }); - - if (!model) NcError.notFound('Table not found'); - - const base = await Base.get(model.base_id); - - const baseModel = await Model.getBaseModelSQL({ - id: model.id, - viewId: view?.id, - dbDriver: NcConnectionMgrv2.get(base), - }); - - await baseModel.removeChild({ - colId: req.params.colId, - childId: req.params.childId, - rowId: req.params.rowId, - cookie: req, - }); - - res.json({ msg: 'success' }); -} - -//@ts-ignore -async function relationDataAdd(req, res) { - const view = await View.get(req.params.viewId); - - const model = await Model.getByIdOrName({ - id: view?.fk_model_id || req.params.viewId, - }); - - if (!model) NcError.notFound('Table not found'); - - const base = await Base.get(model.base_id); - - const baseModel = await Model.getBaseModelSQL({ - id: model.id, - viewId: view?.id, - dbDriver: NcConnectionMgrv2.get(base), - }); - - await baseModel.addChild({ - colId: req.params.colId, - childId: req.params.childId, - rowId: req.params.rowId, - cookie: req, - }); - - res.json({ msg: 'success' }); -} - -const router = Router({ mergeParams: true }); - -// router.get('/data/:orgs/:projectName/:tableName',apiMetrics,ncMetaAclMw(dataListNew)); -// router.get( -// '/data/:orgs/:projectName/:tableName/views/:viewName', -// ncMetaAclMw(dataListNew) -// ); -// -// router.post( -// '/data/:orgs/:projectName/:tableName/views/:viewName', -// ncMetaAclMw(dataInsertNew) -// ); -// router.patch( -// '/data/:orgs/:projectName/:tableName/views/:viewName/:rowId', -// ncMetaAclMw(dataUpdateNew) -// ); -// router.delete( -// '/data/:orgs/:projectName/:tableName/views/:viewName/:rowId', -// ncMetaAclMw(dataDeleteNew) -// ); - -router.get('/data/:viewId/', apiMetrics, ncMetaAclMw(dataList, 'dataList')); -router.post( - '/data/:viewId/', - apiMetrics, - ncMetaAclMw(dataInsert, 'dataInsert') -); -router.get( - '/data/:viewId/:rowId', - apiMetrics, - ncMetaAclMw(dataRead, 'dataRead') -); -router.patch( - '/data/:viewId/:rowId', - apiMetrics, - ncMetaAclMw(dataUpdate, 'dataUpdate') -); -router.delete( - '/data/:viewId/:rowId', - apiMetrics, - ncMetaAclMw(dataDelete, 'dataDelete') -); - -router.get( - '/data/:viewId/:rowId/mm/:colId', - apiMetrics, - ncMetaAclMw(mmList, 'mmList') -); -router.get( - '/data/:viewId/:rowId/hm/:colId', - apiMetrics, - ncMetaAclMw(hmList, 'hmList') -); - -router.get( - '/data/:viewId/:rowId/mm/:colId/exclude', - ncMetaAclMw(mmExcludedList, 'mmExcludedList') -); -router.get( - '/data/:viewId/:rowId/hm/:colId/exclude', - ncMetaAclMw(hmExcludedList, 'hmExcludedList') -); -router.get( - '/data/:viewId/:rowId/bt/:colId/exclude', - ncMetaAclMw(btExcludedList, 'btExcludedList') -); - -router.post( - '/data/:viewId/:rowId/:relationType/:colId/:childId', - ncMetaAclMw(relationDataAdd, 'relationDataAdd') -); -router.delete( - '/data/:viewId/:rowId/:relationType/:colId/:childId', - ncMetaAclMw(relationDataDelete, 'relationDataDelete') -); -export default router; diff --git a/packages/nocodb/src/lib/meta/api/dataApis/index.ts b/packages/nocodb/src/lib/meta/api/dataApis/index.ts deleted file mode 100644 index 34bb194ee0..0000000000 --- a/packages/nocodb/src/lib/meta/api/dataApis/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -import dataApis from './dataApis'; -import oldDataApis from './oldDataApis'; -import dataAliasApis from './dataAliasApis'; -import bulkDataAliasApis from './bulkDataAliasApis'; -import dataAliasNestedApis from './dataAliasNestedApis'; -import dataAliasExportApis from './dataAliasExportApis'; - -export { - dataApis, - oldDataApis, - dataAliasApis, - bulkDataAliasApis, - dataAliasNestedApis, - dataAliasExportApis, -}; diff --git a/packages/nocodb/src/lib/meta/api/ee/orgTokenApis.ts b/packages/nocodb/src/lib/meta/api/ee/orgTokenApis.ts deleted file mode 100644 index 410d040c11..0000000000 --- a/packages/nocodb/src/lib/meta/api/ee/orgTokenApis.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { OrgUserRoles } from 'nocodb-sdk'; -import ApiToken from '../../../models/ApiToken'; -import { PagedResponseImpl } from '../../helpers/PagedResponse'; - -export async function apiTokenListEE(req, res) { - let fk_user_id = req.user.id; - - // if super admin get all tokens - if (req.user.roles.includes(OrgUserRoles.SUPER_ADMIN)) { - fk_user_id = undefined; - } - - res.json( - new PagedResponseImpl( - await ApiToken.listWithCreatedBy({ ...req.query, fk_user_id }), - { - ...req.query, - count: await ApiToken.count({}), - } - ) - ); -} diff --git a/packages/nocodb/src/lib/meta/api/filterApis.ts b/packages/nocodb/src/lib/meta/api/filterApis.ts deleted file mode 100644 index 1be850b7d8..0000000000 --- a/packages/nocodb/src/lib/meta/api/filterApis.ts +++ /dev/null @@ -1,175 +0,0 @@ -import { Request, Response, Router } from 'express'; -// @ts-ignore -import Model from '../../models/Model'; -import { Tele } from 'nc-help'; -// @ts-ignore -import { PagedResponseImpl } from '../helpers/PagedResponse'; -// @ts-ignore -import { Table, TableList, TableListParams, TableReq } from 'nocodb-sdk'; -// @ts-ignore -import ProjectMgrv2 from '../../db/sql-mgr/v2/ProjectMgrv2'; -// @ts-ignore -import Project from '../../models/Project'; -import Filter from '../../models/Filter'; -import ncMetaAclMw from '../helpers/ncMetaAclMw'; -import { metaApiMetrics } from '../helpers/apiMetrics'; -import { getAjvValidatorMw } from './helpers'; - -// @ts-ignore -export async function filterGet(req: Request, res: Response, next) { - try { - const filter = await Filter.get(req.params.filterId); - - res.json(filter); - } catch (e) { - console.log(e); - next(e); - } -} - -// @ts-ignore -export async function filterList( - req: Request, - res: Response, - next -) { - try { - const filter = await Filter.rootFilterList({ viewId: req.params.viewId }); - - res.json(filter); - } catch (e) { - console.log(e); - next(e); - } -} -// @ts-ignore -export async function filterChildrenRead( - req: Request, - res: Response, - next -) { - try { - const filter = await Filter.parentFilterList({ - parentId: req.params.filterParentId, - }); - - res.json(filter); - } catch (e) { - console.log(e); - next(e); - } -} - -export async function filterCreate( - req: Request, - res, - next -) { - try { - const filter = await Filter.insert({ - ...req.body, - fk_view_id: req.params.viewId, - }); - - Tele.emit('evt', { evt_type: 'filter:created' }); - res.json(filter); - } catch (e) { - console.log(e); - next(e); - } -} - -// @ts-ignore -export async function filterUpdate(req, res, next) { - try { - const filter = await Filter.update(req.params.filterId, { - ...req.body, - fk_view_id: req.params.viewId, - }); - Tele.emit('evt', { evt_type: 'filter:updated' }); - res.json(filter); - } catch (e) { - console.log(e); - next(e); - } -} - -// @ts-ignore -export async function filterDelete(req: Request, res: Response, next) { - try { - const filter = await Filter.delete(req.params.filterId); - Tele.emit('evt', { evt_type: 'filter:deleted' }); - res.json(filter); - } catch (e) { - console.log(e); - next(e); - } -} - -export async function hookFilterList( - req: Request, - res: Response -) { - const filter = await Filter.rootFilterListByHook({ - hookId: req.params.hookId, - }); - - res.json(filter); -} - -export async function hookFilterCreate(req: Request, res) { - const filter = await Filter.insert({ - ...req.body, - fk_hook_id: req.params.hookId, - }); - - Tele.emit('evt', { evt_type: 'hookFilter:created' }); - res.json(filter); -} - -const router = Router({ mergeParams: true }); -router.get( - '/api/v1/db/meta/views/:viewId/filters', - metaApiMetrics, - ncMetaAclMw(filterList, 'filterList') -); -router.post( - '/api/v1/db/meta/views/:viewId/filters', - metaApiMetrics, - getAjvValidatorMw('swagger.json#/components/schemas/FilterReq'), - ncMetaAclMw(filterCreate, 'filterCreate') -); - -router.get( - '/api/v1/db/meta/hooks/:hookId/filters', - ncMetaAclMw(hookFilterList, 'filterList') -); -router.post( - '/api/v1/db/meta/hooks/:hookId/filters', - metaApiMetrics, - getAjvValidatorMw('swagger.json#/components/schemas/FilterReq'), - ncMetaAclMw(hookFilterCreate, 'filterCreate') -); - -router.get( - '/api/v1/db/meta/filters/:filterId', - metaApiMetrics, - ncMetaAclMw(filterGet, 'filterGet') -); -router.patch( - '/api/v1/db/meta/filters/:filterId', - metaApiMetrics, - getAjvValidatorMw('swagger.json#/components/schemas/FilterReq'), - ncMetaAclMw(filterUpdate, 'filterUpdate') -); -router.delete( - '/api/v1/db/meta/filters/:filterId', - metaApiMetrics, - ncMetaAclMw(filterDelete, 'filterDelete') -); -router.get( - '/api/v1/db/meta/filters/:filterParentId/children', - metaApiMetrics, - ncMetaAclMw(filterChildrenRead, 'filterChildrenRead') -); -export default router; diff --git a/packages/nocodb/src/lib/meta/api/formViewApis.ts b/packages/nocodb/src/lib/meta/api/formViewApis.ts deleted file mode 100644 index beadf3cded..0000000000 --- a/packages/nocodb/src/lib/meta/api/formViewApis.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { Request, Response, Router } from 'express'; -// @ts-ignore -import Model from '../../models/Model'; -import { Tele } from 'nc-help'; -// @ts-ignore -import { PagedResponseImpl } from '../helpers/PagedResponse'; -import { FormType, ViewTypes } from 'nocodb-sdk'; -// @ts-ignore -import ProjectMgrv2 from '../../db/sql-mgr/v2/ProjectMgrv2'; -// @ts-ignore -import Project from '../../models/Project'; -import View from '../../models/View'; -import FormView from '../../models/FormView'; -import ncMetaAclMw from '../helpers/ncMetaAclMw'; -import { metaApiMetrics } from '../helpers/apiMetrics'; -import { getAjvValidatorMw } from './helpers'; - -// @ts-ignore -export async function formViewGet(req: Request, res: Response) { - const formViewData = await FormView.getWithInfo(req.params.formViewId); - res.json(formViewData); -} - -export async function formViewCreate(req: Request, res) { - Tele.emit('evt', { evt_type: 'vtable:created', show_as: 'form' }); - const view = await View.insert({ - ...req.body, - // todo: sanitize - fk_model_id: req.params.tableId, - type: ViewTypes.FORM, - }); - res.json(view); -} -// @ts-ignore -export async function formViewUpdate(req, res) { - Tele.emit('evt', { evt_type: 'view:updated', type: 'grid' }); - res.json(await FormView.update(req.params.formViewId, req.body)); -} - -// @ts-ignore -export async function formViewDelete(req: Request, res: Response, next) {} - -const router = Router({ mergeParams: true }); -router.post( - '/api/v1/db/meta/tables/:tableId/forms', - metaApiMetrics, - getAjvValidatorMw('swagger.json#/components/schemas/FormCreateReq'), - ncMetaAclMw(formViewCreate, 'formViewCreate') -); -router.get( - '/api/v1/db/meta/forms/:formViewId', - metaApiMetrics, - ncMetaAclMw(formViewGet, 'formViewGet') -); -router.patch( - '/api/v1/db/meta/forms/:formViewId', - metaApiMetrics, - getAjvValidatorMw('swagger.json#/components/schemas/FormReq'), - ncMetaAclMw(formViewUpdate, 'formViewUpdate') -); -router.delete( - '/api/v1/db/meta/forms/:formViewId', - metaApiMetrics, - ncMetaAclMw(formViewDelete, 'formViewDelete') -); -export default router; diff --git a/packages/nocodb/src/lib/meta/api/formViewColumnApis.ts b/packages/nocodb/src/lib/meta/api/formViewColumnApis.ts deleted file mode 100644 index bad2f91b0a..0000000000 --- a/packages/nocodb/src/lib/meta/api/formViewColumnApis.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Request, Response, Router } from 'express'; -import FormViewColumn from '../../models/FormViewColumn'; -import { Tele } from 'nc-help'; -import ncMetaAclMw from '../helpers/ncMetaAclMw'; -import { metaApiMetrics } from '../helpers/apiMetrics'; -import { getAjvValidatorMw } from './helpers'; - -export async function columnUpdate(req: Request, res: Response) { - Tele.emit('evt', { evt_type: 'formViewColumn:updated' }); - res.json(await FormViewColumn.update(req.params.formViewColumnId, req.body)); -} - -const router = Router({ mergeParams: true }); -router.patch( - '/api/v1/db/meta/form-columns/:formViewColumnId', - metaApiMetrics, - getAjvValidatorMw('swagger.json#/components/schemas/FormColumnReq'), - ncMetaAclMw(columnUpdate, 'columnUpdate') -); -export default router; diff --git a/packages/nocodb/src/lib/meta/api/galleryViewApis.ts b/packages/nocodb/src/lib/meta/api/galleryViewApis.ts deleted file mode 100644 index 2c6c79db9e..0000000000 --- a/packages/nocodb/src/lib/meta/api/galleryViewApis.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { Request, Response, Router } from 'express'; -import { GalleryType, ViewTypes } from 'nocodb-sdk'; -import View from '../../models/View'; -import GalleryView from '../../models/GalleryView'; -import { Tele } from 'nc-help'; -import ncMetaAclMw from '../helpers/ncMetaAclMw'; -import { metaApiMetrics } from '../helpers/apiMetrics'; -import { getAjvValidatorMw } from './helpers'; -export async function galleryViewGet(req: Request, res: Response) { - res.json(await GalleryView.get(req.params.galleryViewId)); -} - -export async function galleryViewCreate(req: Request, res) { - Tele.emit('evt', { evt_type: 'vtable:created', show_as: 'gallery' }); - const view = await View.insert({ - ...req.body, - // todo: sanitize - fk_model_id: req.params.tableId, - type: ViewTypes.GALLERY, - }); - res.json(view); -} - -export async function galleryViewUpdate(req, res) { - Tele.emit('evt', { evt_type: 'view:updated', type: 'gallery' }); - res.json(await GalleryView.update(req.params.galleryViewId, req.body)); -} - -const router = Router({ mergeParams: true }); -router.post( - '/api/v1/db/meta/tables/:tableId/galleries', - metaApiMetrics, - getAjvValidatorMw('swagger.json#/components/schemas/GalleryReq'), - ncMetaAclMw(galleryViewCreate, 'galleryViewCreate') -); -router.patch( - '/api/v1/db/meta/galleries/:galleryViewId', - metaApiMetrics, - getAjvValidatorMw('swagger.json#/components/schemas/GalleryReq'), - ncMetaAclMw(galleryViewUpdate, 'galleryViewUpdate') -); -router.get( - '/api/v1/db/meta/galleries/:galleryViewId', - metaApiMetrics, - ncMetaAclMw(galleryViewGet, 'galleryViewGet') -); -export default router; diff --git a/packages/nocodb/src/lib/meta/api/gridViewApis.ts b/packages/nocodb/src/lib/meta/api/gridViewApis.ts deleted file mode 100644 index 96880398cb..0000000000 --- a/packages/nocodb/src/lib/meta/api/gridViewApis.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { Request, Router } from 'express'; -// @ts-ignore -import Model from '../../models/Model'; -import { Tele } from 'nc-help'; -// @ts-ignore -import { PagedResponseImpl } from '../helpers/PagedResponse'; -import { ViewTypes } from 'nocodb-sdk'; -// @ts-ignore -import ProjectMgrv2 from '../../db/sql-mgr/v2/ProjectMgrv2'; -// @ts-ignore -import Project from '../../models/Project'; -import View from '../../models/View'; -import ncMetaAclMw from '../helpers/ncMetaAclMw'; -import { metaApiMetrics } from '../helpers/apiMetrics'; -import GridView from '../../models/GridView'; -import { getAjvValidatorMw } from './helpers'; - -// @ts-ignore -export async function gridViewCreate(req: Request, res) { - const view = await View.insert({ - ...req.body, - // todo: sanitize - fk_model_id: req.params.tableId, - type: ViewTypes.GRID, - }); - Tele.emit('evt', { evt_type: 'vtable:created', show_as: 'grid' }); - res.json(view); -} - -export async function gridViewUpdate(req, res) { - Tele.emit('evt', { evt_type: 'view:updated', type: 'grid' }); - res.json(await GridView.update(req.params.viewId, req.body)); -} - -const router = Router({ mergeParams: true }); -router.post( - '/api/v1/db/meta/tables/:tableId/grids/', - metaApiMetrics, - getAjvValidatorMw('swagger.json#/components/schemas/GridReq'), - ncMetaAclMw(gridViewCreate, 'gridViewCreate') -); -router.patch( - '/api/v1/db/meta/grids/:viewId', - metaApiMetrics, - ncMetaAclMw(gridViewUpdate, 'gridViewUpdate') -); -export default router; diff --git a/packages/nocodb/src/lib/meta/api/gridViewColumnApis.ts b/packages/nocodb/src/lib/meta/api/gridViewColumnApis.ts deleted file mode 100644 index 28669a6a2f..0000000000 --- a/packages/nocodb/src/lib/meta/api/gridViewColumnApis.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { Request, Response, Router } from 'express'; -import GridViewColumn from '../../models/GridViewColumn'; -import { Tele } from 'nc-help'; -import ncMetaAclMw from '../helpers/ncMetaAclMw'; -import { metaApiMetrics } from '../helpers/apiMetrics'; -import { getAjvValidatorMw } from './helpers'; - -export async function columnList(req: Request, res: Response) { - res.json(await GridViewColumn.list(req.params.gridViewId)); -} - -export async function gridColumnUpdate(req: Request, res: Response) { - Tele.emit('evt', { evt_type: 'gridViewColumn:updated' }); - res.json(await GridViewColumn.update(req.params.gridViewColumnId, req.body)); -} - -const router = Router({ mergeParams: true }); -router.get( - '/api/v1/db/meta/grids/:gridViewId/grid-columns', - metaApiMetrics, - ncMetaAclMw(columnList, 'columnList') -); -router.patch( - '/api/v1/db/meta/grid-columns/:gridViewColumnId', - metaApiMetrics, - getAjvValidatorMw('swagger.json#/components/schemas/GridColumnReq'), - ncMetaAclMw(gridColumnUpdate, 'gridColumnUpdate') -); -export default router; diff --git a/packages/nocodb/src/lib/meta/api/helpers/apiHelpers.ts b/packages/nocodb/src/lib/meta/api/helpers/apiHelpers.ts index 49d1fbc462..4319f59c82 100644 --- a/packages/nocodb/src/lib/meta/api/helpers/apiHelpers.ts +++ b/packages/nocodb/src/lib/meta/api/helpers/apiHelpers.ts @@ -1,7 +1,10 @@ -import { NextFunction, Request, Response } from 'express'; -import Ajv, { ErrorObject } from 'ajv'; +import Ajv from 'ajv'; +import addFormats from 'ajv-formats'; // @ts-ignore import swagger from '../../../../schema/swagger.json'; +import { NcError } from '../../helpers/catchError'; +import type { ErrorObject } from 'ajv'; +import type { NextFunction, Request, Response } from 'express'; export function parseHrtimeToSeconds(hrtime) { const seconds = (hrtime[0] + hrtime[1] / 1e6).toFixed(3); @@ -11,6 +14,7 @@ export function parseHrtimeToSeconds(hrtime) { const ajv = new Ajv({ strictSchema: false, strict: false }); // Initialize AJV ajv.addSchema(swagger, 'swagger.json'); +addFormats(ajv); // A middleware generator to validate the request body export const getAjvValidatorMw = (schema) => { @@ -29,10 +33,29 @@ export const getAjvValidatorMw = (schema) => { // If the request body is invalid, send a response with an error message res.status(400).json({ - status: 'error', message: 'Invalid request body', errors, }); } }; }; + +// a function to validate the payload against the schema +export const validatePayload = (schema, payload) => { + // Validate the request body against the schema + const valid = ajv.validate( + typeof schema === 'string' ? { $ref: schema } : schema, + payload + ); + + // If the request body is not valid, throw error + if (!valid) { + const errors: ErrorObject[] | null | undefined = ajv.errors; + + // If the request body is invalid, throw error with error message and errors + NcError.ajvValidationError({ + message: 'Invalid request body', + errors, + }); + } +}; diff --git a/packages/nocodb/src/lib/meta/api/helpers/columnHelpers.ts b/packages/nocodb/src/lib/meta/api/helpers/columnHelpers.ts index daf9344126..49dd049de1 100644 --- a/packages/nocodb/src/lib/meta/api/helpers/columnHelpers.ts +++ b/packages/nocodb/src/lib/meta/api/helpers/columnHelpers.ts @@ -1,20 +1,20 @@ import { customAlphabet } from 'nanoid'; -import { +import { UITypes } from 'nocodb-sdk'; +import Column from '../../../models/Column'; +import { getUniqueColumnAliasName } from '../../helpers/getUniqueName'; +import validateParams from '../../helpers/validateParams'; +import type { + BoolType, ColumnReqType, LinkToAnotherRecordType, LookupColumnReqType, - BoolType, RelationTypes, RollupColumnReqType, TableType, - UITypes, } from 'nocodb-sdk'; -import Column from '../../../models/Column'; -import LinkToAnotherRecordColumn from '../../../models/LinkToAnotherRecordColumn'; -import LookupColumn from '../../../models/LookupColumn'; -import Model from '../../../models/Model'; -import { getUniqueColumnAliasName } from '../../helpers/getUniqueName'; -import validateParams from '../../helpers/validateParams'; +import type LinkToAnotherRecordColumn from '../../../models/LinkToAnotherRecordColumn'; +import type LookupColumn from '../../../models/LookupColumn'; +import type Model from '../../../models/Model'; export const randomID = customAlphabet( '1234567890abcdefghijklmnopqrstuvwxyz_', @@ -77,9 +77,7 @@ export async function createHmAndBtColumn( } } -export async function validateRollupPayload( - payload: ColumnReqType & { uidt: UITypes } -) { +export async function validateRollupPayload(payload: ColumnReqType | Column) { validateParams( [ 'title', @@ -125,7 +123,7 @@ export async function validateRollupPayload( } export async function validateLookupPayload( - payload: ColumnReqType & { uidt: UITypes }, + payload: ColumnReqType, columnId?: string ) { validateParams( diff --git a/packages/nocodb/src/lib/meta/api/helpers/populateMeta.ts b/packages/nocodb/src/lib/meta/api/helpers/populateMeta.ts index ffe246a131..2e5b3a8aa8 100644 --- a/packages/nocodb/src/lib/meta/api/helpers/populateMeta.ts +++ b/packages/nocodb/src/lib/meta/api/helpers/populateMeta.ts @@ -1,19 +1,19 @@ -import Project from '../../../models/Project'; +import { ModelTypes, UITypes, ViewTypes } from 'nocodb-sdk'; import Column from '../../../models/Column'; import Model from '../../../models/Model'; import NcHelp from '../../../utils/NcHelp'; -import Base from '../../../models/Base'; import View from '../../../models/View'; import NcConnectionMgrv2 from '../../../utils/common/NcConnectionMgrv2'; import getTableNameAlias, { getColumnNameAlias, } from '../../helpers/getTableName'; -import LinkToAnotherRecordColumn from '../../../models/LinkToAnotherRecordColumn'; import getColumnUiType from '../../helpers/getColumnUiType'; import mapDefaultDisplayValue from '../../helpers/mapDefaultDisplayValue'; -import { extractAndGenerateManyToManyRelations } from '../metaDiffApis'; -import { ModelTypes, UITypes, ViewTypes } from 'nocodb-sdk'; +import { extractAndGenerateManyToManyRelations } from '../../../services/metaDiff.svc'; import { IGNORE_TABLES } from '../../../utils/common/BaseApiBuilder'; +import type LinkToAnotherRecordColumn from '../../../models/LinkToAnotherRecordColumn'; +import type Base from '../../../models/Base'; +import type Project from '../../../models/Project'; export async function populateMeta(base: Base, project: Project): Promise { const info = { @@ -22,7 +22,7 @@ export async function populateMeta(base: Base, project: Project): Promise { tablesCount: 0, relationsCount: 0, viewsCount: 0, - client: base?.getConnectionConfig()?.client, + client: (await base?.getConnectionConfig())?.client, timeTaken: 0, }; diff --git a/packages/nocodb/src/lib/meta/api/hookApis.ts b/packages/nocodb/src/lib/meta/api/hookApis.ts deleted file mode 100644 index bf0b29b6ec..0000000000 --- a/packages/nocodb/src/lib/meta/api/hookApis.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { Tele } from 'nc-help'; -import catchError from '../helpers/catchError'; -import { Request, Response, Router } from 'express'; -import Hook from '../../models/Hook'; -import { HookListType, HookType } from 'nocodb-sdk'; -import { PagedResponseImpl } from '../helpers/PagedResponse'; -import { invokeWebhook } from '../helpers/webhookHelpers'; -import Model from '../../models/Model'; -import populateSamplePayload from '../helpers/populateSamplePayload'; -import ncMetaAclMw from '../helpers/ncMetaAclMw'; -import { metaApiMetrics } from '../helpers/apiMetrics'; -import { getAjvValidatorMw } from './helpers'; - -export async function hookList( - req: Request, - res: Response -) { - // todo: pagination - res.json( - new PagedResponseImpl(await Hook.list({ fk_model_id: req.params.tableId })) - ); -} - -export async function hookCreate( - req: Request, - res: Response -) { - Tele.emit('evt', { evt_type: 'webhooks:created' }); - const hook = await Hook.insert({ - ...req.body, - fk_model_id: req.params.tableId, - }); - res.json(hook); -} - -export async function hookDelete( - req: Request, - res: Response -) { - Tele.emit('evt', { evt_type: 'webhooks:deleted' }); - res.json(await Hook.delete(req.params.hookId)); -} - -export async function hookUpdate( - req: Request, - res: Response -) { - Tele.emit('evt', { evt_type: 'webhooks:updated' }); - - res.json(await Hook.update(req.params.hookId, req.body)); -} - -export async function hookTest(req: Request, res: Response) { - const model = await Model.getByIdOrName({ id: req.params.tableId }); - - const { - hook, - payload: { data, user }, - } = req.body; - await invokeWebhook( - new Hook(hook), - model, - data, - user, - (hook as any)?.filters, - true - ); - - Tele.emit('evt', { evt_type: 'webhooks:tested' }); - - res.json({ msg: 'Success' }); -} -export async function tableSampleData(req: Request, res: Response) { - const model = await Model.getByIdOrName({ id: req.params.tableId }); - - res // todo: pagination - .json(await populateSamplePayload(model, false, req.params.operation)); -} - -const router = Router({ mergeParams: true }); -router.get( - '/api/v1/db/meta/tables/:tableId/hooks', - metaApiMetrics, - ncMetaAclMw(hookList, 'hookList') -); -router.post( - '/api/v1/db/meta/tables/:tableId/hooks/test', - metaApiMetrics, - getAjvValidatorMw('swagger.json#/components/schemas/HookTestReq'), - ncMetaAclMw(hookTest, 'hookTest') -); -router.post( - '/api/v1/db/meta/tables/:tableId/hooks', - metaApiMetrics, - getAjvValidatorMw('swagger.json#/components/schemas/HookReq'), - ncMetaAclMw(hookCreate, 'hookCreate') -); -router.delete( - '/api/v1/db/meta/hooks/:hookId', - metaApiMetrics, - ncMetaAclMw(hookDelete, 'hookDelete') -); -router.patch( - '/api/v1/db/meta/hooks/:hookId', - metaApiMetrics, - getAjvValidatorMw('swagger.json#/components/schemas/HookReq'), - ncMetaAclMw(hookUpdate, 'hookUpdate') -); -router.get( - '/api/v1/db/meta/tables/:tableId/hooks/samplePayload/:operation', - metaApiMetrics, - catchError(tableSampleData) -); -export default router; diff --git a/packages/nocodb/src/lib/meta/api/hookFilterApis.ts b/packages/nocodb/src/lib/meta/api/hookFilterApis.ts deleted file mode 100644 index 7b182fcab4..0000000000 --- a/packages/nocodb/src/lib/meta/api/hookFilterApis.ts +++ /dev/null @@ -1,145 +0,0 @@ -import { Request, Response, Router } from 'express'; -// @ts-ignore -import Model from '../../models/Model'; -import { Tele } from 'nc-help'; -// @ts-ignore -import { PagedResponseImpl } from '../helpers/PagedResponse'; -// @ts-ignore -import { Table, TableList, TableListParams, TableReq } from 'nocodb-sdk'; -// @ts-ignore -import ProjectMgrv2 from '../../db/sql-mgr/v2/ProjectMgrv2'; -// @ts-ignore -import Project from '../../models/Project'; -import Filter from '../../models/Filter'; -import ncMetaAclMw from '../helpers/ncMetaAclMw'; -import { metaApiMetrics } from '../helpers/apiMetrics'; -import { getAjvValidatorMw } from './helpers'; - -// @ts-ignore -export async function filterGet(req: Request, res: Response, next) { - try { - const filter = await Filter.getFilterObject({ hookId: req.params.hookId }); - - res.json(filter); - } catch (e) { - console.log(e); - next(e); - } -} - -// @ts-ignore -export async function filterList( - req: Request, - res: Response, - next -) { - try { - const filter = await Filter.rootFilterListByHook({ - hookId: req.params.hookId, - }); - - res.json(filter); - } catch (e) { - console.log(e); - next(e); - } -} -// @ts-ignore -export async function filterChildrenRead( - req: Request, - res: Response, - next -) { - try { - const filter = await Filter.parentFilterListByHook({ - hookId: req.params.hookId, - parentId: req.params.filterParentId, - }); - - res.json(filter); - } catch (e) { - console.log(e); - next(e); - } -} - -export async function filterCreate( - req: Request, - res, - next -) { - try { - const filter = await Filter.insert({ - ...req.body, - fk_hook_id: req.params.hookId, - }); - - Tele.emit('evt', { evt_type: 'hookFilter:created' }); - res.json(filter); - } catch (e) { - console.log(e); - next(e); - } -} - -// @ts-ignore -export async function filterUpdate(req, res, next) { - try { - const filter = await Filter.update(req.params.filterId, { - ...req.body, - fk_hook_id: req.params.hookId, - }); - Tele.emit('evt', { evt_type: 'hookFilter:updated' }); - res.json(filter); - } catch (e) { - console.log(e); - next(e); - } -} - -// @ts-ignore -export async function filterDelete(req: Request, res: Response, next) { - try { - const filter = await Filter.delete(req.params.filterId); - Tele.emit('evt', { evt_type: 'hookFilter:deleted' }); - res.json(filter); - } catch (e) { - console.log(e); - next(e); - } -} - -const router = Router({ mergeParams: true }); -router.get( - '/hooks/:hookId/filters/', - metaApiMetrics, - ncMetaAclMw(filterList, 'filterList') -); -router.post( - '/hooks/:hookId/filters/', - metaApiMetrics, - getAjvValidatorMw('swagger.json#/components/schemas/FilterReq'), - ncMetaAclMw(filterCreate, 'filterCreate') -); -router.get( - '/hooks/:hookId/filters/:filterId', - metaApiMetrics, - ncMetaAclMw(filterGet, 'filterGet') -); -router.patch( - '/hooks/:hookId/filters/:filterId', - metaApiMetrics, - getAjvValidatorMw('swagger.json#/components/schemas/FilterReq'), - ncMetaAclMw(filterUpdate, 'filterUpdate') -); -router.delete( - '/hooks/:hookId/filters/:filterId', - metaApiMetrics, - ncMetaAclMw(filterDelete, 'filterDelete') -); -router.get( - '/hooks/:hookId/filters/:filterParentId/children', - metaApiMetrics, - ncMetaAclMw(filterChildrenRead, 'filterChildrenRead') -); -export default router; diff --git a/packages/nocodb/src/lib/meta/api/index.ts b/packages/nocodb/src/lib/meta/api/index.ts index 67e6203407..9900eb9537 100644 --- a/packages/nocodb/src/lib/meta/api/index.ts +++ b/packages/nocodb/src/lib/meta/api/index.ts @@ -1,114 +1,114 @@ -import { Tele } from 'nc-help'; -import orgLicenseApis from './orgLicenseApis'; -import orgTokenApis from './orgTokenApis'; -import orgUserApis from './orgUserApis'; -import projectApis from './projectApis'; -import baseApis from './baseApis'; -import tableApis from './tableApis'; -import columnApis from './columnApis'; -import { Router } from 'express'; -import sortApis from './sortApis'; -import filterApis from './filterApis'; -import viewColumnApis from './viewColumnApis'; -import gridViewApis from './gridViewApis'; -import viewApis from './viewApis'; -import galleryViewApis from './galleryViewApis'; -import formViewApis from './formViewApis'; -import formViewColumnApis from './formViewColumnApis'; -import attachmentApis from './attachmentApis'; -import exportApis from './exportApis'; -import auditApis from './auditApis'; -import hookApis from './hookApis'; -import pluginApis from './pluginApis'; -import gridViewColumnApis from './gridViewColumnApis'; -import kanbanViewApis from './kanbanViewApis'; -import { userApis } from './userApi'; +import crypto from 'crypto'; +import { T } from 'nc-help'; +import { Server } from 'socket.io'; +import passport from 'passport'; +import orgLicenseController from '../../controllers/orgLicense.ctl'; +import orgTokenController from '../../controllers/orgToken.ctl'; +import orgUserController from '../../controllers/orgUser.ctl'; +import projectController from '../../controllers/project.ctl'; +import baseController from '../../controllers/base.ctl'; +import tableController from '../../controllers/table.ctl'; +import columnController from '../../controllers/column.ctl'; +import sortController from '../../controllers/sort.ctl'; +import filterController from '../../controllers/filter.ctl'; +import viewColumnController from '../../controllers/viewColumn.ctl'; +import gridViewController from '../../controllers/views/gridView.ctl'; +import viewController from '../../controllers/view.ctl'; +import galleryViewController from '../../controllers/views/galleryView.ctl'; +import formViewController from '../../controllers/views/formView.ctl'; +import formViewColumnController from '../../controllers/views/formViewColumn.ctl'; +import attachmentController from '../../controllers/attachment.ctl'; +import exportController from '../../controllers/export.ctl'; +import auditController from '../../controllers/audit.ctl'; +import hookController from '../../controllers/hook.ctl'; +import pluginController from '../../controllers/plugin.ctl'; +import gridViewColumnController from '../../controllers/views/gridViewColumn.ctl'; +import kanbanViewController from '../../controllers/views/kanbanView.ctl'; +import { userController } from '../../controllers/user'; // import extractProjectIdAndAuthenticate from './helpers/extractProjectIdAndAuthenticate'; -import utilApis from './utilApis'; -import projectUserApis from './projectUserApis'; -import sharedBaseApis from './sharedBaseApis'; -import { initStrategies } from './userApi/initStrategies'; -import modelVisibilityApis from './modelVisibilityApis'; -import metaDiffApis from './metaDiffApis'; -import cacheApis from './cacheApis'; -import apiTokenApis from './apiTokenApis'; -import hookFilterApis from './hookFilterApis'; -import testApis from './testApis'; +import utilController from '../../controllers/util.ctl'; +import projectUserController from '../../controllers/projectUser.ctl'; +import sharedBaseController from '../../controllers/sharedBase.ctl'; +import { initStrategies } from '../../controllers/user/initStrategies'; +import modelVisibilityController from '../../controllers/modelVisibility.ctl'; +import metaDiffController from '../../controllers/metaDiff.ctl'; +import cacheController from '../../controllers/cache.ctl'; +import apiTokenController from '../../controllers/apiToken.ctl'; +import hookFilterController from '../../controllers/hookFilter.ctl'; +import testController from '../../controllers/test.ctl'; import { - bulkDataAliasApis, - dataAliasApis, - dataAliasExportApis, - dataAliasNestedApis, - dataApis, - oldDataApis, -} from './dataApis'; + bulkDataAliasController, + dataAliasController, + dataAliasExportController, + dataAliasNestedController, + dataController, + oldDataController, +} from '../../controllers/dbData'; import { - publicDataApis, - publicDataExportApis, - publicMetaApis, -} from './publicApis'; -import { Server, Socket } from 'socket.io'; -import passport from 'passport'; + publicDataController, + publicDataExportController, + publicMetaController, +} from '../../controllers/publicControllers'; -import crypto from 'crypto'; -import swaggerApis from './swagger/swaggerApis'; -import importApis from './sync/importApis'; -import syncSourceApis from './sync/syncSourceApis'; -import mapViewApis from './mapViewApis'; +import swaggerController from '../../controllers/apiDocs'; +import { importController, syncSourceController } from '../../controllers/sync'; +import mapViewController from '../../controllers/views/mapView.ctl'; +import type { Socket } from 'socket.io'; +import type { Router } from 'express'; const clients: { [id: string]: Socket } = {}; const jobs: { [id: string]: { last_message: any } } = {}; export default function (router: Router, server) { initStrategies(router); - projectApis(router); - baseApis(router); - utilApis(router); + projectController(router); + baseController(router); + utilController(router); if (process.env['PLAYWRIGHT_TEST'] === 'true') { - router.use(testApis); + router.use(testController); } - router.use(columnApis); - router.use(exportApis); - router.use(dataApis); - router.use(bulkDataAliasApis); - router.use(dataAliasApis); - router.use(dataAliasNestedApis); - router.use(dataAliasExportApis); - router.use(oldDataApis); - router.use(sortApis); - router.use(filterApis); - router.use(viewColumnApis); - router.use(gridViewApis); - router.use(formViewColumnApis); - router.use(publicDataApis); - router.use(publicDataExportApis); - router.use(publicMetaApis); - router.use(gridViewColumnApis); - router.use(tableApis); - router.use(galleryViewApis); - router.use(formViewApis); - router.use(viewApis); - router.use(attachmentApis); - router.use(auditApis); - router.use(hookApis); - router.use(pluginApis); - router.use(projectUserApis); - router.use(orgUserApis); - router.use(orgTokenApis); - router.use(orgLicenseApis); - router.use(sharedBaseApis); - router.use(modelVisibilityApis); - router.use(metaDiffApis); - router.use(cacheApis); - router.use(apiTokenApis); - router.use(hookFilterApis); - router.use(swaggerApis); - router.use(syncSourceApis); - router.use(kanbanViewApis); - router.use(mapViewApis); + router.use(columnController); + router.use(exportController); + router.use(dataController); + router.use(bulkDataAliasController); + router.use(dataAliasController); + router.use(dataAliasNestedController); + router.use(dataAliasExportController); + router.use(oldDataController); + router.use(sortController); + router.use(filterController); + router.use(viewColumnController); + router.use(gridViewController); + router.use(formViewColumnController); + router.use(publicDataController); + router.use(publicDataExportController); + router.use(publicMetaController); + router.use(gridViewColumnController); + router.use(tableController); + router.use(galleryViewController); + router.use(formViewController); + router.use(viewController); + router.use(attachmentController); + router.use(auditController); + router.use(hookController); + router.use(pluginController); + router.use(projectUserController); + router.use(orgUserController); + router.use(orgTokenController); + router.use(orgLicenseController); + router.use(sharedBaseController); + router.use(modelVisibilityController); + router.use(metaDiffController); + router.use(cacheController); + router.use(apiTokenController); + router.use(hookFilterController); + router.use(swaggerController); + router.use(syncSourceController); + router.use(kanbanViewController); + router.use(mapViewController); - userApis(router); + userController(router); const io = new Server(server, { cors: { @@ -133,15 +133,15 @@ export default function (router: Router, server) { }).on('connection', (socket) => { clients[socket.id] = socket; const id = getHash( - (process.env.NC_SERVER_UUID || Tele.id) + + (process.env.NC_SERVER_UUID || T.id) + (socket?.handshake as any)?.user?.id ); socket.on('page', (args) => { - Tele.page({ ...args, id }); + T.page({ ...args, id }); }); socket.on('event', (args) => { - Tele.event({ ...args, id }); + T.event({ ...args, id }); }); socket.on('subscribe', (room) => { if (room in jobs) { @@ -152,7 +152,7 @@ export default function (router: Router, server) { }); }); - importApis(router, io, jobs); + importController(router, io, jobs); } function getHash(str) { diff --git a/packages/nocodb/src/lib/meta/api/mapViewApis.ts b/packages/nocodb/src/lib/meta/api/mapViewApis.ts deleted file mode 100644 index 5771284da4..0000000000 --- a/packages/nocodb/src/lib/meta/api/mapViewApis.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { Request, Response, Router } from 'express'; -import { MapType, ViewTypes } from 'nocodb-sdk'; -import View from '../../models/View'; -import ncMetaAclMw from '../helpers/ncMetaAclMw'; -import { Tele } from 'nc-help'; -import { metaApiMetrics } from '../helpers/apiMetrics'; -import MapView from '../../models/MapView'; - -export async function mapViewGet(req: Request, res: Response) { - res.json(await MapView.get(req.params.mapViewId)); -} - -export async function mapViewCreate(req: Request, res) { - Tele.emit('evt', { evt_type: 'vtable:created', show_as: 'map' }); - const view = await View.insert({ - ...req.body, - // todo: sanitize - fk_model_id: req.params.tableId, - type: ViewTypes.MAP, - }); - res.json(view); -} - -export async function mapViewUpdate(req, res) { - Tele.emit('evt', { evt_type: 'view:updated', type: 'map' }); - res.json(await MapView.update(req.params.mapViewId, req.body)); -} - -const router = Router({ mergeParams: true }); - -// todo: add schema in swagger and use getAjvValidatorMw -router.post( - '/api/v1/db/meta/tables/:tableId/maps', - metaApiMetrics, - ncMetaAclMw(mapViewCreate, 'mapViewCreate') -); -router.patch( - '/api/v1/db/meta/maps/:mapViewId', - metaApiMetrics, - ncMetaAclMw(mapViewUpdate, 'mapViewUpdate') -); -router.get( - '/api/v1/db/meta/maps/:mapViewId', - metaApiMetrics, - ncMetaAclMw(mapViewGet, 'mapViewGet') -); -export default router; diff --git a/packages/nocodb/src/lib/meta/api/modelVisibilityApis.ts b/packages/nocodb/src/lib/meta/api/modelVisibilityApis.ts deleted file mode 100644 index 26dc965bb1..0000000000 --- a/packages/nocodb/src/lib/meta/api/modelVisibilityApis.ts +++ /dev/null @@ -1,129 +0,0 @@ -import Model from '../../models/Model'; -import ModelRoleVisibility from '../../models/ModelRoleVisibility'; -import { Router } from 'express'; -import { Tele } from 'nc-help'; -import ncMetaAclMw from '../helpers/ncMetaAclMw'; -import { metaApiMetrics } from '../helpers/apiMetrics'; -import { getAjvValidatorMw } from './helpers'; -async function xcVisibilityMetaSetAll(req, res) { - Tele.emit('evt', { evt_type: 'uiAcl:updated' }); - for (const d of req.body) { - for (const role of Object.keys(d.disabled)) { - const dataInDb = await ModelRoleVisibility.get({ - role, - // fk_model_id: d.fk_model_id, - fk_view_id: d.id, - }); - if (dataInDb) { - if (d.disabled[role]) { - if (!dataInDb.disabled) { - await ModelRoleVisibility.update(d.id, role, { - disabled: d.disabled[role], - }); - } - } else { - await dataInDb.delete(); - } - } else if (d.disabled[role]) { - await ModelRoleVisibility.insert({ - fk_view_id: d.id, - disabled: d.disabled[role], - role, - }); - } - } - } - Tele.emit('evt', { evt_type: 'uiAcl:updated' }); - - res.json({ msg: 'success' }); -} - -// @ts-ignore -export async function xcVisibilityMetaGet( - projectId, - _models: Model[] = null, - includeM2M = true - // type: 'table' | 'tableAndViews' | 'views' = 'table' -) { - // todo: move to - const roles = ['owner', 'creator', 'viewer', 'editor', 'commenter', 'guest']; - - const defaultDisabled = roles.reduce((o, r) => ({ ...o, [r]: false }), {}); - - let models = - _models || - (await Model.list({ - project_id: projectId, - base_id: undefined, - })); - - models = includeM2M ? models : (models.filter((t) => !t.mm) as Model[]); - - const result = await models.reduce(async (_obj, model) => { - const obj = await _obj; - // obj[model.id] = { - // tn: model.tn, - // _tn: model._tn, - // order: model.order, - // fk_model_id: model.id, - // id: model.id, - // type: model.type, - // disabled: { ...defaultDisabled } - // }; - // if (type === 'tableAndViews') { - const views = await model.getViews(); - for (const view of views) { - obj[view.id] = { - ptn: model.table_name, - _ptn: model.title, - ptype: model.type, - tn: view.title, - _tn: view.title, - table_meta: model.meta, - ...view, - disabled: { ...defaultDisabled }, - }; - // } - } - - return obj; - }, Promise.resolve({})); - - const disabledList = await ModelRoleVisibility.list(projectId); - - for (const d of disabledList) { - // if (d.fk_model_id) result[d.fk_model_id].disabled[d.role] = !!d.disabled; - // else if (type === 'tableAndViews' && d.fk_view_id) - if (result[d.fk_view_id]) - result[d.fk_view_id].disabled[d.role] = !!d.disabled; - } - - return Object.values(result); - // ?.sort( - // (a: any, b: any) => - // (a.order || 0) - (b.order || 0) || - // (a?._tn || a?.tn)?.localeCompare(b?._tn || b?.tn) - // ); -} - -const router = Router({ mergeParams: true }); -router.get( - '/api/v1/db/meta/projects/:projectId/visibility-rules', - metaApiMetrics, - ncMetaAclMw(async (req, res) => { - res.json( - await xcVisibilityMetaGet( - req.params.projectId, - null, - req.query.includeM2M === true || req.query.includeM2M === 'true' - ) - ); - }, 'modelVisibilityList') -); -router.post( - '/api/v1/db/meta/projects/:projectId/visibility-rules', - metaApiMetrics, - getAjvValidatorMw('swagger.json#/components/schemas/VisibilityRuleReq'), - ncMetaAclMw(xcVisibilityMetaSetAll, 'modelVisibilitySet') -); -export default router; diff --git a/packages/nocodb/src/lib/meta/api/orgTokenApis.ts b/packages/nocodb/src/lib/meta/api/orgTokenApis.ts deleted file mode 100644 index 300a804c4e..0000000000 --- a/packages/nocodb/src/lib/meta/api/orgTokenApis.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { Request, Response, Router } from 'express'; -import { OrgUserRoles } from 'nocodb-sdk'; -import ApiToken from '../../models/ApiToken'; -import { Tele } from 'nc-help'; -import { metaApiMetrics } from '../helpers/apiMetrics'; -import { NcError } from '../helpers/catchError'; -import getHandler from '../helpers/getHandler'; -import ncMetaAclMw from '../helpers/ncMetaAclMw'; -import { PagedResponseImpl } from '../helpers/PagedResponse'; -import { apiTokenListEE } from './ee/orgTokenApis'; -import { getAjvValidatorMw } from './helpers'; - -async function apiTokenList(req, res) { - const fk_user_id = req.user.id; - let includeUnmappedToken = false; - if (req['user'].roles.includes(OrgUserRoles.SUPER_ADMIN)) { - includeUnmappedToken = true; - } - - res.json( - new PagedResponseImpl( - await ApiToken.listWithCreatedBy({ - ...req.query, - fk_user_id, - includeUnmappedToken, - }), - { - ...req.query, - count: await ApiToken.count({ - includeUnmappedToken, - fk_user_id, - }), - } - ) - ); -} - -export async function apiTokenCreate(req: Request, res: Response) { - Tele.emit('evt', { evt_type: 'org:apiToken:created' }); - res.json(await ApiToken.insert({ ...req.body, fk_user_id: req['user'].id })); -} - -export async function apiTokenDelete(req: Request, res: Response) { - const fk_user_id = req['user'].id; - const apiToken = await ApiToken.getByToken(req.params.token); - if ( - !req['user'].roles.includes(OrgUserRoles.SUPER_ADMIN) && - apiToken.fk_user_id !== fk_user_id - ) { - NcError.notFound('Token not found'); - } - Tele.emit('evt', { evt_type: 'org:apiToken:deleted' }); - res.json(await ApiToken.delete(req.params.token)); -} - -const router = Router({ mergeParams: true }); - -router.get( - '/api/v1/tokens', - metaApiMetrics, - ncMetaAclMw(getHandler(apiTokenList, apiTokenListEE), 'apiTokenList', { - // allowedRoles: [OrgUserRoles.SUPER], - blockApiTokenAccess: true, - }) -); -router.post( - '/api/v1/tokens', - metaApiMetrics, - getAjvValidatorMw('swagger.json#/components/schemas/ApiTokenReq'), - ncMetaAclMw(apiTokenCreate, 'apiTokenCreate', { - // allowedRoles: [OrgUserRoles.SUPER], - blockApiTokenAccess: true, - }) -); -router.delete( - '/api/v1/tokens/:token', - metaApiMetrics, - ncMetaAclMw(apiTokenDelete, 'apiTokenDelete', { - // allowedRoles: [OrgUserRoles.SUPER], - blockApiTokenAccess: true, - }) -); -export default router; diff --git a/packages/nocodb/src/lib/meta/api/orgUserApis.ts b/packages/nocodb/src/lib/meta/api/orgUserApis.ts deleted file mode 100644 index 62c3cdf2aa..0000000000 --- a/packages/nocodb/src/lib/meta/api/orgUserApis.ts +++ /dev/null @@ -1,337 +0,0 @@ -import { Router } from 'express'; -import { - AuditOperationSubTypes, - AuditOperationTypes, - PluginCategory, -} from 'nocodb-sdk'; -import { v4 as uuidv4 } from 'uuid'; -import validator from 'validator'; -import { OrgUserRoles } from 'nocodb-sdk'; -import { NC_APP_SETTINGS } from '../../constants'; -import Audit from '../../models/Audit'; -import ProjectUser from '../../models/ProjectUser'; -import Store from '../../models/Store'; -import SyncSource from '../../models/SyncSource'; -import User from '../../models/User'; -import Noco from '../../Noco'; -import { MetaTable } from '../../utils/globals'; -import { Tele } from 'nc-help'; -import { metaApiMetrics } from '../helpers/apiMetrics'; -import { NcError } from '../helpers/catchError'; -import { extractProps } from '../helpers/extractProps'; -import ncMetaAclMw from '../helpers/ncMetaAclMw'; -import { PagedResponseImpl } from '../helpers/PagedResponse'; -import { randomTokenString } from '../helpers/stringHelpers'; -import { getAjvValidatorMw } from './helpers'; -import { sendInviteEmail } from './projectUserApis'; - -async function userList(req, res) { - res.json( - new PagedResponseImpl(await User.list(req.query), { - ...req.query, - count: await User.count(req.query), - }) - ); -} - -async function userUpdate(req, res) { - const updateBody = extractProps(req.body, ['roles']); - - const user = await User.get(req.params.userId); - - if (user.roles.includes(OrgUserRoles.SUPER_ADMIN)) { - NcError.badRequest('Cannot update super admin roles'); - } - - res.json( - await User.update(req.params.userId, { - ...updateBody, - token_version: null, - }) - ); -} - -async function userDelete(req, res) { - const ncMeta = await Noco.ncMeta.startTransaction(); - try { - const user = await User.get(req.params.userId, ncMeta); - - if (user.roles.includes(OrgUserRoles.SUPER_ADMIN)) { - NcError.badRequest('Cannot delete super admin'); - } - - // delete project user entry and assign to super admin - const projectUsers = await ProjectUser.getProjectsIdList( - req.params.userId, - ncMeta - ); - - // todo: clear cache - - // TODO: assign super admin as project owner - for (const projectUser of projectUsers) { - await ProjectUser.delete( - projectUser.project_id, - projectUser.fk_user_id, - ncMeta - ); - } - - // delete sync source entry - await SyncSource.deleteByUserId(req.params.userId, ncMeta); - - // delete user - await User.delete(req.params.userId, ncMeta); - await ncMeta.commit(); - } catch (e) { - await ncMeta.rollback(e); - throw e; - } - - res.json({ msg: 'success' }); -} - -async function userAdd(req, res, next) { - // allow only viewer or creator role - if ( - req.body.roles && - ![OrgUserRoles.VIEWER, OrgUserRoles.CREATOR].includes(req.body.roles) - ) { - NcError.badRequest('Invalid role'); - } - - // extract emails from request body - const emails = (req.body.email || '') - .toLowerCase() - .split(/\s*,\s*/) - .map((v) => v.trim()); - - // check for invalid emails - const invalidEmails = emails.filter((v) => !validator.isEmail(v)); - - if (!emails.length) { - return NcError.badRequest('Invalid email address'); - } - if (invalidEmails.length) { - NcError.badRequest('Invalid email address : ' + invalidEmails.join(', ')); - } - - const invite_token = uuidv4(); - const error = []; - - for (const email of emails) { - // add user to project if user already exist - const user = await User.getByEmail(email); - - if (user) { - NcError.badRequest('User already exist'); - } else { - try { - // create new user with invite token - await User.insert({ - invite_token, - invite_token_expires: new Date(Date.now() + 24 * 60 * 60 * 1000), - email, - roles: req.body.roles || OrgUserRoles.VIEWER, - token_version: randomTokenString(), - }); - - const count = await User.count(); - Tele.emit('evt', { evt_type: 'org:user:invite', count }); - - await Audit.insert({ - op_type: AuditOperationTypes.ORG_USER, - op_sub_type: AuditOperationSubTypes.INVITE, - user: req.user.email, - description: `invited ${email} to ${req.params.projectId} project `, - ip: req.clientIp, - }); - // in case of single user check for smtp failure - // and send back token if failed - if ( - emails.length === 1 && - !(await sendInviteEmail(email, invite_token, req)) - ) { - return res.json({ invite_token, email }); - } else { - sendInviteEmail(email, invite_token, req); - } - } catch (e) { - console.log(e); - if (emails.length === 1) { - return next(e); - } else { - error.push({ email, error: e.message }); - } - } - } - } - - if (emails.length === 1) { - res.json({ - msg: 'success', - }); - } else { - return res.json({ invite_token, emails, error }); - } -} - -async function userSettings(_req, _res): Promise { - NcError.notImplemented(); -} - -async function userInviteResend(req, res): Promise { - const user = await User.get(req.params.userId); - - if (!user) { - NcError.badRequest(`User with id '${req.params.userId}' not found`); - } - - const invite_token = uuidv4(); - - await User.update(user.id, { - invite_token, - invite_token_expires: new Date(Date.now() + 24 * 60 * 60 * 1000), - }); - - const pluginData = await Noco.ncMeta.metaGet2(null, null, MetaTable.PLUGIN, { - category: PluginCategory.EMAIL, - active: true, - }); - - if (!pluginData) { - NcError.badRequest( - `No Email Plugin is found. Please go to App Store to configure first or copy the invitation URL to users instead.` - ); - } - - await sendInviteEmail(user.email, invite_token, req); - - await Audit.insert({ - op_type: AuditOperationTypes.ORG_USER, - op_sub_type: AuditOperationSubTypes.RESEND_INVITE, - user: user.email, - description: `resent a invite to ${user.email} `, - ip: req.clientIp, - }); - - res.json({ msg: 'success' }); -} - -async function generateResetUrl(req, res) { - const user = await User.get(req.params.userId); - - if (!user) { - NcError.badRequest(`User with id '${req.params.userId}' not found`); - } - const token = uuidv4(); - await User.update(user.id, { - email: user.email, - reset_password_token: token, - reset_password_expires: new Date(Date.now() + 60 * 60 * 1000), - token_version: null, - }); - - res.json({ - reset_password_token: token, - reset_password_url: req.ncSiteUrl + `/auth/password/reset/${token}`, - }); -} - -async function appSettingsGet(_req, res) { - let settings = {}; - try { - settings = JSON.parse((await Store.get(NC_APP_SETTINGS))?.value); - } catch {} - res.json(settings); -} - -async function appSettingsSet(req, res) { - await Store.saveOrUpdate({ - value: JSON.stringify(req.body), - key: NC_APP_SETTINGS, - }); - - res.json({ msg: 'Settings saved' }); -} - -const router = Router({ mergeParams: true }); -router.get( - '/api/v1/users', - metaApiMetrics, - ncMetaAclMw(userList, 'userList', { - allowedRoles: [OrgUserRoles.SUPER_ADMIN], - blockApiTokenAccess: true, - }) -); -router.patch( - '/api/v1/users/:userId', - metaApiMetrics, - getAjvValidatorMw('swagger.json#/components/schemas/OrgUserReq'), - ncMetaAclMw(userUpdate, 'userUpdate', { - allowedRoles: [OrgUserRoles.SUPER_ADMIN], - blockApiTokenAccess: true, - }) -); -router.delete( - '/api/v1/users/:userId', - metaApiMetrics, - ncMetaAclMw(userDelete, 'userDelete', { - allowedRoles: [OrgUserRoles.SUPER_ADMIN], - blockApiTokenAccess: true, - }) -); -router.post( - '/api/v1/users', - metaApiMetrics, - getAjvValidatorMw('swagger.json#/components/schemas/OrgUserReq'), - ncMetaAclMw(userAdd, 'userAdd', { - allowedRoles: [OrgUserRoles.SUPER_ADMIN], - blockApiTokenAccess: true, - }) -); -router.post( - '/api/v1/users/settings', - metaApiMetrics, - ncMetaAclMw(userSettings, 'userSettings', { - allowedRoles: [OrgUserRoles.SUPER_ADMIN], - blockApiTokenAccess: true, - }) -); -router.post( - '/api/v1/users/:userId/resend-invite', - metaApiMetrics, - ncMetaAclMw(userInviteResend, 'userInviteResend', { - allowedRoles: [OrgUserRoles.SUPER_ADMIN], - blockApiTokenAccess: true, - }) -); - -router.post( - '/api/v1/users/:userId/generate-reset-url', - metaApiMetrics, - ncMetaAclMw(generateResetUrl, 'generateResetUrl', { - allowedRoles: [OrgUserRoles.SUPER_ADMIN], - blockApiTokenAccess: true, - }) -); - -router.get( - '/api/v1/app-settings', - metaApiMetrics, - ncMetaAclMw(appSettingsGet, 'appSettingsGet', { - allowedRoles: [OrgUserRoles.SUPER_ADMIN], - blockApiTokenAccess: true, - }) -); - -router.post( - '/api/v1/app-settings', - metaApiMetrics, - ncMetaAclMw(appSettingsSet, 'appSettingsSet', { - allowedRoles: [OrgUserRoles.SUPER_ADMIN], - blockApiTokenAccess: true, - }) -); - -export default router; diff --git a/packages/nocodb/src/lib/meta/api/projectApis.ts b/packages/nocodb/src/lib/meta/api/projectApis.ts deleted file mode 100644 index 3c5b536e05..0000000000 --- a/packages/nocodb/src/lib/meta/api/projectApis.ts +++ /dev/null @@ -1,288 +0,0 @@ -import { Request, Response } from 'express'; -import { OrgUserRoles, ProjectType } from 'nocodb-sdk'; -import Project from '../../models/Project'; -import { ProjectListType } from 'nocodb-sdk'; -import DOMPurify from 'isomorphic-dompurify'; -import { packageVersion } from '../../utils/packageVersion'; -import { Tele } from 'nc-help'; -import { PagedResponseImpl } from '../helpers/PagedResponse'; -import syncMigration from '../helpers/syncMigration'; -import NcConnectionMgrv2 from '../../utils/common/NcConnectionMgrv2'; -import ncMetaAclMw from '../helpers/ncMetaAclMw'; -import ProjectUser from '../../models/ProjectUser'; -import { customAlphabet } from 'nanoid'; -import Noco from '../../Noco'; -import isDocker from 'is-docker'; -import { NcError } from '../helpers/catchError'; -import { metaApiMetrics } from '../helpers/apiMetrics'; -import { extractPropsAndSanitize } from '../helpers/extractProps'; -import NcConfigFactory from '../../utils/NcConfigFactory'; -import { promisify } from 'util'; -import { getAjvValidatorMw, populateMeta } from './helpers'; -import Filter from '../../models/Filter'; - -const nanoid = customAlphabet('1234567890abcdefghijklmnopqrstuvwxyz_', 4); - -// // Project CRUD - -export async function projectGet( - req: Request, - res: Response -) { - const project = await Project.getWithInfo(req.params.projectId); - - // delete datasource connection details - project.bases?.forEach((b) => { - ['config'].forEach((k) => delete b[k]); - }); - - res.json(project); -} - -export async function projectUpdate( - req: Request, - res: Response -) { - const project = await Project.getWithInfo(req.params.projectId); - - const data: Partial = extractPropsAndSanitize(req?.body, [ - 'title', - 'meta', - 'color', - ]); - - if ( - data?.title && - project.title !== data.title && - (await Project.getByTitle(data.title)) - ) { - NcError.badRequest('Project title already in use'); - } - - const result = await Project.update(req.params.projectId, data); - Tele.emit('evt', { evt_type: 'project:update' }); - res.json(result); -} - -export async function projectList( - req: Request & { user: { id: string; roles: string } }, - res: Response, - next -) { - try { - const projects = req.user?.roles?.includes(OrgUserRoles.SUPER_ADMIN) - ? await Project.list(req.query) - : await ProjectUser.getProjectsList(req.user.id, req.query); - - res // todo: pagination - .json( - new PagedResponseImpl(projects as ProjectType[], { - count: projects.length, - limit: projects.length, - }) - ); - } catch (e) { - console.log(e); - next(e); - } -} - -export async function projectDelete( - req: Request, - res: Response -) { - const result = await Project.softDelete(req.params.projectId); - Tele.emit('evt', { evt_type: 'project:deleted' }); - res.json(result); -} - -// -// - -async function projectCreate(req: Request, res) { - const projectBody = req.body; - if (!projectBody.external) { - const ranId = nanoid(); - projectBody.prefix = `nc_${ranId}__`; - projectBody.is_meta = true; - if (process.env.NC_MINIMAL_DBS) { - // if env variable NC_MINIMAL_DBS is set, then create a SQLite file/connection for each project - // each file will be named as nc_.db - const fs = require('fs'); - const toolDir = NcConfigFactory.getToolDir(); - const nanoidv2 = customAlphabet( - '1234567890abcdefghijklmnopqrstuvwxyz', - 14 - ); - if (!(await promisify(fs.exists)(`${toolDir}/nc_minimal_dbs`))) { - await promisify(fs.mkdir)(`${toolDir}/nc_minimal_dbs`); - } - const dbId = nanoidv2(); - const projectTitle = DOMPurify.sanitize(projectBody.title); - projectBody.prefix = ''; - projectBody.bases = [ - { - type: 'sqlite3', - config: { - client: 'sqlite3', - connection: { - client: 'sqlite3', - database: projectTitle, - connection: { - filename: `${toolDir}/nc_minimal_dbs/${projectTitle}_${dbId}.db`, - }, - }, - }, - inflection_column: 'camelize', - inflection_table: 'camelize', - }, - ]; - } else { - const db = Noco.getConfig().meta?.db; - projectBody.bases = [ - { - type: db?.client, - config: null, - is_meta: true, - inflection_column: 'camelize', - inflection_table: 'camelize', - }, - ]; - } - } else { - if (process.env.NC_CONNECT_TO_EXTERNAL_DB_DISABLED) { - NcError.badRequest('Connecting to external db is disabled'); - } - projectBody.is_meta = false; - } - - if (projectBody?.title.length > 50) { - NcError.badRequest('Project title exceeds 50 characters'); - } - - if (await Project.getByTitle(projectBody?.title)) { - NcError.badRequest('Project title already in use'); - } - - projectBody.title = DOMPurify.sanitize(projectBody.title); - projectBody.slug = projectBody.title; - - const project = await Project.createProject(projectBody); - await ProjectUser.insert({ - fk_user_id: (req as any).user.id, - project_id: project.id, - roles: 'owner', - }); - - await syncMigration(project); - - // populate metadata if existing table - for (const base of await project.getBases()) { - const info = await populateMeta(base, project); - - Tele.emit('evt_api_created', info); - delete base.config; - } - - Tele.emit('evt', { - evt_type: 'project:created', - xcdb: !projectBody.external, - }); - - Tele.emit('evt', { evt_type: 'project:rest' }); - - res.json(project); -} - -export async function projectInfoGet(_req, res) { - res.json({ - Node: process.version, - Arch: process.arch, - Platform: process.platform, - Docker: isDocker(), - RootDB: Noco.getConfig()?.meta?.db?.client, - PackageVersion: packageVersion, - }); -} - -export async function projectCost(req, res) { - let cost = 0; - const project = await Project.getWithInfo(req.params.projectId); - - for (const base of project.bases) { - const sqlClient = await NcConnectionMgrv2.getSqlClient(base); - const userCount = await ProjectUser.getUsersCount(req.query); - const recordCount = (await sqlClient.totalRecords())?.data.TotalRecords; - - if (recordCount > 100000) { - // 36,000 or $79/user/month - cost = Math.max(36000, 948 * userCount); - } else if (recordCount > 50000) { - // $36,000 or $50/user/month - cost = Math.max(36000, 600 * userCount); - } else if (recordCount > 10000) { - // $240/user/yr - cost = Math.min(240 * userCount, 36000); - } else if (recordCount > 1000) { - // $120/user/yr - cost = Math.min(120 * userCount, 36000); - } - } - - Tele.event({ - event: 'a:project:cost', - data: { - cost, - }, - }); - - res.json({ cost }); -} - -export async function hasEmptyOrNullFilters(req, res) { - res.json(await Filter.hasEmptyOrNullFilters(req.params.projectId)); -} - -export default (router) => { - router.get( - '/api/v1/db/meta/projects/:projectId/info', - metaApiMetrics, - ncMetaAclMw(projectInfoGet, 'projectInfoGet') - ); - router.get( - '/api/v1/db/meta/projects/:projectId', - metaApiMetrics, - ncMetaAclMw(projectGet, 'projectGet') - ); - router.patch( - '/api/v1/db/meta/projects/:projectId', - metaApiMetrics, - ncMetaAclMw(projectUpdate, 'projectUpdate') - ); - router.get( - '/api/v1/db/meta/projects/:projectId/cost', - metaApiMetrics, - ncMetaAclMw(projectCost, 'projectCost') - ); - router.delete( - '/api/v1/db/meta/projects/:projectId', - metaApiMetrics, - ncMetaAclMw(projectDelete, 'projectDelete') - ); - router.post( - '/api/v1/db/meta/projects', - metaApiMetrics, - getAjvValidatorMw('swagger.json#/components/schemas/ProjectReq'), - ncMetaAclMw(projectCreate, 'projectCreate') - ); - router.get( - '/api/v1/db/meta/projects', - metaApiMetrics, - ncMetaAclMw(projectList, 'projectList') - ); - router.get( - '/api/v1/db/meta/projects/:projectId/has-empty-or-null-filters', - metaApiMetrics, - ncMetaAclMw(hasEmptyOrNullFilters, 'hasEmptyOrNullFilters') - ); -}; diff --git a/packages/nocodb/src/lib/meta/api/projectUserApis.ts b/packages/nocodb/src/lib/meta/api/projectUserApis.ts deleted file mode 100644 index 3f0610fee6..0000000000 --- a/packages/nocodb/src/lib/meta/api/projectUserApis.ts +++ /dev/null @@ -1,333 +0,0 @@ -import { OrgUserRoles } from 'nocodb-sdk'; -import { Tele } from 'nc-help'; -import ncMetaAclMw from '../helpers/ncMetaAclMw'; -import { Router } from 'express'; -import { PagedResponseImpl } from '../helpers/PagedResponse'; -import ProjectUser from '../../models/ProjectUser'; -import validator from 'validator'; -import { NcError } from '../helpers/catchError'; -import { v4 as uuidv4 } from 'uuid'; -import User from '../../models/User'; -import Audit from '../../models/Audit'; -import NocoCache from '../../cache/NocoCache'; -import { CacheGetType, CacheScope, MetaTable } from '../../utils/globals'; -import * as ejs from 'ejs'; -import NcPluginMgrv2 from '../helpers/NcPluginMgrv2'; -import Noco from '../../Noco'; -import { PluginCategory } from 'nocodb-sdk'; -import { metaApiMetrics } from '../helpers/apiMetrics'; -import { randomTokenString } from '../helpers/stringHelpers'; -import { getAjvValidatorMw } from './helpers'; - -async function userList(req, res) { - res.json({ - users: new PagedResponseImpl( - await ProjectUser.getUsersList({ - ...req.query, - project_id: req.params.projectId, - }), - { - ...req.query, - count: await ProjectUser.getUsersCount(req.query), - } - ), - }); -} - -async function userInvite(req, res, next): Promise { - const emails = (req.body.email || '') - .toLowerCase() - .split(/\s*,\s*/) - .map((v) => v.trim()); - - // check for invalid emails - const invalidEmails = emails.filter((v) => !validator.isEmail(v)); - if (!emails.length) { - return NcError.badRequest('Invalid email address'); - } - if (invalidEmails.length) { - NcError.badRequest('Invalid email address : ' + invalidEmails.join(', ')); - } - - const invite_token = uuidv4(); - const error = []; - - for (const email of emails) { - // add user to project if user already exist - const user = await User.getByEmail(email); - - if (user) { - // check if this user has been added to this project - const projectUser = await ProjectUser.get(req.params.projectId, user.id); - if (projectUser) { - NcError.badRequest( - `${user.email} with role ${projectUser.roles} already exists in this project` - ); - } - - await ProjectUser.insert({ - project_id: req.params.projectId, - fk_user_id: user.id, - roles: req.body.roles || 'editor', - }); - - const cachedUser = await NocoCache.get( - `${CacheScope.USER}:${email}___${req.params.projectId}`, - CacheGetType.TYPE_OBJECT - ); - - if (cachedUser) { - cachedUser.roles = req.body.roles || 'editor'; - await NocoCache.set( - `${CacheScope.USER}:${email}___${req.params.projectId}`, - cachedUser - ); - } - - await Audit.insert({ - project_id: req.params.projectId, - op_type: 'AUTHENTICATION', - op_sub_type: 'INVITE', - user: req.user.email, - description: `invited ${email} to ${req.params.projectId} project `, - ip: req.clientIp, - }); - } else { - try { - // create new user with invite token - const { id } = await User.insert({ - invite_token, - invite_token_expires: new Date(Date.now() + 24 * 60 * 60 * 1000), - email, - roles: OrgUserRoles.VIEWER, - token_version: randomTokenString(), - }); - - // add user to project - await ProjectUser.insert({ - project_id: req.params.projectId, - fk_user_id: id, - roles: req.body.roles, - }); - - const count = await User.count(); - Tele.emit('evt', { evt_type: 'project:invite', count }); - - await Audit.insert({ - project_id: req.params.projectId, - op_type: 'AUTHENTICATION', - op_sub_type: 'INVITE', - user: req.user.email, - description: `invited ${email} to ${req.params.projectId} project `, - ip: req.clientIp, - }); - // in case of single user check for smtp failure - // and send back token if failed - if ( - emails.length === 1 && - !(await sendInviteEmail(email, invite_token, req)) - ) { - return res.json({ invite_token, email }); - } else { - sendInviteEmail(email, invite_token, req); - } - } catch (e) { - console.log(e); - if (emails.length === 1) { - return next(e); - } else { - error.push({ email, error: e.message }); - } - } - } - } - - if (emails.length === 1) { - res.json({ - msg: 'success', - }); - } else { - return res.json({ invite_token, emails, error }); - } -} - -// @ts-ignore -async function projectUserUpdate(req, res, next): Promise { - if (!req?.body?.project_id) { - return next(new Error('Missing project id in request body.')); - } - - if ( - req.session?.passport?.user?.roles?.owner && - req.session?.passport?.user?.id === req.params.userId && - req.body.roles.indexOf('owner') === -1 - ) { - NcError.badRequest("Super admin can't remove Super role themselves"); - } - try { - const user = await User.get(req.params.userId); - - if (!user) { - NcError.badRequest(`User with id '${req.params.userId}' doesn't exist`); - } - - // todo: handle roles which contains super - if ( - !req.session?.passport?.user?.roles?.owner && - req.body.roles.indexOf('owner') > -1 - ) { - NcError.forbidden('Insufficient privilege to add super admin role.'); - } - - await ProjectUser.update( - req.params.projectId, - req.params.userId, - req.body.roles - ); - - await Audit.insert({ - op_type: 'AUTHENTICATION', - op_sub_type: 'ROLES_MANAGEMENT', - user: req.user.email, - description: `updated roles for ${user.email} with ${req.body.roles} `, - ip: req.clientIp, - }); - - res.json({ - msg: 'User details updated successfully', - }); - } catch (e) { - next(e); - } -} - -async function projectUserDelete(req, res): Promise { - const project_id = req.params.projectId; - - if (req.session?.passport?.user?.id === req.params.userId) { - NcError.badRequest("Admin can't delete themselves!"); - } - - if (!req.session?.passport?.user?.roles?.owner) { - const user = await User.get(req.params.userId); - if (user.roles?.split(',').includes('super')) - NcError.forbidden('Insufficient privilege to delete a super admin user.'); - - const projectUser = await ProjectUser.get(project_id, req.params.userId); - if (projectUser?.roles?.split(',').includes('super')) - NcError.forbidden('Insufficient privilege to delete a owner user.'); - } - - await ProjectUser.delete(project_id, req.params.userId); - res.json({ - msg: 'success', - }); -} - -async function projectUserInviteResend(req, res): Promise { - const user = await User.get(req.params.userId); - - if (!user) { - NcError.badRequest(`User with id '${req.params.userId}' not found`); - } - - req.body.roles = user.roles; - const invite_token = uuidv4(); - - await User.update(user.id, { - invite_token, - invite_token_expires: new Date(Date.now() + 24 * 60 * 60 * 1000), - }); - - const pluginData = await Noco.ncMeta.metaGet2(null, null, MetaTable.PLUGIN, { - category: PluginCategory.EMAIL, - active: true, - }); - - if (!pluginData) { - NcError.badRequest( - `No Email Plugin is found. Please go to App Store to configure first or copy the invitation URL to users instead.` - ); - } - - await sendInviteEmail(user.email, invite_token, req); - - await Audit.insert({ - op_type: 'AUTHENTICATION', - op_sub_type: 'RESEND_INVITE', - user: user.email, - description: `resent a invite to ${user.email} `, - ip: req.clientIp, - project_id: req.params.projectId, - }); - - res.json({ msg: 'success' }); -} - -export async function sendInviteEmail( - email: string, - token: string, - req: any -): Promise { - try { - const template = (await import('./userApi/ui/emailTemplates/invite')) - .default; - - const emailAdapter = await NcPluginMgrv2.emailAdapter(); - - if (emailAdapter) { - await emailAdapter.mailSend({ - to: email, - subject: 'Verify email', - html: ejs.render(template, { - signupLink: `${req.ncSiteUrl}${ - Noco.getConfig()?.dashboardPath - }#/signup/${token}`, - projectName: req.body?.projectName, - roles: (req.body?.roles || '') - .split(',') - .map((r) => r.replace(/^./, (m) => m.toUpperCase())) - .join(', '), - adminEmail: req.session?.passport?.user?.email, - }), - }); - return true; - } - } catch (e) { - console.log( - 'Warning : `mailSend` failed, Please configure emailClient configuration.', - e.message - ); - throw e; - } -} - -const router = Router({ mergeParams: true }); -router.get( - '/api/v1/db/meta/projects/:projectId/users', - metaApiMetrics, - ncMetaAclMw(userList, 'userList') -); -router.post( - '/api/v1/db/meta/projects/:projectId/users', - metaApiMetrics, - getAjvValidatorMw('swagger.json#/components/schemas/ProjectUserReq'), - ncMetaAclMw(userInvite, 'userInvite') -); -router.patch( - '/api/v1/db/meta/projects/:projectId/users/:userId', - metaApiMetrics, - getAjvValidatorMw('swagger.json#/components/schemas/ProjectUserReq'), - ncMetaAclMw(projectUserUpdate, 'projectUserUpdate') -); -router.delete( - '/api/v1/db/meta/projects/:projectId/users/:userId', - metaApiMetrics, - ncMetaAclMw(projectUserDelete, 'projectUserDelete') -); -router.post( - '/api/v1/db/meta/projects/:projectId/users/:userId/resend-invite', - metaApiMetrics, - ncMetaAclMw(projectUserInviteResend, 'projectUserInviteResend') -); -export default router; diff --git a/packages/nocodb/src/lib/meta/api/publicApis/index.ts b/packages/nocodb/src/lib/meta/api/publicApis/index.ts deleted file mode 100644 index 60028a421f..0000000000 --- a/packages/nocodb/src/lib/meta/api/publicApis/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -import publicDataApis from './publicDataApis'; -import publicDataExportApis from './publicDataExportApis'; -import publicMetaApis from './publicMetaApis'; - -export { publicDataApis, publicDataExportApis, publicMetaApis }; diff --git a/packages/nocodb/src/lib/meta/api/publicApis/publicDataApis.ts b/packages/nocodb/src/lib/meta/api/publicApis/publicDataApis.ts deleted file mode 100644 index bb678b10f3..0000000000 --- a/packages/nocodb/src/lib/meta/api/publicApis/publicDataApis.ts +++ /dev/null @@ -1,472 +0,0 @@ -import { Request, Response, Router } from 'express'; -import Model from '../../../models/Model'; -import { nocoExecute } from 'nc-help'; -import Base from '../../../models/Base'; -import NcConnectionMgrv2 from '../../../utils/common/NcConnectionMgrv2'; -import { PagedResponseImpl } from '../../helpers/PagedResponse'; -import View from '../../../models/View'; -import catchError, { NcError } from '../../helpers/catchError'; -import multer from 'multer'; -import { ErrorMessages, UITypes, ViewTypes } from 'nocodb-sdk'; -import Column from '../../../models/Column'; -import LinkToAnotherRecordColumn from '../../../models/LinkToAnotherRecordColumn'; -import NcPluginMgrv2 from '../../helpers/NcPluginMgrv2'; -import path from 'path'; -import { nanoid } from 'nanoid'; -import { mimeIcons } from '../../../utils/mimeTypes'; -import slash from 'slash'; -import { sanitizeUrlPath } from '../attachmentApis'; -import getAst from '../../../db/sql-data-mapper/lib/sql/helpers/getAst'; -import { getColumnByIdOrName } from '../dataApis/helpers'; -import { NC_ATTACHMENT_FIELD_SIZE } from '../../../constants'; - -export async function dataList(req: Request, res: Response) { - try { - const view = await View.getByUUID(req.params.sharedViewUuid); - - if (!view) NcError.notFound('Not found'); - if ( - view.type !== ViewTypes.GRID && - view.type !== ViewTypes.KANBAN && - view.type !== ViewTypes.GALLERY && - view.type !== ViewTypes.MAP - ) { - NcError.notFound('Not found'); - } - - if (view.password && view.password !== req.headers?.['xc-password']) { - return NcError.forbidden(ErrorMessages.INVALID_SHARED_VIEW_PASSWORD); - } - - const model = await Model.getByIdOrName({ - id: view?.fk_model_id, - }); - - const base = await Base.get(model.base_id); - - const baseModel = await Model.getBaseModelSQL({ - id: model.id, - viewId: view?.id, - dbDriver: NcConnectionMgrv2.get(base), - }); - - const listArgs: any = { ...req.query }; - try { - listArgs.filterArr = JSON.parse(listArgs.filterArrJson); - } catch (e) {} - try { - listArgs.sortArr = JSON.parse(listArgs.sortArrJson); - } catch (e) {} - - let data = []; - let count = 0; - - try { - data = await nocoExecute( - await getAst({ - query: req.query, - model, - view, - }), - await baseModel.list(listArgs), - {}, - listArgs - ); - count = await baseModel.count(listArgs); - } catch (e) { - // show empty result instead of throwing error here - // e.g. search some text in a numeric field - } - - res.json({ - data: new PagedResponseImpl(data, { ...req.query, count }), - }); - } catch (e) { - console.log(e); - res.status(500).json({ msg: e.message }); - } -} - -// todo: Handle the error case where view doesnt belong to model -async function groupedDataList(req: Request, res: Response) { - try { - const view = await View.getByUUID(req.params.sharedViewUuid); - - if (!view) NcError.notFound('Not found'); - - if ( - view.type !== ViewTypes.GRID && - view.type !== ViewTypes.KANBAN && - view.type !== ViewTypes.GALLERY - ) { - NcError.notFound('Not found'); - } - - if (view.password && view.password !== req.headers?.['xc-password']) { - return NcError.forbidden(ErrorMessages.INVALID_SHARED_VIEW_PASSWORD); - } - - const model = await Model.getByIdOrName({ - id: view?.fk_model_id, - }); - - res.json(await getGroupedDataList(model, view, req)); - } catch (e) { - console.log(e); - res.status(500).json({ msg: e.message }); - } -} - -async function getGroupedDataList(model, view: View, req) { - const base = await Base.get(model.base_id); - - const baseModel = await Model.getBaseModelSQL({ - id: model.id, - viewId: view?.id, - dbDriver: NcConnectionMgrv2.get(base), - }); - - const requestObj = await getAst({ model, query: req.query, view }); - - const listArgs: any = { ...req.query }; - try { - listArgs.filterArr = JSON.parse(listArgs.filterArrJson); - } catch (e) {} - try { - listArgs.sortArr = JSON.parse(listArgs.sortArrJson); - } catch (e) {} - try { - listArgs.options = JSON.parse(listArgs.optionsArrJson); - } catch (e) {} - - let data = []; - - try { - const groupedData = await baseModel.groupedList({ - ...listArgs, - groupColumnId: req.params.columnId, - }); - data = await nocoExecute( - { key: 1, value: requestObj }, - groupedData, - {}, - listArgs - ); - const countArr = await baseModel.groupedListCount({ - ...listArgs, - groupColumnId: req.params.columnId, - }); - data = data.map((item) => { - // todo: use map to avoid loop - const count = - countArr.find((countItem: any) => countItem.key === item.key)?.count ?? - 0; - - item.value = new PagedResponseImpl(item.value, { - ...req.query, - count: count, - }); - return item; - }); - } catch (e) { - // show empty result instead of throwing error here - // e.g. search some text in a numeric field - } - return data; -} - -async function dataInsert( - req: Request & { files: any[] }, - res: Response, - next -) { - const view = await View.getByUUID(req.params.sharedViewUuid); - - if (!view) return next(new Error('Not found')); - if (view.type !== ViewTypes.FORM) return next(new Error('Not found')); - - if (view.password && view.password !== req.headers?.['xc-password']) { - return res.status(403).json(ErrorMessages.INVALID_SHARED_VIEW_PASSWORD); - } - - const model = await Model.getByIdOrName({ - id: view?.fk_model_id, - }); - const base = await Base.get(model.base_id); - const project = await base.getProject(); - - const baseModel = await Model.getBaseModelSQL({ - id: model.id, - viewId: view?.id, - dbDriver: NcConnectionMgrv2.get(base), - }); - - await view.getViewWithInfo(); - await view.getColumns(); - await view.getModelWithInfo(); - await view.model.getColumns(); - - const fields = (view.model.columns = view.columns - .filter((c) => c.show) - .reduce((o, c) => { - o[view.model.columnsById[c.fk_column_id].title] = new Column({ - ...c, - ...view.model.columnsById[c.fk_column_id], - } as any); - return o; - }, {}) as any); - - let body = req.body?.data; - - if (typeof body === 'string') body = JSON.parse(body); - - const insertObject = Object.entries(body).reduce((obj, [key, val]) => { - if (key in fields) { - obj[key] = val; - } - return obj; - }, {}); - - const attachments = {}; - const storageAdapter = await NcPluginMgrv2.storageAdapter(); - - for (const file of req.files || []) { - // remove `_` prefix and `[]` suffix - const fieldName = file?.fieldname?.replace(/^_|\[\d*]$/g, ''); - - const filePath = sanitizeUrlPath([ - 'v1', - project.title, - model.title, - fieldName, - ]); - - if (fieldName in fields && fields[fieldName].uidt === UITypes.Attachment) { - attachments[fieldName] = attachments[fieldName] || []; - const fileName = `${nanoid(6)}_${file.originalname}`; - let url = await storageAdapter.fileCreate( - slash(path.join('nc', 'uploads', ...filePath, fileName)), - file - ); - - if (!url) { - url = `${(req as any).ncSiteUrl}/download/${filePath.join( - '/' - )}/${fileName}`; - } - - attachments[fieldName].push({ - url, - title: file.originalname, - mimetype: file.mimetype, - size: file.size, - icon: mimeIcons[path.extname(file.originalname).slice(1)] || undefined, - }); - } - } - - for (const [column, data] of Object.entries(attachments)) { - insertObject[column] = JSON.stringify(data); - } - - res.json(await baseModel.nestedInsert(insertObject, null)); -} - -async function relDataList(req, res) { - const view = await View.getByUUID(req.params.sharedViewUuid); - - if (!view) NcError.notFound('Not found'); - if (view.type !== ViewTypes.FORM) NcError.notFound('Not found'); - - if (view.password && view.password !== req.headers?.['xc-password']) { - NcError.forbidden(ErrorMessages.INVALID_SHARED_VIEW_PASSWORD); - } - - const column = await Column.get({ colId: req.params.columnId }); - const colOptions = await column.getColOptions(); - - const model = await colOptions.getRelatedTable(); - - const base = await Base.get(model.base_id); - - const baseModel = await Model.getBaseModelSQL({ - id: model.id, - viewId: view?.id, - dbDriver: NcConnectionMgrv2.get(base), - }); - - const requestObj = await getAst({ - query: req.query, - model, - extractOnlyPrimaries: true, - }); - - let data = []; - let count = 0; - try { - data = data = await nocoExecute( - requestObj, - await baseModel.list(req.query), - {}, - req.query - ); - count = await baseModel.count(req.query); - } catch (e) { - // show empty result instead of throwing error here - // e.g. search some text in a numeric field - } - - res.json(new PagedResponseImpl(data, { ...req.query, count })); -} - -export async function publicMmList(req: Request, res: Response) { - const view = await View.getByUUID(req.params.sharedViewUuid); - - if (!view) NcError.notFound('Not found'); - if (view.type !== ViewTypes.GRID) NcError.notFound('Not found'); - - if (view.password && view.password !== req.headers?.['xc-password']) { - NcError.forbidden(ErrorMessages.INVALID_SHARED_VIEW_PASSWORD); - } - - const column = await getColumnByIdOrName( - req.params.colId, - await view.getModel() - ); - - if (column.fk_model_id !== view.fk_model_id) - NcError.badRequest("Column doesn't belongs to the model"); - - const base = await Base.get(view.base_id); - - const baseModel = await Model.getBaseModelSQL({ - id: view.fk_model_id, - viewId: view?.id, - dbDriver: NcConnectionMgrv2.get(base), - }); - - const key = `List`; - const requestObj: any = { - [key]: 1, - }; - - const data = ( - await nocoExecute( - requestObj, - { - [key]: async (args) => { - return await baseModel.mmList( - { - colId: req.params.colId, - parentId: req.params.rowId, - }, - args - ); - }, - }, - {}, - - { nested: { [key]: req.query } } - ) - )?.[key]; - - const count: any = await baseModel.mmListCount({ - colId: req.params.colId, - parentId: req.params.rowId, - }); - - res.json(new PagedResponseImpl(data, { ...req.query, count })); -} - -export async function publicHmList(req: Request, res: Response) { - const view = await View.getByUUID(req.params.sharedViewUuid); - - if (!view) NcError.notFound('Not found'); - if (view.type !== ViewTypes.GRID) NcError.notFound('Not found'); - - if (view.password && view.password !== req.headers?.['xc-password']) { - NcError.forbidden(ErrorMessages.INVALID_SHARED_VIEW_PASSWORD); - } - - const column = await getColumnByIdOrName( - req.params.colId, - await view.getModel() - ); - - if (column.fk_model_id !== view.fk_model_id) - NcError.badRequest("Column doesn't belongs to the model"); - - const base = await Base.get(view.base_id); - - const baseModel = await Model.getBaseModelSQL({ - id: view.fk_model_id, - viewId: view?.id, - dbDriver: NcConnectionMgrv2.get(base), - }); - - const key = `List`; - const requestObj: any = { - [key]: 1, - }; - - const data = ( - await nocoExecute( - requestObj, - { - [key]: async (args) => { - return await baseModel.hmList( - { - colId: req.params.colId, - id: req.params.rowId, - }, - args - ); - }, - }, - {}, - { nested: { [key]: req.query } } - ) - )?.[key]; - - const count = await baseModel.hmListCount({ - colId: req.params.colId, - id: req.params.rowId, - }); - - res.json(new PagedResponseImpl(data, { ...req.query, count })); -} - -const router = Router({ mergeParams: true }); -router.get( - '/api/v1/db/public/shared-view/:sharedViewUuid/rows', - catchError(dataList) -); -router.get( - '/api/v1/db/public/shared-view/:sharedViewUuid/group/:columnId', - catchError(groupedDataList) -); -router.get( - '/api/v1/db/public/shared-view/:sharedViewUuid/nested/:columnId', - catchError(relDataList) -); -router.post( - '/api/v1/db/public/shared-view/:sharedViewUuid/rows', - multer({ - storage: multer.diskStorage({}), - limits: { - fieldSize: NC_ATTACHMENT_FIELD_SIZE, - }, - }).any(), - catchError(dataInsert) -); - -router.get( - '/api/v1/db/public/shared-view/:sharedViewUuid/rows/:rowId/mm/:colId', - catchError(publicMmList) -); -router.get( - '/api/v1/db/public/shared-view/:sharedViewUuid/rows/:rowId/hm/:colId', - catchError(publicHmList) -); - -export default router; diff --git a/packages/nocodb/src/lib/meta/api/sharedBaseApis.ts b/packages/nocodb/src/lib/meta/api/sharedBaseApis.ts deleted file mode 100644 index c232327aa8..0000000000 --- a/packages/nocodb/src/lib/meta/api/sharedBaseApis.ts +++ /dev/null @@ -1,112 +0,0 @@ -import { Router } from 'express'; -import { Tele } from 'nc-help'; -import ncMetaAclMw from '../helpers/ncMetaAclMw'; -import { v4 as uuidv4 } from 'uuid'; -import Project from '../../models/Project'; -import { NcError } from '../helpers/catchError'; -import { getAjvValidatorMw } from './helpers'; -// todo: load from config -const config = { - dashboardPath: '/nc', -}; - -async function createSharedBaseLink(req, res): Promise { - const project = await Project.get(req.params.projectId); - - let roles = req.body?.roles; - if (!roles || (roles !== 'editor' && roles !== 'viewer')) { - roles = 'viewer'; - } - - if (!project) { - NcError.badRequest('Invalid project id'); - } - const data: any = { - uuid: uuidv4(), - password: req.body?.password, - roles, - }; - - await Project.update(project.id, data); - - data.url = `${req.ncSiteUrl}${config.dashboardPath}#/nc/base/${data.uuid}`; - delete data.password; - Tele.emit('evt', { evt_type: 'sharedBase:generated-link' }); - res.json(data); -} -async function updateSharedBaseLink(req, res): Promise { - const project = await Project.get(req.params.projectId); - - let roles = req.body?.roles; - if (!roles || (roles !== 'editor' && roles !== 'viewer')) { - roles = 'viewer'; - } - - if (!project) { - NcError.badRequest('Invalid project id'); - } - const data: any = { - uuid: project.uuid || uuidv4(), - password: req.body?.password, - roles, - }; - - await Project.update(project.id, data); - - data.url = `${req.ncSiteUrl}${config.dashboardPath}#/nc/base/${data.uuid}`; - delete data.password; - Tele.emit('evt', { evt_type: 'sharedBase:generated-link' }); - res.json(data); -} - -async function disableSharedBaseLink(req, res): Promise { - const project = await Project.get(req.params.projectId); - - if (!project) { - NcError.badRequest('Invalid project id'); - } - const data: any = { - uuid: null, - }; - - await Project.update(project.id, data); - Tele.emit('evt', { evt_type: 'sharedBase:disable-link' }); - res.json({ uuid: null }); -} - -async function getSharedBaseLink(req, res): Promise { - const project = await Project.get(req.params.projectId); - - if (!project) { - NcError.badRequest('Invalid project id'); - } - const data: any = { - uuid: project.uuid, - roles: project.roles, - }; - if (data.uuid) - data.url = `${req.ncSiteUrl}${config.dashboardPath}#/nc/base/${data.shared_base_id}`; - - res.json(data); -} - -const router = Router({ mergeParams: true }); -router.get( - '/api/v1/db/meta/projects/:projectId/shared', - ncMetaAclMw(getSharedBaseLink, 'getSharedBaseLink') -); -router.post( - '/api/v1/db/meta/projects/:projectId/shared', - getAjvValidatorMw('swagger.json#/components/schemas/SharedBaseReq'), - ncMetaAclMw(createSharedBaseLink, 'createSharedBaseLink') -); -router.patch( - '/api/v1/db/meta/projects/:projectId/shared', - getAjvValidatorMw('swagger.json#/components/schemas/SharedBaseReq'), - ncMetaAclMw(updateSharedBaseLink, 'updateSharedBaseLink') -); -router.delete( - '/api/v1/db/meta/projects/:projectId/shared', - ncMetaAclMw(disableSharedBaseLink, 'disableSharedBaseLink') -); -export default router; diff --git a/packages/nocodb/src/lib/meta/api/sortApis.ts b/packages/nocodb/src/lib/meta/api/sortApis.ts deleted file mode 100644 index 5341d07cba..0000000000 --- a/packages/nocodb/src/lib/meta/api/sortApis.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { Request, Response, Router } from 'express'; -// @ts-ignore -import Model from '../../models/Model'; -import { Tele } from 'nc-help'; -// @ts-ignore -import { PagedResponseImpl } from '../helpers/PagedResponse'; -import { SortListType, SortType, TableType } from 'nocodb-sdk'; -// @ts-ignore -import ProjectMgrv2 from '../../db/sql-mgr/v2/ProjectMgrv2'; -// @ts-ignore -import Project from '../../models/Project'; -import Sort from '../../models/Sort'; -import ncMetaAclMw from '../helpers/ncMetaAclMw'; -import { metaApiMetrics } from '../helpers/apiMetrics'; -import { getAjvValidatorMw } from './helpers'; - -// @ts-ignore -export async function sortGet(req: Request, res: Response) {} - -// @ts-ignore -export async function sortList( - req: Request, - res: Response -) { - const sortList = await Sort.list({ viewId: req.params.viewId }); - res.json({ - sorts: new PagedResponseImpl(sortList), - }); -} - -// @ts-ignore -export async function sortCreate(req: Request, res) { - const sort = await Sort.insert({ - ...req.body, - fk_view_id: req.params.viewId, - } as Sort); - Tele.emit('evt', { evt_type: 'sort:created' }); - res.json(sort); -} - -export async function sortUpdate(req, res) { - const sort = await Sort.update(req.params.sortId, req.body); - Tele.emit('evt', { evt_type: 'sort:updated' }); - res.json(sort); -} - -export async function sortDelete(req: Request, res: Response) { - Tele.emit('evt', { evt_type: 'sort:deleted' }); - const sort = await Sort.delete(req.params.sortId); - res.json(sort); -} - -const router = Router({ mergeParams: true }); -router.get( - '/api/v1/db/meta/views/:viewId/sorts/', - metaApiMetrics, - ncMetaAclMw(sortList, 'sortList') -); -router.post( - '/api/v1/db/meta/views/:viewId/sorts/', - metaApiMetrics, - getAjvValidatorMw('swagger.json#/components/schemas/SortReq'), - ncMetaAclMw(sortCreate, 'sortCreate') -); -router.get( - '/api/v1/db/meta/sorts/:sortId', - metaApiMetrics, - ncMetaAclMw(sortGet, 'sortGet') -); -router.patch( - '/api/v1/db/meta/sorts/:sortId', - metaApiMetrics, - getAjvValidatorMw('swagger.json#/components/schemas/SortReq'), - ncMetaAclMw(sortUpdate, 'sortUpdate') -); -router.delete( - '/api/v1/db/meta/sorts/:sortId', - metaApiMetrics, - ncMetaAclMw(sortDelete, 'sortDelete') -); -export default router; diff --git a/packages/nocodb/src/lib/meta/api/swagger/swaggerApis.ts b/packages/nocodb/src/lib/meta/api/swagger/swaggerApis.ts deleted file mode 100644 index c8cb637ba1..0000000000 --- a/packages/nocodb/src/lib/meta/api/swagger/swaggerApis.ts +++ /dev/null @@ -1,61 +0,0 @@ -// @ts-ignore -import catchError, { NcError } from '../../helpers/catchError'; -import { Router } from 'express'; -import Model from '../../../models/Model'; -import ncMetaAclMw from '../../helpers/ncMetaAclMw'; -import getSwaggerJSON from './helpers/getSwaggerJSON'; -import Project from '../../../models/Project'; -import getSwaggerHtml from './swaggerHtml'; -import getRedocHtml from './redocHtml'; - -async function swaggerJson(req, res) { - const project = await Project.get(req.params.projectId); - - if (!project) NcError.notFound(); - - const models = await Model.list({ - project_id: req.params.projectId, - base_id: null, - }); - - const swagger = await getSwaggerJSON(project, models); - - swagger.servers = [ - { - url: req.ncSiteUrl, - }, - { - url: '{customUrl}', - variables: { - customUrl: { - default: req.ncSiteUrl, - description: 'Provide custom nocodb app base url', - }, - }, - }, - ] as any; - - res.json(swagger); -} - -function swaggerHtml(_, res) { - res.send(getSwaggerHtml({ ncSiteUrl: process.env.NC_PUBLIC_URL || '' })); -} - -function redocHtml(_, res) { - res.send(getRedocHtml({ ncSiteUrl: process.env.NC_PUBLIC_URL || '' })); -} - -const router = Router({ mergeParams: true }); - -// todo: auth -router.get( - '/api/v1/db/meta/projects/:projectId/swagger.json', - ncMetaAclMw(swaggerJson, 'swaggerJson') -); - -router.get('/api/v1/db/meta/projects/:projectId/swagger', swaggerHtml); - -router.get('/api/v1/db/meta/projects/:projectId/redoc', redocHtml); - -export default router; diff --git a/packages/nocodb/src/lib/meta/api/tableApis.ts b/packages/nocodb/src/lib/meta/api/tableApis.ts deleted file mode 100644 index 4c5d6856a5..0000000000 --- a/packages/nocodb/src/lib/meta/api/tableApis.ts +++ /dev/null @@ -1,447 +0,0 @@ -import { Request, Response, Router } from 'express'; -import Model from '../../models/Model'; -import { Tele } from 'nc-help'; -import { PagedResponseImpl } from '../helpers/PagedResponse'; -import DOMPurify from 'isomorphic-dompurify'; -import { - AuditOperationSubTypes, - AuditOperationTypes, - isVirtualCol, - ModelTypes, - NormalColumnRequestType, - TableListType, - TableReqType, - TableType, - UITypes, -} from 'nocodb-sdk'; -import ProjectMgrv2 from '../../db/sql-mgr/v2/ProjectMgrv2'; -import Project from '../../models/Project'; -import Audit from '../../models/Audit'; -import ncMetaAclMw from '../helpers/ncMetaAclMw'; -import { getAjvValidatorMw } from './helpers'; -import { xcVisibilityMetaGet } from './modelVisibilityApis'; -import View from '../../models/View'; -import getColumnPropsFromUIDT from '../helpers/getColumnPropsFromUIDT'; -import mapDefaultDisplayValue from '../helpers/mapDefaultDisplayValue'; -import { NcError } from '../helpers/catchError'; -import getTableNameAlias, { getColumnNameAlias } from '../helpers/getTableName'; -import Column from '../../models/Column'; -import NcConnectionMgrv2 from '../../utils/common/NcConnectionMgrv2'; -import getColumnUiType from '../helpers/getColumnUiType'; -import LinkToAnotherRecordColumn from '../../models/LinkToAnotherRecordColumn'; -import { metaApiMetrics } from '../helpers/apiMetrics'; - -export async function tableGet(req: Request, res: Response) { - const table = await Model.getWithInfo({ - id: req.params.tableId, - }); - - // todo: optimise - const viewList = await xcVisibilityMetaGet(table.project_id, [table]); - - //await View.list(req.params.tableId) - table.views = viewList.filter((table: any) => { - return Object.keys((req as any).session?.passport?.user?.roles).some( - (role) => - (req as any)?.session?.passport?.user?.roles[role] && - !table.disabled[role] - ); - }); - - res.json(table); -} - -export async function tableReorder(req: Request, res: Response) { - res.json(Model.updateOrder(req.params.tableId, req.body.order)); -} - -export async function tableList(req: Request, res: Response) { - const viewList = await xcVisibilityMetaGet(req.params.projectId); - - // todo: optimise - const tableViewMapping = viewList.reduce((o, view: any) => { - o[view.fk_model_id] = o[view.fk_model_id] || 0; - if ( - Object.keys((req as any).session?.passport?.user?.roles).some( - (role) => - (req as any)?.session?.passport?.user?.roles[role] && - !view.disabled[role] - ) - ) { - o[view.fk_model_id]++; - } - return o; - }, {}); - - const tableList = ( - await Model.list({ - project_id: req.params.projectId, - base_id: req.params.baseId, - }) - ).filter((t) => tableViewMapping[t.id]); - - res.json( - new PagedResponseImpl( - req.query?.includeM2M === 'true' - ? tableList - : (tableList.filter((t) => !t.mm) as Model[]) - ) - ); -} - -export async function tableCreate(req: Request, res) { - const project = await Project.getWithInfo(req.params.projectId); - let base = project.bases[0]; - - if (req.params.baseId) { - base = project.bases.find((b) => b.id === req.params.baseId); - } - - if ( - !req.body.table_name || - (project.prefix && project.prefix === req.body.table_name) - ) { - NcError.badRequest( - 'Missing table name `table_name` property in request body' - ); - } - - if (base.is_meta && project.prefix) { - if (!req.body.table_name.startsWith(project.prefix)) { - req.body.table_name = `${project.prefix}_${req.body.table_name}`; - } - } - - req.body.table_name = DOMPurify.sanitize(req.body.table_name); - - // validate table name - if (/^\s+|\s+$/.test(req.body.table_name)) { - NcError.badRequest( - 'Leading or trailing whitespace not allowed in table names' - ); - } - - if ( - !(await Model.checkTitleAvailable({ - table_name: req.body.table_name, - project_id: project.id, - base_id: base.id, - })) - ) { - NcError.badRequest('Duplicate table name'); - } - - if (!req.body.title) { - req.body.title = getTableNameAlias( - req.body.table_name, - project.prefix, - base - ); - } - - if ( - !(await Model.checkAliasAvailable({ - title: req.body.title, - project_id: project.id, - base_id: base.id, - })) - ) { - NcError.badRequest('Duplicate table alias'); - } - - const sqlMgr = await ProjectMgrv2.getSqlMgr(project); - - const sqlClient = await NcConnectionMgrv2.getSqlClient(base); - - let tableNameLengthLimit = 255; - const sqlClientType = sqlClient.knex.clientType(); - if (sqlClientType === 'mysql2' || sqlClientType === 'mysql') { - tableNameLengthLimit = 64; - } else if (sqlClientType === 'pg') { - tableNameLengthLimit = 63; - } else if (sqlClientType === 'mssql') { - tableNameLengthLimit = 128; - } - - if (req.body.table_name.length > tableNameLengthLimit) { - NcError.badRequest(`Table name exceeds ${tableNameLengthLimit} characters`); - } - - const mxColumnLength = Column.getMaxColumnNameLength(sqlClientType); - - for (const column of req.body.columns) { - if (column.column_name.length > mxColumnLength) { - NcError.badRequest( - `Column name ${column.column_name} exceeds ${mxColumnLength} characters` - ); - } - } - - req.body.columns = req.body.columns?.map((c) => ({ - ...getColumnPropsFromUIDT(c as any, base), - cn: c.column_name, - })); - await sqlMgr.sqlOpPlus(base, 'tableCreate', { - ...req.body, - tn: req.body.table_name, - }); - - const columns: Array< - Omit & { - cn: string; - system?: boolean; - } - > = (await sqlClient.columnList({ tn: req.body.table_name }))?.data?.list; - - const tables = await Model.list({ - project_id: project.id, - base_id: base.id, - }); - - await Audit.insert({ - project_id: project.id, - base_id: base.id, - op_type: AuditOperationTypes.TABLE, - op_sub_type: AuditOperationSubTypes.CREATED, - user: (req as any)?.user?.email, - description: `created table ${req.body.table_name} with alias ${req.body.title} `, - ip: (req as any).clientIp, - }).then(() => {}); - - mapDefaultDisplayValue(req.body.columns); - - Tele.emit('evt', { evt_type: 'table:created' }); - - res.json( - await Model.insert(project.id, base.id, { - ...req.body, - columns: columns.map((c, i) => { - const colMetaFromReq = req.body?.columns?.find( - (c1) => c.cn === c1.column_name - ) as NormalColumnRequestType; - return { - ...colMetaFromReq, - uidt: - (colMetaFromReq?.uidt as string) || - c.uidt || - getColumnUiType(base, c), - ...c, - dtxp: [UITypes.MultiSelect, UITypes.SingleSelect].includes( - colMetaFromReq.uidt as any - ) - ? colMetaFromReq.dtxp - : c.dtxp, - title: colMetaFromReq?.title || getColumnNameAlias(c.cn, base), - column_name: c.cn, - order: i + 1, - } as NormalColumnRequestType; - }), - order: +(tables?.pop()?.order ?? 0) + 1, - }) - ); -} - -export async function tableUpdate(req: Request
Are you sure you want to delete this row?