Implemented adding/renaming of areas and sections

This commit is contained in:
Magnus Åhall 2024-05-01 21:02:45 +02:00
parent d935eb282b
commit 62405c3138
13 changed files with 175 additions and 13 deletions

20
area.go
View File

@ -10,13 +10,13 @@ import (
)
type Area struct {
ID int
ID int
Name string
Sections []Section
}
func AreaRetrieve() (areas []Area, err error) {// {{{
func AreaRetrieve() (areas []Area, err error) { // {{{
areas = []Area{}
row := service.Db.Conn.QueryRow(`
SELECT
@ -32,7 +32,7 @@ func AreaRetrieve() (areas []Area, err error) {// {{{
)
) AS sections
FROM area a
INNER JOIN section s ON s.area_id = a.id
LEFT JOIN section s ON s.area_id = a.id
GROUP BY
a.id, a.name
) jsonsections`,
@ -51,12 +51,20 @@ func AreaRetrieve() (areas []Area, err error) {// {{{
return
}
return
} // }}}
func AreaCreate(name string) (err error) {// {{{
_, err = service.Db.Conn.Exec(`INSERT INTO area(name) VALUES($1)`, name)
return
}// }}}
func AreaRename(id int, name string) (err error) {// {{{
_, err = service.Db.Conn.Exec(`UPDATE area SET name=$2 WHERE id=$1`, id, name)
return
}// }}}
func (a Area) SortedSections() []Section {// {{{
sort.SliceStable(a.Sections, func (i, j int) bool {
func (a Area) SortedSections() []Section { // {{{
sort.SliceStable(a.Sections, func(i, j int) bool {
return a.Sections[i].Name < a.Sections[j].Name
})
return a.Sections
}// }}}
} // }}}

78
main.go
View File

@ -97,6 +97,13 @@ func main() { // {{{
}
service.Register("/", false, false, staticHandler)
service.Register("/area/new/{name}", false, false, areaNew)
service.Register("/area/rename/{id}/{name}", false, false, areaRename)
service.Register("/section/new/{areaID}/{name}", false, false, sectionNew)
service.Register("/section/rename/{id}/{name}", false, false, sectionRename)
service.Register("/problems", false, false, pageProblems)
service.Register("/problem/acknowledge/{id}", false, false, pageProblemAcknowledge)
service.Register("/problem/unacknowledge/{id}", false, false, pageProblemUnacknowledge)
@ -276,6 +283,77 @@ func pageIndex(w http.ResponseWriter, _ *http.Request, _ *session.T) { // {{{
page.Render(w)
} // }}}
func areaNew(w http.ResponseWriter, r *http.Request, _ *session.T) { // {{{
name := r.PathValue("name")
err := AreaCreate(name)
if err != nil {
httpError(w, we.Wrap(err).Log())
return
}
w.Header().Add("Location", "/configuration")
w.WriteHeader(302)
return
} // }}}
func areaRename(w http.ResponseWriter, r *http.Request, _ *session.T) { // {{{
idStr := r.PathValue("id")
id, err := strconv.Atoi(idStr)
if err != nil {
httpError(w, we.Wrap(err).Log())
return
}
name := r.PathValue("name")
err = AreaRename(id, name)
if err != nil {
httpError(w, we.Wrap(err).Log())
return
}
w.Header().Add("Location", "/configuration")
w.WriteHeader(302)
return
} // }}}
func sectionNew(w http.ResponseWriter, r *http.Request, _ *session.T) { // {{{
idStr := r.PathValue("areaID")
areaID, err := strconv.Atoi(idStr)
if err != nil {
httpError(w, we.Wrap(err).Log())
return
}
name := r.PathValue("name")
err = SectionCreate(areaID, name)
if err != nil {
httpError(w, we.Wrap(err).Log())
return
}
w.Header().Add("Location", "/configuration")
w.WriteHeader(302)
return
} // }}}
func sectionRename(w http.ResponseWriter, r *http.Request, _ *session.T) { // {{{
idStr := r.PathValue("id")
id, err := strconv.Atoi(idStr)
if err != nil {
httpError(w, we.Wrap(err).Log())
return
}
name := r.PathValue("name")
err = SectionRename(id, name)
if err != nil {
httpError(w, we.Wrap(err).Log())
return
}
w.Header().Add("Location", "/configuration")
w.WriteHeader(302)
return
} // }}}
func pageProblems(w http.ResponseWriter, _ *http.Request, _ *session.T) { // {{{
page := Page{
LAYOUT: "main",

View File

@ -21,3 +21,12 @@ func (s *Section) SortedTriggers() []Trigger {
return s.Triggers
}
func SectionCreate(areaID int, name string) (err error) {// {{{
_, err = service.Db.Conn.Exec(`INSERT INTO section(area_id, name) VALUES($1, $2)`, areaID, name)
return
}// }}}
func SectionRename(id int, name string) (err error) {// {{{
_, err = service.Db.Conn.Exec(`UPDATE section SET name=$2 WHERE id=$1`, id, name)
return
}// }}}

View File

@ -32,9 +32,11 @@ h2 {
h1 {
font-size: 1.5em;
color: #fb4934;
font-weight: 500;
}
h2 {
font-size: 1.25em;
font-weight: 500;
}
a {
color: #fabd2f;

View File

@ -32,9 +32,11 @@ h2 {
h1 {
font-size: 1.5em;
color: #fb4934;
font-weight: 500;
}
h2 {
font-size: 1.25em;
font-weight: 500;
}
a {
color: #fabd2f;

View File

@ -32,9 +32,11 @@ h2 {
h1 {
font-size: 1.5em;
color: #fb4934;
font-weight: 500;
}
h2 {
font-size: 1.25em;
font-weight: 500;
}
a {
color: #fabd2f;
@ -98,7 +100,7 @@ label {
#problems-list,
#acknowledged-list {
display: grid;
grid-template-columns: repeat(5, min-content);
grid-template-columns: repeat(6, min-content);
grid-gap: 4px 16px;
margin-bottom: 32px;
}

View File

@ -32,9 +32,11 @@ h2 {
h1 {
font-size: 1.5em;
color: #fb4934;
font-weight: 500;
}
h2 {
font-size: 1.25em;
font-weight: 500;
}
a {
color: #fabd2f;

View File

@ -32,9 +32,11 @@ h2 {
h1 {
font-size: 1.5em;
color: #fb4934;
font-weight: 500;
}
h2 {
font-size: 1.25em;
font-weight: 500;
}
a {
color: #fabd2f;

View File

@ -37,7 +37,7 @@
margin-bottom: 32px;
div {
font-weight: 500;
font-weight: @bold;
font-size: 1.5em;
color: @color1;
}

View File

@ -2,7 +2,7 @@
#problems-list, #acknowledged-list {
display: grid;
grid-template-columns: repeat(5, min-content);
grid-template-columns: repeat(6, min-content);
grid-gap: 4px 16px;
margin-bottom: 32px;

View File

@ -59,10 +59,12 @@ h2 {
h1 {
font-size: 1.5em;
color: @color1;
font-weight: @bold;
}
h2 {
font-size: 1.25em;
font-weight: @bold;
}
a {

View File

@ -1,16 +1,71 @@
{{ define "page" }}
<script type="text/javascript">
function newArea() {
let name = prompt("Area name")
if (name === null)
return
if (name.trim() == '') {
alert("Name can't be empty")
return
}
location.href = `/area/new/${name.trim()}`
}
function renameArea(id, name) {
const newName = prompt('Rename area', name)
if (newName === null)
return
if (newName.trim() == '') {
alert("Name can't be empty")
return
}
location.href = `/area/rename/${id}/${newName.trim()}`
}
function newSection(areaID) {
let name = prompt("Section name")
if (name === null)
return
if (name.trim() == '') {
alert("Name can't be empty")
return
}
location.href = `/section/new/${areaID}/${name.trim()}`
}
function renameSection(id, name) {
const newName = prompt('Rename section', name)
if (newName === null)
return
if (newName.trim() == '') {
alert("Name can't be empty")
return
}
location.href = `/section/rename/${id}/${newName.trim()}`
}
</script>
{{ block "page_label" . }}{{end}}
<h1>Areas</h1>
<a href="#" onclick="newArea()">Create</a>
<div id="areas">
{{ range .Data.Areas }}
<div class="area">
<div class="name">{{ .Name }}</div>
<div class="name" onclick="renameArea({{ .ID }}, {{ .Name }})">{{ .Name }}</div>
<div style="margin: 8px 16px">
<a href="#" onclick="newSection({{ .ID }})">Create</a>
</div>
{{ range .SortedSections }}
<div class="section">
<div class="name">{{ .Name }}</div>
<div class="name" onclick="renameSection({{ .ID }}, {{ .Name }})">{{ .Name }}</div>
</div>
{{ end }}
</div>

View File

@ -9,6 +9,8 @@
{{ block "page_label" . }}{{end}}
<input type="checkbox" id="show-acked" onclick="_ui.toggleAcknowledged(event)"> <label for="show-acked">Show acknowledged</label>
<div id="problems-list">
<div style="grid-column: 1/-1; margin-top: 32px;"><h2>Current</h2></div>
@ -29,8 +31,6 @@
{{ end }}
</div>
<input type="checkbox" id="show-acked" onclick="_ui.toggleAcknowledged(event)"> <label for="show-acked">Show acknowledged</label>
<div id="acknowledged-list" class="hidden">
<div style="grid-column: 1/-1; margin-top: 32px;"><h2>Acknowledged</h2></div>
<div class="header">Trigger</div>