Pick first dashboard if there's any, dashboards are now deletable

This commit is contained in:
Jan Zípek 2022-09-03 21:59:37 +02:00
parent 4173629693
commit c7d430805a
Signed by: kamen
GPG Key ID: A17882625B33AC31
8 changed files with 94 additions and 8 deletions

View File

@ -41,3 +41,12 @@ export const updateDashboard = ({
contents: JSON.stringify(body.contents), contents: JSON.stringify(body.contents),
}), }),
}) })
export const deleteDashboard = (id: number) =>
request<DashboardInfo>(
`/api/dashboards/${id}`,
{
method: 'DELETE',
},
'void'
)

View File

@ -66,6 +66,8 @@ export const DashboardHeader = () => {
<CancelIcon /> <CancelIcon />
</div> </div>
<DashboardSwitch />
<DashboardFilters /> <DashboardFilters />
</div> </div>
</div> </div>

View File

@ -1,9 +1,12 @@
import { import {
createDashboard, createDashboard,
DashboardInfo, DashboardInfo,
deleteDashboard,
updateDashboard, updateDashboard,
} from '@/api/dashboards' } from '@/api/dashboards'
import { Modal } from '@/components/Modal' import { Modal } from '@/components/Modal'
import { useConfirmModal } from '@/contexts/ConfirmModalsContext'
import { useDashboardContext } from '@/pages/dashboard/contexts/DashboardContext'
import { createDashboardContent } from '@/utils/createDashboardContent' import { createDashboardContent } from '@/utils/createDashboardContent'
import { useForm } from '@/utils/hooks/useForm' import { useForm } from '@/utils/hooks/useForm'
import { useMutation, useQueryClient } from 'react-query' import { useMutation, useQueryClient } from 'react-query'
@ -13,17 +16,40 @@ type Props = {
onClose: () => void onClose: () => void
} }
export const DashboardModal = ({ dashboard, onClose }: Props) => { export const DashboardSettings = ({ dashboard, onClose }: Props) => {
const { setDashboardId, dashboardId } = useDashboardContext()
const queryClient = useQueryClient() const queryClient = useQueryClient()
const createMutation = useMutation(createDashboard) const createMutation = useMutation(createDashboard)
const updateMutation = useMutation(updateDashboard) const updateMutation = useMutation(updateDashboard)
const deleteMutation = useMutation(deleteDashboard, {
onSuccess: () => {
queryClient.invalidateQueries(['/dashboards'])
onClose()
if (dashboardId === dashboard?.id) {
setDashboardId(-1)
}
},
})
const isLoading =
deleteMutation.isLoading ||
updateMutation.isLoading ||
createMutation.isLoading
const deleteConfirm = useConfirmModal({
content: `Are you sure you want to delete ${dashboard?.name} dashboard?`,
onConfirm: () => !isLoading && deleteMutation.mutate(dashboard?.id ?? 1),
})
const { handleSubmit, register } = useForm({ const { handleSubmit, register } = useForm({
defaultValue: () => ({ defaultValue: () => ({
name: dashboard?.name ?? '', name: dashboard?.name ?? '',
}), }),
onSubmit: async (v) => { onSubmit: async (v) => {
if (updateMutation.isLoading || createMutation.isLoading) { if (isLoading) {
return return
} }
@ -54,6 +80,10 @@ export const DashboardModal = ({ dashboard, onClose }: Props) => {
</div> </div>
<div className="actions"> <div className="actions">
<button className="remove" type="button" onClick={deleteConfirm.show}>
Remove
</button>
<button className="cancel" onClick={onClose} type="button"> <button className="cancel" onClick={onClose} type="button">
Cancel Cancel
</button> </button>

View File

@ -3,7 +3,7 @@ import { EditIcon, PlusIcon } from '@/icons'
import { useDashboardContext } from '@/pages/dashboard/contexts/DashboardContext' import { useDashboardContext } from '@/pages/dashboard/contexts/DashboardContext'
import { useState } from 'preact/hooks' import { useState } from 'preact/hooks'
import { useQuery } from 'react-query' import { useQuery } from 'react-query'
import { DashboardModal } from './DashboardModal' import { DashboardSettings } from './DashboardSettings'
export const DashboardSwitch = () => { export const DashboardSwitch = () => {
const { dashboardId, setDashboardId, dashboard } = useDashboardContext() const { dashboardId, setDashboardId, dashboard } = useDashboardContext()
@ -26,16 +26,16 @@ export const DashboardSwitch = () => {
</select> </select>
<button onClick={() => setEdited(dashboard)}> <button onClick={() => setEdited(dashboard)}>
<EditIcon /> Edit <EditIcon />
</button> </button>
<button onClick={() => setShowNew(true)}> <button onClick={() => setShowNew(true)}>
<PlusIcon /> Add <PlusIcon />
</button> </button>
{showNew && <DashboardModal onClose={() => setShowNew(false)} />} {showNew && <DashboardSettings onClose={() => setShowNew(false)} />}
{edited && ( {edited && (
<DashboardModal <DashboardSettings
dashboard={edited} dashboard={edited}
onClose={() => setEdited(undefined)} onClose={() => setEdited(undefined)}
/> />

View File

@ -1,4 +1,9 @@
import { DashboardInfo, getDashboard, updateDashboard } from '@/api/dashboards' import {
DashboardInfo,
getDashboard,
getDashboards,
updateDashboard,
} from '@/api/dashboards'
import { parseDashboard } from '@/utils/dashboard/parseDashboard' import { parseDashboard } from '@/utils/dashboard/parseDashboard'
import { useViewportSize } from '@/utils/hooks/useViewportSize' import { useViewportSize } from '@/utils/hooks/useViewportSize'
import { intervalToRange } from '@/utils/intervalToRange' import { intervalToRange } from '@/utils/intervalToRange'
@ -40,6 +45,8 @@ export const DashboardContextProvider = ({
const [dashboardId, setDashboardId] = useState(-1) const [dashboardId, setDashboardId] = useState(-1)
const isDashboardSelected = !isNaN(dashboardId) && dashboardId >= 0 const isDashboardSelected = !isNaN(dashboardId) && dashboardId >= 0
const dashboards = useQuery(['/dashboards'], getDashboards)
const dashboard = useQuery( const dashboard = useQuery(
['/dashboards', dashboardId], ['/dashboards', dashboardId],
() => getDashboard(dashboardId), () => getDashboard(dashboardId),
@ -77,6 +84,12 @@ export const DashboardContextProvider = ({
setBoxes(dashboardContent?.boxes ?? []) setBoxes(dashboardContent?.boxes ?? [])
}, [dashboardContent]) }, [dashboardContent])
useEffect(() => {
if (dashboards.data && !dashboards.isFetching && !isDashboardSelected) {
setDashboardId(dashboards.data[0]?.id)
}
}, [dashboards.data, isDashboardSelected])
const [filter, setFilter] = useState<FilterValue>(() => { const [filter, setFilter] = useState<FilterValue>(() => {
const range = intervalToRange('week', new Date(), new Date()) const range = intervalToRange('week', new Date(), new Date())

View File

@ -51,6 +51,7 @@ func main() {
loginProtected.POST("/api/dashboards", routes.PostDashboard(server)) loginProtected.POST("/api/dashboards", routes.PostDashboard(server))
loginProtected.GET("/api/dashboards/:id", routes.GetDashboardById(server)) loginProtected.GET("/api/dashboards/:id", routes.GetDashboardById(server))
loginProtected.PUT("/api/dashboards/:id", routes.PutDashboard(server)) loginProtected.PUT("/api/dashboards/:id", routes.PutDashboard(server))
loginProtected.DELETE("/api/dashboards/:id", routes.DeleteDashboard(server))
loginProtected.POST("/api/logout", routes.Logout(server)) loginProtected.POST("/api/logout", routes.Logout(server))
// Routes accessible using auth key // Routes accessible using auth key

View File

@ -2,6 +2,7 @@ package routes
import ( import (
"basic-sensor-receiver/app" "basic-sensor-receiver/app"
"database/sql"
"net/http" "net/http"
"strconv" "strconv"
@ -42,6 +43,11 @@ func GetDashboardById(s *app.Server) gin.HandlerFunc {
item, err := s.Services.Dashboards.GetById(id) item, err := s.Services.Dashboards.GetById(id)
if err == sql.ErrNoRows {
c.Status(404)
return
}
if err != nil { if err != nil {
c.AbortWithError(500, err) c.AbortWithError(500, err)
return return
@ -97,6 +103,25 @@ func PutDashboard(s *app.Server) gin.HandlerFunc {
} }
} }
func DeleteDashboard(s *app.Server) gin.HandlerFunc {
return func(c *gin.Context) {
id, err := getIntParam(c, "id")
if err != nil {
c.AbortWithError(400, err)
return
}
err = s.Services.Dashboards.Delete(id)
if err != nil {
c.AbortWithError(500, err)
return
}
c.Status(http.StatusOK)
}
}
func getIntParam(c *gin.Context, key string) (int64, error) { func getIntParam(c *gin.Context, key string) (int64, error) {
value := c.Param(key) value := c.Param(key)

View File

@ -72,6 +72,12 @@ func (s *DashboardsService) Update(id int64, name string, contents string) (*Das
return &item, nil return &item, nil
} }
func (s *DashboardsService) Delete(id int64) error {
_, err := s.ctx.DB.Exec("DELETE FROM dashboards WHERe id = ?", id)
return err
}
func (s *DashboardsService) GetById(id int64) (*DashboardItem, error) { func (s *DashboardsService) GetById(id int64) (*DashboardItem, error) {
item := DashboardItem{} item := DashboardItem{}