- 프론트엔드 아키텍처
- 새로운 작업 항목 위젯을 프런트엔드의 상세 보기에서 구현하는 단계
- 새 작업 항목 위젯을 생성 뷰의 프론트엔드에 구현하는 단계
- 생성 뷰에 값을 저장하기 위해 사용되는 Apollo 캐시
- Apollo 캐시에서 생성 양식의 새로운 위젯 지원
- 작업 항목 유형에 위젯 매핑
- 백엔드 아키텍처
- 새로운 백엔드 위젯 생성
작업 항목 위젯
프론트엔드 아키텍처
작업 항목을 위한 위젯은 프론트엔드 위젯에서 영감을 많이 받았습니다.
작업 항목은 발행 가능한 항목과 건축적으로 다르기 때문에 몇 가지 차이를 예상할 수 있습니다.
GraphQL (Vue Apollo)는 작업 항목 위젯 스택의 핵심을 구성합니다.
작업 항목을 위한 위젯 정보 가져오기
작업 항목 페이지를 표시하기 위해, 프론트엔드는 표시하려는 작업 항목에서 사용 가능한 위젯을 알아야 합니다. 이를 위해 위젯 목록을 가져와야 하며, 쿼리는 다음과 같이 됩니다:
query workItem($workItemId: WorkItemID!) {
workItem(id: $workItemId) {
id
widgets {
... on WorkItemWidgetAssignees {
type
assignees {
nodes {
name
}
}
}
}
}
}
GraphQL 쿼리 및 변조
GraphQL 쿼리 및 변조는 작업 항목과 무관합니다. 작업 항목 쿼리 및 변조는 위젯 수준에서 이루어져야 하므로 위젯은 독립적으로 재사용 가능한 컴포넌트입니다.
작업 항목 쿼리와 변조는 모든 작업 항목 유형을 지원하며 동적이어야 합니다.
위젯 식별자를 지정하여 작업 항목 속성을 쿼리하고 변조할 수 있어야 합니다.
다음 쿼리 예시에서, 설명 위젯은 쿼리 및 변조를 사용하여 모든 작업 항목의 설명을 보여주고 업데이트합니다:
query workItem($fullPath: ID!, $iid: String!) {
workspace: namespace(fullPath: $fullPath) {
id
workItem(iid: $iid) {
id
iid
widgets {
... on WorkItemWidgetDescription {
description
descriptionHtml
}
}
}
}
}
변조 예시:
mutation {
workItemUpdate(input: {
id: "gid://gitlab/AnyWorkItem/499"
descriptionWidget: {
description: "새 설명"
}
}) {
errors
workItem {
description
}
}
}
위젯의 책임 및 구조
위젯은 제목, 설명 또는 레이블과 같은 단일 속성을 표시하고 업데이트할 책임이 있습니다.
위젯은 모든 유형의 작업 항목을 지원해야 합니다.
컴포넌트의 재사용성을 극대화하기 위해, 위젯은 책임이 있는 속성의 작업 항목 쿼리 및 변조를 소유하는 필드 래퍼여야 합니다.
필드 컴포넌트는 일반적이고 간단한 컴포넌트입니다. 입력 필드, 날짜 선택기 또는 드롭다운 목록과 같은 속성이나 작업 항목 세부사항에 대한 지식이 없습니다.
위젯은 작업 항목에 따라 다양한 사용 사례를 지원하기 위해 구성 가능해야 합니다.
위젯을 만들 때, props 및 주입된 속성의 사용을 최소화하면서 추가 컨텍스트를 제공하기 위해 슬롯을 사용하세요.
예시
현재, 우리는 많은 편집 가능한 위젯을 보유하고 있으며, 이들은 폴더에서 찾을 수 있습니다. 이들은 다음과 같습니다:
우리는 또한 새로운 드롭다운을 가진 어떤 위젯에도 사용할 수 있는 재사용 가능한 기본 드롭다운 위젯 래퍼를 보유하고 있습니다. 이는 다중 선택 및 단일 선택을 모두 지원합니다.
새로운 작업 항목 위젯을 프런트엔드의 상세 보기에서 구현하는 단계
새로운 위젯 작업 시작 전에
-
새로운 위젯의 범위와 디자인을 준비했는지 확인하세요.
-
새로운 위젯이 이미 백엔드에 구현되어 있고 유효한 작업 항목 유형에 대해 작업 항목 쿼리에서 반환되고 있는지 확인하세요. 다중 버전 호환성으로 인해 백엔드와 프런트엔드는 별도의 마일스톤에 있어야 합니다.
-
workItemUpdate
에서 위젯 업데이트가 지원되는지 확인하세요. -
모든 위젯은 요구 사항이 다르므로, 사전에 질문하고 PM/UX와 논의한 후 MVC를 만드는 것이 좋습니다.
새로운 위젯 작업 시작 시
-
드롭다운, 텍스트 입력 또는 기타 사용자 정의 디자인과 같은 입력 필드에 따라 기존 래퍼를 사용하거나 완전히 새로운 컴포넌트를 만들어야 합니다.
-
이상적으로 모든 새로운 위젯은 테스트 공간을 확보하기 위해 FF 뒤에 있어야 합니다. 위젯에 우선 순위가 없는 경우에는 말입니다.
-
폴더에 새로운 위젯을 생성하세요.
-
사이드바에 있는 편집 가능한 위젯이라면 work_item_attributes_wrapper에 포함시켜야 합니다.
단계
새로운 작업 항목 위젯 추가 프로세스의 예시는 병합 요청 #159720를 참조하세요.
-
app/assets/javascripts/work_items/constants.js
에I18N_WORK_ITEM_ERROR_FETCHING_<widget_name>
을 정의하세요. -
app/assets/javascripts/work_items/components/work_item_<widget_name>.vue
또는ee/app/assets/javascripts/work_items/components/work_item_<widget_name>.vue
에서 컴포넌트를 생성하세요.- 컴포넌트는
workItemByIidQuery
에서 가능한 모든 props를 수신해서는 안 됩니다. - 이슈 #461761 참조.
- 컴포넌트는
-
app/assets/javascripts/work_items/components/work_item_attributes_wrapper.vue
에서 보기/편집 작업 항목 화면에 컴포넌트를 추가하세요. -
위젯이 새로운 작업 항목을 생성할 때 사용 가능하다면:
-
app/assets/javascripts/work_items/components/create_work_item.vue
에서 작업 항목 생성 화면에 컴포넌트를 추가하세요. -
app/assets/javascripts/work_items/graphql/typedefs.graphql
에 로컬 입력 유형을 정의하세요. -
app/assets/javascripts/work_items/graphql/cache_utils.js
에서 위젯을 위한 새로운 작업 항목 상태 GraphQL 데이터를 스텁하세요. -
app/assets/javascripts/work_items/graphql/resolvers.js
에서 GraphQL이 GraphQL 데이터를 업데이트하는 방법을 정의하세요.-
단일 값 위젯에 대해서는 값이
null
일 때 우리가 지운 것인지, 또는 우리가 설정하지 않았기 때문에null
인지 구분할 수 없기 때문에 특별한CLEAR_VALUE
상수가 필요합니다.예를 들어
ee/app/assets/javascripts/work_items/components/work_item_health_status.vue
.대부분의 다중 값을 지원하는 위젯에는 필요하지 않습니다. 여기서는
[]
와null
을 구분할 수 있습니다. -
작업 생성 보기에 값을 저장하기 위해 Apollo 캐시가 어떻게 사용되는지에 대해 자세히 읽어보세요.
-
-
-
위젯에 대한 GraphQL 쿼리를 추가하세요:
-
CE 위젯의 경우
app/assets/javascripts/work_items/graphql/work_item_widgets.fragment.graphql
및ee/app/assets/javascripts/work_items/graphql/work_item_widgets.fragment.graphql
에 추가하세요. -
EE 위젯의 경우
ee/app/assets/javascripts/work_items/graphql/work_item_widgets.fragment.graphql
에 추가하세요.
-
-
번역 업데이트:
tooling/bin/gettext_extractor locale/gitlab.pot
.
이 시점에서 프런트엔드에서 위젯을 사용할 수 있습니다.
이제 기존 파일에 대한 테스트를 업데이트하고 새 파일에 대한 테스트를 작성할 수 있습니다:
-
spec/frontend/work_items/components/create_work_item_spec.js
또는ee/spec/frontend/work_items/components/create_work_item_spec.js
. -
spec/frontend/work_items/components/work_item_attributes_wrapper_spec.js
또는ee/spec/frontend/work_items/components/work_item_attributes_wrapper_spec.js
. -
spec/frontend/work_items/components/work_item_<widget_name>_spec.js
또는ee/spec/frontend/work_items/components/work_item_<widget_name>_spec.js
. -
spec/frontend/work_items/graphql/resolvers_spec.js
또는ee/spec/frontend/work_items/graphql/resolvers_spec.js
. -
spec/features/projects/work_items/work_item_spec.rb
또는ee/spec/features/projects/work_items/work_item_spec.rb
.
이를 해결하려면, spec/support/shared_examples/features/work_items/rolledup_dates_shared_examples.rb
에 있는 모의 Gitlab::QueryLimiting::Transaction.threshold
를 업데이트하세요.
새 작업 항목 위젯을 생성 뷰의 프론트엔드에 구현하는 단계
-
새로운 위젯의 범위를 이해하고 디자인을 준비했는지 확인하세요.
-
새로운 위젯이 이미 백엔드에서 구현되었고 유효한 작업 항목 유형에 대해 작업 항목 쿼리에서 반환되고 있는지 확인하세요. 다중 버전 호환성으로 인해 우리는 ~backend와 ~frontend를 별도의 마일스톤으로 두어야 합니다.
-
workItemCreate
변형에서 위젯이 지원되는지 확인하세요. -
디자인을 기반으로 새로운 프론트엔드 위젯을 만든 후, 작업 항목 생성 뷰에 포함시키는 것을 잊지 마세요.
생성 뷰에 값을 저장하기 위해 사용되는 Apollo 캐시
생성 뷰는 세부 뷰와 거의 동일하며, 각 위젯의 초안 데이터를 저장하고 싶기 때문에 특정 유형의 새로운 작업 항목마다 Apollo에 새 캐시 항목이 생성됩니다.
예를 들어, 생성 뷰를 초기화할 때, 작업 항목 캐시 유틸리티의 setNewWorkItemCache
함수가 호출되며, 이는 작업 항목 생성 뷰 모달과 작업 항목 생성 컴포넌트 모두에서 호출됩니다.
작업 항목 생성 뷰를 사용 용도에 따라 어떤 Vue 파일에도 포함할 수 있습니다. 생성 뷰의 workItemType
을 전달하면, 작업 항목 유형 쿼리에서 가져온 적용 가능한 작업 항목 위젯만 포함되며, 위젯 정의에서 정의된 것만 표시됩니다.
생성 뷰에서 작업 항목 초안 데이터를 업데이트하기 위해 로컬 변형이 있습니다.
Apollo 캐시에서 생성 양식의 새로운 위젯 지원
-
모든 위젯이 별도로 사용될 수 있으므로, 각 위젯은
updateWorkItem
변형을 사용합니다. -
이제 초안 데이터를 업데이트하기 위해, 데이터를 사용하여 캐시를 업데이트해야 합니다.
-
작업 항목을 업데이트하기 전에, 새로운 작업 항목인지 아니면 작업 항목
id
/iid
가 존재하는지 확인합니다. 예시.
if (this.workItemId === newWorkItemId(this.workItemType)) {
this.$apollo.mutate({
mutation: updateNewWorkItemMutation,
variables: {
input: {
workItemType: this.workItemType,
fullPath: this.fullPath,
assignees: this.localAssignees,
},
},
});
로컬 변형에서 새로운 작업 항목 위젯 지원
- 작업 항목 로컬 변형 유형 정의에 입력 유형을 추가합니다. 커스텀 객체나 원시 값을 사용할 수 있습니다.
부모의 이름과 ID를 가지는 parent
를 추가하고 싶다면 예시를 들어보세요.
input LocalParentWidgetInput {
id: String
name: String
}
input LocalUpdateNewWorkItemInput {
fullPath: String!
workItemType: String!
healthStatus: String
color: String
title: String
description: String
confidential: Boolean
parent: [LocalParentWidgetInput]
}
- 생성 뷰에서 초안 저장을 지원하기 위해 위젯에서 새 매개변수를 전달합니다.
this.$apollo.mutate({
mutation: updateNewWorkItemMutation,
variables: {
input: {
workItemType: this.workItemType,
fullPath: this.fullPath,
parent: {
id: 'gid:://gitlab/WorkItem/1',
name: '작업 항목의 부모'
}
},
},
})
- graphql 리졸버에서 업데이트를 지원하고 새로운 작업 항목 캐시를 업데이트하는 논리를 추가합니다.
const { parent } = input;
if (parent) {
const parentWidget = findWidget(WIDGET_TYPE_PARENT, draftData?.workspace?.workItem);
parentWidget.parent = parent;
const parentWidgetIndex = draftData.workspace.workItem.widgets.findIndex(
(widget) => widget.type === WIDGET_TYPE_PARENT,
);
draftData.workspace.workItem.widgets[parentWidgetIndex] = parentWidget;
}
- 작업 항목 생성 뷰에서 초안의 값을 가져옵니다.
if (this.isWidgetSupported(WIDGET_TYPE_PARENT)) {
workItemCreateInput.parentWidget = {
id: this.workItemParentId
};
}
await this.$apollo.mutate({
mutation: createWorkItemMutation,
variables: {
input: {
...workItemCreateInput,
},
});
작업 항목 유형에 위젯 매핑
모든 작업 항목 유형은 동일한 기본 정의 위젯 풀을 공유하며, 특정 유형에서 활성화된 위젯에 의해 사용자 정의됩니다. 사용자가 새로운 작업 항목 유형을 생성하고 이를 위한 설정 위젯을 정의할 수 있도록 계획하고 있기 때문에, 각 작업 항목 유형에 대한 위젯 매핑은 데이터베이스에 저장됩니다. 위젯 매핑은 widget_definitions
테이블에 저장되며, 기본 작업 항목 유형 및 향후 사용자 정의 유형에 대한 위젯 정의에 사용할 수 있습니다. 예상 데이터베이스 테이블 구조에 대한 자세한 내용은 이 이슈 설명에서 확인할 수 있습니다.
작업 항목 유형에 새로운 위젯 추가
각 작업 항목 유형에 할당된 위젯에 대한 정보는 데이터베이스에 저장되므로, 작업 항목 유형에 새로운 위젯을 추가하는 것은 데이터베이스 마이그레이션을 통해 이루어져야 합니다. 또한 위젯 가져오기 도구(lib/gitlab/database_importers/work_items/widgets_importer.rb
)도 업데이트해야 합니다.
위젯 정의 테이블 구조
테이블의 각 레코드는 위젯을 작업 항목 유형에 매핑합니다. 현재 “전역” 정의(NULL namespace_id
가 있는 정의)만 사용됩니다. 다음 단계에서는 이러한 매핑의 사용자 정의를 허용할 계획입니다. 예를 들어, 아래 테이블은 다음을 정의합니다:
- Weight 위젯은 작업 항목 유형 0과 1에 대해 활성화됩니다.
- Weight 위젯은 작업 항목 유형 1에 대해 편집할 수 없으며, 롤업 값만 포함되어 있고 작업 항목 유형 0은 편집 가능한 값만 포함됩니다.
- 네임스페이스 1에서 Weight 위젯은 MyWeight로 이름이 변경됩니다. 사용자가 위젯 이름을 변경할 때, 네임스페이스 내의 모든 위젯 매핑의 이름을 변경하는 것이 합리적입니다.
name
속성이 비정규화되어 있기 때문에, 이 위젯 유형에 대해 모든 작업 항목 유형에 대한 네임스페이스 매핑을 생성해야 합니다. - Weight 위젯은 특정 작업 항목 유형에서 비활성화될 수 있습니다(네임스페이스 3에서는 작업 항목 유형 0에 대해 비활성화되고, 여전히 작업 항목 유형 1에 대해 활성화되어 있습니다).
ID | namespace_id |
work_item_type_id |
widget_type |
widget_options |
Name | Disabled |
---|---|---|---|---|---|---|
1 | 0 | 1 | {‘editable’ => true, ‘rollup’ => false } | Weight | false | |
2 | 1 | 1 | {‘editable’ => false, ‘rollup’ => true } | Weight | false | |
3 | 1 | 0 | 1 | {‘editable’ => true, ‘rollup’ => false } | MyWeight | false |
4 | 1 | 1 | 1 | {‘editable’ => false, ‘rollup’ => true } | MyWeight | false |
5 | 2 | 0 | 1 | {‘editable’ => true, ‘rollup’ => false } | Other Weight | false |
6 | 3 | 0 | 1 | {‘editable’ => true, ‘rollup’ => false } | Weight | true |
백엔드 아키텍처
사용자 정의 세부적인 변형(예: WorkItemCreateFromTask
)을 사용하여 위젯을 업데이트하거나 workItemCreate
또는 workItemUpdate
변형의 일부로 사용할 수 있습니다.
위젯 콜백
작업 항목의 변형과 함께 위젯을 업데이트할 때, 백엔드 코드는 WorkItems::Callbacks::Base
에서 상속되는 콜백 클래스를 사용하여 구현해야 합니다. 이 클래스에는 ActiveRecord 콜백과 유사한 이름의 콜백 메서드가 있으며, 유사하게 동작합니다.
위젯과 같은 이름을 가진 콜백 클래스가 자동으로 사용됩니다. 예를 들어, 작업 항목에 AwardEmoji
위젯이 있을 때 WorkItems::Callbacks::AwardEmoji
가 호출됩니다. 다른 클래스를 사용하려면 callback_class
클래스 메서드를 오버라이드할 수 있습니다.
콜백 클래스가 머지 요청이나 에픽과 같이 다른 발행물에도 사용되는 경우, Issuable::Callbacks
아래에 클래스를 정의하고 IssuableBaseService#available_callbacks
목록에 클래스를 추가해야 합니다. 이는 작업 항목 업데이트와 레거시 이슈, 머지 요청 또는 에픽 업데이트 모두에 대해 실행됩니다.
excluded_in_new_type?
를 사용하여 작업 항목 유형이 변경되었고 위젯이 더 이상 사용 가능하지 않은지 확인하세요. 이는 일반적으로 더 이상 관련이 없는 연관 레코드를 제거하는 트리거입니다.
사용 가능한 콜백
-
after_initialize
는 작업 항목이BuildService
에 의해 초기화된 후와CreateService
및UpdateService
에 의해 작업 항목이 저장되기 전에 호출됩니다. 이 콜백은 생성 또는 업데이트 데이터베이스 트랜잭션 외부에서 실행됩니다. -
before_create
는 작업 항목이CreateService
에 의해 저장되기 전에 호출됩니다. 이 콜백은 생성 데이터베이스 트랜잭션 내에서 실행됩니다. -
before_update
는 작업 항목이UpdateService
에 의해 저장되기 전에 호출됩니다. 이 콜백은 업데이트 데이터베이스 트랜잭션 내에서 실행됩니다. -
after_create
는 작업 항목이CreateService
에 의해 저장된 후에 호출됩니다. 이 콜백은 생성 데이터베이스 트랜잭션 내에서 실행됩니다. -
after_update
는 작업 항목이UpdateService
에 의해 저장된 후에 호출됩니다. 이 콜백은 업데이트 데이터베이스 트랜잭션 내에서 실행됩니다. -
after_save
는 작업 항목 생성 또는 DB 업데이트 트랜잭션이CreateService
또는UpdateService
에 의해 커밋되기 전에 호출됩니다. -
after_update_commit
는 DB 업데이트 트랜잭션이UpdateService
에 의해 커밋된 후에 호출됩니다. -
after_save_commit
는 작업 항목 생성 또는 DB 업데이트 트랜잭션이CreateService
또는UpdateService
에 의해 커밋된 후에 호출됩니다.
새로운 백엔드 위젯 생성
새 작업 항목 위젯 추가 프로세스의 예는 머지 요청 #158688을 참조하십시오.
- 작업 항목 변형에 위젯 인수를 추가합니다:
- 위젯이 사용 가능하고 작업 항목 생성 및 업데이트에 대해 동일한 인수가 있는 CE 기능의 경우:
app/graphql/mutations/concerns/mutations/work_items/shared_arguments.rb
. - 위젯이 하나에만 사용 가능하거나 두 변형 간 인수가 다른 EE 기능의 경우:
- 생성:
app/graphql/mutations/concerns/mutations/work_items/create_arguments.rb
또는ee/app/graphql/ee/mutations/work_items/create.rb
. - 업데이트:
app/graphql/mutations/concerns/mutations/work_items/update_arguments.rb
또는ee/app/graphql/ee/mutations/work_items/update.rb
.
- 생성:
- 위젯이 사용 가능하고 작업 항목 생성 및 업데이트에 대해 동일한 인수가 있는 CE 기능의 경우:
-
app/graphql/types/work_items/widgets/<widget_name>_input_type.rb
또는ee/app/graphql/types/work_items/widgets/<widget_name>_input_type.rb
에서 위젯 입력 유형을 추가하여 위젯 인수를 정의합니다.- 생성 및 업데이트 변형에 대해 입력 유형이 다른 경우,
<widget_name>_create_input_type.rb
및/또는<widget_name>_update_input_type.rb
를 사용합니다.
- 생성 및 업데이트 변형에 대해 입력 유형이 다른 경우,
-
app/graphql/types/work_items/widgets/<widget_name>_type.rb
또는ee/app/graphql/types/work_items/widgets/<widget_name>_type.rb
에서 위젯 유형을 추가하여 위젯 필드를 정의합니다. -
app/assets/javascripts/graphql_shared/possible_types.json
의WorkItemWidget
배열에 위젯을 추가합니다. -
app/graphql/types/work_items/widget_interface.rb
의TYPE_MAPPINGS
또는ee/app/graphql/ee/types/work_items/widget_interface.rb
의EE_TYPE_MAPPINGS
에 위젯 유형 매핑을 추가합니다. -
app/models/work_items/widget_definition.rb
의widget_type
열거형에 위젯 유형을 추가합니다. -
app/models/work_items/widgets/<widget_name>.rb
에서 위젯의 일부로 사용할 수 있는 빠른 작업을 정의합니다. -
app/services/work_items/callbacks/<widget_name>.rb
에서 변형이 작업 항목을 생성/업데이트하는 방법을 정의합니다.-
if excluded_in_new_type?
를 처리할 필요가 있는지 고려합니다. - 오류 처리를 위해
raise_error
를 사용합니다.
-
-
lib/gitlab/database_importers/work_items/base_type_importer.rb
의WIDGET_NAMES
해시에 위젯을 정의합니다. - 위젯을 적절한 작업 항목 유형에 할당합니다:
-
lib/gitlab/database_importers/work_items/base_type_importer.rb
의WIDGETS_FOR_TYPE
해시에 추가합니다. -
db/migrate/<version>_add_<widget_name>_widget_to_work_item_types.rb
에서 마이그레이션을 생성합니다. 최신 모범 사례는db/migrate/20240812081354_add_email_participants_widget_to_work_item_types.rb
를 참조하십시오. 포스트 마이그레이션을 사용할 필요는 없습니다. 머지 요청 148119에 대한 논의를 참조하십시오.
-
- GraphQL 문서를 업데이트합니다:
bundle exec rake gitlab:graphql:compile_docs
. - 번역을 업데이트합니다:
tooling/bin/gettext_extractor locale/gitlab.pot
.
이 시점에서 GraphQL 쿼리 및 변형을 사용할 수 있어야 합니다.
이제 기존 파일의 테스트를 업데이트하고 새로운 파일에 대한 테스트를 작성할 수 있습니다:
-
spec/graphql/types/work_items/widget_interface_spec.rb
또는ee/spec/graphql/types/work_items/widget_interface_spec.rb
. -
spec/models/work_items/widget_definition_spec.rb
또는ee/spec/models/ee/work_items/widget_definition_spec.rb
. -
spec/models/work_items/widgets/<widget_name>_spec.rb
또는ee/spec/models/work_items/widgets/<widget_name>_spec.rb
. - 요청:
- CE:
spec/requests/api/graphql/mutations/work_items/update_spec.rb
및/또는spec/requests/api/graphql/mutations/work_items/create_spec.rb
. - EE:
ee/spec/requests/api/graphql/mutations/work_items/update_spec.rb
및/또는ee/spec/requests/api/graphql/mutations/work_items/create_spec.rb
.
- CE:
- 콜백:
spec/services/work_items/callbacks/<widget_name>_spec.rb
또는ee/spec/services/work_items/callbacks/<widget_name>_spec.rb
. - GraphQL 유형:
spec/graphql/types/work_items/widgets/<widget_name>_type_spec.rb
또는ee/spec/graphql/types/work_items/widgets/<widget_name>_type_spec.rb
. - GraphQL 입력 유형:
- CE:
spec/graphql/types/work_items/widgets/<widget_name>_input_type_spec.rb
또는spec/graphql/types/work_items/widgets/<widget_name>_create_input_type_spec.rb
및spec/graphql/types/work_items/widgets/<widget_name>_update_input_type_spec.rb
. - EE:
ee/spec/graphql/types/work_items/widgets/<widget_name>_input_type_spec.rb
또는ee/spec/graphql/types/work_items/widgets/<widget_name>_create_input_type_spec.rb
및ee/spec/graphql/types/work_items/widgets/<widget_name>_update_input_type_spec.rb
.
- CE:
- 마이그레이션:
spec/migrations/<version>_add_<widget_name>_widget_to_work_item_types_spec.rb
.