mirror of https://github.com/nocodb/nocodb
Pranav C
2 years ago
committed by
GitHub
19 changed files with 536 additions and 2353 deletions
@ -1,126 +0,0 @@ |
|||||||
<script> |
|
||||||
import ListChildItems from './ListChildItems.vue' |
|
||||||
|
|
||||||
export default { |
|
||||||
name: 'ListChildItemsModal', |
|
||||||
components: { ListChildItems }, |
|
||||||
props: { |
|
||||||
type: String, |
|
||||||
readOnly: Boolean, |
|
||||||
localState: Array, |
|
||||||
isNew: Boolean, |
|
||||||
password: String, |
|
||||||
value: Boolean, |
|
||||||
title: { |
|
||||||
type: String, |
|
||||||
default: 'Link Record', |
|
||||||
}, |
|
||||||
queryParams: { |
|
||||||
type: Object, |
|
||||||
default() { |
|
||||||
return {} |
|
||||||
}, |
|
||||||
}, |
|
||||||
primaryKey: String, |
|
||||||
primaryCol: String, |
|
||||||
meta: Object, |
|
||||||
parentMeta: Object, |
|
||||||
size: Number, |
|
||||||
api: [Object, Function], |
|
||||||
mm: [Object, Boolean], |
|
||||||
isPublic: Boolean, |
|
||||||
rowId: [String, Number], |
|
||||||
column: Object, |
|
||||||
}, |
|
||||||
emits: ['input'], |
|
||||||
data: () => ({ |
|
||||||
data: null, |
|
||||||
page: 1, |
|
||||||
}), |
|
||||||
computed: { |
|
||||||
show: { |
|
||||||
set(v) { |
|
||||||
this.$emit('input', v) |
|
||||||
}, |
|
||||||
get() { |
|
||||||
return this.value |
|
||||||
}, |
|
||||||
}, |
|
||||||
}, |
|
||||||
mounted() {}, |
|
||||||
methods: { |
|
||||||
async loadData() { |
|
||||||
if (this.$refs && this.$refs.child) { |
|
||||||
await this.$refs.child.loadData() |
|
||||||
} |
|
||||||
}, |
|
||||||
}, |
|
||||||
} |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<v-dialog v-model="show" width="600" content-class="dialog"> |
|
||||||
<v-icon small class="close-icon" @click="$emit('input', false)"> mdi-close </v-icon> |
|
||||||
<ListChildItems |
|
||||||
v-if="show" |
|
||||||
ref="child" |
|
||||||
:type="type" |
|
||||||
:row-id="rowId" |
|
||||||
:local-state="localState" |
|
||||||
:is-new="isNew" |
|
||||||
:size="10" |
|
||||||
:meta="meta" |
|
||||||
:password="password" |
|
||||||
:parent-meta="parentMeta" |
|
||||||
:primary-col="primaryCol" |
|
||||||
:primary-key="primaryKey" |
|
||||||
:api="api" |
|
||||||
:query-params="queryParams" |
|
||||||
v-bind="$attrs" |
|
||||||
:read-only="readOnly" |
|
||||||
:is-public="isPublic" |
|
||||||
:column="column" |
|
||||||
/> |
|
||||||
</v-dialog> |
|
||||||
</template> |
|
||||||
|
|
||||||
<style scoped lang="scss"> |
|
||||||
::v-deep { |
|
||||||
.dialog { |
|
||||||
position: relative; |
|
||||||
|
|
||||||
.close-icon { |
|
||||||
width: auto; |
|
||||||
position: absolute; |
|
||||||
right: 10px; |
|
||||||
top: 10px; |
|
||||||
z-index: 9; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
</style> |
|
||||||
|
|
||||||
<!-- |
|
||||||
/** |
|
||||||
* @copyright Copyright (c) 2021, Xgene Cloud Ltd |
|
||||||
* |
|
||||||
* @author Naveen MR <oof1lab@gmail.com> |
|
||||||
* @author Pranav C Balan <pranavxc@gmail.com> |
|
||||||
* |
|
||||||
* @license GNU AGPL version 3 or any later version |
|
||||||
* |
|
||||||
* This program is free software: you can redistribute it and/or modify |
|
||||||
* it under the terms of the GNU Affero General Public License as |
|
||||||
* published by the Free Software Foundation, either version 3 of the |
|
||||||
* License, or (at your option) any later version. |
|
||||||
* |
|
||||||
* This program is distributed in the hope that it will be useful, |
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
* GNU Affero General Public License for more details. |
|
||||||
* |
|
||||||
* You should have received a copy of the GNU Affero General Public License |
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
||||||
* |
|
||||||
*/ |
|
||||||
--> |
|
@ -1,19 +0,0 @@ |
|||||||
import type { ColumnType, TableType } from 'nocodb-sdk' |
|
||||||
import { useMetas } from './useMetas' |
|
||||||
|
|
||||||
export function useBelongsTo(column: ColumnType) { |
|
||||||
const { metas, getMeta } = useMetas() |
|
||||||
const parentMeta = computed<TableType>(() => { |
|
||||||
return metas.value?.[(column.colOptions as any)?.fk_related_model_id as string] |
|
||||||
}) |
|
||||||
|
|
||||||
const loadParentMeta = async () => { |
|
||||||
await getMeta((column.colOptions as any)?.fk_related_model_id as string) |
|
||||||
} |
|
||||||
|
|
||||||
const primaryValueProp = computed(() => { |
|
||||||
return (parentMeta?.value?.columns?.find((c) => c.pv) || parentMeta?.value?.columns?.[0])?.title |
|
||||||
}) |
|
||||||
|
|
||||||
return { parentMeta, loadParentMeta, primaryValueProp } |
|
||||||
} |
|
@ -1,19 +0,0 @@ |
|||||||
import type { ColumnType, TableType } from 'nocodb-sdk' |
|
||||||
import { useMetas } from './useMetas' |
|
||||||
|
|
||||||
export function useHasMany(column: ColumnType) { |
|
||||||
const { metas, getMeta } = useMetas() |
|
||||||
const childMeta = computed<TableType>(() => { |
|
||||||
return metas.value?.[(column.colOptions as any)?.fk_related_model_id as string] |
|
||||||
}) |
|
||||||
|
|
||||||
const loadChildMeta = async () => { |
|
||||||
await getMeta((column.colOptions as any)?.fk_related_model_id as string) |
|
||||||
} |
|
||||||
|
|
||||||
const primaryValueProp = computed(() => { |
|
||||||
return (childMeta?.value?.columns?.find((c) => c.pv) || childMeta?.value?.columns?.[0])?.title |
|
||||||
}) |
|
||||||
|
|
||||||
return { childMeta, loadChildMeta, primaryValueProp } |
|
||||||
} |
|
@ -0,0 +1,258 @@ |
|||||||
|
import type { ColumnType, LinkToAnotherRecordType, PaginatedType, TableType } from 'nocodb-sdk' |
||||||
|
import type { Ref } from 'vue' |
||||||
|
import { Modal, notification } from 'ant-design-vue' |
||||||
|
import { useInjectionState, useMetas, useProject } from '#imports' |
||||||
|
import { NOCO } from '~/lib' |
||||||
|
import type { Row } from '~/composables' |
||||||
|
import { extractSdkResponseErrorMsg } from '~/utils' |
||||||
|
|
||||||
|
interface DataApiResponse { |
||||||
|
list: Record<string, any> |
||||||
|
pageInfo: PaginatedType |
||||||
|
} |
||||||
|
|
||||||
|
/** Store for managing Link to another cells */ |
||||||
|
const [useProvideLTARStore, useLTARStore] = useInjectionState( |
||||||
|
(column: Required<ColumnType>, row?: Ref<Row>, reloadData = () => {}) => { |
||||||
|
// state
|
||||||
|
const { metas, getMeta } = useMetas() |
||||||
|
const { project } = useProject() |
||||||
|
const { $api } = useNuxtApp() |
||||||
|
const childrenExcludedList: Ref<DataApiResponse | undefined> = ref() |
||||||
|
const childrenList: Ref<DataApiResponse | undefined> = ref() |
||||||
|
const childrenExcludedListPagination = reactive({ |
||||||
|
page: 1, |
||||||
|
query: '', |
||||||
|
size: 10, |
||||||
|
}) |
||||||
|
const childrenListPagination = reactive({ |
||||||
|
page: 1, |
||||||
|
query: '', |
||||||
|
size: 10, |
||||||
|
}) |
||||||
|
|
||||||
|
const colOptions = column.colOptions as LinkToAnotherRecordType |
||||||
|
|
||||||
|
// getters
|
||||||
|
const meta = computed(() => metas?.value?.[column.fk_model_id as string]) |
||||||
|
const relatedTableMeta = computed<TableType>(() => { |
||||||
|
return metas.value?.[(column.colOptions as any)?.fk_related_model_id as string] |
||||||
|
}) |
||||||
|
|
||||||
|
const rowId = computed(() => |
||||||
|
meta.value.columns |
||||||
|
.filter((c: Required<ColumnType>) => c.pk) |
||||||
|
.map((c: Required<ColumnType>) => row?.value?.row?.[c.title]) |
||||||
|
.join('___'), |
||||||
|
) |
||||||
|
|
||||||
|
// actions
|
||||||
|
const getRelatedTableRowId = (row: Record<string, any>) => { |
||||||
|
return relatedTableMeta.value?.columns |
||||||
|
?.filter((c) => c.pk) |
||||||
|
.map((c) => row?.[c.title as string]) |
||||||
|
.join('___') |
||||||
|
} |
||||||
|
|
||||||
|
const loadRelatedTableMeta = async () => { |
||||||
|
await getMeta(colOptions?.fk_related_model_id as string) |
||||||
|
} |
||||||
|
|
||||||
|
const relatedTablePrimaryValueProp = computed(() => { |
||||||
|
return (relatedTableMeta?.value?.columns?.find((c) => c.pv) || relatedTableMeta?.value?.columns?.[0])?.title |
||||||
|
}) |
||||||
|
const primaryValueProp = computed(() => { |
||||||
|
return (meta?.value?.columns?.find((c: Required<ColumnType>) => c.pv) || relatedTableMeta?.value?.columns?.[0])?.title |
||||||
|
}) |
||||||
|
|
||||||
|
const loadChildrenExcludedList = async () => { |
||||||
|
try { |
||||||
|
childrenExcludedList.value = await $api.dbTableRow.nestedChildrenExcludedList( |
||||||
|
NOCO, |
||||||
|
project.value.id as string, |
||||||
|
meta.value.id, |
||||||
|
rowId.value, |
||||||
|
(column.colOptions as LinkToAnotherRecordType).type as 'mm' | 'hm', |
||||||
|
column.title, |
||||||
|
// todo: swagger type correction
|
||||||
|
{ |
||||||
|
limit: childrenExcludedListPagination.size, |
||||||
|
offset: childrenExcludedListPagination.size * (childrenExcludedListPagination.page - 1), |
||||||
|
where: |
||||||
|
childrenExcludedListPagination.query && |
||||||
|
`(${relatedTablePrimaryValueProp.value},like,${childrenExcludedListPagination.query})`, |
||||||
|
} as any, |
||||||
|
) |
||||||
|
} catch (e: any) { |
||||||
|
notification.error({ |
||||||
|
message: 'Failed to load list', |
||||||
|
description: await extractSdkResponseErrorMsg(e), |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const loadChildrenList = async () => { |
||||||
|
try { |
||||||
|
childrenList.value = await $api.dbTableRow.nestedList( |
||||||
|
NOCO, |
||||||
|
project.value.id as string, |
||||||
|
meta.value.id, |
||||||
|
rowId.value, |
||||||
|
colOptions.type as 'mm' | 'hm', |
||||||
|
column.title, |
||||||
|
// todo: swagger type correction
|
||||||
|
{ |
||||||
|
limit: childrenListPagination.size, |
||||||
|
offset: childrenListPagination.size * (childrenListPagination.page - 1), |
||||||
|
where: childrenListPagination.query && `(${relatedTablePrimaryValueProp.value},like,${childrenListPagination.query})`, |
||||||
|
} as any, |
||||||
|
) |
||||||
|
} catch (e: any) { |
||||||
|
notification.error({ |
||||||
|
message: 'Failed to load children list', |
||||||
|
description: await extractSdkResponseErrorMsg(e), |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const deleteRelatedRow = async (row: Record<string, any>) => { |
||||||
|
Modal.confirm({ |
||||||
|
title: 'Do you want to delete the record?', |
||||||
|
type: 'warning', |
||||||
|
onOk: async () => { |
||||||
|
const id = getRelatedTableRowId(row) |
||||||
|
try { |
||||||
|
$api.dbTableRow.delete(NOCO, project.value.id as string, relatedTableMeta.value.id as string, id as string) |
||||||
|
reloadData?.() |
||||||
|
await loadChildrenList() |
||||||
|
} catch (e: any) { |
||||||
|
notification.error({ |
||||||
|
message: 'Delete failed', |
||||||
|
description: await extractSdkResponseErrorMsg(e), |
||||||
|
}) |
||||||
|
} |
||||||
|
}, |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
const unlink = async (row: Record<string, any>) => { |
||||||
|
// const column = meta.columns.find(c => c.id === this.column.colOptions.fk_child_column_id);
|
||||||
|
// todo: handle if new record
|
||||||
|
// if (this.isNew) {
|
||||||
|
// this.$emit('updateCol', this.row, _cn, null);
|
||||||
|
// this.localState = null;
|
||||||
|
// this.$emit('update:localState', this.localState);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// todo: handle bt column if required
|
||||||
|
// if (column.rqd) {
|
||||||
|
// this.$toast.info('Unlink is not possible, instead map to another parent.').goAway(3000);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
try { |
||||||
|
// todo: audit
|
||||||
|
await $api.dbTableRow.nestedRemove( |
||||||
|
NOCO, |
||||||
|
project.value.title as string, |
||||||
|
meta.value.title, |
||||||
|
rowId.value, |
||||||
|
colOptions.type as 'mm' | 'hm', |
||||||
|
column.title, |
||||||
|
getRelatedTableRowId(row) as string, |
||||||
|
) |
||||||
|
} catch (e) { |
||||||
|
notification.error({ |
||||||
|
message: 'Unlink failed', |
||||||
|
description: await extractSdkResponseErrorMsg(e), |
||||||
|
}) |
||||||
|
} |
||||||
|
reloadData?.() |
||||||
|
// todo: reload table data and children list
|
||||||
|
// this.$emit('loadTableData');
|
||||||
|
// if (this.isForm && this.$refs.childList) {
|
||||||
|
// this.$refs.childList.loadData();
|
||||||
|
// }
|
||||||
|
} |
||||||
|
|
||||||
|
const link = async (row: Record<string, any>) => { |
||||||
|
// todo: handle new record
|
||||||
|
// const pid = this._extractRowId(parent, this.parentMeta);
|
||||||
|
// const id = this._extractRowId(this.row, this.meta);
|
||||||
|
// const _cn = this.meta.columns.find(c => c.id === this.column.colOptions.fk_child_column_id).title;
|
||||||
|
//
|
||||||
|
// if (this.isNew) {
|
||||||
|
// const _rcn = this.parentMeta.columns.find(c => c.id === this.column.colOptions.fk_parent_column_id).title;
|
||||||
|
// this.localState = parent;
|
||||||
|
// this.$emit('update:localState', this.localState);
|
||||||
|
// this.$emit('updateCol', this.row, _cn, parent[_rcn]);
|
||||||
|
// this.newRecordModal = false;
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
try { |
||||||
|
await $api.dbTableRow.nestedAdd( |
||||||
|
NOCO, |
||||||
|
project.value.title as string, |
||||||
|
meta.value.title as string, |
||||||
|
rowId.value, |
||||||
|
colOptions.type as 'mm' | 'hm', |
||||||
|
column.title, |
||||||
|
getRelatedTableRowId(row) as string, |
||||||
|
) |
||||||
|
} catch (e) { |
||||||
|
notification.error({ |
||||||
|
message: 'Linking failed', |
||||||
|
description: await extractSdkResponseErrorMsg(e), |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
// todo: reload table data and child list
|
||||||
|
// this.pid = pid;
|
||||||
|
//
|
||||||
|
// this.newRecordModal = false;
|
||||||
|
//
|
||||||
|
// this.$emit('loadTableData');
|
||||||
|
// if (this.isForm && this.$refs.childList) {
|
||||||
|
// this.$refs.childList.loadData();
|
||||||
|
// }
|
||||||
|
|
||||||
|
reloadData?.() |
||||||
|
} |
||||||
|
|
||||||
|
// watchers
|
||||||
|
watch(childrenExcludedListPagination, async () => { |
||||||
|
await loadChildrenExcludedList() |
||||||
|
}) |
||||||
|
watch(childrenListPagination, async () => { |
||||||
|
await loadChildrenList() |
||||||
|
}) |
||||||
|
|
||||||
|
return { |
||||||
|
relatedTableMeta, |
||||||
|
loadRelatedTableMeta, |
||||||
|
relatedTablePrimaryValueProp, |
||||||
|
childrenExcludedList, |
||||||
|
childrenList, |
||||||
|
rowId, |
||||||
|
childrenExcludedListPagination, |
||||||
|
childrenListPagination, |
||||||
|
primaryValueProp, |
||||||
|
meta, |
||||||
|
unlink, |
||||||
|
link, |
||||||
|
loadChildrenExcludedList, |
||||||
|
loadChildrenList, |
||||||
|
row, |
||||||
|
deleteRelatedRow, |
||||||
|
getRelatedTableRowId, |
||||||
|
} |
||||||
|
}, |
||||||
|
'ltar-store', |
||||||
|
) |
||||||
|
|
||||||
|
export { useProvideLTARStore } |
||||||
|
|
||||||
|
export function useLTARStoreOrThrow() { |
||||||
|
const ltarStore = useLTARStore() |
||||||
|
if (ltarStore == null) throw new Error('Please call `useLTARStore` on the appropriate parent component') |
||||||
|
return ltarStore |
||||||
|
} |
@ -1,19 +0,0 @@ |
|||||||
import type { ColumnType, TableType } from 'nocodb-sdk' |
|
||||||
import { useMetas } from './useMetas' |
|
||||||
|
|
||||||
export function useManyToMany(column: ColumnType) { |
|
||||||
const { metas, getMeta } = useMetas() |
|
||||||
const childMeta = computed<TableType>(() => { |
|
||||||
return metas.value?.[(column.colOptions as any)?.fk_related_model_id as string] |
|
||||||
}) |
|
||||||
|
|
||||||
const loadChildMeta = async () => { |
|
||||||
await getMeta((column.colOptions as any)?.fk_related_model_id as string) |
|
||||||
} |
|
||||||
|
|
||||||
const primaryValueProp = computed(() => { |
|
||||||
return (childMeta?.value?.columns?.find((c) => c.pv) || childMeta?.value?.columns?.[0])?.title |
|
||||||
}) |
|
||||||
|
|
||||||
return { childMeta, loadChildMeta, primaryValueProp } |
|
||||||
} |
|
Loading…
Reference in new issue