fetch all sentry projects in modal
This commit is contained in:
parent
419ff0b5a1
commit
2d5cf75f52
@ -135,7 +135,10 @@ func (p *Plugin) commandHelp() *model.CommandResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *Plugin) commandSetup(args *model.CommandArgs) (*model.CommandResponse, *model.AppError) {
|
func (p *Plugin) commandSetup(args *model.CommandArgs) (*model.CommandResponse, *model.AppError) {
|
||||||
|
p.API.LogDebug("commandSetup called", "triggerId", args.TriggerId)
|
||||||
|
|
||||||
if args.TriggerId == "" {
|
if args.TriggerId == "" {
|
||||||
|
p.API.LogWarn("commandSetup: triggerId is empty")
|
||||||
return &model.CommandResponse{
|
return &model.CommandResponse{
|
||||||
ResponseType: model.CommandResponseTypeEphemeral,
|
ResponseType: model.CommandResponseTypeEphemeral,
|
||||||
Text: "This command must be run from Mattermost UI",
|
Text: "This command must be run from Mattermost UI",
|
||||||
@ -145,20 +148,61 @@ func (p *Plugin) commandSetup(args *model.CommandArgs) (*model.CommandResponse,
|
|||||||
// Получаем каналы пользователя
|
// Получаем каналы пользователя
|
||||||
channels, appErr := p.API.GetChannelsForTeamForUser(args.TeamId, args.UserId, false)
|
channels, appErr := p.API.GetChannelsForTeamForUser(args.TeamId, args.UserId, false)
|
||||||
if appErr != nil {
|
if appErr != nil {
|
||||||
|
p.API.LogError("Failed to load channels", "error", appErr.Error())
|
||||||
return &model.CommandResponse{
|
return &model.CommandResponse{
|
||||||
ResponseType: model.CommandResponseTypeEphemeral,
|
ResponseType: model.CommandResponseTypeEphemeral,
|
||||||
Text: "❌ Failed to load channels",
|
Text: "❌ Failed to load channels",
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
options := []*model.PostActionOptions{}
|
channelOptions := []*model.PostActionOptions{}
|
||||||
for _, ch := range channels {
|
for _, ch := range channels {
|
||||||
options = append(options, &model.PostActionOptions{
|
channelOptions = append(channelOptions, &model.PostActionOptions{
|
||||||
Text: ch.DisplayName,
|
Text: ch.DisplayName,
|
||||||
Value: ch.Id,
|
Value: ch.Id,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Получаем проекты из Sentry
|
||||||
|
sentryProjects, err := p.fetchSentryProjects()
|
||||||
|
var projectElement model.DialogElement
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
// Если не удалось получить проекты, используем текстовое поле как fallback
|
||||||
|
p.API.LogWarn("Failed to load Sentry projects, using text input", "error", err.Error())
|
||||||
|
projectElement = model.DialogElement{
|
||||||
|
DisplayName: "Sentry project slug",
|
||||||
|
Name: "project_slug",
|
||||||
|
Type: "text",
|
||||||
|
Placeholder: "frontend-app",
|
||||||
|
}
|
||||||
|
} else if len(sentryProjects) == 0 {
|
||||||
|
// Если список проектов пустой, используем текстовое поле
|
||||||
|
p.API.LogWarn("No Sentry projects found, using text input")
|
||||||
|
projectElement = model.DialogElement{
|
||||||
|
DisplayName: "Sentry project slug",
|
||||||
|
Name: "project_slug",
|
||||||
|
Type: "text",
|
||||||
|
Placeholder: "frontend-app",
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Формируем опции для select проектов
|
||||||
|
projectOptions := []*model.PostActionOptions{}
|
||||||
|
for _, proj := range sentryProjects {
|
||||||
|
projectOptions = append(projectOptions, &model.PostActionOptions{
|
||||||
|
Text: fmt.Sprintf("%s (%s)", proj.Name, proj.Slug),
|
||||||
|
Value: proj.Slug,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
projectElement = model.DialogElement{
|
||||||
|
DisplayName: "Sentry project",
|
||||||
|
Name: "project_slug",
|
||||||
|
Type: "select",
|
||||||
|
Options: projectOptions,
|
||||||
|
}
|
||||||
|
p.API.LogDebug("Loaded Sentry projects", "count", len(sentryProjects))
|
||||||
|
}
|
||||||
|
|
||||||
modal := &model.Dialog{
|
modal := &model.Dialog{
|
||||||
Title: "Sentry Setup",
|
Title: "Sentry Setup",
|
||||||
CallbackId: "sentry_setup",
|
CallbackId: "sentry_setup",
|
||||||
@ -169,15 +213,10 @@ func (p *Plugin) commandSetup(args *model.CommandArgs) (*model.CommandResponse,
|
|||||||
DisplayName: "Default channel",
|
DisplayName: "Default channel",
|
||||||
Name: "default_channel_id",
|
Name: "default_channel_id",
|
||||||
Type: "select",
|
Type: "select",
|
||||||
Options: options,
|
Options: channelOptions,
|
||||||
Default: args.ChannelId,
|
Default: args.ChannelId,
|
||||||
},
|
},
|
||||||
{
|
projectElement,
|
||||||
DisplayName: "Sentry project slug",
|
|
||||||
Name: "project_slug",
|
|
||||||
Type: "text",
|
|
||||||
Placeholder: "frontend-app",
|
|
||||||
},
|
|
||||||
|
|
||||||
// ───── Webhook types ─────
|
// ───── Webhook types ─────
|
||||||
{DisplayName: "Event alerts", Name: "hook_event_alert", Type: "bool", Default: "true"},
|
{DisplayName: "Event alerts", Name: "hook_event_alert", Type: "bool", Default: "true"},
|
||||||
@ -187,6 +226,8 @@ func (p *Plugin) commandSetup(args *model.CommandArgs) (*model.CommandResponse,
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p.API.LogDebug("Opening dialog", "elements_count", len(modal.Elements))
|
||||||
|
|
||||||
req := model.OpenDialogRequest{
|
req := model.OpenDialogRequest{
|
||||||
TriggerId: args.TriggerId,
|
TriggerId: args.TriggerId,
|
||||||
URL: "/plugins/ru.loop.plugin.sentry/dialog/submit",
|
URL: "/plugins/ru.loop.plugin.sentry/dialog/submit",
|
||||||
@ -194,16 +235,17 @@ func (p *Plugin) commandSetup(args *model.CommandArgs) (*model.CommandResponse,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if appErr := p.API.OpenInteractiveDialog(req); appErr != nil {
|
if appErr := p.API.OpenInteractiveDialog(req); appErr != nil {
|
||||||
|
p.API.LogError("Failed to open setup dialog", "error", appErr.Error())
|
||||||
return &model.CommandResponse{
|
return &model.CommandResponse{
|
||||||
ResponseType: model.CommandResponseTypeEphemeral,
|
ResponseType: model.CommandResponseTypeEphemeral,
|
||||||
Text: "❌ Failed to open setup dialog: " + appErr.Error(),
|
Text: "❌ Failed to open setup dialog: " + appErr.Error(),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p.API.LogDebug("Dialog opened successfully")
|
||||||
return &model.CommandResponse{}, nil
|
return &model.CommandResponse{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (p *Plugin) commandSetupHook(
|
func (p *Plugin) commandSetupHook(
|
||||||
args *model.CommandArgs,
|
args *model.CommandArgs,
|
||||||
hook string,
|
hook string,
|
||||||
|
|||||||
@ -66,6 +66,62 @@ func (p *Plugin) fetchSentryProject(projectSlug string) (*LinkedProject, error)
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SentryProject представляет проект из Sentry API
|
||||||
|
type SentryProject struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Slug string `json:"slug"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetchSentryProjects получает список всех проектов из Sentry API
|
||||||
|
func (p *Plugin) fetchSentryProjects() ([]SentryProject, error) {
|
||||||
|
cfg := p.GetConfiguration()
|
||||||
|
|
||||||
|
if cfg.SentryUrl == "" || cfg.SentryOrganisationName == "" || cfg.SentryAuthToken == "" {
|
||||||
|
return nil, errors.New("sentry is not configured")
|
||||||
|
}
|
||||||
|
|
||||||
|
url := fmt.Sprintf(
|
||||||
|
"%s/api/0/organizations/%s/projects/",
|
||||||
|
strings.TrimRight(cfg.SentryUrl, "/"),
|
||||||
|
cfg.SentryOrganisationName,
|
||||||
|
)
|
||||||
|
|
||||||
|
p.API.LogDebug("Fetching Sentry projects", "url", url)
|
||||||
|
|
||||||
|
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||||||
|
if err != nil {
|
||||||
|
p.API.LogError("Failed to create request", "error", err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Set("Authorization", "Bearer "+cfg.SentryAuthToken)
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
client := &http.Client{Timeout: 10 * time.Second}
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
p.API.LogError("Failed to execute request", "error", err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
body, _ := io.ReadAll(resp.Body)
|
||||||
|
p.API.LogError("Sentry API error", "status", resp.StatusCode, "body", string(body))
|
||||||
|
return nil, fmt.Errorf("sentry api error (%d): %s", resp.StatusCode, body)
|
||||||
|
}
|
||||||
|
|
||||||
|
var projects []SentryProject
|
||||||
|
if err := json.NewDecoder(resp.Body).Decode(&projects); err != nil {
|
||||||
|
p.API.LogError("Failed to decode response", "error", err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
p.API.LogDebug("Fetched Sentry projects", "count", len(projects))
|
||||||
|
return projects, nil
|
||||||
|
}
|
||||||
|
|
||||||
// linkProjectToChannel связывает проект Sentry с каналом Mattermost
|
// linkProjectToChannel связывает проект Sentry с каналом Mattermost
|
||||||
func (p *Plugin) linkProjectToChannel(
|
func (p *Plugin) linkProjectToChannel(
|
||||||
projectSlug string,
|
projectSlug string,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user