diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
index 4e554ea..4b3f1c0 100644
--- a/.github/workflows/build.yaml
+++ b/.github/workflows/build.yaml
@@ -13,9 +13,33 @@ env:
IMAGE_NAME: ${{ github.repository }}
jobs:
+ test:
+ name: Test
+ runs-on: ubuntu-latest
+
+ services:
+ test_db:
+ image: postgres:16
+ env:
+ POSTGRES_USER: sgs
+ POSTGRES_PASSWORD: sgs-pass
+ ports:
+ - 5433:5432
+ volumes:
+ - test_data:/var/lib/postgresql/data
+
+ steps:
+ - uses: actions/checkout@v4
+ - uses: DeterminateSystems/nix-installer-action@v11
+ - uses: DeterminateSystems/magic-nix-cache-action@v6
+
+ - name: Run tests
+ run: nix develop -c make check
+
build:
name: Build
runs-on: ubuntu-latest
+ needs: test
steps:
- uses: actions/checkout@v4
- uses: DeterminateSystems/nix-installer-action@v11
diff --git a/model/mock/mock.go b/model/mock/mock.go
index 99e6cf1..ca613a3 100644
--- a/model/mock/mock.go
+++ b/model/mock/mock.go
@@ -56,7 +56,15 @@ func (svc *mockWorkspaces) CreateWorkspace(ctx context.Context, ws *model.Worksp
newWS.ID = svc.nextID
svc.nextID++
newWS.Enabled = false
- newWS.Request = nil
+ newWS.Request = &model.WorkspaceUpdate{
+ WorkspaceID: newWS.ID,
+ ByUser: newWS.Users[0],
+ Enabled: true,
+ Nodegroup: newWS.Nodegroup,
+ Userdata: newWS.Userdata,
+ Quotas: maps.Clone(newWS.Quotas),
+ Users: slices.Clone(newWS.Users),
+ }
slices.Sort(newWS.Users)
svc.data[newWS.ID] = newWS
diff --git a/model/postgres/postgres.go b/model/postgres/postgres.go
index 1f3cb8b..90c210a 100644
--- a/model/postgres/postgres.go
+++ b/model/postgres/postgres.go
@@ -131,6 +131,15 @@ func (svc *workspacesRepository) CreateWorkspace(ctx context.Context, ws *model.
}
}
+ upd := ws.InitialRequest()
+ upd.WorkspaceID = id
+ tx.Exec(ctx, `
+ INSERT INTO workspaces_updaterequests (workspace_id, by_user, data)
+ VALUES ($1, $2, $3)
+ ON CONFLICT (workspace_id) DO UPDATE
+ SET by_user = EXCLUDED.by_user, data = EXCLUDED.data`,
+ upd.WorkspaceID, upd.ByUser, upd)
+
// we could reconstruct the ws here, but it's easier to just query it
newWs, err = queryWorkspace(ctx, tx, id)
return err
diff --git a/model/test/workspace.go b/model/test/workspace.go
index 0005537..98ea883 100644
--- a/model/test/workspace.go
+++ b/model/test/workspace.go
@@ -22,6 +22,7 @@ func TestWorkspace(t *testing.T, wsf func() model.WorkspaceService) {
Users: []string{"user1"},
}
want.ID = testWorkspaceCreate(t, wsSvc, &want, nil)
+ want.Request = want.InitialRequest()
testWorkspaceListAll(t, wsSvc, []*model.Workspace{&want})
testWorkspaceListUser(t, wsSvc, "user1", []*model.Workspace{&want})
@@ -209,18 +210,21 @@ func TestWorkspace(t *testing.T, wsf func() model.WorkspaceService) {
Users: []string{"user1"},
}
ws1.ID = testWorkspaceCreate(t, wsSvc, &ws1, nil)
+ ws1.Request = ws1.InitialRequest()
ws2 := model.Workspace{
Nodegroup: model.NodegroupGraduate,
Users: []string{"user2"},
}
ws2.ID = testWorkspaceCreate(t, wsSvc, &ws2, nil)
+ ws2.Request = ws2.InitialRequest()
wsAll := model.Workspace{
Nodegroup: model.NodegroupUndergraduate,
Users: []string{"user1", "user2"},
}
wsAll.ID = testWorkspaceCreate(t, wsSvc, &wsAll, nil)
+ wsAll.Request = wsAll.InitialRequest()
testWorkspaceListAll(t, wsSvc, []*model.Workspace{&ws1, &ws2, &wsAll})
testWorkspaceListUser(t, wsSvc, "user1", []*model.Workspace{&ws1, &wsAll})
@@ -291,7 +295,7 @@ func testWorkspaceCreate(t *testing.T, wsSvc model.WorkspaceService, ws *model.W
want := *ws
want.ID = got.ID
want.Enabled = false
- want.Request = nil
+ want.Request = want.InitialRequest()
if diff := cmp.Diff(got, &want, cmpopts.EquateEmpty()); diff != "" {
t.Fatalf("CreateWorkspace(%#v) = mismatch\n%s", ws, diff)
}
diff --git a/model/workspace.go b/model/workspace.go
index c531a95..c37d3d9 100644
--- a/model/workspace.go
+++ b/model/workspace.go
@@ -43,6 +43,20 @@ func (ws Workspace) Valid() bool {
return true
}
+// InitialRequest returns the initial request for a new workspace. It has the
+// same attributes as the workspace itself, but enabled.
+func (ws *Workspace) InitialRequest() *WorkspaceUpdate {
+ return &WorkspaceUpdate{
+ WorkspaceID: ws.ID,
+ ByUser: ws.Users[0],
+ Enabled: true,
+ Nodegroup: ws.Nodegroup,
+ Userdata: ws.Userdata,
+ Quotas: ws.Quotas,
+ Users: ws.Users,
+ }
+}
+
type WorkspaceUpdate struct {
WorkspaceID ID
ByUser string
diff --git a/view/workspace.templ b/view/workspace.templ
index eec3494..cda2d30 100644
--- a/view/workspace.templ
+++ b/view/workspace.templ
@@ -67,18 +67,25 @@ templ PageWorkspaceDetails(ws *model.Workspace, kubeconfig string) {
// Render the status badge
templ wsStatusButton(ws *model.Workspace) {
- if ws.Enabled && ws.Request == nil {
- // enabled (and created) and no pending requests: all good
- Enabled
- } else if !ws.Created {
- // hasn't ever been enabled: pending approval
- Pending approval
- } else if !ws.Enabled {
- // created && !enabled: disabled by admin
- Disabled
- } else if ws.Enabled && ws.Request != nil {
- // otherwise, enabled but has pending changes
- Pending changes
+ switch true {
+ case !ws.Created && ws.Request != nil:
+ // pending approval (initial state)
+ Pending
+ case !ws.Created && ws.Request == nil:
+ // request has been rejected
+ Rejected
+ case ws.Enabled && ws.Request == nil:
+ // enabled
+ Enabled
+ case !ws.Enabled && ws.Request == nil:
+ // disabled
+ Disabled
+ case ws.Enabled && ws.Request != nil:
+ // enabled, changes requested
+ Enabled, pending request
+ case !ws.Enabled && ws.Request != nil:
+ // disabled, changes requested
+ Disabled, pending request
}
}
diff --git a/view/workspace_templ.go b/view/workspace_templ.go
index 48047cd..872fd81 100644
--- a/view/workspace_templ.go
+++ b/view/workspace_templ.go
@@ -230,23 +230,34 @@ func wsStatusButton(ws *model.Workspace) templ.Component {
templ_7745c5c3_Var10 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
- if ws.Enabled && ws.Request == nil {
- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" Enabled")
+ switch true {
+ case !ws.Created && ws.Request != nil:
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" Pending")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ case !ws.Created && ws.Request == nil:
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" Rejected")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- } else if !ws.Created {
- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" Pending approval")
+ case ws.Enabled && ws.Request == nil:
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" Enabled")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- } else if !ws.Enabled {
+ case !ws.Enabled && ws.Request == nil:
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" Disabled")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- } else if ws.Enabled && ws.Request != nil {
- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" Pending changes")
+ case ws.Enabled && ws.Request != nil:
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" Enabled, pending request")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ case !ws.Enabled && ws.Request != nil:
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" Disabled, pending request")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -280,7 +291,7 @@ func workspaceDetails(ws, newWS *model.Workspace, kubeconfig string) templ.Compo
var templ_7745c5c3_Var12 string
templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(ws.ID.Hash())
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/workspace.templ`, Line: 87, Col: 63}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/workspace.templ`, Line: 94, Col: 63}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12))
if templ_7745c5c3_Err != nil {
@@ -293,7 +304,7 @@ func workspaceDetails(ws, newWS *model.Workspace, kubeconfig string) templ.Compo
var templ_7745c5c3_Var13 string
templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprint(ws.ID))
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/workspace.templ`, Line: 88, Col: 63}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/workspace.templ`, Line: 95, Col: 63}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13))
if templ_7745c5c3_Err != nil {
@@ -315,7 +326,7 @@ func workspaceDetails(ws, newWS *model.Workspace, kubeconfig string) templ.Compo
var templ_7745c5c3_Var14 string
templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(ws.Request.ByUser)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/workspace.templ`, Line: 91, Col: 83}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/workspace.templ`, Line: 98, Col: 83}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14))
if templ_7745c5c3_Err != nil {
@@ -441,7 +452,7 @@ func workspaceDetails(ws, newWS *model.Workspace, kubeconfig string) templ.Compo
var templ_7745c5c3_Var23 string
templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.JoinStringErrs(string(ws.Nodegroup))
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/workspace.templ`, Line: 103, Col: 34}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/workspace.templ`, Line: 110, Col: 34}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var23))
if templ_7745c5c3_Err != nil {
@@ -460,7 +471,7 @@ func workspaceDetails(ws, newWS *model.Workspace, kubeconfig string) templ.Compo
var templ_7745c5c3_Var24 string
templ_7745c5c3_Var24, templ_7745c5c3_Err = templ.JoinStringErrs(string(ng))
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/workspace.templ`, Line: 109, Col: 32}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/workspace.templ`, Line: 116, Col: 32}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var24))
if templ_7745c5c3_Err != nil {
@@ -483,7 +494,7 @@ func workspaceDetails(ws, newWS *model.Workspace, kubeconfig string) templ.Compo
var templ_7745c5c3_Var25 string
templ_7745c5c3_Var25, templ_7745c5c3_Err = templ.JoinStringErrs(string(ng))
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/workspace.templ`, Line: 109, Col: 83}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/workspace.templ`, Line: 116, Col: 83}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var25))
if templ_7745c5c3_Err != nil {
@@ -546,7 +557,7 @@ func workspaceDetails(ws, newWS *model.Workspace, kubeconfig string) templ.Compo
var templ_7745c5c3_Var30 string
templ_7745c5c3_Var30, templ_7745c5c3_Err = templ.JoinStringErrs(ws.Userdata)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/workspace.templ`, Line: 114, Col: 84}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/workspace.templ`, Line: 121, Col: 84}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var30))
if templ_7745c5c3_Err != nil {
@@ -559,7 +570,7 @@ func workspaceDetails(ws, newWS *model.Workspace, kubeconfig string) templ.Compo
var templ_7745c5c3_Var31 string
templ_7745c5c3_Var31, templ_7745c5c3_Err = templ.JoinStringErrs(newWS.Userdata)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/workspace.templ`, Line: 115, Col: 98}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/workspace.templ`, Line: 122, Col: 98}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var31))
if templ_7745c5c3_Err != nil {
@@ -641,7 +652,7 @@ func workspaceDetails(ws, newWS *model.Workspace, kubeconfig string) templ.Compo
var templ_7745c5c3_Var36 string
templ_7745c5c3_Var36, templ_7745c5c3_Err = templ.JoinStringErrs(user)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/workspace.templ`, Line: 125, Col: 67}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/workspace.templ`, Line: 132, Col: 67}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var36))
if templ_7745c5c3_Err != nil {
@@ -664,7 +675,7 @@ func workspaceDetails(ws, newWS *model.Workspace, kubeconfig string) templ.Compo
var templ_7745c5c3_Var37 string
templ_7745c5c3_Var37, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("user-%d", i))
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/workspace.templ`, Line: 131, Col: 64}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/workspace.templ`, Line: 138, Col: 64}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var37))
if templ_7745c5c3_Err != nil {
@@ -677,7 +688,7 @@ func workspaceDetails(ws, newWS *model.Workspace, kubeconfig string) templ.Compo
var templ_7745c5c3_Var38 string
templ_7745c5c3_Var38, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("user-%d", i))
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/workspace.templ`, Line: 131, Col: 99}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/workspace.templ`, Line: 138, Col: 99}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var38))
if templ_7745c5c3_Err != nil {
@@ -690,7 +701,7 @@ func workspaceDetails(ws, newWS *model.Workspace, kubeconfig string) templ.Compo
var templ_7745c5c3_Var39 string
templ_7745c5c3_Var39, templ_7745c5c3_Err = templ.JoinStringErrs(user)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/workspace.templ`, Line: 131, Col: 114}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/workspace.templ`, Line: 138, Col: 114}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var39))
if templ_7745c5c3_Err != nil {
@@ -774,7 +785,7 @@ func workspaceDetails(ws, newWS *model.Workspace, kubeconfig string) templ.Compo
var templ_7745c5c3_Var46 string
templ_7745c5c3_Var46, templ_7745c5c3_Err = templ.JoinStringErrs(ctxCSRF(ctx))
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/workspace.templ`, Line: 138, Col: 56}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/workspace.templ`, Line: 145, Col: 56}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var46))
if templ_7745c5c3_Err != nil {
@@ -887,7 +898,7 @@ func workspaceDetails(ws, newWS *model.Workspace, kubeconfig string) templ.Compo
var templ_7745c5c3_Var55 string
templ_7745c5c3_Var55, templ_7745c5c3_Err = templ.JoinStringErrs(kubeconfig)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/workspace.templ`, Line: 159, Col: 128}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/workspace.templ`, Line: 166, Col: 128}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var55))
if templ_7745c5c3_Err != nil {
@@ -975,7 +986,7 @@ func wsQuotaInput(label, name, units string, res model.Resource, ws, newWS *mode
var templ_7745c5c3_Var62 string
templ_7745c5c3_Var62, templ_7745c5c3_Err = templ.JoinStringErrs(label)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/workspace.templ`, Line: 170, Col: 9}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/workspace.templ`, Line: 177, Col: 9}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var62))
if templ_7745c5c3_Err != nil {
@@ -993,7 +1004,7 @@ func wsQuotaInput(label, name, units string, res model.Resource, ws, newWS *mode
var templ_7745c5c3_Var63 string
templ_7745c5c3_Var63, templ_7745c5c3_Err = templ.JoinStringErrs(units)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/workspace.templ`, Line: 172, Col: 58}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/workspace.templ`, Line: 179, Col: 58}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var63))
if templ_7745c5c3_Err != nil {
@@ -1033,7 +1044,7 @@ func wsQuotaInput(label, name, units string, res model.Resource, ws, newWS *mode
var templ_7745c5c3_Var66 string
templ_7745c5c3_Var66, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprint(ws.Quotas[res]))
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/workspace.templ`, Line: 175, Col: 75}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/workspace.templ`, Line: 182, Col: 75}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var66))
if templ_7745c5c3_Err != nil {
@@ -1046,7 +1057,7 @@ func wsQuotaInput(label, name, units string, res model.Resource, ws, newWS *mode
var templ_7745c5c3_Var67 string
templ_7745c5c3_Var67, templ_7745c5c3_Err = templ.JoinStringErrs(name)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/workspace.templ`, Line: 176, Col: 31}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/workspace.templ`, Line: 183, Col: 31}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var67))
if templ_7745c5c3_Err != nil {
@@ -1059,7 +1070,7 @@ func wsQuotaInput(label, name, units string, res model.Resource, ws, newWS *mode
var templ_7745c5c3_Var68 string
templ_7745c5c3_Var68, templ_7745c5c3_Err = templ.JoinStringErrs(name)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/workspace.templ`, Line: 176, Col: 45}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/workspace.templ`, Line: 183, Col: 45}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var68))
if templ_7745c5c3_Err != nil {
@@ -1072,7 +1083,7 @@ func wsQuotaInput(label, name, units string, res model.Resource, ws, newWS *mode
var templ_7745c5c3_Var69 string
templ_7745c5c3_Var69, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprint(newWS.Quotas[res]))
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/workspace.templ`, Line: 176, Col: 107}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/workspace.templ`, Line: 183, Col: 107}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var69))
if templ_7745c5c3_Err != nil {