Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Standard issue filter provider, add issue complexity and states #3469

Merged
merged 1 commit into from
Jan 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion conf/dop/dop.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,12 @@ erda.dop.contribution:

# component-protocol framework
component-protocol:

# default components
component-protocol.default-components.issueFilter:

# components
## issue manage
component-protocol.components.issue-manage.content:
component-protocol.components.issue-manage.head:
component-protocol.components.issue-manage.issueExport:
Expand Down Expand Up @@ -305,7 +310,7 @@ component-protocol.components.requirement-task-overview.stackChartFilter:
## issue-kanban
component-protocol.components.issue-kanban.toolbar:
component-protocol.components.issue-kanban.issueExport:
component-protocol.components.issue-kanban.issueFilter:
# component-protocol.components.issue-kanban.issueFilter:
component-protocol.components.issue-kanban.issueImport:
component-protocol.components.issue-kanban.issueKanbanV2:
component-protocol.components.issue-kanban.page:
Expand Down
1 change: 1 addition & 0 deletions modules/dop/component-protocol/components/all.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,5 @@ import (
_ "github.com/erda-project/erda/modules/dop/component-protocol/components/scenes-import-record"
_ "github.com/erda-project/erda/modules/dop/component-protocol/components/test-dashboard"
_ "github.com/erda-project/erda/modules/dop/component-protocol/components/test-report"
_ "github.com/erda-project/erda/providers/component-protocol/issueFilter"
)
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import (
_ "github.com/erda-project/erda/modules/dop/component-protocol/components/issue-kanban/content"
_ "github.com/erda-project/erda/modules/dop/component-protocol/components/issue-kanban/inputFilter"
_ "github.com/erda-project/erda/modules/dop/component-protocol/components/issue-kanban/issueExport"
_ "github.com/erda-project/erda/modules/dop/component-protocol/components/issue-kanban/issueFilter"
_ "github.com/erda-project/erda/modules/dop/component-protocol/components/issue-kanban/issueImport"
_ "github.com/erda-project/erda/modules/dop/component-protocol/components/issue-kanban/issueKanbanV2"
_ "github.com/erda-project/erda/modules/dop/component-protocol/components/issue-kanban/issueOperations"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ type FrontendConditions struct {
CreatedAtStartEnd []*int64 `json:"createdAtStartEnd,omitempty"`
FinishedAtStartEnd []*int64 `json:"finishedAtStartEnd,omitempty"`
ClosedAtStartEnd []*int64 `json:"closedAtStartEnd,omitempty"`
Complexities []apistructs.IssueComplexity `json:"complexities,omitempty"`
}

func (f *ComponentFilter) generateFrontendConditionProps(ctx context.Context, fixedIssueType string, state State) FrontendConditionProps {
Expand Down Expand Up @@ -136,20 +137,18 @@ func (f *ComponentFilter) generateFrontendConditionProps(ctx context.Context, fi
},
},
{
Key: PropConditionKeySeverities,
Label: cputil.I18n(ctx, "severity"),
EmptyText: cputil.I18n(ctx, "all"),
Fixed: false,
ShowIndex: 0,
HaveFilter: false,
Type: filter.PropConditionTypeSelect,
Placeholder: cputil.I18n(ctx, "choose-severity"),
Key: PropConditionKeyComplexity,
Label: cputil.I18n(ctx, "complexity"),
EmptyText: cputil.I18n(ctx, "all"),
Fixed: false,
ShowIndex: 0,
HaveFilter: false,
Type: filter.PropConditionTypeSelect,
// Placeholder: cputil.I18n(ctx, "choose-severity"),
Options: []filter.PropConditionOption{
{Label: cputil.I18n(ctx, "fatal"), Value: "FATAL", Icon: ""},
{Label: cputil.I18n(ctx, "serious"), Value: "SERIOUS", Icon: ""},
{Label: cputil.I18n(ctx, "ordinary"), Value: "NORMAL", Icon: ""},
{Label: cputil.I18n(ctx, "slight"), Value: "SLIGHT", Icon: ""},
{Label: cputil.I18n(ctx, "suggest"), Value: "SUGGEST", Icon: ""},
{Label: cputil.I18n(ctx, "HARD"), Value: "HARD", Icon: ""},
{Label: cputil.I18n(ctx, "NORMAL"), Value: "NORMAL", Icon: ""},
{Label: cputil.I18n(ctx, "EASY"), Value: "EASY", Icon: ""},
},
},
{
Expand Down Expand Up @@ -257,6 +256,24 @@ func (f *ComponentFilter) generateFrontendConditionProps(ctx context.Context, fi
}

if fixedIssueType == apistructs.IssueTypeBug.String() {
severity := filter.PropCondition{
Key: PropConditionKeySeverities,
Label: cputil.I18n(ctx, "severity"),
EmptyText: cputil.I18n(ctx, "all"),
Fixed: false,
ShowIndex: 0,
HaveFilter: false,
Type: filter.PropConditionTypeSelect,
Placeholder: cputil.I18n(ctx, "choose-severity"),
Options: []filter.PropConditionOption{
{Label: cputil.I18n(ctx, "fatal"), Value: "FATAL", Icon: ""},
{Label: cputil.I18n(ctx, "serious"), Value: "SERIOUS", Icon: ""},
{Label: cputil.I18n(ctx, "ordinary"), Value: "NORMAL", Icon: ""},
{Label: cputil.I18n(ctx, "slight"), Value: "SLIGHT", Icon: ""},
{Label: cputil.I18n(ctx, "suggest"), Value: "SUGGEST", Icon: ""},
},
}
conditionProps = append(conditionProps[:4], append([]filter.PropCondition{severity}, conditionProps[4:]...)...)
conditionProps = append(conditionProps, filter.PropCondition{
Key: PropConditionKeyClosed,
Label: cputil.I18n(ctx, "closed-at"),
Expand Down Expand Up @@ -349,6 +366,7 @@ var (
PropConditionKeyCreatedAtStartEnd filter.PropConditionKey = "createdAtStartEnd"
PropConditionKeyFinishedAtStartEnd filter.PropConditionKey = "finishedAtStartEnd"
PropConditionKeyClosed filter.PropConditionKey = "closedAtStartEnd"
PropConditionKeyComplexity filter.PropConditionKey = "complexities"
)

func GetAllOperations() map[filter.OperationKey]filter.Operation {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ func (f *ComponentFilter) generateIssuePagingRequest() (apistructs.IssuePagingRe
StartClosedAt: startClosedAt,
EndClosedAt: endClosedAt,
Priority: f.State.FrontendConditionValues.Priorities,
Complexity: nil,
Complexity: f.State.FrontendConditionValues.Complexities,
Severity: f.State.FrontendConditionValues.Severities,
RelatedIssueIDs: nil,
Source: "",
Expand Down
12 changes: 10 additions & 2 deletions modules/openapi/component-protocol/components/base/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,15 @@ func InitProvider(scenario, compName string) {

// InitProviderWithCreator register component as provider with custom providerCreator.
func InitProviderWithCreator(scenario, compName string, creator servicehub.Creator) {
initProviderWithCustomName(MakeComponentProviderName(scenario, compName), creator)
}

func initProviderWithCustomName(providerName string, creator servicehub.Creator) {
if creator == nil {
creator = func() servicehub.Provider { return &DefaultProvider{} }
}
servicehub.Register(MakeComponentProviderName(scenario, compName), &servicehub.Spec{Creator: creator})
compCreatorMap[MakeComponentProviderName(scenario, compName)] = func() Creators {
servicehub.Register(providerName, &servicehub.Spec{Creator: creator})
compCreatorMap[providerName] = func() Creators {
switch creator().(type) {
case cptype.IComponent:
return Creators{ComponentCreator: func() cptype.IComponent {
Expand All @@ -90,3 +94,7 @@ func InitProviderWithCreator(scenario, compName string, creator servicehub.Creat
}
}()
}

func InitProviderToDefaultNamespace(compName string, creator servicehub.Creator) {
initProviderWithCustomName(defaultComponentProviderNamePrefix+compName, creator)
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ import (
)

const (
componentProviderNamePrefix = "component-protocol.components."
componentProviderNamePrefix = "component-protocol.components."
defaultComponentProviderNamePrefix = "component-protocol.default-components."
)

func MustGetScenarioAndCompNameFromProviderKey(providerKey string) (scenario, compName, instanceName string) {
Expand All @@ -33,6 +34,10 @@ func MustGetScenarioAndCompNameFromProviderKey(providerKey string) (scenario, co
}

func GetScenarioAndCompNameFromProviderKey(providerKey string) (scenario, compName, instanceName string, err error) {
if strings.HasPrefix(providerKey, defaultComponentProviderNamePrefix) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add ut for this.

ss := strings.SplitN(providerKey, ".", 3)
return "", ss[2], ss[2], nil
}
if !strings.HasPrefix(providerKey, componentProviderNamePrefix) {
return "", "", "", fmt.Errorf("invalid prefix")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,16 @@ func TestGetScenarioAndCompNameFromProviderKey(t *testing.T) {
wantInstanceName: "",
haveErr: true,
},
{
name: "valid default namespace key",
args: args{
providerKey: "component-protocol.default-components.filter",
},
wantScenario: "",
wantCompName: "filter",
wantInstanceName: "filter",
haveErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,15 @@
package issueFilter

import (
"context"
"strings"

model "github.com/erda-project/erda-infra/providers/component-protocol/components/filter/models"
"github.com/erda-project/erda-infra/providers/component-protocol/utils/cputil"
"github.com/erda-project/erda/apistructs"
)

var (
const (
PropConditionKeyFilterID string = "filterID" // special, need emit it when hashing filter
PropConditionKeyIterationIDs string = "iterationIDs"
PropConditionKeyTitle string = "title"
Expand All @@ -36,8 +39,28 @@ var (
PropConditionKeyCreatedAtStartEnd string = "createdAtStartEnd"
PropConditionKeyFinishedAtStartEnd string = "finishedAtStartEnd"
PropConditionKeyClosed string = "closedAtStartEnd"
PropConditionKeyComplexity string = "complexities"
)

type FrontendConditions struct {
FilterID string `json:"filterID,omitempty"`
IterationIDs []int64 `json:"iterationIDs,omitempty"`
Title string `json:"title,omitempty"`
StateBelongs []apistructs.IssueStateBelong `json:"stateBelongs,omitempty"`
States []int64 `json:"states,omitempty"`
LabelIDs []uint64 `json:"labelIDs,omitempty"`
Priorities []apistructs.IssuePriority `json:"priorities,omitempty"`
Severities []apistructs.IssueSeverity `json:"severities,omitempty"`
CreatorIDs []string `json:"creatorIDs,omitempty"`
AssigneeIDs []string `json:"assigneeIDs,omitempty"`
OwnerIDs []string `json:"ownerIDs,omitempty"`
BugStages []string `json:"bugStages,omitempty"`
CreatedAtStartEnd []*int64 `json:"createdAtStartEnd,omitempty"`
FinishedAtStartEnd []*int64 `json:"finishedAtStartEnd,omitempty"`
ClosedAtStartEnd []*int64 `json:"closedAtStartEnd,omitempty"`
Complexities []apistructs.IssueComplexity `json:"complexities,omitempty"`
}

func (f *IssueFilter) ConditionRetriever() ([]interface{}, error) {
needIterationCond := true
if f.InParams.FrontendFixedIteration != "" {
Expand Down Expand Up @@ -89,6 +112,12 @@ func (f *IssueFilter) ConditionRetriever() ([]interface{}, error) {
*model.NewSelectOption(cputil.I18n(f.sdk.Ctx, "architecture-design"), "architectureDesign"),
*model.NewSelectOption(cputil.I18n(f.sdk.Ctx, "code-development"), "codeDevelopment"),
}
if f.InParams.FrontendFixedIssueType == apistructs.IssueTypeTask.String() || f.InParams.FrontendFixedIssueType == apistructs.IssueTypeBug.String() {
stageOptions, err = f.getPropStagesOptions(f.InParams.FrontendFixedIssueType)
if err != nil {
return nil, err
}
}
stage := model.NewSelectCondition(PropConditionKeyBugStages, func() string {
switch f.InParams.FrontendFixedIssueType {
case "ALL":
Expand All @@ -110,35 +139,64 @@ func (f *IssueFilter) ConditionRetriever() ([]interface{}, error) {
if needIterationCond {
conditions = []interface{}{iterations}
}

complexityOptions := []model.SelectOption{
*model.NewSelectOption(cputil.I18n(f.sdk.Ctx, "HARD"), "HARD"),
*model.NewSelectOption(cputil.I18n(f.sdk.Ctx, "NORMAL"), "NORMAL"),
*model.NewSelectOption(cputil.I18n(f.sdk.Ctx, "EASY"), "EASY"),
}
complexity := model.NewSelectCondition(PropConditionKeyComplexity, cputil.I18n(f.sdk.Ctx, "complexity"), complexityOptions)

// statesMap, err := f.issueStateSvc.GetIssueStatesMap(&apistructs.IssueStatesGetRequest{
// ProjectID: f.InParams.ProjectID,
// })
// if err != nil {
// return nil, err
// }

// status := func() interface{} {
// switch f.InParams.FrontendFixedIssueType {
// case "ALL":
// return model.NewSelectConditionWithChildren(PropConditionKeyStates, cputil.I18n(f.sdk.Ctx, "state"), convertAllConditions(f.sdk.Ctx, statesMap))
// case apistructs.IssueTypeRequirement.String():
// return model.NewSelectCondition(PropConditionKeyStates, cputil.I18n(f.sdk.Ctx, "state"), convertConditions(statesMap[apistructs.IssueTypeRequirement]))
// case apistructs.IssueTypeTask.String():
// return model.NewSelectCondition(PropConditionKeyStates, cputil.I18n(f.sdk.Ctx, "state"), convertConditions(statesMap[apistructs.IssueTypeTask]))
// case apistructs.IssueTypeBug.String():
// return model.NewSelectCondition(PropConditionKeyStates, cputil.I18n(f.sdk.Ctx, "state"), convertConditions(statesMap[apistructs.IssueTypeBug]))
// }
// return nil
// }()

switch f.InParams.FrontendFixedIssueType {
case apistructs.IssueTypeRequirement.String():
conditions = append(conditions, labels, priority, creator, assignee, created, finished)
conditions = append(conditions, labels, priority, complexity, creator, assignee, created, finished)
case apistructs.IssueTypeTask.String():
conditions = append(conditions, labels, priority, creator, assignee, stage, created, finished)
conditions = append(conditions, labels, priority, complexity, creator, assignee, stage, created, finished)
case apistructs.IssueTypeBug.String():
conditions = append(conditions, labels, priority, severity, creator, assignee, owner, stage, created, finished, closed)
conditions = append(conditions, labels, priority, complexity, severity, creator, assignee, owner, stage, created, finished, closed)
case "ALL":
conditions = append(conditions, labels, priority, complexity, creator, assignee, owner, created, finished)
}

return conditions, nil
// stateBelongs := map[string][]apistructs.IssueStateBelong{
// "TASK": {apistructs.IssueStateBelongOpen, apistructs.IssueStateBelongWorking},
// "REQUIREMENT": {apistructs.IssueStateBelongOpen, apistructs.IssueStateBelongWorking},
// "BUG": {apistructs.IssueStateBelongOpen, apistructs.IssueStateBelongWorking, apistructs.IssueStateBelongWontfix, apistructs.IssueStateBelongReopen, apistructs.IssueStateBelongResolved},
// "ALL": {apistructs.IssueStateBelongOpen, apistructs.IssueStateBelongWorking, apistructs.IssueStateBelongWontfix, apistructs.IssueStateBelongReopen, apistructs.IssueStateBelongResolved},
// }[f.InParams.FrontendFixedIssueType]
// types := []apistructs.IssueType{apistructs.IssueTypeRequirement, apistructs.IssueTypeTask, apistructs.IssueTypeBug}
// res := make(map[string][]int64)
// res["ALL"] = make([]int64, 0)
// for _, v := range types {
// req := &apistructs.IssueStatesGetRequest{
// ProjectID: f.InParams.ProjectID,
// StateBelongs: stateBelongs,
// IssueType: v,
// }
// ids, err := f.issueStateSvc.GetIssueStateIDs(req)
// if err != nil {
// panic(err)
// }
// res[v.String()] = ids
// res["ALL"] = append(res["ALL"], ids...)
// }
}

func convertConditions(status []apistructs.IssueStatus) []model.SelectOption {
options := make([]model.SelectOption, 0, len(status))
for _, i := range status {
options = append(options, *model.NewSelectOption(i.StateName, i.StateID))
}
return options
}

func convertAllConditions(ctx context.Context, stateMap map[apistructs.IssueType][]apistructs.IssueStatus) []model.SelectOptionWithChildren {
options := make([]model.SelectOptionWithChildren, 0, len(stateMap))
for i, v := range stateMap {
options = append(options, model.SelectOptionWithChildren{
SelectOption: *model.NewSelectOption(cputil.I18n(ctx, strings.ToLower(i.String())), i.String()),
Children: convertConditions(v),
})
}
return options
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ func (f *IssueFilter) FilterSet() ([]filter.SetItem, error) {
if err != nil {
return nil, err
}
// for
options = append(options, filter.SetItem{
ID: i.ID,
Label: i.Name,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package issueFilter

import (
model "github.com/erda-project/erda-infra/providers/component-protocol/components/filter/models"
"github.com/erda-project/erda-infra/providers/component-protocol/utils/cputil"
"github.com/erda-project/erda/apistructs"
)

Expand Down Expand Up @@ -70,5 +71,19 @@ func (f *IssueFilter) getProjectMemberOptions() ([]model.SelectOption, error) {
member.UserID,
))
}
selectMe := model.NewSelectOption(cputil.I18n(f.sdk.Ctx, "choose-yourself"), f.sdk.Identity.UserID).WithFix(true)
results = append(results, *selectMe)
return results, nil
}

func (f *IssueFilter) getPropStagesOptions(tp string) ([]model.SelectOption, error) {
stages, err := f.bdl.GetIssueStage(int64(f.InParams.OrgID), apistructs.IssueType(tp))
if err != nil {
return nil, err
}
var options []model.SelectOption
for _, stage := range stages {
options = append(options, *model.NewSelectOption(stage.Name, stage.Value))
}
return options, nil
}
Loading