feat: add view workspace button to app error page (#20960)

Closes #19984 

As part of this, I refactored the error template to take in a slice of
actions rather than using individual booleans and strings to control the
behavior.

We decided a link resolves the issue for now so that is what I added,
although we may want to consider a way to start the workspace and follow
the logs dynamically on that page and then show the app when finished
(similar to the tasks page), or at least make the link automatically
start the workspace instead of only taking you to the dashboard where
you have to then start the workspace.
This commit is contained in:
Asher
2025-12-08 14:16:00 -09:00
committed by GitHub
parent 50d42ab0b9
commit 3a0e8af6e3
9 changed files with 233 additions and 107 deletions
+52 -21
View File
@@ -4,6 +4,7 @@ import (
"fmt"
"net/http"
"net/url"
"path"
"cdr.dev/slog"
"github.com/coder/coder/v2/codersdk"
@@ -30,12 +31,16 @@ func WriteWorkspaceApp404(log slog.Logger, accessURL *url.URL, rw http.ResponseW
}
site.RenderStaticErrorPage(rw, r, site.ErrorPageData{
Status: http.StatusNotFound,
Title: "Application Not Found",
Description: "The application or workspace you are trying to access does not exist or you do not have permission to access it.",
RetryEnabled: false,
DashboardURL: accessURL.String(),
Warnings: warnings,
Status: http.StatusNotFound,
Title: "Application Not Found",
Description: "The application or workspace you are trying to access does not exist or you do not have permission to access it.",
Warnings: warnings,
Actions: []site.Action{
{
URL: accessURL.String(),
Text: "Back to site",
},
},
})
}
@@ -60,11 +65,15 @@ func WriteWorkspaceApp500(log slog.Logger, accessURL *url.URL, rw http.ResponseW
)
site.RenderStaticErrorPage(rw, r, site.ErrorPageData{
Status: http.StatusInternalServerError,
Title: "Internal Server Error",
Description: "An internal server error occurred.",
RetryEnabled: false,
DashboardURL: accessURL.String(),
Status: http.StatusInternalServerError,
Title: "Internal Server Error",
Description: "An internal server error occurred.",
Actions: []site.Action{
{
URL: accessURL.String(),
Text: "Back to site",
},
},
})
}
@@ -85,11 +94,18 @@ func WriteWorkspaceAppOffline(log slog.Logger, accessURL *url.URL, rw http.Respo
}
site.RenderStaticErrorPage(rw, r, site.ErrorPageData{
Status: http.StatusBadGateway,
Title: "Application Unavailable",
Description: msg,
RetryEnabled: true,
DashboardURL: accessURL.String(),
Status: http.StatusBadGateway,
Title: "Application Unavailable",
Description: msg,
Actions: []site.Action{
{
Text: "Retry",
},
{
URL: accessURL.String(),
Text: "Back to site",
},
},
})
}
@@ -109,11 +125,26 @@ func WriteWorkspaceOffline(log slog.Logger, accessURL *url.URL, rw http.Response
)
}
actions := []site.Action{
{
URL: accessURL.String(),
Text: "Back to site",
},
}
workspaceURL, err := url.Parse(accessURL.String())
if err == nil {
workspaceURL.Path = path.Join(accessURL.Path, "@"+appReq.UsernameOrID, appReq.WorkspaceNameOrID)
actions = append(actions, site.Action{
URL: workspaceURL.String(),
Text: "View workspace",
})
}
site.RenderStaticErrorPage(rw, r, site.ErrorPageData{
Status: http.StatusBadRequest,
Title: "Workspace Offline",
Description: fmt.Sprintf("Last workspace transition was to the %q state. Start the workspace to access its applications.", codersdk.WorkspaceTransitionStop),
RetryEnabled: false,
DashboardURL: accessURL.String(),
Status: http.StatusBadRequest,
Title: "Workspace Offline",
Description: fmt.Sprintf("Last workspace transition was to the %q state. Start the workspace to access its applications.", codersdk.WorkspaceTransitionStop),
Actions: actions,
})
}