Skip to content

Commit

Permalink
Merge pull request #41 from fraunhoferfokus/development
Browse files Browse the repository at this point in the history
improved support for progress and notice
  • Loading branch information
JGottschick authored Aug 29, 2024
2 parents c8c0ca0 + 7e5edf6 commit ed06ba3
Show file tree
Hide file tree
Showing 13 changed files with 113 additions and 46 deletions.
2 changes: 1 addition & 1 deletion core/version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.2.29
0.3.0
24 changes: 13 additions & 11 deletions generator/frontend.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,6 @@ func generateEmptyFrontend(_ *openapi3.T, conf GeneratorConfig) {
func generateFrontend(spec *openapi3.T, conf GeneratorConfig) {
generateOpenAPIDoc(conf)

if spec.Paths.Find("/events") == nil || (spec.Paths.Find("/events").Operations()[http.MethodGet] != nil && slices.Contains(spec.Paths.Find("/events").Operations()[http.MethodGet].Tags, "builtin")) {
log.Debug().Msg("Generating default /events endpoint.")

op := openapi3.NewOperation()
op.AddResponse(http.StatusOK, createOAPIResponse("The service support sse"))
updateOAPIOperation(op, "HandleEvents", "support for sse", "200")
spec.AddOperation("/events", http.MethodGet, op)
spec.AddOperation("/events", http.MethodPost, op)
}

// create folders
restPath := filepath.Join(conf.OutputPath, "rest")
frontendPath := filepath.Join(conf.OutputPath, "web")
Expand Down Expand Up @@ -79,7 +69,6 @@ func generateFrontend(spec *openapi3.T, conf GeneratorConfig) {

// files in pages directory
fs.CopyWebFile("web/pages", restPath, "render.go", true)
createFileFromTemplate(filepath.Join(restPath, "progress.go"), "templates/web/pages/progress.go.tmpl", conf)
createFileFromTemplate(filepath.Join(pagesPath, "localize.go"), "templates/web/pages/localize.go.tmpl", conf)
if _, err := os.Stat(filepath.Join(pagesPath, "languages.templ")); errors.Is(err, os.ErrNotExist) {
createFileFromTemplate(filepath.Join(pagesPath, "languages.templ"), "templates/web/pages/languages.templ.tmpl", conf)
Expand Down Expand Up @@ -116,6 +105,19 @@ func generateFrontend(spec *openapi3.T, conf GeneratorConfig) {
// files in public directory
fs.CopyWebFile("web", publicPath, "README-public.md", false)

// support for events
if spec.Paths.Find("/events") != nil && spec.Paths.Find("/events").Operations()[http.MethodGet] != nil && slices.Contains(spec.Paths.Find("/events").Operations()[http.MethodGet].Tags, "builtin") {
log.Debug().Msg("Generating default /events endpoint.")
createFileFromTemplate(filepath.Join(restPath, "progress.go"), "templates/web/pages/progress.go.tmpl", conf)
createFileFromTemplate(filepath.Join(restPath, "notice.go"), "templates/web/pages/notice.go.tmpl", conf)

op := openapi3.NewOperation()
op.AddResponse(http.StatusOK, createOAPIResponse("The service support sse"))
updateOAPIOperation(op, "HandleEvents", "support for sse", "200")
spec.AddOperation("/events", http.MethodGet, op)
spec.AddOperation("/events", http.MethodPost, op)
}

log.Info().Msg("Created Frontend successfully.")
}

Expand Down
12 changes: 8 additions & 4 deletions generator/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func generateHandlerFuncStub(op *openapi3.Operation, method string, path string,
log.Warn().Msg("No summary found for endpoint: " + methodPath)
}

conf.OperationID = xstrings.ToCamelCase(op.OperationID)
conf.OperationID = xstrings.FirstRuneToUpper(xstrings.ToCamelCase(op.OperationID))
if op.OperationID == "" {
log.Error().Msg("No operation ID found for endpoint: " + methodPath)
return conf, errors.New("no operation id, can't create function")
Expand Down Expand Up @@ -121,19 +121,23 @@ func generateHandlerFuncStub(op *openapi3.Operation, method string, path string,
}
}

canBeEdited := true
fileName := xstrings.FirstRuneToLower(xstrings.ToCamelCase(conf.OperationID)) + ".go"
filePath := filepath.Join(config.Path, RestPkg, fileName)
templateFile := "templates/rest/handlerFunc.go.tmpl"
if hasHtmlResponse && slices.Contains(op.Tags, "page") {
templateFile = "templates/rest/pageHandlerFunc.go.tmpl"
}
if conf.OperationID == "GetLive" {
canBeEdited = false
templateFile = "templates/rest/getLive.go.tmpl"
}
if conf.OperationID == "GetInfo" {
canBeEdited = false
templateFile = "templates/rest/getInfo.go.tmpl"
}
if conf.OperationID == "GetRobots" {
canBeEdited = false
templateFile = "templates/rest/getRobots.go.tmpl"
}
if conf.OperationID == "GetIndex" {
Expand All @@ -146,13 +150,13 @@ func generateHandlerFuncStub(op *openapi3.Operation, method string, path string,
templateFile = "templates/rest/getContent.go.tmpl"
}
if conf.OperationID == "HandleEvents" {
canBeEdited = false
templateFile = "templates/rest/handleEvents.go.tmpl"
}

if _, err := os.Stat(filePath); errors.Is(err, os.ErrNotExist) {
log.Debug().Str("operation", conf.OperationID).Str("template", templateFile).Msg("Generate handler")
if _, err := os.Stat(filePath); !canBeEdited || errors.Is(err, os.ErrNotExist) {
createFileFromTemplate(filePath, templateFile, conf)
} else {
log.Debug().Err(err).Str("template", templateFile).Msg("Creating handler failed")
}
// remove unused imports
extCmd.RunCommand("goimports -w "+fileName, filepath.Join(config.Path, RestPkg))
Expand Down
2 changes: 1 addition & 1 deletion generator/info.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func generateInfoFiles(spec *openapi3.T, serverConf ServerConfig) {
createFileFromTemplate(filePath, templateFile, serverConf)
}

if spec.Paths.Find("/infoz") == nil || (spec.Paths.Find("/infoz").Operations()[http.MethodGet] != nil && slices.Contains(spec.Paths.Find("/infoz").Operations()[http.MethodGet].Tags, "builtin")) {
if spec.Paths.Find("/infoz") != nil && (spec.Paths.Find("/infoz").Operations()[http.MethodGet] != nil && slices.Contains(spec.Paths.Find("/infoz").Operations()[http.MethodGet].Tags, "builtin")) {
log.Debug().Msg("Generating default /infoz endpoint.")

op := openapi3.NewOperation()
Expand Down
6 changes: 3 additions & 3 deletions generator/lifecycle.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
)

func generateLifecycleFiles(spec *openapi3.T, conf GeneratorConfig) {
if spec.Paths.Find("/livez") == nil || (spec.Paths.Find("/livez").Operations()[http.MethodGet] != nil && slices.Contains(spec.Paths.Find("/livez").Operations()[http.MethodGet].Tags, "builtin")) {
if spec.Paths.Find("/livez") != nil && (spec.Paths.Find("/livez").Operations()[http.MethodGet] != nil && slices.Contains(spec.Paths.Find("/livez").Operations()[http.MethodGet].Tags, "builtin")) {
log.Debug().Msg("Generating default /livez endpoint.")

op := openapi3.NewOperation()
Expand All @@ -20,7 +20,7 @@ func generateLifecycleFiles(spec *openapi3.T, conf GeneratorConfig) {
spec.AddOperation("/livez", http.MethodGet, op)
}

if spec.Paths.Find("/readyz") == nil || (spec.Paths.Find("/readyz").Operations()[http.MethodGet] != nil && slices.Contains(spec.Paths.Find("/readyz").Operations()[http.MethodGet].Tags, "builtin")) {
if spec.Paths.Find("/readyz") != nil && (spec.Paths.Find("/readyz").Operations()[http.MethodGet] != nil && slices.Contains(spec.Paths.Find("/readyz").Operations()[http.MethodGet].Tags, "builtin")) {
log.Debug().Msg("Generating default /readyz endpoint.")

op := openapi3.NewOperation()
Expand All @@ -30,7 +30,7 @@ func generateLifecycleFiles(spec *openapi3.T, conf GeneratorConfig) {
spec.AddOperation("/readyz", http.MethodGet, op)
}

if spec.Paths.Find("/robots.txt") == nil || (spec.Paths.Find("/robots.txt").Operations()[http.MethodGet] != nil && slices.Contains(spec.Paths.Find("/robots.txt").Operations()[http.MethodGet].Tags, "builtin")) {
if spec.Paths.Find("/robots.txt") != nil && (spec.Paths.Find("/robots.txt").Operations()[http.MethodGet] != nil && slices.Contains(spec.Paths.Find("/robots.txt").Operations()[http.MethodGet].Tags, "builtin")) {
log.Debug().Msg("Generating default /robots.txt endpoint.")

op := openapi3.NewOperation()
Expand Down
2 changes: 1 addition & 1 deletion generator/templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func createFileFromTemplate(filePath string, tmplPath string, config interface{}
panic(tmplErr)
}

log.Info().Msg("CREATE " + filePath)
log.Info().Str("template", templateName).Msg("CREATE " + filePath)
}

func createFileFromTemplates(filePath string, tmplPaths []string, config interface{}) {
Expand Down
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func main() {
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
// Set pretty logging on
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
zerolog.SetGlobalLevel(zerolog.InfoLevel)
zerolog.SetGlobalLevel(zerolog.DebugLevel)
// Export embed template filesystem to generator package
generator.TmplFS = tmplFS

Expand Down
1 change: 1 addition & 0 deletions templates/rest/handleEvents.go.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ var HandleEvents echo.HandlerFunc
func init() {
SseServer = sse.New()
SseServer.CreateStream("progress")
SseServer.CreateStream("notice")
HandleEvents = echo.WrapHandler(SseServer)
}
Binary file added templates/web/images/favicon.ico
Binary file not shown.
3 changes: 3 additions & 0 deletions templates/web/pages/content.templ.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,7 @@ import (

// the main content of the index page
templ Content(lzr *i18n.Localizer) {
// enable the lines, if you want to use events for notices and a progress bar
// <div hx-ext="sse" sse-connect="events?stream=notice" sse-swap="Notice"></div>
// <div hx-ext="sse" sse-connect="events?stream=progress" sse-swap="Progress"></div>
}
1 change: 1 addition & 0 deletions templates/web/pages/index.templ.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ templ Index(lzr *i18n.Localizer) {
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<link rel="icon" type="image/x-icon" href="/images/favicon.ico">
<title>index</title>
<link rel="stylesheet" href="css/pico.min.css"/>
<link rel="stylesheet" href="css/simple.min.css"/>
Expand Down
37 changes: 37 additions & 0 deletions templates/web/pages/notice.go.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Don't edit this file, as it is generated by dredger
package rest

import (
"fmt"

"github.com/r3labs/sse/v2"
)

const bsSuccessNotice = `<div class="alert alert-success alert-dismissible fade show" role="alert">%s<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button></div>`

func NoticeSuccessBootstrap(msg string) {
SseServer.Publish("notice", &sse.Event{
Event: []byte("Notice"),
Data: []byte(fmt.Sprintf(bsSuccessNotice, msg)),
})
}

const bsWarningNotice = `<div class="alert alert-warning alert-dismissible fade show" role="alert">%s<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button></div>`

func NoticeWarningBootstrap(msg string) {
SseServer.Publish("notice", &sse.Event{
Event: []byte("Notice"),
Data: []byte(fmt.Sprintf(bsWarningNotice, msg)),
})

}

const bsErrorNotice = `<div class="alert alert-error alert-dismissible fade show" role="alert">%s<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button></div>`

func NoticeErrorBootstrap(msg string) {
SseServer.Publish("notice", &sse.Event{
Event: []byte("Notice"),
Data: []byte(fmt.Sprintf(bsErrorNotice, msg)),
})

}
67 changes: 43 additions & 24 deletions templates/web/pages/progress.go.tmpl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Edit this file, as it is a specific handler function for your service
// Don't edit this file, as it is generated by dredger
package rest

import (
Expand All @@ -11,17 +11,22 @@ import (
)

// learn medium duration
// ToDo: use a map for more than one progress case
var durationSum int = core.AppConfig.ProgressDuration // initial duration in deciseconds
var durationNb int = 1
var durationSum map[string]int = map[string]int{"": core.AppConfig.ProgressDuration} // initial duration in deciseconds
var durationNb map[string]int = map[string]int{"": 1}

// InitialDuration sets the expected duration time in deciseconds
func InitialDuration(context string, duration int) {
durationSum[context] = duration
durationNb[context] = 1
}

const picoNull = `<progress value="0" max="100" />`
const picoEndless = `<progress />`
const picoProgress = `<progress value="%d" max="100" />`
const picoEmpty = `<div/>`

func ProgressPico(f func()) {
duration := durationSum / durationNb
func ProgressPico(context string, f func()) {
duration := durationSum[context] / durationNb[context]
c1 := make(chan bool)
go func() {
f()
Expand Down Expand Up @@ -58,22 +63,35 @@ func ProgressPico(f func()) {
})

// update medium duration
durationSum += v
durationNb += 1
durationSum[context] += v
durationNb[context] += 1
// avoid overflow of durationNb
if durationNb > 10000 {
durationSum = durationSum / durationNb
durationNb = 1
if durationNb[context] > 10000 {
durationSum[context] = durationSum[context] / durationNb[context]
durationNb[context] = 1
}
}

const bsNull = `<div class="progress" role="progressbar" aria-label="Fortschritt " aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"><div class="progress-bar" style="width: 0%"></div></div>`
const bsEndless = `<div class="progress" role="progressbar" aria-label="Fortschritt" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"><div class="progress-bar" style="width: 100%"></div></div>`
const bsProgress = `<div class="progress" role="progressbar" aria-label="Fortschritt" aria-valuenow="%d" aria-valuemin="0" aria-valuemax="100"><div class="progress-bar" style="width: %d%%"></div></div>`
const styleProgress = ` style="--bs-progress-border-radius:0px;--bs-progress-height:15px;"`
const styleProgressBar = `--bs-progress-bar-bg:#005b7f;`

const bsNull = `<div class="progress" role="progressbar" aria-label="Success striped" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"` + styleProgress + `><div class="progress-bar progress-bar-striped" style="width: 0%;` + styleProgressBar + `"></div></div>`
const bsEndless = `<div class="progress" role="progressbar" aria-label="Success striped" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"` + styleProgress + `><div class="progress-bar progress-bar-striped progress-bar-animated" style="width: 100%%;` + styleProgressBar + `">%s</div></div>`
const bsProgress = `<div class="progress" role="progressbar" aria-label="Success striped" aria-valuenow="%d" aria-valuemin="0" aria-valuemax="100"` + styleProgress + `><div class="progress-bar progress-bar-striped" style="width: %d%%;` + styleProgressBar + `">%s</div></div>`
const bsEmpty = `<div/>`

func ProgressBootstrap(f func()) {
duration := durationSum / durationNb
func ProgressBootstrap(context string, f func(), labels ...string) {
duration := durationSum[context] / durationNb[context]

if len(labels) == 0 {
labels = append(labels, "")
}
if len(labels) == 1 {
labels = append(labels, "")
}
msg := labels[0]
nbOfIntervals := len(labels) - 1

c1 := make(chan bool)
go func() {
f()
Expand All @@ -91,15 +109,16 @@ func ProgressBootstrap(f func()) {
ready = true
case <-time.After(500 * time.Millisecond):
v = v + 5
if v > duration {
if v >= duration {
SseServer.Publish("progress", &sse.Event{
Event: []byte("Progress"),
Data: []byte(bsEndless),
Data: []byte(fmt.Sprintf(bsEndless, msg)),
})
} else {
label := labels[(v/(duration/nbOfIntervals))+1]
SseServer.Publish("progress", &sse.Event{
Event: []byte("Progress"),
Data: []byte(fmt.Sprintf(bsProgress, v, v)),
Data: []byte(fmt.Sprintf(bsProgress, v, v, label)),
})
}
}
Expand All @@ -110,11 +129,11 @@ func ProgressBootstrap(f func()) {
})

// update medium duration
durationSum += v
durationNb += 1
durationSum[context] += v
durationNb[context] += 1
// avoid overflow of durationNb
if durationNb > 10000 {
durationSum = durationSum / durationNb
durationNb = 1
if durationNb[context] > 10000 {
durationSum[context] = durationSum[context] / durationNb[context]
durationNb[context] = 1
}
}

0 comments on commit ed06ba3

Please sign in to comment.