Browse Source

geodata: add select geodata select field menu and missing fields in migrations

pull/4140/head
flisowna 2 years ago
parent
commit
6de762a4b6
  1. 56
      packages/nc-gui/components/dlg/ViewCreate.vue
  2. 61
      packages/nc-gui/components/smartsheet/Map.vue
  3. 35
      packages/nc-gui/composables/useMapViewDataStore.ts
  4. 3
      packages/nc-gui/composables/useViewData.ts
  5. 3
      packages/nc-gui/lang/en.json
  6. 10
      packages/nocodb/src/lib/migrations/v2/nc_021_map_view.ts

56
packages/nc-gui/components/dlg/ViewCreate.vue

@ -25,13 +25,14 @@ interface Props {
title?: string title?: string
selectedViewId?: string selectedViewId?: string
groupingFieldColumnId?: string groupingFieldColumnId?: string
geoDataFieldColumnId?: string
views: ViewType[] views: ViewType[]
meta: TableType meta: TableType
} }
interface Emits { interface Emits {
(event: 'update:modelValue', value: boolean): void (event: 'update:modelValue', value: boolean): void
(event: 'created', value: GridType | KanbanType | GalleryType | FormType): void (event: 'created', value: GridType | KanbanType | GalleryType | FormType | MapType): void
} }
interface Form { interface Form {
@ -40,9 +41,10 @@ interface Form {
copy_from_id: string | null copy_from_id: string | null
// for kanban view only // for kanban view only
fk_grp_col_id: string | null fk_grp_col_id: string | null
fk_geo_data_col_id: string | null
} }
const { views = [], meta, selectedViewId, groupingFieldColumnId, ...props } = defineProps<Props>() const { views = [], meta, selectedViewId, groupingFieldColumnId, geoDataFieldColumnId, ...props } = defineProps<Props>()
const emits = defineEmits<Emits>() const emits = defineEmits<Emits>()
@ -61,9 +63,10 @@ const form = reactive<Form>({
type: props.type, type: props.type,
copy_from_id: null, copy_from_id: null,
fk_grp_col_id: null, fk_grp_col_id: null,
fk_geo_data_col_id: null,
}) })
const singleSelectFieldOptions = ref<SelectProps['options']>([]) const viewSelectFieldOptions = ref<SelectProps['options']>([])
const viewNameRules = [ const viewNameRules = [
// name is required // name is required
@ -72,7 +75,7 @@ const viewNameRules = [
{ {
validator: (_: unknown, v: string) => validator: (_: unknown, v: string) =>
new Promise((resolve, reject) => { new Promise((resolve, reject) => {
views.every((v1) => ((v1 as GridType | KanbanType | GalleryType).alias || v1.title) !== v) views.every((v1) => ((v1 as GridType | KanbanType | GalleryType | MapType).alias || v1.title) !== v)
? resolve(true) ? resolve(true)
: reject(new Error(`View name should be unique`)) : reject(new Error(`View name should be unique`))
}), }),
@ -85,6 +88,11 @@ const groupingFieldColumnRules = [
{ required: true, message: `${t('general.groupingField')} ${t('general.required')}` }, { required: true, message: `${t('general.groupingField')} ${t('general.required')}` },
] ]
const geoDataFieldColumnRules = [
// name is required
{ required: true, message: `${t('general.geoDataField')} ${t('general.required')}` },
]
const typeAlias = computed( const typeAlias = computed(
() => () =>
({ ({
@ -114,7 +122,7 @@ function init() {
// preset the grouping field column // preset the grouping field column
if (props.type === ViewTypes.KANBAN) { if (props.type === ViewTypes.KANBAN) {
singleSelectFieldOptions.value = meta viewSelectFieldOptions.value = meta
.columns!.filter((el) => el.uidt === UITypes.SingleSelect) .columns!.filter((el) => el.uidt === UITypes.SingleSelect)
.map((field) => { .map((field) => {
return { return {
@ -128,7 +136,26 @@ function init() {
form.fk_grp_col_id = groupingFieldColumnId form.fk_grp_col_id = groupingFieldColumnId
} else { } else {
// take the first option // take the first option
form.fk_grp_col_id = singleSelectFieldOptions.value?.[0]?.value as string form.fk_grp_col_id = viewSelectFieldOptions.value?.[0]?.value as string
}
}
if (props.type === ViewTypes.MAP) {
viewSelectFieldOptions.value = meta
.columns!.filter((el) => el.uidt === UITypes.GeoData)
.map((field) => {
return {
value: field.id,
label: field.title,
}
})
if (geoDataFieldColumnId) {
// take from the one from copy view
form.fk_geo_data_col_id = geoDataFieldColumnId
} else {
// take the first option
form.fk_geo_data_col_id = viewSelectFieldOptions.value?.[0]?.value as string
} }
} }
@ -205,12 +232,27 @@ async function onSubmit() {
<a-select <a-select
v-model:value="form.fk_grp_col_id" v-model:value="form.fk_grp_col_id"
class="w-full nc-kanban-grouping-field-select" class="w-full nc-kanban-grouping-field-select"
:options="singleSelectFieldOptions" :options="viewSelectFieldOptions"
:disabled="groupingFieldColumnId" :disabled="groupingFieldColumnId"
placeholder="Select a Grouping Field" placeholder="Select a Grouping Field"
not-found-content="No Single Select Field can be found. Please create one first." not-found-content="No Single Select Field can be found. Please create one first."
/> />
</a-form-item> </a-form-item>
<a-form-item
v-if="form.type === ViewTypes.MAP"
:label="$t('general.geoDataField')"
name="fk_geo_data_col_id"
:rules="geoDataFieldColumnRules"
>
<a-select
v-model:value="form.fk_geo_data_col_id"
class="w-full nc-kanban-grouping-field-select"
:options="viewSelectFieldOptions"
:disabled="geoDataFieldColumnId"
placeholder="Select a GeoData Field"
not-found-content="No Geometry Field can be found. Please create one first."
/>
</a-form-item>
</a-form> </a-form>
<template #footer> <template #footer>

61
packages/nc-gui/components/smartsheet/Map.vue

@ -2,7 +2,7 @@
import 'leaflet/dist/leaflet.css' import 'leaflet/dist/leaflet.css'
import * as L from 'leaflet' import * as L from 'leaflet'
// import { ViewTypes } from '~~/../nocodb-sdk/build/main' // import { ViewTypes } from '~~/../nocodb-sdk/build/main'
import { ViewTypes } from 'nocodb-sdk' // import { ViewTypes } from 'nocodb-sdk'
import { IsFormInj, IsGalleryInj, IsGridInj, IsMapInj, ReadonlyInj, onMounted, provide, ref, useUIPermission } from '#imports' import { IsFormInj, IsGalleryInj, IsGridInj, IsMapInj, ReadonlyInj, onMounted, provide, ref, useUIPermission } from '#imports'
const { isUIAllowed } = useUIPermission() const { isUIAllowed } = useUIPermission()
@ -17,8 +17,30 @@ const reloadViewDataHook = inject(ReloadViewDataHookInj)
// const meta = inject(MetaInj, ref()) // const meta = inject(MetaInj, ref())
// const view = inject(ActiveViewInj, ref()) // const view = inject(ActiveViewInj, ref())
const view = inject(ActiveViewInj, ref())
const meta = inject(MetaInj, ref())
const { formattedData, loadMapData, mapData } = useMapViewStoreOrThrow()
// const { loadData, formattedData: data } = useViewData(meta, view) // const { loadData, formattedData: data } = useViewData(meta, view)
const { formattedData, loadMapData } = useMapViewStoreOrThrow() // const { sharedView, sorts, nestedFilters } = useSharedView()
const {
showSystemFields,
// sortedAndFilteredFields,
fields,
filteredFieldList,
// filterQuery,
showAll,
// hideAll,
// saveOrUpdate,
// metaColumnById,
} = useViewColumns(view, meta)
console.log('fields.value', fields.value)
console.log('showSystemFields.value', showSystemFields.value)
console.log('filteredFieldList.value', filteredFieldList.value)
console.log('showAll.value', showAll.value)
console.log('fields.value', fields.value)
const markerRef = ref() const markerRef = ref()
const myMapRef = ref() const myMapRef = ref()
@ -41,18 +63,32 @@ onMounted(async () => {
// const geodata = data.value[0].row.geo.split(';') // const geodata = data.value[0].row.geo.split(';')
}) })
// const geoDataColumn: any = $(
// computed(() =>
// meta.value?.columnsById
// ? meta.value.columnsById[mapData?.value?.fk_geo_data_col_id as keyof typeof meta.value.columnsById]
// : {},
// ),
// )
watch(formattedData, () => { watch(formattedData, () => {
markersRef.value?.clearLayers() markersRef.value?.clearLayers()
console.log('mapData', mapData?.value?.fk_geo_data_col_id)
formattedData.value?.forEach((row) => { formattedData.value?.forEach((row) => {
// const [lat, long] = // const [lat, long] =
console.log('meta', meta?.value?.columns)
console.log('row', row) console.log('row', row)
if (row?.geo == null) return if (row?.geonew == null) return
const [lat, long] = row?.geo.split(';').map(parseFloat)
// if (lat == null || long == null) { const [lat, long] = row?.geonew.split(';').map(parseFloat)
// return if (lat == null || long == null) {
// } return
}
console.log('lat', lat) console.log('lat', lat)
addMarker(lat, long) addMarker(lat, long)
const selected = row?.rowMeta?.selected
console.log(selected)
}) })
}) })
@ -62,17 +98,16 @@ reloadViewDataHook?.on(async () => {
function addMarker(lat: number, long: number) { function addMarker(lat: number, long: number) {
// markersRef.value?.clearLayers() // markersRef.value?.clearLayers()
const markerNew = markerRef.value([lat, long]) const markerNew = markerRef?.value?.([lat, long])
console.log(markersRef.value) console.log(markersRef.value)
markersRef.value.addLayer(markerNew) markersRef?.value?.addLayer(markerNew)
myMapRef.value.addLayer(markersRef.value) myMapRef?.value?.addLayer(markersRef.value)
} }
onMounted(async () => { onMounted(async () => {
const { map, tileLayer, marker } = await import('leaflet') const { map, tileLayer, marker } = await import('leaflet')
await import('leaflet.markercluster') await import('leaflet.markercluster')
const myMap = map('map').setView([51.505, -0.09], 13) const myMap = map('map').setView([51.505, -0.09], 13)
markerRef.value = marker markerRef.value = marker
myMapRef.value = myMap myMapRef.value = myMap
@ -90,7 +125,9 @@ onMounted(async () => {
<template> <template>
<div class="flex flex-col h-full w-full"> <div class="flex flex-col h-full w-full">
{{ JSON.stringify(formattedData) }} {{ JSON.stringify(mapData1) }}
<!-- {{ JSON.stringify(selected) }} -->
<!-- {{ JSON.stringify(meta?.columns) }} -->
<!-- <div class="flex m-4 gap-4"> <!-- <div class="flex m-4 gap-4">
<label :for="latitude">latitude</label> <label :for="latitude">latitude</label>
<input v-model="latitude" /> <input v-model="latitude" />

35
packages/nc-gui/composables/useMapViewDataStore.ts

@ -1,5 +1,5 @@
import type { ComputedRef, Ref } from 'vue' import type { ComputedRef, Ref } from 'vue'
import type { MapType, TableType, ViewType } from 'nocodb-sdk' import type { ColumnType, MapType, TableType, ViewType } from 'nocodb-sdk'
import { ref, useApi, useInjectionState } from '#imports' import { ref, useApi, useInjectionState } from '#imports'
import type { Row } from '~/lib' import type { Row } from '~/lib'
@ -13,15 +13,43 @@ const [useProvideMapViewStore, useMapViewStore] = useInjectionState(
const { api } = useApi() const { api } = useApi()
const { project } = useProject() const { project } = useProject()
const mapMetaData = ref<MapType>({})
const geoDataField = ref<string>('')
const geoDataFieldColumn = ref<ColumnType | undefined>()
async function loadMapData() { async function loadMapData() {
if (!viewMeta?.value?.id || !meta?.value?.columns) return
formattedData.value = []
const res = await api.dbViewRow.list(
'noco',
project.value.id!,
meta.value!.id!,
viewMeta.value!.id!,
geoDataFieldColumn!.value!.id,
)
geoDataFieldColumn.value =
(meta.value.columns as ColumnType[]).filter((f) => f.id === mapMetaData.value.fk_geo_data_col_id)[0] || {}
geoDataField.value = geoDataFieldColumn.value.title!
const { fk_geo_data_col_id, meta: stack_meta } = mapMetaData.value
const stackMetaObj: any.value = stack_meta ? JSON.parse(stack_meta as string) : {}
console.log('column geodata', stackMetaObj.value[fk_geo_data_col_id])
// if ((!project?.value?.id || !meta.value?.id || !viewMeta?.value?.id) && !isPublic.value) return // if ((!project?.value?.id || !meta.value?.id || !viewMeta?.value?.id) && !isPublic.value) return
// reset formattedData & countByStack to avoid storing previous data after changing grouping field // reset formattedData & countByStack to avoid storing previous data after changing grouping field
formattedData.value = []
// alert('in loadMapData') // alert('in loadMapData')
// debugger // debugger
const res = await api.dbViewRow.list('noco', project.value.id!, meta.value!.id!, viewMeta.value!.id!)
console.log('res in mapviewdatastore', res) console.log('res in mapviewdatastore', res)
@ -34,6 +62,7 @@ const [useProvideMapViewStore, useMapViewStore] = useInjectionState(
return { return {
formattedData, formattedData,
loadMapData, loadMapData,
mapMetaData,
} }
}, },
) )

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

@ -58,8 +58,6 @@ export function useViewData(
const formViewData = ref<FormType>() const formViewData = ref<FormType>()
const mapData = ref<MapType>()
const formattedData = ref<Row[]>([]) const formattedData = ref<Row[]>([])
const isPublic = inject(IsPublicInj, ref(false)) const isPublic = inject(IsPublicInj, ref(false))
@ -453,7 +451,6 @@ export function useViewData(
syncCount, syncCount,
syncPagination, syncPagination,
galleryData, galleryData,
mapData,
loadGalleryData, loadGalleryData,
loadFormView, loadFormView,
formColumnData, formColumnData,

3
packages/nc-gui/lang/en.json

@ -69,7 +69,8 @@
"betaNote": "This feature is currently in beta.", "betaNote": "This feature is currently in beta.",
"moreInfo": "More information can be found here", "moreInfo": "More information can be found here",
"logs": "Logs", "logs": "Logs",
"groupingField": "Grouping Field" "groupingField": "Grouping Field",
"geoDataField": "GeoData Field"
}, },
"objects": { "objects": {
"project": "Project", "project": "Project",

10
packages/nocodb/src/lib/migrations/v2/nc_021_map_view.ts

@ -1,6 +1,7 @@
import { MetaTable } from '../../utils/globals'; import { MetaTable } from '../../utils/globals';
import Knex from 'knex';
const up = async (knex) => { const up = async (knex: Knex) => {
await knex.schema.createTable(MetaTable.MAP_VIEW, (table) => { await knex.schema.createTable(MetaTable.MAP_VIEW, (table) => {
table.string('fk_view_id', 20).primary(); table.string('fk_view_id', 20).primary();
table.foreign('fk_view_id').references(`${MetaTable.VIEWS}.id`); table.foreign('fk_view_id').references(`${MetaTable.VIEWS}.id`);
@ -14,10 +15,13 @@ const up = async (knex) => {
table.string('uuid'); table.string('uuid');
table.string('title'); table.string('title');
table.string('fk_geodata_col_id', 20); table.string('fk_geo_data_col_id', 20);
table.foreign('fk_geodata_col_id').references(`${MetaTable.COLUMNS}.id`); table.foreign('fk_geo_data_col_id').references(`${MetaTable.COLUMNS}.id`);
table.text('meta'); table.text('meta');
table.dateTime('created_at');
table.dateTime('updated_at');
}); });
}; };

Loading…
Cancel
Save