upd: connected api monitoring
Deskripsi: - update version No Issues
This commit is contained in:
@@ -27,6 +27,7 @@
|
|||||||
"@mantine/charts": "^9.0.0",
|
"@mantine/charts": "^9.0.0",
|
||||||
"@mantine/core": "^8.3.18",
|
"@mantine/core": "^8.3.18",
|
||||||
"@mantine/hooks": "^8.3.18",
|
"@mantine/hooks": "^8.3.18",
|
||||||
|
"@mantine/notifications": "^8.3.18",
|
||||||
"@prisma/client": "6",
|
"@prisma/client": "6",
|
||||||
"@tanstack/react-query": "^5.95.2",
|
"@tanstack/react-query": "^5.95.2",
|
||||||
"@tanstack/react-router": "^1.168.10",
|
"@tanstack/react-router": "^1.168.10",
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import { ColorSchemeScript, MantineProvider, createTheme } from '@mantine/core'
|
import { ColorSchemeScript, MantineProvider, createTheme } from '@mantine/core'
|
||||||
import '@mantine/core/styles.css'
|
import '@mantine/core/styles.css'
|
||||||
|
import '@mantine/notifications/styles.css'
|
||||||
|
import { Notifications } from '@mantine/notifications'
|
||||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||||
import { createRouter, RouterProvider } from '@tanstack/react-router'
|
import { createRouter, RouterProvider } from '@tanstack/react-router'
|
||||||
import { routeTree } from './routeTree.gen'
|
import { routeTree } from './routeTree.gen'
|
||||||
@@ -61,6 +63,7 @@ export function App() {
|
|||||||
<>
|
<>
|
||||||
<ColorSchemeScript defaultColorScheme="auto" />
|
<ColorSchemeScript defaultColorScheme="auto" />
|
||||||
<MantineProvider theme={theme} defaultColorScheme="auto">
|
<MantineProvider theme={theme} defaultColorScheme="auto">
|
||||||
|
<Notifications />
|
||||||
<QueryClientProvider client={queryClient}>
|
<QueryClientProvider client={queryClient}>
|
||||||
<RouterProvider router={router} />
|
<RouterProvider router={router} />
|
||||||
</QueryClientProvider>
|
</QueryClientProvider>
|
||||||
|
|||||||
@@ -16,4 +16,5 @@ export const API_URLS = {
|
|||||||
getGridOverview: () => `${API_BASE_URL}/api/monitoring/grid-overview`,
|
getGridOverview: () => `${API_BASE_URL}/api/monitoring/grid-overview`,
|
||||||
getDailyActivity: () => `${API_BASE_URL}/api/monitoring/daily-activity`,
|
getDailyActivity: () => `${API_BASE_URL}/api/monitoring/daily-activity`,
|
||||||
getComparisonActivity: () => `${API_BASE_URL}/api/monitoring/comparison-activity`,
|
getComparisonActivity: () => `${API_BASE_URL}/api/monitoring/comparison-activity`,
|
||||||
|
postVersionUpdate: () => `${API_BASE_URL}/api/monitoring/version-update`,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
import { notifications } from '@mantine/notifications'
|
||||||
import { VillageActivityLineChart, VillageComparisonBarChart } from '@/frontend/components/DashboardCharts'
|
import { VillageActivityLineChart, VillageComparisonBarChart } from '@/frontend/components/DashboardCharts'
|
||||||
import { ErrorDataTable } from '@/frontend/components/ErrorDataTable'
|
import { ErrorDataTable } from '@/frontend/components/ErrorDataTable'
|
||||||
import { SummaryCard } from '@/frontend/components/SummaryCard'
|
import { SummaryCard } from '@/frontend/components/SummaryCard'
|
||||||
@@ -40,6 +42,13 @@ function AppOverviewPage() {
|
|||||||
const isDesaPlus = appId === 'desa-plus'
|
const isDesaPlus = appId === 'desa-plus'
|
||||||
const [versionModalOpened, { open: openVersionModal, close: closeVersionModal }] = useDisclosure(false)
|
const [versionModalOpened, { open: openVersionModal, close: closeVersionModal }] = useDisclosure(false)
|
||||||
|
|
||||||
|
// Form State
|
||||||
|
const [latestVersion, setLatestVersion] = useState('')
|
||||||
|
const [minVersion, setMinVersion] = useState('')
|
||||||
|
const [messageUpdate, setMessageUpdate] = useState('')
|
||||||
|
const [maintenance, setMaintenance] = useState(false)
|
||||||
|
const [isSaving, setIsSaving] = useState(false)
|
||||||
|
|
||||||
// Data Fetching
|
// Data Fetching
|
||||||
const { data: gridRes, isLoading: gridLoading, mutate: mutateGrid } = useSWR(isDesaPlus ? API_URLS.getGridOverview() : null, fetcher)
|
const { data: gridRes, isLoading: gridLoading, mutate: mutateGrid } = useSWR(isDesaPlus ? API_URLS.getGridOverview() : null, fetcher)
|
||||||
const { data: dailyRes, isLoading: dailyLoading, mutate: mutateDaily } = useSWR(isDesaPlus ? API_URLS.getDailyActivity() : null, fetcher)
|
const { data: dailyRes, isLoading: dailyLoading, mutate: mutateDaily } = useSWR(isDesaPlus ? API_URLS.getDailyActivity() : null, fetcher)
|
||||||
@@ -49,31 +58,93 @@ function AppOverviewPage() {
|
|||||||
const dailyData = dailyRes?.data || []
|
const dailyData = dailyRes?.data || []
|
||||||
const comparisonData = comparisonRes?.data || []
|
const comparisonData = comparisonRes?.data || []
|
||||||
|
|
||||||
|
// Initialize form when data loads or modal opens
|
||||||
|
useEffect(() => {
|
||||||
|
if (grid?.version && versionModalOpened) {
|
||||||
|
setLatestVersion(grid.version.mobile_latest_version || '')
|
||||||
|
setMinVersion(grid.version.mobile_minimum_version || '')
|
||||||
|
setMessageUpdate(grid.version.mobile_message_update || '')
|
||||||
|
setMaintenance(grid.version.mobile_maintenance === 'true')
|
||||||
|
}
|
||||||
|
}, [grid, versionModalOpened])
|
||||||
|
|
||||||
const handleRefresh = () => {
|
const handleRefresh = () => {
|
||||||
mutateGrid()
|
mutateGrid()
|
||||||
mutateDaily()
|
mutateDaily()
|
||||||
mutateComparison()
|
mutateComparison()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleSaveVersion = async () => {
|
||||||
|
setIsSaving(true)
|
||||||
|
try {
|
||||||
|
const response = await fetch(API_URLS.postVersionUpdate(), {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
mobile_latest_version: latestVersion,
|
||||||
|
mobile_minimum_version: minVersion,
|
||||||
|
mobile_maintenance: maintenance,
|
||||||
|
mobile_message_update: messageUpdate,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
notifications.show({
|
||||||
|
title: 'Update Successful',
|
||||||
|
message: 'Application version information has been updated.',
|
||||||
|
color: 'teal',
|
||||||
|
})
|
||||||
|
mutateGrid()
|
||||||
|
closeVersionModal()
|
||||||
|
} else {
|
||||||
|
notifications.show({
|
||||||
|
title: 'Update Failed',
|
||||||
|
message: 'Failed to update version information. Please check your data.',
|
||||||
|
color: 'red',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
notifications.show({
|
||||||
|
title: 'Network Error',
|
||||||
|
message: 'Could not connect to the server. Please try again later.',
|
||||||
|
color: 'red',
|
||||||
|
})
|
||||||
|
} finally {
|
||||||
|
setIsSaving(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Modal opened={versionModalOpened} onClose={closeVersionModal} title="Update Version Information" radius="md">
|
<Modal opened={versionModalOpened} onClose={closeVersionModal} title="Update Version Information" radius="md">
|
||||||
<Stack gap="md">
|
<Stack gap="md">
|
||||||
<TextInput label="Active Version" defaultValue={grid?.version?.mobile_latest_version || 'v1.2.0'} />
|
<TextInput
|
||||||
<TextInput label="Minimum Version" defaultValue={grid?.version?.mobile_minimum_version || 'v1.0.0'} />
|
label="Active Version"
|
||||||
|
placeholder="e.g. 2.0.5"
|
||||||
|
value={latestVersion}
|
||||||
|
onChange={(e) => setLatestVersion(e.currentTarget.value)}
|
||||||
|
/>
|
||||||
|
<TextInput
|
||||||
|
label="Minimum Version"
|
||||||
|
placeholder="e.g. 2.0.0"
|
||||||
|
value={minVersion}
|
||||||
|
onChange={(e) => setMinVersion(e.currentTarget.value)}
|
||||||
|
/>
|
||||||
<Textarea
|
<Textarea
|
||||||
label="Update Message"
|
label="Update Message"
|
||||||
placeholder="Enter release notes or update message..."
|
placeholder="Enter release notes or update message..."
|
||||||
defaultValue={grid?.version?.mobile_message_update || ''}
|
value={messageUpdate}
|
||||||
|
onChange={(e) => setMessageUpdate(e.currentTarget.value)}
|
||||||
minRows={3}
|
minRows={3}
|
||||||
autosize
|
autosize
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
label="Maintenance Mode"
|
label="Maintenance Mode"
|
||||||
description="Enable to put the app in maintenance mode for users."
|
description="Enable to put the app in maintenance mode for users."
|
||||||
defaultChecked={grid?.version?.mobile_maintenance === 'true'}
|
checked={maintenance}
|
||||||
|
onChange={(e) => setMaintenance(e.currentTarget.checked)}
|
||||||
/>
|
/>
|
||||||
<Button fullWidth onClick={closeVersionModal}>Save Changes</Button>
|
<Button fullWidth onClick={handleSaveVersion} loading={isSaving}>Save Changes</Button>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
||||||
@@ -84,11 +155,11 @@ function AppOverviewPage() {
|
|||||||
<Text size="sm" c="dimmed">Detailed metrics for {isDesaPlus ? 'Desa+' : appId}</Text>
|
<Text size="sm" c="dimmed">Detailed metrics for {isDesaPlus ? 'Desa+' : appId}</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
<Group gap="md">
|
{/* <Group gap="md">
|
||||||
<ActionIcon variant="light" color="brand-blue" size="lg" radius="md" onClick={handleRefresh}>
|
<ActionIcon variant="light" color="brand-blue" size="lg" radius="md" onClick={handleRefresh}>
|
||||||
<TbRefresh size={20} />
|
<TbRefresh size={20} />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
</Group>
|
</Group> */}
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
<SimpleGrid cols={{ base: 1, sm: 2, lg: 4 }} spacing="lg">
|
<SimpleGrid cols={{ base: 1, sm: 2, lg: 4 }} spacing="lg">
|
||||||
|
|||||||
Reference in New Issue
Block a user