Skip to content

Commit

Permalink
feat: add gis features
Browse files Browse the repository at this point in the history
  • Loading branch information
jingsam committed Sep 10, 2024
1 parent f82d50f commit 810d2eb
Show file tree
Hide file tree
Showing 12 changed files with 346 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export const ProtectedSchemaModal = ({
>
<Modal.Content className="space-y-2">
<p className="text-sm">
以下模式由系统管理,当前被设置为只读,无法通过表编辑器进行编辑
以下模式由系统管理,当前被设置为只读,无法通过本界面进行编辑
</p>
<div className="flex flex-wrap gap-1">
{EXCLUDED_SCHEMAS.map((schema) => (
Expand Down Expand Up @@ -63,7 +63,7 @@ const ProtectedSchemaWarning = ({ schema, entity }: { schema: string; entity: st
<AlertTitle_Shadcn_>当前正在一个受保护的模式下查看{entity}</AlertTitle_Shadcn_>
<AlertDescription_Shadcn_>
<p className="mb-2">
模式 <code className="text-xs">{schema}</code> 是由系统管理的,当前被设置为只读,无法通过表编辑器进行编辑
模式 <code className="text-xs">{schema}</code> 是由系统管理的,当前被设置为只读,无法通过本界面进行编辑
</p>
<Button type="default" size="tiny" onClick={() => setShowModal(true)}>
了解更多
Expand Down
115 changes: 115 additions & 0 deletions apps/studio/components/interfaces/GIS/Features/FeatureList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import { includes, sortBy } from 'lodash'
import { useRouter } from 'next/router'
import Link from 'next/link'

import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
import Table from 'components/to-be-cleaned/Table'
import { useProjectApiQuery } from 'data/config/project-api-query'
import { useGISFeaturesQuery } from 'data/gis/gis-features-query'
import { ArrowUpRight } from 'lucide-react'
import { Button } from 'ui'

interface FeatureListProps {
schema: string
filterString: string
}

const FeatureList = ({
schema,
filterString,
}: FeatureListProps) => {
const router = useRouter()
const { project: selectedProject } = useProjectContext()

const { data: features } = useGISFeaturesQuery({
projectRef: selectedProject?.ref
})

const filteredFeatures = (features ?? []).filter((x) =>
includes(x.id.toLowerCase(), filterString.toLowerCase())
)
const _features = sortBy(
filteredFeatures.filter((x) => x.id.startsWith(schema)),
(feature) => feature.id.toLocaleLowerCase()
)

const { data, error } = useProjectApiQuery({ projectRef: selectedProject?.ref })
const { protocol, endpoint } = data?.autoApiService ?? {}
const apiUrl = endpoint ? `${protocol ?? 'http'}://${endpoint}` : undefined

if (error) {
return (
<div className="p-6 mx-auto text-center sm:w-full md:w-3/4">
<p className="text-foreground-light">
<p>连接到 API 出错</p>
<p>{`${error}`}</p>
</p>
</div>
)
}

if (_features.length === 0 && filterString.length === 0) {
return (
<Table.tr key={schema}>
<Table.td colSpan={3}>
<p className="text-sm text-foreground">未找到要素服务</p>
<p className="text-sm text-foreground-light">
在模式 "{schema}" 中未找到要素服务
</p>
</Table.td>
</Table.tr>
)
}

if (_features.length === 0 && filterString.length > 0) {
return (
<Table.tr key={schema}>
<Table.td colSpan={3}>
<p className="text-sm text-foreground">未找到结果</p>
<p className="text-sm text-foreground-light">
您搜索的 "{filterString}" 没有返回任何结果
</p>
</Table.td>
</Table.tr>
)
}

return (
<>
{_features.map((x) => {
return (
<Table.tr key={x.id}>
<Table.td className="truncate">
<p title={x.id}>{x.id}</p>
</Table.td>
<Table.td className="hidden md:table-cell md:overflow-auto">
{x.description ? (
<span className="lg:max-w-48 truncate inline-block" title={x.description}>
{x.description}
</span>
) : (
<p className="text-border-stronger">无描述信息</p>
)}
</Table.td>
<Table.td className="w-1/5">
<div className="flex justify-end items-center space-x-2">
<Button asChild type="default" iconRight={<ArrowUpRight strokeWidth={1} />}>
<Link href={`${apiUrl}/pg_featureserv/collections/${x.id}.json`} target="_blank">
元数据
</Link>
</Button>
<Button asChild type="default" iconRight={<ArrowUpRight strokeWidth={1} />}>
<Link href={`${apiUrl}/pg_featureserv/collections/${x.id}/items.html`} target="_blank">
查看
</Link>
</Button>
</div>
</Table.td>
</Table.tr>
)
})}
</>
)
}

export default FeatureList
124 changes: 124 additions & 0 deletions apps/studio/components/interfaces/GIS/Features/FeaturesList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import { Search } from 'lucide-react'
import { partition } from 'lodash'
import { useRouter } from 'next/router'

import { useParams } from 'common'
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
import ProductEmptyState from 'components/to-be-cleaned/ProductEmptyState'
import Table from 'components/to-be-cleaned/Table'
import AlertError from 'components/ui/AlertError'
import SchemaSelector from 'components/ui/SchemaSelector'
import { GenericSkeletonLoader } from 'components/ui/ShimmeringLoader'
import { useGISFeaturesQuery } from 'data/gis/gis-features-query'
import { useSchemasQuery } from 'data/database/schemas-query'
import { useQuerySchemaState } from 'hooks/misc/useSchemaQueryState'
import { EXCLUDED_SCHEMAS } from 'lib/constants/schemas'
import { Input } from 'ui'
import ProtectedSchemaWarning from 'components/interfaces/Database/ProtectedSchemaWarning'
import FeatureList from './FeatureList'

const FeaturesList = () => {
const { project } = useProjectContext()
const router = useRouter()
const { search } = useParams()
const { selectedSchema, setSelectedSchema } = useQuerySchemaState()
const filterString = search ?? ''

const setFilterString = (str: string) => {
const url = new URL(document.URL)
if (str === '') {
url.searchParams.delete('search')
} else {
url.searchParams.set('search', str)
}
router.push(url)
}

const { data: schemas } = useSchemasQuery({
projectRef: project?.ref,
connectionString: project?.connectionString,
})
const [protectedSchemas] = partition(schemas ?? [], (schema) =>
EXCLUDED_SCHEMAS.includes(schema?.name ?? '')
)
const foundSchema = schemas?.find((schema) => schema.name === selectedSchema)
const isLocked = protectedSchemas.some((s) => s.id === foundSchema?.id)

const {
data: features,
error,
isLoading,
isError,
} = useGISFeaturesQuery({
projectRef: project?.ref,
})

if (isLoading) return <GenericSkeletonLoader />
if (isError) return <AlertError error={error} subject="获取要素服务列表失败" />

return (
<>
{(features ?? []).length == 0 ? (
<div className="flex h-full w-full items-center justify-center">
<ProductEmptyState
title="要素服务"
>
<p className="text-sm text-foreground-light">
要素服务是基于数据库的矢量数据服务,用户可以查询和获取空间要素。
</p>
</ProductEmptyState>
</div>
) : (
<div className="w-full space-y-4">
<div className="flex items-center justify-between">
<div className="flex items-center space-x-4">
<SchemaSelector
className="w-[260px]"
size="small"
showError={false}
selectedSchemaName={selectedSchema}
onSelectSchema={(schema) => {
const url = new URL(document.URL)
url.searchParams.delete('search')
router.push(url)
setSelectedSchema(schema)
}}
/>
<Input
placeholder="查找要素服务"
size="small"
icon={<Search size={14} />}
value={filterString}
className="w-64"
onChange={(e) => setFilterString(e.target.value)}
/>
</div>
</div>

{isLocked && <ProtectedSchemaWarning schema={selectedSchema} entity="要素服务" />}

<Table
className="table-fixed"
head={
<>
<Table.th key="id">服务 ID</Table.th>
<Table.th key="description" className="hidden md:table-cell">
服务描述
</Table.th>
<Table.th key="buttons" className="w-1/5"></Table.th>
</>
}
body={
<FeatureList
schema={selectedSchema}
filterString={filterString}
/>
}
/>
</div>
)}
</>
)
}

export default FeaturesList
13 changes: 5 additions & 8 deletions apps/studio/components/interfaces/GIS/Tiles/TileList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const TileList = ({
)
const _tiles = sortBy(
filteredTiles.filter((x) => x.schema == schema),
(func) => func.name.toLocaleLowerCase()
(tile) => tile.name.toLocaleLowerCase()
)

const { data, error } = useProjectApiQuery({ projectRef: selectedProject?.ref })
Expand All @@ -51,7 +51,7 @@ const TileList = ({
if (_tiles.length === 0 && filterString.length === 0) {
return (
<Table.tr key={schema}>
<Table.td colSpan={5}>
<Table.td colSpan={3}>
<p className="text-sm text-foreground">未找到瓦片服务</p>
<p className="text-sm text-foreground-light">
在模式 "{schema}" 中未找到瓦片服务
Expand All @@ -64,7 +64,7 @@ const TileList = ({
if (_tiles.length === 0 && filterString.length > 0) {
return (
<Table.tr key={schema}>
<Table.td colSpan={5}>
<Table.td colSpan={3}>
<p className="text-sm text-foreground">未找到结果</p>
<p className="text-sm text-foreground-light">
您搜索的 "{filterString}" 没有返回任何结果
Expand All @@ -91,19 +91,16 @@ const TileList = ({
<p className="text-border-stronger">无描述信息</p>
)}
</Table.td>
<Table.td className="hidden lg:table-cell w-[120px]">
<p title={x.type}>{x.type}</p>
</Table.td>
<Table.td className="w-1/5">
<div className="flex justify-end items-center space-x-2">
<Button asChild type="default" iconRight={<ArrowUpRight strokeWidth={1} />}>
<Link href={`${apiUrl}/pg_tileserv/${x.id}.json`} target="_blank">
详情
元数据
</Link>
</Button>
<Button asChild type="default" iconRight={<ArrowUpRight strokeWidth={1} />}>
<Link href={`${apiUrl}/pg_tileserv/${x.id}.html`} target="_blank">
预览
查看
</Link>
</Button>
</div>
Expand Down
21 changes: 17 additions & 4 deletions apps/studio/components/interfaces/GIS/Tiles/TilesList.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Search } from 'lucide-react'
import { partition } from 'lodash'
import { useRouter } from 'next/router'

import { useParams } from 'common'
Expand All @@ -9,8 +10,11 @@ import AlertError from 'components/ui/AlertError'
import SchemaSelector from 'components/ui/SchemaSelector'
import { GenericSkeletonLoader } from 'components/ui/ShimmeringLoader'
import { useGISTilesQuery } from 'data/gis/gis-tiles-query'
import { useSchemasQuery } from 'data/database/schemas-query'
import { useQuerySchemaState } from 'hooks/misc/useSchemaQueryState'
import { EXCLUDED_SCHEMAS } from 'lib/constants/schemas'
import { Input } from 'ui'
import ProtectedSchemaWarning from 'components/interfaces/Database/ProtectedSchemaWarning'
import TileList from './TileList'

const TilesList = () => {
Expand All @@ -30,6 +34,16 @@ const TilesList = () => {
router.push(url)
}

const { data: schemas } = useSchemasQuery({
projectRef: project?.ref,
connectionString: project?.connectionString,
})
const [protectedSchemas] = partition(schemas ?? [], (schema) =>
EXCLUDED_SCHEMAS.includes(schema?.name ?? '')
)
const foundSchema = schemas?.find((schema) => schema.name === selectedSchema)
const isLocked = protectedSchemas.some((s) => s.id === foundSchema?.id)

const {
data: tiles,
error,
Expand Down Expand Up @@ -81,17 +95,16 @@ const TilesList = () => {
</div>
</div>

{isLocked && <ProtectedSchemaWarning schema={selectedSchema} entity="瓦片服务" />}

<Table
className="table-fixed"
head={
<>
<Table.th key="id">服务名称</Table.th>
<Table.th key="id">服务 ID</Table.th>
<Table.th key="description" className="hidden md:table-cell">
服务描述
</Table.th>
<Table.th key="type" className="hidden lg:table-cell w-[120px]">
数据源类型
</Table.th>
<Table.th key="buttons" className="w-1/5"></Table.th>
</>
}
Expand Down
3 changes: 2 additions & 1 deletion apps/studio/components/interfaces/GIS/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { default as TilesList } from './Tiles/TilesList'
export { default as TilesList } from './Tiles/TilesList'
export { default as FeaturesList } from './Features/FeaturesList'
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ const TableEditorMenu = () => {
</AlertTitle_Shadcn_>
<AlertDescription_Shadcn_ className="text-xs">
<p className="mb-2">
此模式是系统模式,在表编辑器中只读
此模式是系统模式,在本界面中执行只读操作
</p>
<Button type="default" size="tiny" onClick={() => setShowModal(true)}>
了解更多
Expand Down
Loading

0 comments on commit 810d2eb

Please sign in to comment.