Skip to content

Commit

Permalink
feat(dop): issue excel title support i18n (#6085)
Browse files Browse the repository at this point in the history
* ExportExcelIssueRequest add ExportType (byFilter/full)

* excel title support i18n

* remove useless UpdatedAt field in excel

* skip unknown common fields

* no need to check projectIssueTotalNum, use exportType directly

* polish code

* fix start error by issue-excel.yaml
  • Loading branch information
sfwn authored Oct 10, 2023
1 parent df6b959 commit cb27bb8
Show file tree
Hide file tree
Showing 20 changed files with 362 additions and 90 deletions.
1 change: 1 addition & 0 deletions api/proto/dop/issue/core/core.proto
Original file line number Diff line number Diff line change
Expand Up @@ -994,6 +994,7 @@ message ExportExcelIssueRequest {
repeated uint64 projectIDs = 41;
string locale = 42;
bool isDownloadTemplate = 43 [json_name = "isDownload"];
string exportType = 44; // byFilter, full
}

message ExportExcelIssueResponse {
Expand Down
1 change: 1 addition & 0 deletions cmd/erda-server/bootstrap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ i18n:
- conf/i18n/project-pipeline.yaml # dop
- conf/i18n/api-management-trans.yaml # dop
- conf/i18n/contribution.yaml # dop
- conf/i18n/issue-excel.yaml # dop

gorm.v2:
host: "${MYSQL_HOST}"
Expand Down
40 changes: 40 additions & 0 deletions cmd/erda-server/conf/i18n/issue-excel.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
zh:
# Common
Common: 通用字段
ID: ID
IterationName: 迭代
IssueType: 类型
IssueTitle: 标题
Content: 内容
State: 状态
Priority: 优先级
Complexity: 复杂度
Severity: 严重程度
CreatorName: 创建人
AssigneeName: 处理人
CreatedAt: 创建时间
PlanStartedAt: 计划开始时间
PlanFinishedAt: 计划结束时间
StartAt: 实际开始时间
FinishAt: 实际结束时间
EstimateTime: 预估耗时
Labels: 标签
ConnectionIssueIDs: 关联事项ID列表
CustomFields: 自定义字段

# RequirementOnly
RequirementOnly: 需求专属字段
InclusionIssueIDs: 待办事项ID列表

# TaskOnly
TaskOnly: 任务专属字段
TaskType: 任务类型

# BugOnly
BugOnly: 缺陷专属字段
OwnerName: 负责人
Source: 来源
ReopenCount: 重开次数

en: # use key directly
Common: Common # need this line to pass i18n provider validation
1 change: 1 addition & 0 deletions internal/apps/dop/initialize.go
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,7 @@ func (p *provider) initEndpoints(db *dao.DBClient) (*endpoints.Endpoints, error)

p.IssueCoreSvc.WithTestplan(testPlan)
p.IssueCoreSvc.WithTestcase(testCaseSvc)
p.IssueCoreSvc.WithTranslator(p.CPTran)

workBench := workbench.New(
workbench.WithBundle(bdl.Bdl),
Expand Down
23 changes: 5 additions & 18 deletions internal/apps/dop/providers/issue/core/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -305,8 +305,9 @@ func (i *IssueService) createDataForFulfillCommon(locale string, userID string,
// result
dataForFulfill := vars.DataForFulfill{
Bdl: i.bdl,
Locale: i.bdl.GetLocale(locale),
ProjectID: projectID,
Tran: i.translator.Translator("issue-excel"),
Lang: vars.GetI18nLang(locale),
OrgID: orgID,
UserID: userID,
StageMap: stageMap,
Expand Down Expand Up @@ -382,23 +383,9 @@ func (i *IssueService) createDataForFulfillForExport(req *pb.ExportExcelIssueReq
return nil, fmt.Errorf("failed to page issues, err: %v", err)
}
data.ExportOnly.Issues = issues
// get total
_, projectIssueTotalNum, err := i.db.PagingIssues(pb.PagingIssueRequest{
ProjectID: data.ProjectID,
PageNo: 1,
PageSize: 1,
External: req.External,
OnlyIdResult: true,
}, false)
if err != nil {
return nil, fmt.Errorf("failed to get project issues total num, err: %v", err)
}
if uint64(len(issues)) >= projectIssueTotalNum {
// TODO 前端明确区分是项目迁移还是正常导出
// 当用户在 UI 上清除所有筛选条件后,'按筛选条件导出' 和 '全量导出' 的差别就在 external 和 orderby 这两个字段
if req.External == false && req.OrderBy == "" {
data.ExportOnly.IsFullExport = true
}
// 前端明确区分是`按筛选条件导出`还是`全量导出`
if req.ExportType == vars.ExportTypeFull {
data.ExportOnly.IsFullExport = true
}
data.ExportOnly.IsDownloadTemplate = req.IsDownloadTemplate
data.ExportOnly.FileNameWithExt = "issue-export.xlsx"
Expand Down
5 changes: 5 additions & 0 deletions internal/apps/dop/providers/issue/core/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,11 @@ func (p *provider) Init(ctx servicehub.Context) error {
req.OrgID = orgID
// all type return same sample
req.Type = nil
// locale
lang := apis.HTTPLanguage(r)
if lang.Len() > 0 {
req.Locale = lang[0].String()
}
// use new excel export
dataForFulfill, err := p.issueService.createDataForFulfillForExport(&req)
if err != nil {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ func ExportFile(w io.Writer, data *vars.DataForFulfill) (err error) {
&sheet_state.Handler{},
}

sheet_issue.InitI18nMap(data)

for _, h := range handlers {
// only full export need to export other sheets
if h.SheetName() != vars.NameOfSheetIssue {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ func ImportFile(r io.Reader, data *vars.DataForFulfill) error {
&sheet_state.Handler{},
}

sheet_issue.InitI18nMap(data)

for _, h := range handlers {
if err := h.ImportSheet(data, df); err != nil {
return fmt.Errorf("failed to decode sheet %q, err: %v", h.SheetName(), err)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func (h *Handler) ExportSheet(data *vars.DataForFulfill) (excel.Rows, error) {
if err != nil {
return nil, fmt.Errorf("failed to gen sheet title and data by column, err: %v", err)
}
excelRows, err := mapByColumns.ConvertToExcelSheet()
excelRows, err := mapByColumns.ConvertToExcelSheet(data)
if err != nil {
return nil, fmt.Errorf("failed to convert to excel sheet, err: %v", err)
}
Expand Down Expand Up @@ -90,11 +90,11 @@ func genIssueSheetTitleAndDataByColumn(data *vars.DataForFulfill) (*IssueSheetMo

func getCustomFieldBelongingTypeFromUUID(uuid IssueSheetColumnUUID) pb.IssueTypeEnum_Type {
switch uuid.Decode()[0] {
case "RequirementOnly":
case fieldRequirementOnly:
return pb.IssueTypeEnum_REQUIREMENT
case "TaskOnly":
case fieldTaskOnly:
return pb.IssueTypeEnum_TASK
case "BugOnly":
case fieldBugOnly:
return pb.IssueTypeEnum_BUG
default:
panic(fmt.Errorf("failed to get issue type from uuid: %s", uuid.Decode()[0]))
Expand Down Expand Up @@ -140,7 +140,6 @@ func getIssueSheetModels(data *vars.DataForFulfill) ([]vars.IssueSheetModel, err
CreatorName: getUserNick(data, issue.Creator),
AssigneeName: getUserNick(data, issue.Assignee),
CreatedAt: pbutil.GetTimeInLocal(issue.CreatedAt),
UpdatedAt: pbutil.GetTimeInLocal(issue.UpdatedAt),
PlanStartedAt: pbutil.GetTimeInLocal(issue.PlanStartedAt),
PlanFinishedAt: pbutil.GetTimeInLocal(issue.PlanFinishedAt),
StartAt: pbutil.GetTimeInLocal(issue.StartTime),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ func GenerateSampleIssueSheetModels(data *vars.DataForFulfill) []vars.IssueSheet
CreatorName: data.UserID,
AssigneeName: data.UserID,
CreatedAt: &now,
UpdatedAt: &now,
PlanStartedAt: &now,
PlanFinishedAt: &nowPlusOneDay,
StartAt: &now,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// Copyright (c) 2021 Terminus, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package sheet_issue

import (
"github.com/erda-project/erda-infra/providers/i18n"
"github.com/erda-project/erda/internal/apps/dop/providers/issue/core/query/issueexcel/vars"
)

const (
// Common
fieldCommon = "Common"
fieldID = "ID"
fieldIterationName = "IterationName"
fieldIssueType = "IssueType"
fieldIssueTitle = "IssueTitle"
fieldContent = "Content"
fieldState = "State"
fieldPriority = "Priority"
fieldComplexity = "Complexity"
fieldSeverity = "Severity"
fieldCreatorName = "CreatorName"
fieldAssigneeName = "AssigneeName"
fieldCreatedAt = "CreatedAt"
fieldPlanStartedAt = "PlanStartedAt"
fieldPlanFinishedAt = "PlanFinishedAt"
fieldStartAt = "StartAt"
fieldFinishAt = "FinishAt"
fieldEstimateTime = "EstimateTime"
fieldLabels = "Labels"
fieldConnectionIssueIDs = "ConnectionIssueIDs"
fieldCustomFields = "CustomFields"

// RequirementOnly
fieldRequirementOnly = "RequirementOnly"
fieldInclusionIssueIDs = "InclusionIssueIDs"

// TaskOnly
fieldTaskOnly = "TaskOnly"
fieldTaskType = "TaskType"

// BugOnly
fieldBugOnly = "BugOnly"
fieldOwnerName = "OwnerName"
fieldSource = "Source"
fieldReopenCount = "ReopenCount"
)

var excelFields = []string{
// Common
fieldCommon,
fieldID,
fieldIterationName,
fieldIssueType,
fieldIssueTitle,
fieldContent,
fieldState,
fieldPriority,
fieldComplexity,
fieldSeverity,
fieldCreatorName,
fieldAssigneeName,
fieldCreatedAt,
fieldPlanStartedAt,
fieldPlanFinishedAt,
fieldStartAt,
fieldFinishAt,
fieldEstimateTime,
fieldLabels,
fieldConnectionIssueIDs,
fieldCustomFields,

// RequirementOnly
fieldRequirementOnly,
fieldInclusionIssueIDs,

// TaskOnly
fieldTaskOnly,
fieldTaskType,

// BugOnly
fieldBugOnly,
fieldOwnerName,
fieldSource,
fieldReopenCount,
}

var (
i18nMapByText = make(map[string]string)
)

func InitI18nMap(data *vars.DataForFulfill) {
for _, key := range excelFields {
i18nMapByText[key] = key // self
// en-US
enLang, _ := i18n.ParseLanguageCode("en-US")
i18nMapByText[data.Tran.Text(enLang, key)] = key
// zh-CN
zhLang, _ := i18n.ParseLanguageCode("zh-CN")
i18nMapByText[data.Tran.Text(zhLang, key)] = key
}
}
Loading

0 comments on commit cb27bb8

Please sign in to comment.