대시보드 위젯 추가
Azure DevOps Services | Azure DevOps Server 2022 - Azure DevOps Server 2019
대시보드의 위젯은 확장 프레임워크에서 기여로 구현됩니다. 단일 확장에는 여러 기여가 있을 수 있습니다. 여러 위젯을 기여로 사용하여 확장을 만드는 방법을 알아봅니다.
이 문서는 간단한 위젯에서 시작하여 포괄적인 위젯으로 끝나는 이전의 각 건물인 세 부분으로 나뉩니다.
팁
Azure DevOps 확장 SDK를 사용하여 확장 개발에 대한 최신 설명서를 확인하세요.
필수 조건
- 지식: 위젯 개발에 JavaScript, HTML, CSS에 대한 지식이 필요합니다.
- Azure DevOps 조직
- 텍스트 편집기입니다. 대부분의 자습서에서는 Visual Studio Code를 사용합니다.
- 노드의 최신 버전입니다.
- 확장을 패키지하는 Azure DevOps(tfx-cli) 용 플랫폼 간 CLI입니다.
- tfx-cli 를 실행하여 Node.js 구성 요소를 사용하여
npm
설치할 수 있습니다.npm i -g tfx-cli
- tfx-cli 를 실행하여 Node.js 구성 요소를 사용하여
- 프로젝트의 홈 디렉터리입니다. 이 디렉터리를 자습서 전체에서 참조
home
합니다.
확장 파일 구조:
|--- README.md
|--- sdk
|--- node_modules
|--- scripts
|--- VSS.SDK.min.js
|--- img
|--- logo.png
|--- scripts
|--- hello-world.html // html page to be used for your widget
|--- vss-extension.json // extension's manifest
자습서 내용
- 1부: 간단한 "헬로 월드" 메시지를 출력하는 새 위젯을 만드는 방법을 보여 줍니다.
- 2부: Azure DevOps REST API에 대한 호출을 추가하여 첫 번째 부분을 빌드합니다.
- 3부: 위젯에 구성을 추가하는 방법을 설명합니다.
참고 항목
서둘러 코드를 바로 사용하려는 경우 샘플을 다운로드할 수 있습니다.
다운로드한 후 폴더로 widgets
이동한 다음 6단계와 7단계를 직접 수행하여 다양한 복잡성의 세 가지 샘플 위젯이 있는 샘플 확장을 게시합니다.
기본적으로 제공되는 위젯에 대한 몇 가지 기본 스타일과 위젯 구조에 대한 몇 가지 지침을 시작합니다.
1부: 헬로 월드
1부에서는 JavaScript를 사용하여 "헬로 월드"를 인쇄하는 위젯을 제공합니다.
1단계: 클라이언트 SDK 가져오기 - VSS.SDK.min.js
핵심 SDK 스크립트 VSS.SDK.min.js
를 사용하면 웹 확장이 호스트 Azure DevOps 프레임과 통신할 수 있습니다. 스크립트는 초기화, 확장 프로그램 알림 로드 또는 현재 페이지에 대한 컨텍스트 가져오기와 같은 작업을 수행합니다.
클라이언트 SDK VSS.SDK.min.js
파일을 가져와서 웹앱에 추가합니다. 폴더에 배치합니다 home/sdk/scripts
.
SDK를 검색하려면 'npm install' 명령을 사용합니다.
npm install vss-web-extension-sdk
자세한 내용은 클라이언트 SDK GitHub 페이지를 참조 하세요.
2단계: HTML 페이지 설정 - hello-world.html
HTML 페이지는 레이아웃을 함께 포함하고 CSS 및 JavaScript에 대한 참조를 포함하는 붙이기입니다. 이 파일의 이름은 무엇이든 지정할 수 있습니다. 모든 참조를 hello-world
사용하는 이름으로 업데이트합니다.
위젯은 HTML 기반이며 iframe에서 호스트됩니다.
에 다음 HTML을 추가합니다 hello-world.html
. 파일에 대한 필수 참조를 VSS.SDK.min.js
추가하고 향후 단계에서 문자열 헬로 월드 업데이트되는 요소를 포함합니다h2
.
<!DOCTYPE html>
<html>
<head>
<script src="sdk/scripts/VSS.SDK.min.js"></script>
</head>
<body>
<div class="widget">
<h2 class="title"></h2>
</div>
</body>
</html>
HTML 파일을 사용하지만 스크립트 및 링크 이외의 대부분의 HTML 헤드 요소는 프레임워크에서 무시됩니다.
3단계: JavaScript 업데이트
JavaScript를 사용하여 위젯에서 콘텐츠를 렌더링합니다. 이 문서에서는 HTML 파일의 요소 내에 <script>
모든 JavaScript 코드를 래핑합니다. 이 코드를 별도의 JavaScript 파일에 저장하고 HTML 파일에서 참조하도록 선택할 수 있습니다.
코드는 콘텐츠를 렌더링합니다. 또한 이 JavaScript 코드는 VSS SDK를 초기화하고, 위젯의 코드를 위젯 이름에 매핑하고, 위젯 성공 또는 실패의 확장 프레임워크에 알깁니다.
이 경우 다음 코드는 위젯에 "헬로 월드"를 출력합니다. HTML에서 head
이 script
요소를 추가합니다.
<script type="text/javascript">
VSS.init({
explicitNotifyLoaded: true,
usePlatformStyles: true
});
VSS.require("TFS/Dashboards/WidgetHelpers", function (WidgetHelpers) {
WidgetHelpers.IncludeWidgetStyles();
VSS.register("HelloWorldWidget", function () {
return {
load: function (widgetSettings) {
var $title = $('h2.title');
$title.text('Hello World');
return WidgetHelpers.WidgetStatusHelper.Success();
}
};
});
VSS.notifyLoadSucceeded();
});
</script>
VSS.init
위젯을 호스트하는 iframe과 호스트 프레임 간의 핸드셰이크를 초기화합니다.- 위젯이 로드가 완료되면 호스트에 명시적으로 알릴 수 있도록 전달
explicitNotifyLoaded: true
합니다. 이 컨트롤을 사용하면 종속 모듈이 로드되는지 확인한 후 부하 완료를 알릴 수 있습니다. 위젯이 HTML 요소(예: 본문, div 등)에 Azure DevOps 핵심 스타일을 사용할 수 있도록 전달usePlatformStyles: true
합니다. 위젯에서 이러한 스타일을 사용하지 않으려는 경우 전달할usePlatformStyles: false
수 있습니다. VSS.require
는 필요한 VSS 스크립트 라이브러리를 로드하는 데 사용됩니다. 이 메서드를 호출하면 JQuery 및 JQueryUI와 같은 일반 라이브러리가 자동으로 로드됩니다. 이 경우 위젯 상태를 위젯 프레임워크와 통신하는 데 사용되는 WidgetHelpers 라이브러리에 의존합니다. 따라서 해당 모듈 이름TFS/Dashboards/WidgetHelpers
및 콜백을 .에 전달합니다VSS.require
. 모듈이 로드되면 콜백이 호출됩니다. 콜백에는 위젯에 필요한 나머지 JavaScript 코드가 있습니다. 콜백이 끝나면 로드 완료를 알리기 위해 호출VSS.notifyLoadSucceeded
합니다.WidgetHelpers.IncludeWidgetStyles
에는 시작하기 위한 몇 가지 기본 css 가 포함된 스타일시트가 포함되어 있습니다. 이러한 스타일을 사용하려면 클래스widget
를 사용하여 HTML 요소 안에 콘텐츠를 래핑합니다.VSS.register
는 확장의 다양한 기여 중 위젯을 고유하게 식별하는 JavaScript의 함수를 매핑하는 데 사용됩니다. 이름은 5단계에서id
설명한 대로 기여를 식별하는 이름과 일치해야 합니다. 위젯의 경우 전달되는VSS.register
함수는 계약을 충족IWidget
하는 개체를 반환해야 합니다. 예를 들어 반환된 개체에는 위젯을 렌더링하는 핵심 논리가 있는 다른 함수 값이 있는 부하 속성이 있어야 합니다. 이 경우 요소의 텍스트를h2
"헬로 월드"로 업데이트합니다. 위젯 프레임워크가 위젯을 인스턴스화할 때 호출되는 함수입니다. WidgetHelpers를 사용하여WidgetStatusHelper
성공으로 반환합니다WidgetStatus
.
Warning
위젯을 등록하는 데 사용되는 이름이 매니페스트의 기여에 대한 ID와 일치하지 않으면 위젯이 예기치 않게 작동합니다.
vss-extension.json
는 항상 폴더의 루트에 있어야 합니다(이 가이드HelloWorld
에서는). 다른 모든 파일의 경우 폴더 내에 원하는 구조로 배치할 수 있으며 HTML 파일 및vss-extension.json
매니페스트에서 참조를 적절하게 업데이트해야 합니다.
4단계: 확장 로고 업데이트: logo.png
사용자가 확장을 설치하면 로고가 Marketplace 및 위젯 카탈로그에 표시됩니다.
98px x 98px 카탈로그 아이콘이 필요합니다. 이미지를 선택하고 이름을 지정 logo.png
한 다음 폴더에 배치합니다 img
.
그러나 다음 단계의 확장 매니페스트가 사용하는 이름으로 업데이트되는 한 원하는 이미지의 이름을 지정할 수 있습니다.
5단계: 확장 매니페스트 만들기: vss-extension.json
모든 확장에는 확장명 매니페스트 파일이 있어야 합니다.
- 확장 매니페스트 참조를 읽습니다.
- 확장성 지점에서 기여 지점에 대해 자세히 알아봅니다.
- 다음 내용을 사용하여 디렉터리에 json 파일(
vss-extension.json
예:home
)을 만듭니다.
{
"manifestVersion": 1,
"id": "azure-devops-extensions-myExtensions",
"version": "1.0.0",
"name": "My First Set of Widgets",
"description": "Samples containing different widgets extending dashboards",
"publisher": "fabrikam",
"categories": ["Azure Boards"],
"targets": [
{
"id": "Microsoft.VisualStudio.Services"
}
],
"icons": {
"default": "img/logo.png"
},
"contributions": [
{
"id": "HelloWorldWidget",
"type": "ms.vss-dashboards-web.widget",
"targets": [
"ms.vss-dashboards-web.widget-catalog"
],
"properties": {
"name": "Hello World Widget",
"description": "My first widget",
"catalogIconUrl": "img/CatalogIcon.png",
"previewImageUrl": "img/preview.png",
"uri": "hello-world.html",
"supportedSizes": [
{
"rowSpan": 1,
"columnSpan": 2
}
],
"supportedScopes": ["project_team"]
}
}
],
"files": [
{
"path": "hello-world.html",
"addressable": true
},
{
"path": "sdk/scripts",
"addressable": true
},
{
"path": "img",
"addressable": true
}
]
}
필요한 특성에 대한 자세한 내용은 확장 매니페스트 참조를 참조하세요.
참고 항목
게시자를 게시자 이름으로 변경합니다. 게시자를 만들려면 패키지/게시/설치를 참조 하세요.
아이콘
아이콘 stanza는 매니페스트에서 확장 아이콘의 경로를 지정합니다.
참여
각 기여 항목은 속성을 정의합니다.
- 기여를 식별할 ID입니다. 이 ID는 확장 내에서 고유해야 합니다. 이 ID는 위젯을 등록하기 위해 3단계에서 사용한 이름과 일치해야 합니다.
- 기여 유형입니다. 모든 위젯의 경우 형식은 .이어야
ms.vss-dashboards-web.widget
합니다. - 기여가 기여하는 대상의 배열입니다. 모든 위젯의 경우 대상은 .이어야
[ms.vss-dashboards-web.widget-catalog]
합니다. - 속성은 기여 유형에 대한 속성을 포함하는 개체입니다. 위젯의 경우 다음 속성은 필수입니다.
속성 | 설명 |
---|---|
name | 위젯 카탈로그에 표시할 위젯의 이름입니다. |
description | 위젯 카탈로그에 표시할 위젯에 대한 설명입니다. |
catalogIconUrl | 위젯 카탈로그에 표시하기 위해 4단계에서 추가한 카탈로그 아이콘의 상대 경로입니다. 이미지는 98px x 98px여야 합니다. 다른 폴더 구조나 다른 파일 이름을 사용한 경우 여기에 적절한 상대 경로를 지정합니다. |
previewImageUrl | 위젯 카탈로그에 표시하기 위해 4단계에서 추가한 미리 보기 이미지의 상대 경로입니다. 이미지는 330px x 160px여야 합니다. 다른 폴더 구조나 다른 파일 이름을 사용한 경우 여기에 적절한 상대 경로를 지정합니다. |
uri | 1단계에서 추가한 HTML 파일의 상대 경로입니다. 다른 폴더 구조나 다른 파일 이름을 사용한 경우 여기에 적절한 상대 경로를 지정합니다. |
supportedSizes | 위젯에서 지원하는 크기의 배열입니다. 위젯이 여러 크기를 지원하는 경우 배열의 첫 번째 크기는 위젯의 기본 크기입니다. 대시보드 widget size 그리드에서 위젯이 차지하는 행 및 열에 대해 지정됩니다. 하나의 행/열은 160px에 해당합니다. 1x1보다 큰 차원은 위젯 사이의 여백을 나타내는 추가 10픽셀을 가져옵니다. 예를 들어 3x2 위젯은 160*3+10*2 넓고 160*2+10*1 키가 깁니다. 지원되는 최대 크기는 .입니다 4x4 . |
supportedScopes | 현재는 팀 대시보드만 지원됩니다. 값은 .이어야 합니다 project_team . 향후 업데이트에는 대시보드 범위에 대한 추가 옵션이 포함될 수 있습니다. |
Files
파일은 HTML 페이지, 스크립트, SDK 스크립트 및 로고 등 패키지에 포함하려는 파일을 표시합니다.
true
URL 주소를 지정할 필요가 없는 다른 파일을 포함하지 않는 한 설정 addressable
됩니다.
참고 항목
확장명 매니페스트 파일(예: 해당 속성 및 해당 파일의 기능)에 대한 자세한 내용은 확장 매니페스트 참조를 확인하세요.
6단계: 패키지, 게시 및 공유
작성된 확장명이 있으면 Marketplace로 가져오는 다음 단계는 모든 파일을 함께 패키지하는 것입니다. 모든 확장은 VSIX 2.0 호환 .vsix 파일로 패키지됩니다. Microsoft는 확장을 패키지하는 플랫폼 간 CLI(명령줄 인터페이스)를 제공합니다.
패키징 도구 가져오기
명령줄에서 Node.js 구성 요소인 Azure DevOps(tfx-cli)npm
용 플랫폼 간 CLI를 설치하거나 업데이트할 수 있습니다.
npm i -g tfx-cli
확장을 패키지합니다.
tfx-cli가 있으면 확장 프로그램을 .vsix 파일로 패키징하는 것은 간편합니다. 확장의 홈 디렉터리로 이동하여 다음 명령을 실행합니다.
tfx extension create --manifest-globs vss-extension.json
참고 항목
확장/통합 버전은 모든 업데이트에서 증가해야 합니다.
기존 확장을 업데이트할 때 매니페스트에서 버전을 업데이트하거나 명령줄 스위치를 --rev-version
전달합니다. 이렇게 하면 확장의 패치 버전 번호가 증가하고 새 버전이 매니페스트에 저장됩니다.
확장자를 .vsix 파일로 패키지한 후에는 Marketplace에 확장을 게시할 준비가 된 것입니다.
확장에 대한 게시자 만들기
Microsoft의 확장을 포함한 모든 확장은 게시자가 제공하는 것으로 식별됩니다. 기존 게시자의 멤버가 아닌 경우 만듭니다.
- Visual Studio Marketplace 게시 포털에 로그인
- 기존 게시자의 구성원이 아닌 경우 게시자를 만들어야 합니다. 게시자가 이미 있는 경우 관련 사이트로 스크롤하여 확장 게시를 선택합니다.
- 게시자에 대한 식별자를 지정합니다. 예를 들면 다음과 같습니다.
mycompany-myteam
- 식별자는 확장명 매니페스트 파일의
publisher
특성 값으로 사용됩니다.
- 식별자는 확장명 매니페스트 파일의
- 게시자의 표시 이름을 지정합니다. 예를 들면 다음과 같습니다.
My Team
- 게시자에 대한 식별자를 지정합니다. 예를 들면 다음과 같습니다.
- Marketplace 게시자 계약을 검토하고 만들기를 선택합니다.
이제 게시자가 정의됩니다. 이후 릴리스에서는 게시자의 확장을 보고 관리할 수 있는 권한을 부여할 수 있습니다.
공통 게시자에서 확장을 게시하면 팀과 조직의 프로세스가 간소화되어 보다 안전한 접근 방식을 제공합니다. 이 방법을 사용하면 여러 사용자 간에 단일 자격 증명 집합을 배포할 필요가 없으므로 보안이 강화되고
vss-extension.json
더미 게시자 ID를 게시자 ID fabrikam
로 바꾸도록 샘플의 매니페스트 파일을 업데이트합니다.
확장 게시 및 공유
이제 Marketplace에 확장을 업로드할 수 있습니다.
새 확장 업로드를 선택하고 패키지된 .vsix 파일로 이동한 다음 업로드를 선택합니다.
한 단계에서 확장을 패키지하고 게시하는 대신 tfx extension create
명령을 사용하여 tfx extension publish
명령줄을 통해 확장을 업로드할 수도 있습니다.
필요에 따라 게시 후 하나 이상의 계정과 확장을 공유하는 데 사용할 --share-with
수 있습니다.
개인용 액세스 토큰도 필요합니다.
tfx extension publish --manifest-globs your-manifest.json --share-with yourOrganization
7단계: 카탈로그에서 위젯 추가
프로젝트에
http://dev.azure.com/{Your_Organization}/{Your_Project}
로그인합니다.개요>대시보드를 선택합니다.
위젯 추가를 선택합니다.
위젯을 강조 표시한 다음 추가를 선택합니다.
위젯이 대시보드에 나타납니다.
2부: Azure DevOps REST API를 사용하여 헬로 월드
위젯은 Azure DevOps의 REST API 를 호출하여 Azure DevOps 리소스와 상호 작용할 수 있습니다. 다음 예제에서는 WorkItemTracking용 REST API를 사용하여 기존 쿼리에 대한 정보를 가져오고 "헬로 월드" 텍스트 아래의 위젯에 일부 쿼리 정보를 표시합니다.
1단계: HTML 파일 추가
이전 예제에서 파일을 hello-world.html
복사하고 복사본 hello-world2.html
이름을 .로 바꿉니다. 이제 폴더는 다음 예제와 같습니다.
|--- README.md |--- node_modules
|--- SDK
|--- 스크립트 |--- VSS. |--- img |--- logo.png |--- 스크립트 SDK.min.js
위젯 |--- hello-world2.html // 이름이 바뀐 hello-world.html |--- vss-extension.json // 확장 매니페스트의 복사본에 사용할 |--- hello-world.html // html 페이지
쿼리 정보를 저장하려면 아래에 새 div
요소를 추가합니다 h2
.
호출VSS.register
하는 줄에서 HelloWorldWidget
HelloWorldWidget2
위젯의 이름을 업데이트합니다.
이 작업을 통해 프레임워크는 확장 내에서 위젯을 고유하게 식별할 수 있습니다.
<!DOCTYPE html>
<html>
<head>
<script src="sdk/scripts/VSS.SDK.min.js"></script>
<script type="text/javascript">
VSS.init({
explicitNotifyLoaded: true,
usePlatformStyles: true
});
VSS.require("TFS/Dashboards/WidgetHelpers", function (WidgetHelpers) {
WidgetHelpers.IncludeWidgetStyles();
VSS.register("HelloWorldWidget2", function () {
return {
load: function (widgetSettings) {
var $title = $('h2.title');
$title.text('Hello World');
return WidgetHelpers.WidgetStatusHelper.Success();
}
}
});
VSS.notifyLoadSucceeded();
});
</script>
</head>
<body>
<div class="widget">
<h2 class="title"></h2>
<div id="query-info-container"></div>
</div>
</body>
</html>
2단계: Azure DevOps 리소스 액세스
Azure DevOps 리소스 에 대한 액세스를 사용하도록 설정하려면 확장 매니페스트에 범위를 지정해야 합니다. 매니페스트에 vso.work
범위를 추가합니다.
이 범위는 위젯이 쿼리 및 작업 항목에 대한 읽기 전용 액세스 권한이 필요했음을 나타냅니다. 여기에서 사용 가능한 모든 범위를 참조하세요.
확장 매니페스트의 끝에 다음 코드를 추가합니다.
{
"scopes":[
"vso.work"
]
}
다른 속성을 포함하려면 명시적으로 나열해야 합니다. 예를 들면 다음과 같습니다.
{
"name": "example-widget",
"publisher": "example-publisher",
"version": "1.0.0",
"scopes": [
"vso.work"
]
}
Warning
확장을 게시한 후 범위를 추가하거나 변경하는 것은 현재 지원되지 않습니다. 확장이 이미 업로드된 경우 Marketplace에서 제거합니다. Visual Studio Marketplace 게시 포털로 이동하여 확장을 마우스 오른쪽 단추로 선택하고 제거를 선택합니다.
3단계: REST API 호출
Azure DevOps에서 REST API를 호출하기 위해 SDK를 통해 액세스할 수 있는 많은 클라이언트 쪽 라이브러리가 있습니다. 이러한 라이브러리를 REST 클라이언트라고 하며 사용 가능한 모든 서버 쪽 엔드포인트에 대한 Ajax 호출을 중심으로 하는 JavaScript 래퍼입니다. Ajax 호출을 직접 작성하는 대신 이러한 클라이언트에서 제공하는 메서드를 사용할 수 있습니다. 이러한 메서드는 코드에서 사용할 수 있는 개체에 API 응답을 매핑합니다.
이 단계에서는 WorkItemTracking REST 클라이언트를 제공하는 로드 AzureDevOps/WorkItemTracking/RestClient
호출을 업데이트 VSS.require
합니다.
이 REST 클라이언트를 사용하여 폴더 Shared Queries
아래에 호출 Feedback
된 쿼리에 대한 정보를 가져올 수 있습니다.
전달하는 VSS.register
함수 내에서 현재 프로젝트 ID를 보유하는 변수를 만듭니다. 쿼리를 가져오려면 이 변수가 필요합니다.
또한 REST 클라이언트를 사용하는 새 메서드 getQueryInfo
를 만듭니다. 그런 다음, 로드 메서드에서 호출되는 이 메서드입니다.
이 메서드 getClient
는 필요한 REST 클라이언트의 인스턴스를 제공합니다.
이 메서드 getQuery
는 프라미스로 래핑된 쿼리를 반환합니다.
업데이트 VSS.require
된 내용은 다음과 같습니다.
VSS.require(["AzureDevOps/Dashboards/WidgetHelpers", "AzureDevOps/WorkItemTracking/RestClient"],
function (WidgetHelpers, TFS_Wit_WebApi) {
WidgetHelpers.IncludeWidgetStyles();
VSS.register("HelloWorldWidget2", function () {
var projectId = VSS.getWebContext().project.id;
var getQueryInfo = function (widgetSettings) {
// Get a WIT client to make REST calls to Azure DevOps Services
return TFS_Wit_WebApi.getClient().getQuery(projectId, "Shared Queries/Feedback")
.then(function (query) {
// Do something with the query
return WidgetHelpers.WidgetStatusHelper.Success();
}, function (error) {
return WidgetHelpers.WidgetStatusHelper.Failure(error.message);
});
}
return {
load: function (widgetSettings) {
// Set your title
var $title = $('h2.title');
$title.text('Hello World');
return getQueryInfo(widgetSettings);
}
}
});
VSS.notifyLoadSucceeded();
});
에서 Failure 메서드 WidgetStatusHelper
를 사용하는지 확인합니다.
위젯 프레임워크에 오류가 발생했음을 나타내고 모든 위젯에 제공된 표준 오류 환경을 활용할 수 있습니다.
폴더 아래에 Shared Queries
쿼리가 Feedback
없는 경우 코드에서 프로젝트에 있는 쿼리의 경로로 바꿉 Shared Queries\Feedback
니다.
4단계: 응답 표시
마지막 단계는 위젯 내에서 쿼리 정보를 렌더링하는 것입니다.
이 함수는 getQuery
프라미스 내에 있는 형식 Contracts.QueryHierarchyItem
의 개체를 반환합니다.
이 예제에서는 "헬로 월드" 텍스트 아래에 쿼리 ID, 쿼리 이름 및 쿼리 작성자의 이름을 표시합니다.
// Do something with the query
주석을 다음 코드로 바꿉니다.
// Create a list with query details
var $list = $('<ul>');
$list.append($('<li>').text("Query Id: " + query.id));
$list.append($('<li>').text("Query Name: " + query.name));
$list.append($('<li>').text("Created By: " + (query.createdBy ? query.createdBy.displayName : "<unknown>")));
// Append the list to the query-info-container
var $container = $('#query-info-container');
$container.empty();
$container.append($list);
최종 hello-world2.html
결과는 다음 예제와 같습니다.
<!DOCTYPE html>
<html>
<head>
<script src="sdk/scripts/VSS.SDK.min.js"></script>
<script type="text/javascript">
VSS.init({
explicitNotifyLoaded: true,
usePlatformStyles: true
});
VSS.require(["AzureDevOps/Dashboards/WidgetHelpers", "AzureDevOps/WorkItemTracking/RestClient"],
function (WidgetHelpers, TFS_Wit_WebApi) {
WidgetHelpers.IncludeWidgetStyles();
VSS.register("HelloWorldWidget2", function () {
var projectId = VSS.getWebContext().project.id;
var getQueryInfo = function (widgetSettings) {
// Get a WIT client to make REST calls to Azure DevOps Services
return TFS_Wit_WebApi.getClient().getQuery(projectId, "Shared Queries/Feedback")
.then(function (query) {
// Create a list with query details
var $list = $('<ul>');
$list.append($('<li>').text("Query ID: " + query.id));
$list.append($('<li>').text("Query Name: " + query.name));
$list.append($('<li>').text("Created By: " + (query.createdBy ? query.createdBy.displayName : "<unknown>")));
// Append the list to the query-info-container
var $container = $('#query-info-container');
$container.empty();
$container.append($list);
// Use the widget helper and return success as Widget Status
return WidgetHelpers.WidgetStatusHelper.Success();
}, function (error) {
// Use the widget helper and return failure as Widget Status
return WidgetHelpers.WidgetStatusHelper.Failure(error.message);
});
}
return {
load: function (widgetSettings) {
// Set your title
var $title = $('h2.title');
$title.text('Hello World');
return getQueryInfo(widgetSettings);
}
}
});
VSS.notifyLoadSucceeded();
});
</script>
</head>
<body>
<div class="widget">
<h2 class="title"></h2>
<div id="query-info-container"></div>
</div>
</body>
</html>
5단계: 확장 매니페스트 업데이트
이 단계에서는 두 번째 위젯에 대한 항목을 포함하도록 확장 매니페스트를 업데이트합니다.
속성의 배열에 새 기여를 contributions
추가하고 파일 hello-world2.html
속성의 배열에 새 파일을 추가합니다.
두 번째 위젯에 대한 다른 미리 보기 이미지가 필요합니다. 이 preview2.png
이름을 지정하고 폴더에 배치합니다 img
.
{
...,
"contributions": [
...,
{
"id": "HelloWorldWidget2",
"type": "ms.vss-dashboards-web.widget",
"targets": [
"ms.vss-dashboards-web.widget-catalog"
],
"properties": {
"name": "Hello World Widget 2 (with API)",
"description": "My second widget",
"previewImageUrl": "img/preview2.png",
"uri": "hello-world2.html",
"supportedSizes": [
{
"rowSpan": 1,
"columnSpan": 2
}
],
"supportedScopes": ["project_team"]
}
}
],
"files": [
{
"path": "hello-world.html",
"addressable": true
},
{
"path": "hello-world2.html",
"addressable": true
},
{
"path": "sdk/scripts",
"addressable": true
},
{
"path": "img",
"addressable": true
}
],
"scopes": [
"vso.work"
]
}
6단계: 패키지, 게시 및 공유
확장을 패키지, 게시 및 공유합니다. 확장을 이미 게시한 경우 확장을 다시 패키지하고 Marketplace로 직접 업데이트할 수 있습니다.
7단계: 카탈로그에서 위젯 추가
이제 .에서 https:\//dev.azure.com/{Your_Organization}/{Your_Project}
팀 대시보드로 이동합니다. 이 페이지가 이미 열려 있는 경우 새로 고칩니다.
편집을 마우스로 가리키고 추가를 선택합니다. 설치한 위젯을 찾을 수 있는 위젯 카탈로그가 열립니다.
대시보드에 추가하려면 위젯을 선택하고 추가를 선택합니다.
3부: 헬로 월드 구성
이 가이드의 2부에서는 하드 코딩된 쿼리에 대한 쿼리 정보를 표시하는 위젯을 만드는 방법을 알아보았습니다. 이 부분에서는 하드 코딩된 쿼리 대신 사용할 쿼리를 구성하는 기능을 추가합니다. 구성 모드에서 사용자는 변경 내용에 따라 위젯의 라이브 미리 보기를 볼 수 있습니다. 사용자가 저장을 선택하면 이러한 변경 내용이 대시보드의 위젯에 저장됩니다.
1단계: HTML 파일 추가
위젯 및 위젯 구성의 구현은 매우 유사합니다. 둘 다 확장 프레임워크에서 기여로 구현됩니다. 둘 다 동일한 SDK 파일을 VSS.SDK.min.js
사용합니다. 둘 다 HTML, JavaScript 및 CSS를 기반으로 합니다.
이전 예제에서 파일을 html-world2.html
복사하고 복사본 이름을 .로 hello-world3.html
바꿉니다. 라는 configuration.html
다른 HTML 파일을 추가합니다.
이제 폴더는 다음 예제와 같습니다.
|--- README.md
|--- sdk
|--- node_modules
|--- scripts
|--- VSS.SDK.min.js
|--- img
|--- logo.png
|--- scripts
|--- configuration.html
|--- hello-world.html // html page to be used for your widget
|--- hello-world2.html // renamed copy of hello-world.html
|--- hello-world3.html // renamed copy of hello-world2.html
|--- vss-extension.json // extension's manifest
에 다음 HTML을 추가합니다 configuration.html
. 기본적으로 파일에 대한 필수 참조 VSS.SDK.min.js
와 select
드롭다운의 요소를 추가하여 미리 설정된 목록에서 쿼리를 선택합니다.
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script src="sdk/scripts/VSS.SDK.min.js"></script>
</head>
<body>
<div class="container">
<fieldset>
<label class="label">Query: </label>
<select id="query-path-dropdown" style="margin-top:10px">
<option value="" selected disabled hidden>Please select a query</option>
<option value="Shared Queries/Feedback">Shared Queries/Feedback</option>
<option value="Shared Queries/My Bugs">Shared Queries/My Bugs</option>
<option value="Shared Queries/My Tasks">Shared Queries/My Tasks</option>
</select>
</fieldset>
</div>
</body>
</html>
2단계: JavaScript 구성
이 가이드의 1부 3단계에서 위젯에 대해 수행한 것처럼 JavaScript를 사용하여 위젯 구성에서 콘텐츠를 렌더링합니다.
이 JavaScript 코드는 콘텐츠를 렌더링하고, VSS SDK를 초기화하고, 위젯 구성의 코드를 구성 이름에 매핑하고, 구성 설정을 프레임워크에 전달합니다. 이 경우 다음 코드는 위젯 구성을 로드합니다.
파일 configuration.html
및 다음 <script>
요소를 <head>
엽니다.
<script type="text/javascript">
VSS.init({
explicitNotifyLoaded: true,
usePlatformStyles: true
});
VSS.require(["AzureDevOps/Dashboards/WidgetHelpers"], function (WidgetHelpers) {
VSS.register("HelloWorldWidget.Configuration", function () {
var $queryDropdown = $("#query-path-dropdown");
return {
load: function (widgetSettings, widgetConfigurationContext) {
var settings = JSON.parse(widgetSettings.customSettings.data);
if (settings && settings.queryPath) {
$queryDropdown.val(settings.queryPath);
}
return WidgetHelpers.WidgetStatusHelper.Success();
},
onSave: function() {
var customSettings = {
data: JSON.stringify({
queryPath: $queryDropdown.val()
})
};
return WidgetHelpers.WidgetConfigurationSave.Valid(customSettings);
}
}
});
VSS.notifyLoadSucceeded();
});
</script>
VSS.init
VSS.require
에서는VSS.register
1부에 설명된 대로 위젯에 대해 동일한 역할을 합니다. 유일한 차이점은 위젯 구성의 경우 전달되는VSS.register
함수가 계약을 충족IWidgetConfiguration
하는 개체를 반환해야 한다는 것입니다.- 계약의 속성에는
load
IWidgetConfiguration
해당 값으로 함수가 있어야 합니다. 이 함수에는 위젯 구성을 렌더링하는 단계 집합이 있습니다. 이 경우 드롭다운 요소의 선택한 값을 기존 설정(있는 경우)으로 업데이트합니다. 프레임워크에서 인스턴스화할 때 이 함수가 호출됩니다.widget configuration
- 계약의 속성에는
onSave
IWidgetConfiguration
해당 값으로 함수가 있어야 합니다. 이 함수는 사용자가 구성 창에서 저장을 선택하면 프레임워크에서 호출됩니다. 사용자 입력을 저장할 준비가 되면 문자열로 serialize하고 개체를custom settings
형성하여 사용자 입력을 저장하는 데 사용합니다WidgetConfigurationSave.Valid()
.
이 가이드에서는 JSON을 사용하여 사용자 입력을 문자열로 직렬화합니다. 사용자 입력을 문자열로 직렬화하는 다른 방법을 선택할 수 있습니다.
개체의 customSettings 속성을 WidgetSettings
통해 위젯에 액세스할 수 있습니다.
위젯은 역직렬화해야 하며 4단계에서 다룹니다.
3단계: JavaScript - 라이브 미리 보기 사용
사용자가 드롭다운에서 쿼리를 선택할 때 라이브 미리 보기 업데이트를 사용하도록 설정하려면 변경 이벤트 처리기를 단추에 연결합니다. 이 처리기는 구성이 변경되었다는 것을 프레임워크에 알깁니다.
또한 미리 보기를 업데이트하는 데 사용할 대상을 전달 customSettings
합니다. 프레임워크에 알리려면 메서드를 notify
widgetConfigurationContext
호출해야 합니다. 이 매개 변수는 두 개의 매개 변수를 사용합니다. 이 경우는 이벤트의 이름과 도우미 메서드를 사용하여 만든 customSettings
이벤트에 대한 개체입니다.WidgetHelpers.WidgetEvent.ConfigurationChange
EventArgs
WidgetEvent.Args
속성에 할당된 함수에 다음 코드를 추가합니다 load
.
$queryDropdown.on("change", function () {
var customSettings = {
data: JSON.stringify({
queryPath: $queryDropdown.val()
})
};
var eventName = WidgetHelpers.WidgetEvent.ConfigurationChange;
var eventArgs = WidgetHelpers.WidgetEvent.Args(customSettings);
widgetConfigurationContext.notify(eventName, eventArgs);
});
수정됨: 저장 단추를 사용하도록 설정하기 위해 프레임워크에 구성 변경 내용에 대해 한 번 이상 알림을 받도록 합니다.
끝 configuration.html
부분에서 다음 예제와 같습니다.
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script src="sdk/scripts/VSS.SDK.min.js"></script>
<script type="text/javascript">
VSS.init({
explicitNotifyLoaded: true,
usePlatformStyles: true
});
VSS.require(["AzureDevOps/Dashboards/WidgetHelpers"], function (WidgetHelpers) {
VSS.register("HelloWorldWidget.Configuration", function () {
var $queryDropdown = $("#query-path-dropdown");
return {
load: function (widgetSettings, widgetConfigurationContext) {
var settings = JSON.parse(widgetSettings.customSettings.data);
if (settings && settings.queryPath) {
$queryDropdown.val(settings.queryPath);
}
$queryDropdown.on("change", function () {
var customSettings = {data: JSON.stringify({queryPath: $queryDropdown.val()})};
var eventName = WidgetHelpers.WidgetEvent.ConfigurationChange;
var eventArgs = WidgetHelpers.WidgetEvent.Args(customSettings);
widgetConfigurationContext.notify(eventName, eventArgs);
});
return WidgetHelpers.WidgetStatusHelper.Success();
},
onSave: function() {
var customSettings = {data: JSON.stringify({queryPath: $queryDropdown.val()})};
return WidgetHelpers.WidgetConfigurationSave.Valid(customSettings);
}
}
});
VSS.notifyLoadSucceeded();
});
</script>
</head>
<body>
<div class="container">
<fieldset>
<label class="label">Query: </label>
<select id="query-path-dropdown" style="margin-top:10px">
<option value="" selected disabled hidden>Please select a query</option>
<option value="Shared Queries/Feedback">Shared Queries/Feedback</option>
<option value="Shared Queries/My Bugs">Shared Queries/My Bugs</option>
<option value="Shared Queries/My Tasks">Shared Queries/My Tasks</option>
</select>
</fieldset>
</div>
</body>
</html>
4단계: 위젯에서 다시 로드 구현 - JavaScript
사용자가 선택한 쿼리 경로를 저장하도록 위젯 구성을 설정했습니다.
이제 위젯의 코드를 업데이트하여 이전 예제에서 하드 코딩된 Shared Queries/Feedback
대신 이 저장된 구성을 사용해야 합니다.
파일을 hello-world3.html
열고 호출VSS.register
하는 줄에서 HelloWorldWidget2
위젯의 이름을 업데이트합니다HelloWorldWidget3
.
이 작업을 통해 프레임워크는 확장 내에서 위젯을 고유하게 식별할 수 있습니다.
현재 통해 매핑된 HelloWorldWidget3
VSS.register
함수는 계약을 충족하는 개체를 IWidget
반환합니다.
이제 위젯에 구성이 필요하므로 계약을 충족하는 개체를 반환하려면 이 함수를 IConfigurableWidget
업데이트해야 합니다.
이렇게 하려면 다음 코드에 따라 reload라는 속성을 포함하도록 return 문을 업데이트합니다. 이 속성의 값은 메서드를 한 번 더 호출 getQueryInfo
하는 함수입니다.
이 다시 로드 메서드는 사용자가 입력할 때마다 프레임워크에서 호출되어 라이브 미리 보기를 표시합니다. 이 다시 로드 메서드는 구성을 저장할 때도 호출됩니다.
return {
load: function (widgetSettings) {
// Set your title
var $title = $('h2.title');
$title.text('Hello World');
return getQueryInfo(widgetSettings);
},
reload: function (widgetSettings) {
return getQueryInfo(widgetSettings);
}
}
하드 코딩된 쿼리 경로 getQueryInfo
는 구성된 쿼리 경로로 바꿔야 합니다. 이 경로는 메서드에 전달되는 매개 변수 widgetSettings
에서 추출할 수 있습니다.
메서드의 getQueryInfo
시작 부분에 다음 코드를 추가하고 하드 코딩된 쿼리 경로를 settings.queryPath
.
var settings = JSON.parse(widgetSettings.customSettings.data);
if (!settings || !settings.queryPath) {
var $container = $('#query-info-container');
$container.empty();
$container.text("Sorry nothing to show, please configure a query path.");
return WidgetHelpers.WidgetStatusHelper.Success();
}
이 시점에서 위젯은 구성된 설정을 사용하여 렌더링할 준비가 된 것입니다.
load
속성과 reload
속성 모두 비슷한 함수가 있습니다. 가장 간단한 위젯의 경우입니다.
복잡한 위젯의 경우 구성 변경 횟수에 관계없이 한 번만 실행하려는 특정 작업이 있습니다.
또는 두 번 이상 실행할 필요가 없는 중량이 많은 작업이 있을 수 있습니다. 이러한 작업은 속성이 아닌 속성에 load
해당하는 함수의 reload
일부가 됩니다.
5단계: 확장 매니페스트 업데이트
속성을 배열 contributions
에 vss-extension.json
두 개의 새 항목을 포함하도록 파일을 엽니다. 하나는 위젯용 HelloWorldWidget3
이고 다른 하나는 해당 구성에 대한 것입니다.
세 번째 위젯에 대한 또 다른 미리 보기 이미지가 필요합니다. 이 preview3.png
이름을 지정하고 폴더에 배치합니다 img
.
이 예제에서 추가한 files
두 개의 새 HTML 파일을 포함하도록 속성의 배열을 업데이트합니다.
{
...
"contributions": [
... ,
{
"id": "HelloWorldWidget3",
"type": "ms.vss-dashboards-web.widget",
"targets": [
"ms.vss-dashboards-web.widget-catalog",
"fabrikam.azuredevops-extensions-myExtensions.HelloWorldWidget.Configuration"
],
"properties": {
"name": "Hello World Widget 3 (with config)",
"description": "My third widget",
"previewImageUrl": "img/preview3.png",
"uri": "hello-world3.html",
"supportedSizes": [
{
"rowSpan": 1,
"columnSpan": 2
}
],
"supportedScopes": ["project_team"]
}
},
{
"id": "HelloWorldWidget.Configuration",
"type": "ms.vss-dashboards-web.widget-configuration",
"targets": [ "ms.vss-dashboards-web.widget-configuration" ],
"properties": {
"name": "HelloWorldWidget Configuration",
"description": "Configures HelloWorldWidget",
"uri": "configuration.html"
}
}
],
"files": [
{
"path": "hello-world.html", "addressable": true
},
{
"path": "hello-world2.html", "addressable": true
},
{
"path": "hello-world3.html", "addressable": true
},
{
"path": "configuration.html", "addressable": true
},
{
"path": "sdk/scripts", "addressable": true
},
{
"path": "img", "addressable": true
}
],
...
}
위젯 구성에 대한 기여도는 위젯 자체와 약간 다른 모델을 따릅니다. 위젯 구성에 대한 기여 항목은 다음과 같습니다.
- 기여를 식별할 ID입니다. ID는 확장 내에서 고유해야 합니다.
- 기여 유형입니다. 모든 위젯 구성의 경우
ms.vss-dashboards-web.widget-configuration
- 기여가 기여하는 대상의 배열입니다. 모든 위젯 구성의 경우 단일 항목
ms.vss-dashboards-web.widget-configuration
이 있습니다. - 구성에 사용되는 HTML 파일의 이름, 설명 및 URI를 포함하는 속성 집합을 포함하는 속성입니다.
구성을 지원하려면 위젯 기여도 변경해야 합니다. 위젯에 대한 대상의 배열을 업데이트하여 구성publisher
>< ID를 .><id for the extension
.id for the configuration contribution
<> 이 경우 .fabrikam.vsts-extensions-myExtensions.HelloWorldWidget.Configuration
Warning
구성 가능한 위젯에 대한 기여 항목이 앞에서 설명한 대로 올바른 게시자 및 확장 이름을 사용하여 구성을 대상으로 하지 않는 경우 위젯에 대한 구성 단추가 표시되지 않습니다.
이 부분의 끝에서 매니페스트 파일에는 위젯 3개와 구성 1개가 포함되어야 합니다. 여기에서 샘플 에서 전체 매니페스트를 가져올 수 있습니다.
6단계: 패키지, 게시 및 공유
확장이 게시되지 않은 경우 이 섹션을 참조하세요. 확장을 이미 게시한 경우 확장을 다시 패키지하고 Marketplace로 직접 업데이트할 수 있습니다.
7단계: 카탈로그에서 위젯 추가
이제 팀 대시보드로 이동합니다. https://dev.azure.com/{Your_Organization}/{Your_Project}. 이 페이지가 이미 열려 있는 경우 새로 고칩니다. 편집을 마우스로 가리키고 추가를 선택합니다. 이 작업은 설치한 위젯을 찾을 수 있는 위젯 카탈로그를 열어야 합니다. 대시보드에 위젯을 추가하려면 위젯을 선택하고 추가를 선택합니다.
다음과 유사한 메시지는 위젯을 구성하도록 요청합니다.
위젯을 구성하는 방법에는 두 가지가 있습니다. 하나는 위젯을 마우스로 가리키고 오른쪽 위 모서리에 표시되는 줄임표를 선택한 다음 구성을 선택하는 것입니다. 다른 하나는 대시보드의 오른쪽 아래에 있는 편집 단추를 선택한 다음 위젯의 오른쪽 위 모서리에 표시되는 구성 단추를 선택하는 것입니다. 오른쪽에 구성 환경이 열리고 가운데에 위젯 미리 보기가 열립니다. 계속 진행하여 드롭다운에서 쿼리를 선택합니다. 라이브 미리 보기에는 업데이트된 결과가 표시됩니다. 저장을 선택하면 위젯에 업데이트된 결과가 표시됩니다.
8단계: 추가 구성(선택 사항)
더 많은 구성에 configuration.html
필요한 만큼 HTML 양식 요소를 추가할 수 있습니다.
위젯 이름 및 위젯 크기라는 두 가지 구성 가능한 기능을 기본으로 사용할 수 있습니다.
기본적으로 확장 매니페스트에서 위젯에 제공하는 이름은 대시보드에 추가되는 위젯의 모든 인스턴스에 대한 위젯 이름으로 저장됩니다.
사용자가 원하는 이름을 위젯 인스턴스에 추가할 수 있도록 구성할 수 있습니다.
이러한 구성을 허용하려면 확장 매니페스트에서 위젯의 속성 섹션에 추가 isNameConfigurable:true
합니다.
확장 매니페스트의 배열에서 supportedSizes
위젯에 대해 둘 이상의 항목을 제공하는 경우 사용자는 위젯의 크기도 구성할 수 있습니다.
위젯 이름 및 크기 구성을 사용하도록 설정하면 이 가이드의 세 번째 샘플에 대한 확장 매니페스트는 다음 예제와 같습니다.
{
...
"contributions": [
... ,
{
"id": "HelloWorldWidget3",
"type": "ms.vss-dashboards-web.widget",
"targets": [
"ms.vss-dashboards-web.widget-catalog",
"fabrikam.azuredevops-extensions-myExtensions.HelloWorldWidget.Configuration"
],
"properties": {
"name": "Hello World Widget 3 (with config)",
"description": "My third widget",
"previewImageUrl": "img/preview3.png",
"uri": "hello-world3.html",
"isNameConfigurable": true,
"supportedSizes": [
{
"rowSpan": 1,
"columnSpan": 2
},
{
"rowSpan": 2,
"columnSpan": 2
}
],
"supportedScopes": ["project_team"]
}
},
...
]
}
이전 변경 내용으로 확장을 다시 패키키지 하고 업데이트 합니다. 이 위젯이 있는 대시보드를 새로 고칩니다(헬로 월드 위젯 3(구성 포함). 위젯에 대한 구성 모드를 열면 이제 위젯 이름 및 크기를 변경하는 옵션을 볼 수 있습니다.
드롭다운에서 다른 크기를 선택합니다. 라이브 미리 보기의 크기가 조정되는 것을 볼 수 있습니다. 변경 내용 저장 및 대시보드의 위젯 크기도 조정됩니다.
위젯의 이름을 변경해도 위젯에 표시되는 변경은 발생하지 않습니다. 샘플 위젯은 위젯 이름을 어디에도 표시하지 않기 때문입니다. 하드 코딩된 텍스트 "헬로 월드" 대신 위젯 이름을 표시하도록 샘플 코드를 수정해 보겠습니다.
이렇게 하려면 하드 코딩된 텍스트 "헬로 월드"을 widgetSettings.name
요소의 h2
텍스트를 설정한 줄로 바꿉니다.
이 작업을 수행하면 위젯이 페이지 새로 고침 시 로드될 때마다 위젯 이름이 표시됩니다.
구성이 변경될 때마다 라이브 미리 보기를 업데이트하려고 하므로 코드 부분에도 동일한 코드를 reload
추가해야 합니다.
최종 반환 문 hello-world3.html
은 다음과 같습니다.
return {
load: function (widgetSettings) {
// Set your title
var $title = $('h2.title');
$title.text(widgetSettings.name);
return getQueryInfo(widgetSettings);
},
reload: function (widgetSettings) {
// Set your title
var $title = $('h2.title');
$title.text(widgetSettings.name);
return getQueryInfo(widgetSettings);
}
}
확장을 다시 패키지 하고 업데이트 합니다. 이 위젯이 있는 대시보드를 새로 고칩니다.
구성 모드에서 위젯 이름을 변경하면 이제 위젯 제목을 업데이트합니다.