From 04f92ef17d8803579434e9e1b479972c09230596 Mon Sep 17 00:00:00 2001 From: Ben Schumacher Date: Tue, 10 Dec 2024 09:17:59 +0100 Subject: [PATCH 1/3] [MM-61124] Add diagnostics data to the Support Packet (#1957) --- go.mod | 8 +-- go.sum | 8 +-- server/api_runs_test.go | 10 +-- server/app/playbook.go | 6 ++ server/app/playbook_service.go | 4 ++ server/command/command.go | 2 +- server/sqlstore/playbook.go | 108 +++++++++++++++++++------------ server/sqlstore/playbook_test.go | 8 +-- server/support_packet.go | 58 +++++++++++++++++ server/support_packet_test.go | 39 +++++++++++ 10 files changed, 191 insertions(+), 60 deletions(-) create mode 100644 server/support_packet.go create mode 100644 server/support_packet_test.go diff --git a/go.mod b/go.mod index 5625dab0d3..5951c71c05 100644 --- a/go.mod +++ b/go.mod @@ -22,11 +22,12 @@ require ( github.com/gorilla/mux v1.8.1 github.com/graph-gophers/dataloader/v7 v7.1.0 github.com/graph-gophers/graphql-go v1.4.0 + github.com/hashicorp/go-multierror v1.1.1 github.com/jmoiron/sqlx v1.4.0 github.com/lib/pq v1.10.9 github.com/mattermost/mattermost-plugin-playbooks/client v0.7.0 - github.com/mattermost/mattermost/server/public v0.1.8 - github.com/mattermost/mattermost/server/v8 v8.0.0-20241112090719-5eef415a39e1 + github.com/mattermost/mattermost/server/public v0.1.9 + github.com/mattermost/mattermost/server/v8 v8.0.0-20241113102039-053d0b5f0ad5 github.com/mattermost/morph v1.1.0 github.com/mitchellh/mapstructure v1.5.0 github.com/pkg/errors v0.9.1 @@ -36,6 +37,7 @@ require ( github.com/stretchr/testify v1.9.0 github.com/writeas/go-strip-markdown v2.0.1+incompatible gopkg.in/guregu/null.v4 v4.0.0 + gopkg.in/yaml.v3 v3.0.1 ) require ( @@ -107,7 +109,6 @@ require ( github.com/h2non/go-is-svg v0.0.0-20160927212452-35e8c4b0612c // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-hclog v1.6.3 // indirect - github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-plugin v1.6.1 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect @@ -203,7 +204,6 @@ require ( gopkg.in/mail.v2 v2.3.1 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect modernc.org/gc/v3 v3.0.0-20240722195230-4a140ff9c08e // indirect modernc.org/libc v1.55.3 // indirect modernc.org/mathutil v1.6.0 // indirect diff --git a/go.sum b/go.sum index bd306f3ba5..50612c6be3 100644 --- a/go.sum +++ b/go.sum @@ -295,10 +295,10 @@ github.com/mattermost/ldap v0.0.0-20231116144001-0f480c025956 h1:Y1Tu/swM31pVwwb github.com/mattermost/ldap v0.0.0-20231116144001-0f480c025956/go.mod h1:SRl30Lb7/QoYyohYeVBuqYvvmXSZJxZgiV3Zf6VbxjI= github.com/mattermost/logr/v2 v2.0.21 h1:CMHsP+nrbRlEC4g7BwOk1GAnMtHkniFhlSQPXy52be4= github.com/mattermost/logr/v2 v2.0.21/go.mod h1:kZkB/zqKL9e+RY5gB3vGpsyenC+TpuiOenjMkvJJbzc= -github.com/mattermost/mattermost/server/public v0.1.8 h1:Z2PUXR4YGquuSo3ojNUl0aazOMSRqALjyMaf20jNIy4= -github.com/mattermost/mattermost/server/public v0.1.8/go.mod h1:SkTKbMul91Rq0v2dIxe8mqzUOY+3KwlwwLmAlxDfGCk= -github.com/mattermost/mattermost/server/v8 v8.0.0-20241112090719-5eef415a39e1 h1:qNW9//+lx3kwCETTCvqjrFgQ3SH0DyHusE3PnGJfHVE= -github.com/mattermost/mattermost/server/v8 v8.0.0-20241112090719-5eef415a39e1/go.mod h1:B4pQsrbZs6yO4GpWY6nCJPNG7myB0r3gvlFWWlGABmc= +github.com/mattermost/mattermost/server/public v0.1.9 h1:l/OKPRVuFeqL0yqRVC/JpveG5sLNKcT9llxqMkO9e+s= +github.com/mattermost/mattermost/server/public v0.1.9/go.mod h1:SkTKbMul91Rq0v2dIxe8mqzUOY+3KwlwwLmAlxDfGCk= +github.com/mattermost/mattermost/server/v8 v8.0.0-20241113102039-053d0b5f0ad5 h1:XVePV2EZhapQ6JIGFycfTd1QgxICvDs8rRUy3pqxagQ= +github.com/mattermost/mattermost/server/v8 v8.0.0-20241113102039-053d0b5f0ad5/go.mod h1:B4pQsrbZs6yO4GpWY6nCJPNG7myB0r3gvlFWWlGABmc= github.com/mattermost/morph v1.1.0 h1:Q9vrJbeM3s2jfweGheq12EFIzdNp9a/6IovcbvOQ6Cw= github.com/mattermost/morph v1.1.0/go.mod h1:gD+EaqX2UMyyuzmF4PFh4r33XneQ8Nzi+0E8nXjMa3A= github.com/mattermost/rsc v0.0.0-20160330161541-bbaefb05eaa0 h1:G9tL6JXRBMzjuD1kkBtcnd42kUiT6QDwxfFYu7adM6o= diff --git a/server/api_runs_test.go b/server/api_runs_test.go index e518675195..a798121c2d 100644 --- a/server/api_runs_test.go +++ b/server/api_runs_test.go @@ -1304,7 +1304,7 @@ func TestIgnoreKeywords(t *testing.T) { }, }, } - botPost, err := e.Srv.Store().Post().Save(botPost) + botPost, err := e.Srv.Store().Post().Save(e.Context, botPost) require.NoError(t, err) // Create post action request @@ -1321,14 +1321,14 @@ func TestIgnoreKeywords(t *testing.T) { require.NoError(t, err) // Make the request - result, err := e.ServerClient.DoAPIRequestBytes("POST", e.ServerClient.URL+"/plugins/"+manifest.Id+"/api/v0/signal/keywords/ignore-thread", reqBytes, "") + result, err := e.ServerClient.DoAPIRequestBytes(context.Background(), "POST", e.ServerClient.URL+"/plugins/"+manifest.Id+"/api/v0/signal/keywords/ignore-thread", reqBytes, "") require.Error(t, err) require.Equal(t, http.StatusForbidden, result.StatusCode) }) t.Run("has permission to channel", func(t *testing.T) { // Add user to private channel - _, _, err := e.ServerAdminClient.AddChannelMember(e.BasicPrivateChannel.Id, e.RegularUser.Id) + _, _, err := e.ServerAdminClient.AddChannelMember(context.Background(), e.BasicPrivateChannel.Id, e.RegularUser.Id) require.NoError(t, err) // Create a bot post in the private channel @@ -1348,7 +1348,7 @@ func TestIgnoreKeywords(t *testing.T) { }, }, } - botPost, err = e.Srv.Store().Post().Save(botPost) + botPost, err = e.Srv.Store().Post().Save(e.Context, botPost) require.NoError(t, err) // Create post action request @@ -1365,7 +1365,7 @@ func TestIgnoreKeywords(t *testing.T) { require.NoError(t, err) // Make the request - result, err := e.ServerClient.DoAPIRequestBytes("POST", e.ServerClient.URL+"/plugins/"+manifest.Id+"/api/v0/signal/keywords/ignore-thread", reqBytes, "") + result, err := e.ServerClient.DoAPIRequestBytes(context.Background(), "POST", e.ServerClient.URL+"/plugins/"+manifest.Id+"/api/v0/signal/keywords/ignore-thread", reqBytes, "") require.NoError(t, err) require.Equal(t, http.StatusOK, result.StatusCode) }) diff --git a/server/app/playbook.go b/server/app/playbook.go index c7ad006bac..3e4b5d556e 100644 --- a/server/app/playbook.go +++ b/server/app/playbook.go @@ -346,6 +346,9 @@ type PlaybookService interface { // GetPlaybooks retrieves all playbooks GetPlaybooks() ([]Playbook, error) + // GetActivePlaybooks retrieves all active playbooks + GetActivePlaybooks() ([]Playbook, error) + // GetPlaybooksForTeam retrieves all playbooks on the specified team given the provided options GetPlaybooksForTeam(requesterInfo RequesterInfo, teamID string, opts PlaybookFilterOptions) (GetPlaybooksResults, error) @@ -388,6 +391,9 @@ type PlaybookStore interface { // GetPlaybooks retrieves all playbooks GetPlaybooks() ([]Playbook, error) + // GetActivePlaybooks retrieves all active playbooks + GetActivePlaybooks() ([]Playbook, error) + // GetPlaybooksForTeam retrieves all playbooks on the specified team GetPlaybooksForTeam(requesterInfo RequesterInfo, teamID string, opts PlaybookFilterOptions) (GetPlaybooksResults, error) diff --git a/server/app/playbook_service.go b/server/app/playbook_service.go index 53fa7c6bfe..2b2a917689 100644 --- a/server/app/playbook_service.go +++ b/server/app/playbook_service.go @@ -80,6 +80,10 @@ func (s *playbookService) GetPlaybooks() ([]Playbook, error) { return s.store.GetPlaybooks() } +func (s *playbookService) GetActivePlaybooks() ([]Playbook, error) { + return s.store.GetActivePlaybooks() +} + func (s *playbookService) GetPlaybooksForTeam(requesterInfo RequesterInfo, teamID string, opts PlaybookFilterOptions) (GetPlaybooksResults, error) { return s.store.GetPlaybooksForTeam(requesterInfo, teamID, opts) } diff --git a/server/command/command.go b/server/command/command.go index a11e1e9d1d..99bd15e7d7 100644 --- a/server/command/command.go +++ b/server/command/command.go @@ -1155,7 +1155,7 @@ And... yes, of course, we have emojis return } - gotPlaybooks, err := r.playbookService.GetPlaybooks() + gotPlaybooks, err := r.playbookService.GetActivePlaybooks() if err != nil { r.postCommandResponse("There was an error while retrieving all playbooks. Err: " + err.Error()) return diff --git a/server/sqlstore/playbook.go b/server/sqlstore/playbook.go index 23a3a8a5dc..63a9f57fc2 100644 --- a/server/sqlstore/playbook.go +++ b/server/sqlstore/playbook.go @@ -336,10 +336,50 @@ func (p *playbookStore) Get(id string) (app.Playbook, error) { return playbook, nil } +func selectAllPlaybooks(builder sq.StatementBuilderType) sq.SelectBuilder { + return builder.Select( + "p.ID", + "p.Title", + "p.Description", + "p.TeamID", + "p.Public", + "p.CreatePublicIncident AS CreatePublicPlaybookRun", + "p.CreateAt", + "p.DeleteAt", + "p.NumStages", + "p.NumSteps", + "COUNT(i.ID) AS NumRuns", + "COALESCE(MAX(i.CreateAt), 0) AS LastRunAt", + `( + 1 + -- Channel creation is hard-coded + CASE WHEN p.InviteUsersEnabled THEN 1 ELSE 0 END + + CASE WHEN p.DefaultCommanderEnabled THEN 1 ELSE 0 END + + CASE WHEN p.BroadcastEnabled THEN 1 ELSE 0 END + + CASE WHEN p.WebhookOnCreationEnabled THEN 1 ELSE 0 END + + CASE WHEN p.MessageOnJoinEnabled THEN 1 ELSE 0 END + + CASE WHEN p.WebhookOnStatusUpdateEnabled THEN 1 ELSE 0 END + + CASE WHEN p.SignalAnyKeywordsEnabled THEN 1 ELSE 0 END + + CASE WHEN p.CategorizeChannelEnabled THEN 1 ELSE 0 END + + CASE WHEN p.CreateChannelMemberOnNewParticipant THEN 1 ELSE 0 END + + CASE WHEN p.RemoveChannelMemberOnRemovedParticipant THEN 1 ELSE 0 END + ) AS NumActions`, + "COALESCE(ChannelNameTemplate, '') ChannelNameTemplate", + "COALESCE(s.DefaultPlaybookAdminRole, 'playbook_admin') DefaultPlaybookAdminRole", + "COALESCE(s.DefaultPlaybookMemberRole, 'playbook_member') DefaultPlaybookMemberRole", + "COALESCE(s.DefaultRunAdminRole, 'run_admin') DefaultRunAdminRole", + "COALESCE(s.DefaultRunMemberRole, 'run_member') DefaultRunMemberRole", + ). + From("IR_Playbook AS p"). + LeftJoin("IR_Incident AS i ON p.ID = i.PlaybookID"). + LeftJoin("Teams t ON t.Id = p.TeamID"). + LeftJoin("Schemes s ON t.SchemeId = s.Id"). + GroupBy("p.ID"). + GroupBy("s.Id") +} + // GetPlaybooks retrieves all playbooks that are not deleted. // Members are not retrieved for this as the query would be large and we don't need it for this for now. -// This is only used for the keywords feature -func (p *playbookStore) GetPlaybooks() ([]app.Playbook, error) { +func (p *playbookStore) GetActivePlaybooks() ([]app.Playbook, error) { tx, err := p.store.db.Beginx() if err != nil { return nil, errors.Wrap(err, "could not begin transaction") @@ -347,47 +387,31 @@ func (p *playbookStore) GetPlaybooks() ([]app.Playbook, error) { defer p.store.finalizeTransaction(tx) var playbooks []app.Playbook - err = p.store.selectBuilder(tx, &playbooks, p.store.builder. - Select( - "p.ID", - "p.Title", - "p.Description", - "p.TeamID", - "p.Public", - "p.CreatePublicIncident AS CreatePublicPlaybookRun", - "p.CreateAt", - "p.DeleteAt", - "p.NumStages", - "p.NumSteps", - "COUNT(i.ID) AS NumRuns", - "COALESCE(MAX(i.CreateAt), 0) AS LastRunAt", - `( - 1 + -- Channel creation is hard-coded - CASE WHEN p.InviteUsersEnabled THEN 1 ELSE 0 END + - CASE WHEN p.DefaultCommanderEnabled THEN 1 ELSE 0 END + - CASE WHEN p.BroadcastEnabled THEN 1 ELSE 0 END + - CASE WHEN p.WebhookOnCreationEnabled THEN 1 ELSE 0 END + - CASE WHEN p.MessageOnJoinEnabled THEN 1 ELSE 0 END + - CASE WHEN p.WebhookOnStatusUpdateEnabled THEN 1 ELSE 0 END + - CASE WHEN p.SignalAnyKeywordsEnabled THEN 1 ELSE 0 END + - CASE WHEN p.CategorizeChannelEnabled THEN 1 ELSE 0 END + - CASE WHEN p.CreateChannelMemberOnNewParticipant THEN 1 ELSE 0 END + - CASE WHEN p.RemoveChannelMemberOnRemovedParticipant THEN 1 ELSE 0 END - ) AS NumActions`, - "COALESCE(ChannelNameTemplate, '') ChannelNameTemplate", - "COALESCE(s.DefaultPlaybookAdminRole, 'playbook_admin') DefaultPlaybookAdminRole", - "COALESCE(s.DefaultPlaybookMemberRole, 'playbook_member') DefaultPlaybookMemberRole", - "COALESCE(s.DefaultRunAdminRole, 'run_admin') DefaultRunAdminRole", - "COALESCE(s.DefaultRunMemberRole, 'run_member') DefaultRunMemberRole", - ). - From("IR_Playbook AS p"). - LeftJoin("IR_Incident AS i ON p.ID = i.PlaybookID"). - LeftJoin("Teams t ON t.Id = p.TeamID"). - LeftJoin("Schemes s ON t.SchemeId = s.Id"). - Where(sq.Eq{"p.DeleteAt": 0}). - GroupBy("p.ID"). - GroupBy("s.Id")) + err = p.store.selectBuilder(tx, &playbooks, + selectAllPlaybooks(p.store.builder).Where(sq.Eq{"p.DeleteAt": 0}), + ) + if err == sql.ErrNoRows { + return nil, errors.Wrap(app.ErrNotFound, "no playbooks found") + } else if err != nil { + return nil, errors.Wrap(err, "failed to get playbooks") + } + + return playbooks, nil +} +// GetPlaybooks retrieves all playbooks, even deleted ones. +// Members are not retrieved for this as the query would be large and we don't need it for this for now. +func (p *playbookStore) GetPlaybooks() ([]app.Playbook, error) { + tx, err := p.store.db.Beginx() + if err != nil { + return nil, errors.Wrap(err, "could not begin transaction") + } + defer p.store.finalizeTransaction(tx) + + var playbooks []app.Playbook + err = p.store.selectBuilder(tx, &playbooks, + selectAllPlaybooks(p.store.builder), + ) if err == sql.ErrNoRows { return nil, errors.Wrap(app.ErrNotFound, "no playbooks found") } else if err != nil { diff --git a/server/sqlstore/playbook_test.go b/server/sqlstore/playbook_test.go index 736d3d5dfa..a12b475e87 100644 --- a/server/sqlstore/playbook_test.go +++ b/server/sqlstore/playbook_test.go @@ -880,7 +880,7 @@ func TestGetPlaybooksForTeam(t *testing.T) { playbookStore := setupPlaybookStore(t, db) t.Run(driverName+" - zero playbooks", func(t *testing.T) { - result, err := playbookStore.GetPlaybooks() + result, err := playbookStore.GetActivePlaybooks() require.NoError(t, err) require.ElementsMatch(t, []app.Playbook{}, result) }) @@ -1344,7 +1344,7 @@ func TestGetPlaybooksForKeywords(t *testing.T) { playbookStore := setupPlaybookStore(t, db) t.Run("zero playbooks", func(t *testing.T) { - result, err := playbookStore.GetPlaybooks() + result, err := playbookStore.GetActivePlaybooks() require.NoError(t, err) require.ElementsMatch(t, []app.Playbook{}, result) }) @@ -1421,7 +1421,7 @@ func TestGetTimeLastUpdated(t *testing.T) { playbookStore := setupPlaybookStore(t, db) t.Run("zero playbooks", func(t *testing.T) { - result, err := playbookStore.GetPlaybooks() + result, err := playbookStore.GetActivePlaybooks() require.NoError(t, err) require.ElementsMatch(t, []app.Playbook{}, result) @@ -1540,7 +1540,7 @@ func TestGetPlaybookIDsForUser(t *testing.T) { playbookStore := setupPlaybookStore(t, db) t.Run("zero playbooks", func(t *testing.T) { - result, err := playbookStore.GetPlaybooks() + result, err := playbookStore.GetActivePlaybooks() require.NoError(t, err) require.ElementsMatch(t, []app.Playbook{}, result) }) diff --git a/server/support_packet.go b/server/support_packet.go new file mode 100644 index 0000000000..59e0ca7331 --- /dev/null +++ b/server/support_packet.go @@ -0,0 +1,58 @@ +package main + +import ( + "path/filepath" + + "github.com/hashicorp/go-multierror" + "github.com/pkg/errors" + "gopkg.in/yaml.v3" + + "github.com/mattermost/mattermost-plugin-playbooks/server/app" + "github.com/mattermost/mattermost/server/public/model" + "github.com/mattermost/mattermost/server/public/plugin" +) + +type SupportPacket struct { + Version string `yaml:"version"` + // The total number of playbooks. + TotalPlaybooks int64 `yaml:"total_playbooks"` + // The number of active playbooks. + ActivePlaybooks int64 `yaml:"active_playbooks"` + // The total number of playbook runs. + TotalPlaybookRuns int64 `yaml:"total_playbook_runs"` +} + +func (p *Plugin) GenerateSupportData(_ *plugin.Context) ([]*model.FileData, error) { + var result *multierror.Error + + playbooks, err := p.playbookService.GetPlaybooks() + if err != nil { + result = multierror.Append(result, errors.Wrap(err, "Failed to get total number of playbooks for Support Packet")) + } + + activePlaybooks, err := p.playbookService.GetActivePlaybooks() + if err != nil { + result = multierror.Append(result, errors.Wrap(err, "Failed to get number of active playbooks for Support Packet")) + } + + playbookRuns, err := p.playbookRunService.GetPlaybookRuns(app.RequesterInfo{IsAdmin: true}, app.PlaybookRunFilterOptions{SkipExtras: true}) + if err != nil { + result = multierror.Append(result, errors.Wrap(err, "Failed to get total number of playbook runs for Support Packet")) + } + + diagnostics := SupportPacket{ + Version: manifest.Version, + TotalPlaybooks: int64(len(playbooks)), + ActivePlaybooks: int64(len(activePlaybooks)), + TotalPlaybookRuns: int64(playbookRuns.TotalCount), + } + body, err := yaml.Marshal(diagnostics) + if err != nil { + return nil, errors.Wrap(err, "Failed to marshal diagnostics") + } + + return []*model.FileData{{ + Filename: filepath.Join(manifest.Id, "diagnostics.yaml"), + Body: body, + }}, result.ErrorOrNil() +} diff --git a/server/support_packet_test.go b/server/support_packet_test.go new file mode 100644 index 0000000000..b163c4fc52 --- /dev/null +++ b/server/support_packet_test.go @@ -0,0 +1,39 @@ +package main + +import ( + "archive/zip" + "bytes" + "context" + "path" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "gopkg.in/yaml.v3" +) + +func TestGenerateSupportData(t *testing.T) { + e := Setup(t) + e.CreateBasic() + + data, _, err := e.ServerAdminClient.GenerateSupportPacket(context.Background()) + require.NoError(t, err) + require.NotEmpty(t, data) + + zr, err := zip.NewReader(bytes.NewReader(data), int64(len(data))) + require.NoError(t, err) + require.NotNil(t, zr) + + f, err := zr.Open(path.Join(manifest.Id, "diagnostics.yaml")) + require.NoError(t, err) + require.NotNil(t, f) + + var sp SupportPacket + err = yaml.NewDecoder(f).Decode(&sp) + require.NoError(t, err) + + assert.Equal(t, manifest.Version, sp.Version) + assert.Equal(t, int64(4), sp.TotalPlaybooks) + assert.Equal(t, int64(3), sp.ActivePlaybooks) + assert.Equal(t, int64(1), sp.TotalPlaybookRuns) +} From 09772ecbbdd2a5afa8d007c8ecf11575e8b6b854 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Espino?= Date: Tue, 10 Dec 2024 13:44:28 +0100 Subject: [PATCH 2/3] fix: Add horizontal margins to PaginationRow component (#1970) * fix: Add horizontal margins to PaginationRow component * fixing margin of next/previous buttons --- .gitignore | 2 ++ webapp/src/components/pagination_row.tsx | 3 +-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 9b95b203c6..68e78989b8 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,5 @@ server/e2etest.config.json # Notice .notice-work +.aider* +.env diff --git a/webapp/src/components/pagination_row.tsx b/webapp/src/components/pagination_row.tsx index b5c9ca772d..56d2c43298 100644 --- a/webapp/src/components/pagination_row.tsx +++ b/webapp/src/components/pagination_row.tsx @@ -6,13 +6,12 @@ import {FormattedMessage} from 'react-intl'; import styled from 'styled-components'; const PaginationRowDiv = styled.div` - margin: 10px 0 20px; + margin: 10px 16px 20px; font-size: 14px; display: grid; align-items: center; grid-template-columns: minmax(20rem, min-content) auto minmax(20rem, min-content); justify-content: space-between; - padding: 0 2px; `; const Count = styled.span` From 2ac07ecc4645d58982e871b3937e8e7624c70471 Mon Sep 17 00:00:00 2001 From: Takuya N Date: Thu, 12 Dec 2024 23:03:05 +0900 Subject: [PATCH 3/3] fix(api): remove trailing slash from removeTimelineEvent API (#1966) Signed-off-by: Takuya Noguchi Co-authored-by: Caleb Roseland --- server/api/api.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/api/api.yaml b/server/api/api.yaml index ab80721e5c..456e4f7f2c 100644 --- a/server/api/api.yaml +++ b/server/api/api.yaml @@ -1249,7 +1249,7 @@ paths: 500: $ref: "#/components/responses/500" - /plugins/playbooks/api/v0/runs/{id}/timeline/{event_id}/: + /plugins/playbooks/api/v0/runs/{id}/timeline/{event_id}: delete: summary: Remove a timeline event from the playbook run operationId: removeTimelineEvent