@@ -286,6 +286,64 @@ type DeleteSwarmStackOutput struct {
286286 Body base.ApiResponse [base.MessageResponse ]
287287}
288288
289+ type DownSwarmStackInput struct {
290+ EnvironmentID string `path:"id" doc:"Environment ID"`
291+ Name string `path:"name" doc:"Stack name"`
292+ }
293+
294+ type DownSwarmStackOutput struct {
295+ Body base.ApiResponse [base.MessageResponse ]
296+ }
297+
298+ type ListSwarmStackProjectsInput struct {
299+ EnvironmentID string `path:"id" doc:"Environment ID"`
300+ Search string `query:"search" doc:"Search query"`
301+ Sort string `query:"sort" doc:"Column to sort by"`
302+ Order string `query:"order" default:"asc" doc:"Sort direction (asc or desc)"`
303+ Start int `query:"start" default:"0" doc:"Start index for pagination"`
304+ Limit int `query:"limit" default:"20" doc:"Number of items per page"`
305+ }
306+
307+ type ListSwarmStackProjectsOutput struct {
308+ Body SwarmPaginatedResponse [swarmtypes.StackProjectSummary ]
309+ }
310+
311+ type GetSwarmStackProjectCountsInput struct {
312+ EnvironmentID string `path:"id" doc:"Environment ID"`
313+ }
314+
315+ type GetSwarmStackProjectCountsOutput struct {
316+ Body base.ApiResponse [swarmtypes.StackProjectCounts ]
317+ }
318+
319+ type GetSwarmStackProjectInput struct {
320+ EnvironmentID string `path:"id" doc:"Environment ID"`
321+ Name string `path:"name" doc:"Stack name"`
322+ }
323+
324+ type GetSwarmStackProjectOutput struct {
325+ Body base.ApiResponse [swarmtypes.StackProjectDetails ]
326+ }
327+
328+ type UpdateSwarmStackProjectInput struct {
329+ EnvironmentID string `path:"id" doc:"Environment ID"`
330+ Name string `path:"name" doc:"Stack name"`
331+ Body swarmtypes.StackSourceUpdateRequest
332+ }
333+
334+ type UpdateSwarmStackProjectOutput struct {
335+ Body base.ApiResponse [swarmtypes.StackProjectDetails ]
336+ }
337+
338+ type DeleteSwarmStackProjectInput struct {
339+ EnvironmentID string `path:"id" doc:"Environment ID"`
340+ Name string `path:"name" doc:"Stack name"`
341+ }
342+
343+ type DeleteSwarmStackProjectOutput struct {
344+ Body base.ApiResponse [base.MessageResponse ]
345+ }
346+
289347type ListSwarmStackServicesInput struct {
290348 EnvironmentID string `path:"id" doc:"Environment ID"`
291349 Name string `path:"name" doc:"Stack name"`
@@ -542,9 +600,15 @@ func RegisterSwarm(api huma.API, swarmSvc *services.SwarmService, environmentSvc
542600 huma .Register (api , huma.Operation {OperationID : "list-swarm-stacks" , Method : http .MethodGet , Path : "/environments/{id}/swarm/stacks" , Summary : "List swarm stacks" , Tags : []string {"Swarm" }, Security : []map [string ][]string {{"BearerAuth" : {}}, {"ApiKeyAuth" : {}}}}, h .ListStacks )
543601 huma .Register (api , huma.Operation {OperationID : "deploy-swarm-stack" , Method : http .MethodPost , Path : "/environments/{id}/swarm/stacks" , Summary : "Deploy swarm stack" , Tags : []string {"Swarm" }, Security : []map [string ][]string {{"BearerAuth" : {}}, {"ApiKeyAuth" : {}}}}, h .DeployStack )
544602 huma .Register (api , huma.Operation {OperationID : "get-swarm-stack" , Method : http .MethodGet , Path : "/environments/{id}/swarm/stacks/{name}" , Summary : "Get swarm stack" , Tags : []string {"Swarm" }, Security : []map [string ][]string {{"BearerAuth" : {}}, {"ApiKeyAuth" : {}}}}, h .GetStack )
603+ huma .Register (api , huma.Operation {OperationID : "down-swarm-stack" , Method : http .MethodPost , Path : "/environments/{id}/swarm/stacks/{name}/down" , Summary : "Bring down swarm stack runtime" , Tags : []string {"Swarm" }, Security : []map [string ][]string {{"BearerAuth" : {}}, {"ApiKeyAuth" : {}}}}, h .DownStack )
545604 huma .Register (api , huma.Operation {OperationID : "get-swarm-stack-source" , Method : http .MethodGet , Path : "/environments/{id}/swarm/stacks/{name}/source" , Summary : "Get swarm stack source" , Tags : []string {"Swarm" }, Security : []map [string ][]string {{"BearerAuth" : {}}, {"ApiKeyAuth" : {}}}}, h .GetStackSource )
546605 huma .Register (api , huma.Operation {OperationID : "update-swarm-stack-source" , Method : http .MethodPut , Path : "/environments/{id}/swarm/stacks/{name}/source" , Summary : "Update swarm stack source" , Tags : []string {"Swarm" }, Security : []map [string ][]string {{"BearerAuth" : {}}, {"ApiKeyAuth" : {}}}}, h .UpdateStackSource )
547606 huma .Register (api , huma.Operation {OperationID : "delete-swarm-stack" , Method : http .MethodDelete , Path : "/environments/{id}/swarm/stacks/{name}" , Summary : "Delete swarm stack" , Tags : []string {"Swarm" }, Security : []map [string ][]string {{"BearerAuth" : {}}, {"ApiKeyAuth" : {}}}}, h .DeleteStack )
607+ huma .Register (api , huma.Operation {OperationID : "list-swarm-stack-projects" , Method : http .MethodGet , Path : "/environments/{id}/swarm/stackprojects" , Summary : "List saved swarm stack projects" , Tags : []string {"Swarm" }, Security : []map [string ][]string {{"BearerAuth" : {}}, {"ApiKeyAuth" : {}}}}, h .ListStackProjects )
608+ huma .Register (api , huma.Operation {OperationID : "get-swarm-stack-project-counts" , Method : http .MethodGet , Path : "/environments/{id}/swarm/stackprojects/counts" , Summary : "Get saved swarm stack project counts" , Tags : []string {"Swarm" }, Security : []map [string ][]string {{"BearerAuth" : {}}, {"ApiKeyAuth" : {}}}}, h .GetStackProjectCounts )
609+ huma .Register (api , huma.Operation {OperationID : "get-swarm-stack-project" , Method : http .MethodGet , Path : "/environments/{id}/swarm/stackprojects/{name}" , Summary : "Get saved swarm stack project" , Tags : []string {"Swarm" }, Security : []map [string ][]string {{"BearerAuth" : {}}, {"ApiKeyAuth" : {}}}}, h .GetStackProject )
610+ huma .Register (api , huma.Operation {OperationID : "update-swarm-stack-project" , Method : http .MethodPut , Path : "/environments/{id}/swarm/stackprojects/{name}" , Summary : "Create or update saved swarm stack project" , Tags : []string {"Swarm" }, Security : []map [string ][]string {{"BearerAuth" : {}}, {"ApiKeyAuth" : {}}}}, h .UpdateStackProject )
611+ huma .Register (api , huma.Operation {OperationID : "delete-swarm-stack-project" , Method : http .MethodDelete , Path : "/environments/{id}/swarm/stackprojects/{name}" , Summary : "Delete saved swarm stack project" , Tags : []string {"Swarm" }, Security : []map [string ][]string {{"BearerAuth" : {}}, {"ApiKeyAuth" : {}}}}, h .DeleteStackProject )
548612 huma .Register (api , huma.Operation {OperationID : "list-swarm-stack-services" , Method : http .MethodGet , Path : "/environments/{id}/swarm/stacks/{name}/services" , Summary : "List swarm stack services" , Tags : []string {"Swarm" }, Security : []map [string ][]string {{"BearerAuth" : {}}, {"ApiKeyAuth" : {}}}}, h .ListStackServices )
549613 huma .Register (api , huma.Operation {OperationID : "list-swarm-stack-tasks" , Method : http .MethodGet , Path : "/environments/{id}/swarm/stacks/{name}/tasks" , Summary : "List swarm stack tasks" , Tags : []string {"Swarm" }, Security : []map [string ][]string {{"BearerAuth" : {}}, {"ApiKeyAuth" : {}}}}, h .ListStackTasks )
550614 huma .Register (api , huma.Operation {OperationID : "render-swarm-stack-config" , Method : http .MethodPost , Path : "/environments/{id}/swarm/stacks/config/render" , Summary : "Render/validate swarm stack config" , Tags : []string {"Swarm" }, Security : []map [string ][]string {{"BearerAuth" : {}}, {"ApiKeyAuth" : {}}}}, h .RenderStackConfig )
@@ -1184,6 +1248,155 @@ func (h *SwarmHandler) DeployStack(ctx context.Context, input *DeploySwarmStackI
11841248 return & DeploySwarmStackOutput {Body : base.ApiResponse [swarmtypes.StackDeployResponse ]{Success : true , Data : * resp }}, nil
11851249}
11861250
1251+ func (h * SwarmHandler ) DownStack (ctx context.Context , input * DownSwarmStackInput ) (* DownSwarmStackOutput , error ) {
1252+ if h .swarmService == nil {
1253+ return nil , huma .Error500InternalServerError ("service not available" )
1254+ }
1255+ if err := checkAdmin (ctx ); err != nil {
1256+ return nil , err
1257+ }
1258+
1259+ if err := h .swarmService .DownStack (ctx , input .Name ); err != nil {
1260+ return nil , mapSwarmServiceError (err , "Failed to bring down swarm stack" )
1261+ }
1262+
1263+ h .auditSwarmMutation (ctx , input .EnvironmentID , "stack.down" , "swarm_stack" , input .Name , input .Name , map [string ]any {"stack" : input .Name })
1264+
1265+ return & DownSwarmStackOutput {
1266+ Body : base.ApiResponse [base.MessageResponse ]{
1267+ Success : true ,
1268+ Data : base.MessageResponse {Message : "Swarm stack brought down successfully" },
1269+ },
1270+ }, nil
1271+ }
1272+
1273+ func (h * SwarmHandler ) ListStackProjects (
1274+ ctx context.Context ,
1275+ input * ListSwarmStackProjectsInput ,
1276+ ) (* ListSwarmStackProjectsOutput , error ) {
1277+ if h .swarmService == nil {
1278+ return nil , huma .Error500InternalServerError ("service not available" )
1279+ }
1280+ if err := checkAdmin (ctx ); err != nil {
1281+ return nil , err
1282+ }
1283+
1284+ params := buildSwarmQueryParams (input .Search , input .Sort , input .Order , input .Start , input .Limit )
1285+ items , paginationResp , err := h .swarmService .ListStackProjectsPaginated (ctx , input .EnvironmentID , params )
1286+ if err != nil {
1287+ return nil , mapSwarmServiceError (err , "Failed to list saved swarm stack projects" )
1288+ }
1289+ if items == nil {
1290+ items = []swarmtypes.StackProjectSummary {}
1291+ }
1292+
1293+ return & ListSwarmStackProjectsOutput {Body : toSwarmPaginatedResponse (items , paginationResp )}, nil
1294+ }
1295+
1296+ func (h * SwarmHandler ) GetStackProjectCounts (
1297+ ctx context.Context ,
1298+ input * GetSwarmStackProjectCountsInput ,
1299+ ) (* GetSwarmStackProjectCountsOutput , error ) {
1300+ if h .swarmService == nil {
1301+ return nil , huma .Error500InternalServerError ("service not available" )
1302+ }
1303+ if err := checkAdmin (ctx ); err != nil {
1304+ return nil , err
1305+ }
1306+
1307+ counts , err := h .swarmService .GetStackProjectStatusCounts (ctx , input .EnvironmentID )
1308+ if err != nil {
1309+ return nil , mapSwarmServiceError (err , "Failed to load saved swarm stack project counts" )
1310+ }
1311+
1312+ return & GetSwarmStackProjectCountsOutput {
1313+ Body : base.ApiResponse [swarmtypes.StackProjectCounts ]{Success : true , Data : counts },
1314+ }, nil
1315+ }
1316+
1317+ func (h * SwarmHandler ) GetStackProject (
1318+ ctx context.Context ,
1319+ input * GetSwarmStackProjectInput ,
1320+ ) (* GetSwarmStackProjectOutput , error ) {
1321+ if h .swarmService == nil {
1322+ return nil , huma .Error500InternalServerError ("service not available" )
1323+ }
1324+ if err := checkAdmin (ctx ); err != nil {
1325+ return nil , err
1326+ }
1327+
1328+ stackProject , err := h .swarmService .GetStackProject (ctx , input .EnvironmentID , input .Name )
1329+ if err != nil {
1330+ if errdefs .IsNotFound (err ) {
1331+ return nil , huma .Error404NotFound ("Saved swarm stack project not found" )
1332+ }
1333+ return nil , mapSwarmServiceError (err , "Failed to load saved swarm stack project" )
1334+ }
1335+
1336+ return & GetSwarmStackProjectOutput {
1337+ Body : base.ApiResponse [swarmtypes.StackProjectDetails ]{Success : true , Data : * stackProject },
1338+ }, nil
1339+ }
1340+
1341+ func (h * SwarmHandler ) UpdateStackProject (
1342+ ctx context.Context ,
1343+ input * UpdateSwarmStackProjectInput ,
1344+ ) (* UpdateSwarmStackProjectOutput , error ) {
1345+ if h .swarmService == nil {
1346+ return nil , huma .Error500InternalServerError ("service not available" )
1347+ }
1348+ if err := checkAdmin (ctx ); err != nil {
1349+ return nil , err
1350+ }
1351+
1352+ stackProject , err := h .swarmService .UpsertStackProject (ctx , input .EnvironmentID , input .Name , input .Body )
1353+ if err != nil {
1354+ return nil , mapSwarmServiceError (err , "Failed to update saved swarm stack project" )
1355+ }
1356+
1357+ h .auditSwarmMutation (
1358+ ctx ,
1359+ input .EnvironmentID ,
1360+ "stack.project.update" ,
1361+ "swarm_stack" ,
1362+ stackProject .Name ,
1363+ input .Name ,
1364+ map [string ]any {"stack" : stackProject .Name , "previousStack" : input .Name },
1365+ )
1366+
1367+ return & UpdateSwarmStackProjectOutput {
1368+ Body : base.ApiResponse [swarmtypes.StackProjectDetails ]{Success : true , Data : * stackProject },
1369+ }, nil
1370+ }
1371+
1372+ func (h * SwarmHandler ) DeleteStackProject (
1373+ ctx context.Context ,
1374+ input * DeleteSwarmStackProjectInput ,
1375+ ) (* DeleteSwarmStackProjectOutput , error ) {
1376+ if h .swarmService == nil {
1377+ return nil , huma .Error500InternalServerError ("service not available" )
1378+ }
1379+ if err := checkAdmin (ctx ); err != nil {
1380+ return nil , err
1381+ }
1382+
1383+ if err := h .swarmService .DeleteStackProject (ctx , input .EnvironmentID , input .Name ); err != nil {
1384+ if errdefs .IsNotFound (err ) {
1385+ return nil , huma .Error404NotFound ("Saved swarm stack project not found" )
1386+ }
1387+ return nil , mapSwarmServiceError (err , "Failed to delete saved swarm stack project" )
1388+ }
1389+
1390+ h .auditSwarmMutation (ctx , input .EnvironmentID , "stack.project.delete" , "swarm_stack" , input .Name , input .Name , map [string ]any {"stack" : input .Name })
1391+
1392+ return & DeleteSwarmStackProjectOutput {
1393+ Body : base.ApiResponse [base.MessageResponse ]{
1394+ Success : true ,
1395+ Data : base.MessageResponse {Message : "Saved swarm stack project deleted successfully" },
1396+ },
1397+ }, nil
1398+ }
1399+
11871400// GetStack returns detailed information for a specific swarm stack.
11881401//
11891402// It looks up the stack by name through the swarm service and maps missing
0 commit comments