mirror of
				https://github.com/ClusterCockpit/cc-backend
				synced 2025-10-31 16:05:06 +01:00 
			
		
		
		
	Merge pull request #159 from ClusterCockpit/158_fix_searchbar
158 fix searchbar
This commit is contained in:
		| @@ -274,9 +274,10 @@ func main() { | |||||||
| 				rw.Header().Add("Content-Type", "text/html; charset=utf-8") | 				rw.Header().Add("Content-Type", "text/html; charset=utf-8") | ||||||
| 				rw.WriteHeader(http.StatusUnauthorized) | 				rw.WriteHeader(http.StatusUnauthorized) | ||||||
| 				web.RenderTemplate(rw, r, "login.tmpl", &web.Page{ | 				web.RenderTemplate(rw, r, "login.tmpl", &web.Page{ | ||||||
| 					Title: "Login failed - ClusterCockpit", | 					Title:   "Login failed - ClusterCockpit", | ||||||
| 					Error: err.Error(), | 					MsgType: "alert-warning", | ||||||
| 					Build: buildInfo, | 					Message: err.Error(), | ||||||
|  | 					Build:   buildInfo, | ||||||
| 				}) | 				}) | ||||||
| 			})).Methods(http.MethodPost) | 			})).Methods(http.MethodPost) | ||||||
|  |  | ||||||
| @@ -284,9 +285,10 @@ func main() { | |||||||
| 			rw.Header().Add("Content-Type", "text/html; charset=utf-8") | 			rw.Header().Add("Content-Type", "text/html; charset=utf-8") | ||||||
| 			rw.WriteHeader(http.StatusOK) | 			rw.WriteHeader(http.StatusOK) | ||||||
| 			web.RenderTemplate(rw, r, "login.tmpl", &web.Page{ | 			web.RenderTemplate(rw, r, "login.tmpl", &web.Page{ | ||||||
| 				Title: "Bye - ClusterCockpit", | 				Title:   "Bye - ClusterCockpit", | ||||||
| 				Info:  "Logout sucessful", | 				MsgType: "alert-info", | ||||||
| 				Build: buildInfo, | 				Message: "Logout successful", | ||||||
|  | 				Build:   buildInfo, | ||||||
| 			}) | 			}) | ||||||
| 		}))).Methods(http.MethodPost) | 		}))).Methods(http.MethodPost) | ||||||
|  |  | ||||||
| @@ -299,9 +301,10 @@ func main() { | |||||||
| 				func(rw http.ResponseWriter, r *http.Request, err error) { | 				func(rw http.ResponseWriter, r *http.Request, err error) { | ||||||
| 					rw.WriteHeader(http.StatusUnauthorized) | 					rw.WriteHeader(http.StatusUnauthorized) | ||||||
| 					web.RenderTemplate(rw, r, "login.tmpl", &web.Page{ | 					web.RenderTemplate(rw, r, "login.tmpl", &web.Page{ | ||||||
| 						Title: "Authentication failed - ClusterCockpit", | 						Title:   "Authentication failed - ClusterCockpit", | ||||||
| 						Error: err.Error(), | 						MsgType: "alert-danger", | ||||||
| 						Build: buildInfo, | 						Message: err.Error(), | ||||||
|  | 						Build:   buildInfo, | ||||||
| 					}) | 					}) | ||||||
| 				}) | 				}) | ||||||
| 		}) | 		}) | ||||||
| @@ -316,11 +319,11 @@ func main() { | |||||||
|  |  | ||||||
| 	// Send a searchId and then reply with a redirect to a user, or directly send query to job table for jobid and project. | 	// Send a searchId and then reply with a redirect to a user, or directly send query to job table for jobid and project. | ||||||
| 	secured.HandleFunc("/search", func(rw http.ResponseWriter, r *http.Request) { | 	secured.HandleFunc("/search", func(rw http.ResponseWriter, r *http.Request) { | ||||||
| 		routerConfig.HandleSearchBar(rw, r, api) | 		routerConfig.HandleSearchBar(rw, r, buildInfo) | ||||||
| 	}) | 	}) | ||||||
|  |  | ||||||
| 	// Mount all /monitoring/... and /api/... routes. | 	// Mount all /monitoring/... and /api/... routes. | ||||||
| 	routerConfig.SetupRoutes(secured, version, commit, date) | 	routerConfig.SetupRoutes(secured, buildInfo) | ||||||
| 	api.MountRoutes(secured) | 	api.MountRoutes(secured) | ||||||
|  |  | ||||||
| 	if config.Keys.EmbedStaticFiles { | 	if config.Keys.EmbedStaticFiles { | ||||||
|   | |||||||
| @@ -20,11 +20,11 @@ | |||||||
|   * JobName: Job-Table (Allows multiple identical matches, e.g. JobNames from different clusters) |   * JobName: Job-Table (Allows multiple identical matches, e.g. JobNames from different clusters) | ||||||
|   * ProjectId: Job-Table |   * ProjectId: Job-Table | ||||||
|   * Username: Users-Table |   * Username: Users-Table | ||||||
|     * **Please Note**: Only users with jobs will be shown in table! I.e., Users without jobs will be missing in table. |     * **Please Note**: Only users with jobs will be shown in table! I.e., Users without jobs will be missing in table. Also, a `Last 30 Days` is active by default and might filter out expected users. | ||||||
|   * Name: Users-Table |   * Name: Users-Table | ||||||
|     * **Please Note**: Only users with jobs will be shown in table! I.e., Users without jobs will be missing in table. |     * **Please Note**: Only users with jobs will be shown in table! I.e., Users without jobs will be missing in table. Also, a `Last 30 Days` is active by default and might filter out expected users. | ||||||
|   * Best guess search always redirects to Job-Table or `/monitoring/user/$USER` (first username match) |   * Best guess search always redirects to Job-Table or `/monitoring/user/$USER` (first username match) | ||||||
|   * Unprocessable queries will redirect to `/monitoring/jobs/?` |   * Unprocessable queries will display messages detailing the cause (Info, Warning, Error) | ||||||
| * Spaces trimmed (both for searchTag and queryString) | * Spaces trimmed (both for searchTag and queryString) | ||||||
|   * `  job12` == `job12` |   * `  job12` == `job12` | ||||||
|   * `projectID : abcd ` == `projectId:abcd` |   * `projectID : abcd ` == `projectId:abcd` | ||||||
|   | |||||||
| @@ -524,11 +524,10 @@ var ErrForbidden = errors.New("not authorized") | |||||||
| // If query is found to be an integer (= conversion to INT datatype succeeds), skip back to parent call | // If query is found to be an integer (= conversion to INT datatype succeeds), skip back to parent call | ||||||
| // If nothing matches the search, `ErrNotFound` is returned. | // If nothing matches the search, `ErrNotFound` is returned. | ||||||
|  |  | ||||||
| func (r *JobRepository) FindUserOrProjectOrJobname(ctx context.Context, searchterm string) (username string, project string, metasnip string, err error) { | func (r *JobRepository) FindUserOrProjectOrJobname(user *auth.User, searchterm string) (username string, project string, metasnip string, err error) { | ||||||
| 	if _, err := strconv.Atoi(searchterm); err == nil { // Return empty on successful conversion: parent method will redirect for integer jobId | 	if _, err := strconv.Atoi(searchterm); err == nil { // Return empty on successful conversion: parent method will redirect for integer jobId | ||||||
| 		return "", "", "", nil | 		return "", "", "", nil | ||||||
| 	} else { // Has to have letters and logged-in user for other guesses | 	} else { // Has to have letters and logged-in user for other guesses | ||||||
| 		user := auth.GetUser(ctx) |  | ||||||
| 		if user != nil { | 		if user != nil { | ||||||
| 			// Find username in jobs (match) | 			// Find username in jobs (match) | ||||||
| 			uresult, _ := r.FindColumnValue(user, searchterm, "job", "user", "user", false) | 			uresult, _ := r.FindColumnValue(user, searchterm, "job", "user", "user", false) | ||||||
|   | |||||||
| @@ -12,7 +12,6 @@ import ( | |||||||
| 	"strings" | 	"strings" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| 	"github.com/ClusterCockpit/cc-backend/internal/api" |  | ||||||
| 	"github.com/ClusterCockpit/cc-backend/internal/auth" | 	"github.com/ClusterCockpit/cc-backend/internal/auth" | ||||||
| 	"github.com/ClusterCockpit/cc-backend/internal/graph/model" | 	"github.com/ClusterCockpit/cc-backend/internal/graph/model" | ||||||
| 	"github.com/ClusterCockpit/cc-backend/internal/repository" | 	"github.com/ClusterCockpit/cc-backend/internal/repository" | ||||||
| @@ -230,7 +229,7 @@ func buildFilterPresets(query url.Values) map[string]interface{} { | |||||||
| 	return filterPresets | 	return filterPresets | ||||||
| } | } | ||||||
|  |  | ||||||
| func SetupRoutes(router *mux.Router, version string, hash string, buildTime string) { | func SetupRoutes(router *mux.Router, buildInfo web.Build) { | ||||||
| 	userCfgRepo := repository.GetUserCfgRepo() | 	userCfgRepo := repository.GetUserCfgRepo() | ||||||
| 	for _, route := range routes { | 	for _, route := range routes { | ||||||
| 		route := route | 		route := route | ||||||
| @@ -256,7 +255,7 @@ func SetupRoutes(router *mux.Router, version string, hash string, buildTime stri | |||||||
| 				Title:  title, | 				Title:  title, | ||||||
| 				User:   *user, | 				User:   *user, | ||||||
| 				Roles:  availableRoles, | 				Roles:  availableRoles, | ||||||
| 				Build:  web.Build{Version: version, Hash: hash, Buildtime: buildTime}, | 				Build:  buildInfo, | ||||||
| 				Config: conf, | 				Config: conf, | ||||||
| 				Infos:  infos, | 				Infos:  infos, | ||||||
| 			} | 			} | ||||||
| @@ -270,66 +269,64 @@ func SetupRoutes(router *mux.Router, version string, hash string, buildTime stri | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func HandleSearchBar(rw http.ResponseWriter, r *http.Request, api *api.RestApi) { | func HandleSearchBar(rw http.ResponseWriter, r *http.Request, buildInfo web.Build) { | ||||||
|  | 	user := auth.GetUser(r.Context()) | ||||||
|  | 	availableRoles, _ := auth.GetValidRolesMap(user) | ||||||
|  |  | ||||||
| 	if search := r.URL.Query().Get("searchId"); search != "" { | 	if search := r.URL.Query().Get("searchId"); search != "" { | ||||||
| 		user := auth.GetUser(r.Context()) | 		repo := repository.GetJobRepository() | ||||||
| 		splitSearch := strings.Split(search, ":") | 		splitSearch := strings.Split(search, ":") | ||||||
|  |  | ||||||
| 		if len(splitSearch) == 2 { | 		if len(splitSearch) == 2 { | ||||||
| 			switch strings.Trim(splitSearch[0], " ") { | 			switch strings.Trim(splitSearch[0], " ") { | ||||||
| 			case "jobId": | 			case "jobId": | ||||||
| 				http.Redirect(rw, r, "/monitoring/jobs/?jobId="+url.QueryEscape(strings.Trim(splitSearch[1], " ")), http.StatusTemporaryRedirect) // All Users: Redirect to Tablequery | 				http.Redirect(rw, r, "/monitoring/jobs/?jobId="+url.QueryEscape(strings.Trim(splitSearch[1], " ")), http.StatusFound) // All Users: Redirect to Tablequery | ||||||
| 			case "jobName": | 			case "jobName": | ||||||
| 				http.Redirect(rw, r, "/monitoring/jobs/?jobName="+url.QueryEscape(strings.Trim(splitSearch[1], " ")), http.StatusTemporaryRedirect) // All Users: Redirect to Tablequery | 				http.Redirect(rw, r, "/monitoring/jobs/?jobName="+url.QueryEscape(strings.Trim(splitSearch[1], " ")), http.StatusFound) // All Users: Redirect to Tablequery | ||||||
| 			case "projectId": | 			case "projectId": | ||||||
| 				http.Redirect(rw, r, "/monitoring/jobs/?projectMatch=eq&project="+url.QueryEscape(strings.Trim(splitSearch[1], " ")), http.StatusTemporaryRedirect) // All Users: Redirect to Tablequery | 				http.Redirect(rw, r, "/monitoring/jobs/?projectMatch=eq&project="+url.QueryEscape(strings.Trim(splitSearch[1], " ")), http.StatusFound) // All Users: Redirect to Tablequery | ||||||
| 			case "username": | 			case "username": | ||||||
| 				if user.HasAnyRole([]auth.Role{auth.RoleAdmin, auth.RoleSupport, auth.RoleManager}) { | 				if user.HasAnyRole([]auth.Role{auth.RoleAdmin, auth.RoleSupport, auth.RoleManager}) { | ||||||
| 					http.Redirect(rw, r, "/monitoring/users/?user="+url.QueryEscape(strings.Trim(splitSearch[1], " ")), http.StatusTemporaryRedirect) | 					http.Redirect(rw, r, "/monitoring/users/?user="+url.QueryEscape(strings.Trim(splitSearch[1], " ")), http.StatusFound) | ||||||
| 				} else { | 				} else { | ||||||
| 					http.Redirect(rw, r, "/monitoring/jobs/?", http.StatusTemporaryRedirect) // Users: Redirect to Tablequery | 					web.RenderTemplate(rw, r, "message.tmpl", &web.Page{Title: "Error", MsgType: "alert-danger", Message: "Missing Access Rights", User: *user, Roles: availableRoles, Build: buildInfo}) | ||||||
| 				} | 				} | ||||||
| 			case "name": | 			case "name": | ||||||
| 				usernames, _ := api.JobRepository.FindColumnValues(user, strings.Trim(splitSearch[1], " "), "user", "username", "name") | 				usernames, _ := repo.FindColumnValues(user, strings.Trim(splitSearch[1], " "), "user", "username", "name") | ||||||
| 				if len(usernames) != 0 { | 				if len(usernames) != 0 { | ||||||
| 					joinedNames := strings.Join(usernames, "&user=") | 					joinedNames := strings.Join(usernames, "&user=") | ||||||
| 					http.Redirect(rw, r, "/monitoring/users/?user="+joinedNames, http.StatusTemporaryRedirect) | 					http.Redirect(rw, r, "/monitoring/users/?user="+joinedNames, http.StatusFound) | ||||||
| 				} else { | 				} else { | ||||||
| 					if user.HasAnyRole([]auth.Role{auth.RoleAdmin, auth.RoleSupport, auth.RoleManager}) { | 					if user.HasAnyRole([]auth.Role{auth.RoleAdmin, auth.RoleSupport, auth.RoleManager}) { | ||||||
| 						http.Redirect(rw, r, "/monitoring/users/?user=NoUserNameFound", http.StatusTemporaryRedirect) | 						http.Redirect(rw, r, "/monitoring/users/?user=NoUserNameFound", http.StatusPermanentRedirect) | ||||||
| 					} else { | 					} else { | ||||||
| 						http.Redirect(rw, r, "/monitoring/jobs/?", http.StatusTemporaryRedirect) // Users: Redirect to Tablequery | 						web.RenderTemplate(rw, r, "message.tmpl", &web.Page{Title: "Error", MsgType: "alert-danger", Message: "Missing Access Rights", User: *user, Roles: availableRoles, Build: buildInfo}) | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| 			default: | 			default: | ||||||
| 				log.Warnf("Searchbar type parameter '%s' unknown", strings.Trim(splitSearch[0], " ")) | 				web.RenderTemplate(rw, r, "message.tmpl", &web.Page{Title: "Warning", MsgType: "alert-warning", Message: fmt.Sprintf("Unknown search type: %s", strings.Trim(splitSearch[0], " ")), User: *user, Roles: availableRoles, Build: buildInfo}) | ||||||
| 				http.Redirect(rw, r, "/monitoring/jobs/?", http.StatusTemporaryRedirect) // Unknown: Redirect to Tablequery |  | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 		} else if len(splitSearch) == 1 { | 		} else if len(splitSearch) == 1 { | ||||||
| 			username, project, jobname, err := api.JobRepository.FindUserOrProjectOrJobname(r.Context(), strings.Trim(search, " ")) |  | ||||||
|  |  | ||||||
|  | 			username, project, jobname, err := repo.FindUserOrProjectOrJobname(user, strings.Trim(search, " ")) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				log.Errorf("Error while searchbar best guess: %v", err.Error()) | 				web.RenderTemplate(rw, r, "message.tmpl", &web.Page{Title: "Info", MsgType: "alert-info", Message: "Search without result", User: *user, Roles: availableRoles, Build: buildInfo}) | ||||||
| 				http.Redirect(rw, r, "/monitoring/jobs/?", http.StatusTemporaryRedirect) // Unknown: Redirect to Tablequery | 				return | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			if username != "" { | 			if username != "" { | ||||||
| 				http.Redirect(rw, r, "/monitoring/user/"+username, http.StatusTemporaryRedirect) // User: Redirect to user page | 				http.Redirect(rw, r, "/monitoring/user/"+username, http.StatusFound) // User: Redirect to user page | ||||||
| 			} else if project != "" { | 			} else if project != "" { | ||||||
| 				http.Redirect(rw, r, "/monitoring/jobs/?projectMatch=eq&project="+url.QueryEscape(strings.Trim(search, " ")), http.StatusTemporaryRedirect) // projectId (equal) | 				http.Redirect(rw, r, "/monitoring/jobs/?projectMatch=eq&project="+url.QueryEscape(strings.Trim(search, " ")), http.StatusFound) // projectId (equal) | ||||||
| 			} else if jobname != "" { | 			} else if jobname != "" { | ||||||
| 				http.Redirect(rw, r, "/monitoring/jobs/?jobName="+url.QueryEscape(strings.Trim(search, " ")), http.StatusTemporaryRedirect) // JobName (contains) | 				http.Redirect(rw, r, "/monitoring/jobs/?jobName="+url.QueryEscape(strings.Trim(search, " ")), http.StatusFound) // JobName (contains) | ||||||
| 			} else { | 			} else { | ||||||
| 				http.Redirect(rw, r, "/monitoring/jobs/?jobId="+url.QueryEscape(strings.Trim(search, " ")), http.StatusTemporaryRedirect) // No Result: Probably jobId | 				http.Redirect(rw, r, "/monitoring/jobs/?jobId="+url.QueryEscape(strings.Trim(search, " ")), http.StatusFound) // No Result: Probably jobId | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 		} else { | 		} else { | ||||||
| 			log.Warnf("Searchbar query parameters malformed: %v", search) | 			web.RenderTemplate(rw, r, "message.tmpl", &web.Page{Title: "Error", MsgType: "alert-danger", Message: "Searchbar query parameters malformed", User: *user, Roles: availableRoles, Build: buildInfo}) | ||||||
| 			http.Redirect(rw, r, "/monitoring/jobs/?", http.StatusTemporaryRedirect) // Unknown: Redirect to Tablequery |  | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 	} else { | 	} else { | ||||||
| 		http.Redirect(rw, r, "/monitoring/jobs/?", http.StatusTemporaryRedirect) | 		web.RenderTemplate(rw, r, "message.tmpl", &web.Page{Title: "Warning", MsgType: "alert-warning", Message: "Empty search", User: *user, Roles: availableRoles, Build: buildInfo}) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -270,6 +270,7 @@ | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     export function findThresholds(metricConfig, scope, subCluster) { |     export function findThresholds(metricConfig, scope, subCluster) { | ||||||
|  |         // console.log('NAME ' + metricConfig.name + ' / SCOPE ' + scope + ' / SUBCLUSTER ' + subCluster.name) | ||||||
|         if (!metricConfig || !scope || !subCluster) { |         if (!metricConfig || !scope || !subCluster) { | ||||||
|             console.warn('Argument missing for findThresholds!') |             console.warn('Argument missing for findThresholds!') | ||||||
|             return null |             return null | ||||||
| @@ -280,8 +281,10 @@ | |||||||
|                 // console.log('subClusterConfigs array empty, use metricConfig defaults') |                 // console.log('subClusterConfigs array empty, use metricConfig defaults') | ||||||
|                 return { normal: metricConfig.normal, caution: metricConfig.caution, alert: metricConfig.alert } |                 return { normal: metricConfig.normal, caution: metricConfig.caution, alert: metricConfig.alert } | ||||||
|             } else if (metricConfig.subClusters && metricConfig.subClusters.length > 0) { |             } else if (metricConfig.subClusters && metricConfig.subClusters.length > 0) { | ||||||
|                 // console.log('subClusterConfigs found, find and use subCluster Settings') |                 // console.log('subClusterConfigs found, use subCluster Settings if matching jobs subcluster:') | ||||||
|                 return metricConfig.subClusters.find(sc => sc.name == subCluster.name) |                 let forSubCluster = metricConfig.subClusters.find(sc => sc.name == subCluster.name) | ||||||
|  |                 if (forSubCluster && forSubCluster.normal && forSubCluster.caution && forSubCluster.alert) return forSubCluster | ||||||
|  |                 else return { normal: metricConfig.normal, caution: metricConfig.caution, alert: metricConfig.alert } | ||||||
|             } else { |             } else { | ||||||
|                 console.warn('metricConfig.subClusters not found!') |                 console.warn('metricConfig.subClusters not found!') | ||||||
|                 return null |                 return null | ||||||
|   | |||||||
| @@ -17,15 +17,9 @@ | |||||||
|         <div class="container"> |         <div class="container"> | ||||||
|             <div class="row"> |             <div class="row"> | ||||||
|                 <div class="col-4 mx-auto"> |                 <div class="col-4 mx-auto"> | ||||||
|                     {{if .Error}} |                     {{if .MsgType}} | ||||||
|                         <div class="alert alert-warning" role="alert"> |                         <div class="alert {{.MsgType}}" role="alert"> | ||||||
|                             {{.Error}} |                             {{.Message}} | ||||||
|                         </div> |  | ||||||
|                     {{end}} |  | ||||||
|  |  | ||||||
|                     {{if .Info}} |  | ||||||
|                         <div class="alert alert-success" role="alert"> |  | ||||||
|                             {{.Info}} |  | ||||||
|                         </div> |                         </div> | ||||||
|                     {{end}} |                     {{end}} | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										17
									
								
								web/templates/message.tmpl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								web/templates/message.tmpl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | |||||||
|  |  | ||||||
|  | {{define "content"}} | ||||||
|  |     <div class="row justify-content-center"> | ||||||
|  |         <div class="col-4"> | ||||||
|  |             <div class="alert {{.MsgType}} p-3 text-center fs-3" role="alert"> | ||||||
|  |                 {{if eq .MsgType "alert-info"}} | ||||||
|  |                 <i class="bi-info-circle-fill me-3"></i> | ||||||
|  |                 {{else if eq .MsgType "alert-warning"}} | ||||||
|  |                 <i class="bi-question-circle-fill me-3"></i> | ||||||
|  |                 {{else if eq .MsgType "alert-danger"}} | ||||||
|  |                 <i class="bi-exclamation-circle-fill me-3"></i> | ||||||
|  |                 {{end}} | ||||||
|  |                 {{.Message}} | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |     </div> | ||||||
|  | {{end}} | ||||||
| @@ -82,8 +82,8 @@ type Build struct { | |||||||
|  |  | ||||||
| type Page struct { | type Page struct { | ||||||
| 	Title         string                 // Page title | 	Title         string                 // Page title | ||||||
| 	Error         string                 // For generic use (e.g. the exact error message on /login) | 	MsgType       string                 // For generic use in message boxes | ||||||
| 	Info          string                 // For generic use (e.g. "Logout successfull" on /login) | 	Message       string                 // For generic use in message boxes | ||||||
| 	User          auth.User              // Information about the currently logged in user (Full User Info) | 	User          auth.User              // Information about the currently logged in user (Full User Info) | ||||||
| 	Roles         map[string]auth.Role   // Available roles for frontend render checks | 	Roles         map[string]auth.Role   // Available roles for frontend render checks | ||||||
| 	Build         Build                  // Latest information about the application | 	Build         Build                  // Latest information about the application | ||||||
| @@ -96,8 +96,7 @@ type Page struct { | |||||||
| func RenderTemplate(rw http.ResponseWriter, r *http.Request, file string, page *Page) { | func RenderTemplate(rw http.ResponseWriter, r *http.Request, file string, page *Page) { | ||||||
| 	t, ok := templates[file] | 	t, ok := templates[file] | ||||||
| 	if !ok { | 	if !ok { | ||||||
| 		log.Fatalf("WEB/WEB > template '%s' not found", file) | 		log.Errorf("WEB/WEB > template '%s' not found", file) | ||||||
| 		panic("template not found") |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if page.Clusters == nil { | 	if page.Clusters == nil { | ||||||
| @@ -106,7 +105,7 @@ func RenderTemplate(rw http.ResponseWriter, r *http.Request, file string, page * | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	log.Infof("Page config : %v\n", page.Config) | 	log.Debugf("Page config : %v\n", page.Config) | ||||||
| 	if err := t.Execute(rw, page); err != nil { | 	if err := t.Execute(rw, page); err != nil { | ||||||
| 		log.Errorf("Template error: %s", err.Error()) | 		log.Errorf("Template error: %s", err.Error()) | ||||||
| 	} | 	} | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user