위젯
GitLab v19.1프론트엔드 위젯은 독립적인 Vue 애플리케이션 또는 Vue 컴포넌트 트리로, 페이지에 추가하여 특정 기능을 처리할 수 있습니다. 위젯의 좋은 예시로는 사이드바 담당자(sidebar assignees)와 사이드바 기밀성(sidebar confidentiality)이 있습니다.
프론트엔드 위젯은 독립적인 Vue 애플리케이션 또는 Vue 컴포넌트 트리로, 페이지에 추가하여 특정 기능을 처리할 수 있습니다.
위젯의 좋은 예시로는 사이드바 담당자(sidebar assignees)와 사이드바 기밀성(sidebar confidentiality)이 있습니다.
위젯을 구축할 때는 아래에 설명된 몇 가지 원칙을 따라야 합니다.
Vue Apollo 필수#
모든 위젯은 동일한 스택(Vue + Apollo Client)을 사용해야 합니다. 이를 위해 애플리케이션 루트에 Vue Apollo를 추가하거나(위젯을 컴포넌트로 사용하는 경우), 위젯에 직접 제공해야 합니다. 사이드바 위젯의 경우 issuable Apollo Client 및 Apollo Provider를 사용합니다:
import SidebarConfidentialityWidget from '~/sidebar/components/confidential/sidebar_confidentiality_widget.vue';
import { apolloProvider } from '~/graphql_shared/issuable_client';
function mountConfidentialComponent() {
new Vue({
apolloProvider,
components: {
SidebarConfidentialityWidget,
},
/* ... */
});
}
필수 인젝션#
편집 가능한 모든 사이드바 위젯은 SidebarEditableItem을 사용하여 접힘/펼침 상태를 처리해야 합니다.
이 컴포넌트는 애플리케이션 루트에서 제공되는 canUpdate 속성이 필요합니다.
전역 상태 매핑 금지#
위젯을 최대한 재사용 가능하게 만들기 위해, 위젯이나 하위 컴포넌트에 외부 상태 바인딩을 추가하는 것을 지양합니다. 여기에는 Vuex 매핑과 mediator 스토어가 포함됩니다.
위젯 책임#
위젯은 자신이 설계된 엔티티(담당자, 이터레이션 등)의 데이터를 가져오고 업데이트할 책임이 있습니다. 즉, 위젯은 항상 데이터를 가져와야 합니다(Apollo 캐시에 이미 있지 않은 경우). 위젯에 초기값을 제공하더라도, 위젯은 Apollo 캐시에 저장하기 위해 백그라운드에서 GraphQL 쿼리를 수행해야 합니다.
결국 Apollo Client 캐시를 전역 애플리케이션 상태로 사용하게 되면, 사이드바 위젯에 초기 데이터를 전달할 필요가 없어집니다. 그렇게 되면 위젯이 캐시에서 직접 데이터를 가져올 수 있게 됩니다.
GraphQL 쿼리 및 뮤테이션 사용#
위젯은 다양한 엔티티(에픽, 이슈, 머지 리퀘스트 등)와 유연하게 동작해야 합니다. 서로 다른 사이드바에는 서로 다른 GraphQL 쿼리와 뮤테이션이 필요하므로, 다음과 같이 매핑(mappings)을 생성합니다:
export const assigneesQueries = {
[TYPE_ISSUE]: {
query: getIssueParticipants,
mutation: updateAssigneesMutation,
},
[TYPE_MERGE_REQUEST]: {
query: getMergeRequestParticipants,
mutation: updateMergeRequestParticipantsMutation,
},
};
쿼리 업데이트에 동일한 로직을 처리하기 위해 쿼리 필드에 **별칭(alias)**을 사용합니다. 예를 들면:
-
group또는project는namespace가 됩니다. -
issue,epic, 또는mergeRequest는issuable이 됩니다.
안타깝게도 Apollo는 별칭이 붙은 필드에 undefined의 typename을 할당하므로, __typename을 명시적으로 가져와야 합니다:
query issueConfidential($fullPath: ID!, $iid: String) {
namespace: project(fullPath: $fullPath) {
__typename
issuable: issue(iid: $iid) {
__typename
id
confidential
}
}
}
다른 Vue 애플리케이션과의 통신#
위젯 상태 변경(예: 뮤테이션 성공 후)을 부모 애플리케이션에 전달해야 하는 경우, 이벤트를 발생시켜야 합니다:
updateAssignees(assigneeUsernames) {
return this.$apollo
.mutate({
mutation: this.$options.assigneesQueries[this.issuableType].mutation,
variables: {...},
})
.then(({ data }) => {
const assignees = data.issueSetAssignees?.issue?.assignees?.nodes || [];
this.$emit('assignees-updated', assignees);
})
}
때로는 NotesApp과 같이 다른 Vue 애플리케이션의 변경 사항을 수신해야 할 수도 있습니다.
이 경우, 클라이언트를 가져오고 특정 쿼리를 수신하는 renderless 컴포넌트를 사용할 수 있습니다:
import { fetchPolicies } from '~/lib/graphql';
import { confidentialityQueries } from '~/sidebar/constants';
import { defaultClient as gqlClient } from '~/graphql_shared/issuable_client';
created() {
if (this.issuableType !== IssuableType.Issue) {
return;
}
gqlClient
.watchQuery({
query: confidentialityQueries[this.issuableType].query,
variables: {...},
fetchPolicy: fetchPolicies.CACHE_ONLY,
})
.subscribe((res) => {
this.setConfidentiality(issuable.confidential);
});
},
methods: {
...mapActions(['setConfidentiality']),
},
머지 리퀘스트 위젯#
머지 리퀘스트 위젯 프레임워크에 관한 전용 문서를 참조하세요.