1
0
Форкнуть 0

Merge pull request #3 from microsoft/ByAgenT/wit-type-scoping-remove

Remove work item type scoping
This commit is contained in:
Anton Kovalyov 2019-07-31 13:46:56 -07:00 коммит произвёл GitHub
Родитель 86c93d2635 e4b4bd4a28
Коммит c95cce60b1
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
7 изменённых файлов: 58 добавлений и 117 удалений

Просмотреть файл

@ -1,4 +1,4 @@
{
"version": "0.1.2",
"version": "0.1.3",
"baseUri": "https://localhost:44300"
}

Просмотреть файл

@ -1,20 +1,12 @@
import { ConfigurationStorage, ConfigurationType } from './storage.service';
import { IManifest } from './types';
import {
StorageService,
ConfigurationType,
ScopeType,
ConfigurationStorage,
} from './storage.service';
class ManifestService {
private configurationStorage: ConfigurationStorage;
public constructor(projectId: string, workItemType: string) {
this.configurationStorage = new ConfigurationStorage(
ConfigurationType.Manifest,
projectId,
workItemType
);
public constructor(projectId: string) {
this.configurationStorage = new ConfigurationStorage(ConfigurationType.Manifest, projectId);
}
public async getManifest(): Promise<IManifest> {
@ -27,3 +19,4 @@ class ManifestService {
}
export { ManifestService };

Просмотреть файл

@ -1,6 +1,5 @@
import { CommonServiceIds, IExtensionDataService } from 'azure-devops-extension-api';
import * as SDK from 'azure-devops-extension-sdk';
import { CascadeConfiguration } from './types';
enum ScopeType {
Default = 'Default',
@ -57,16 +56,9 @@ class StorageService {
class ConfigurationStorage {
private storageService: StorageService;
public constructor(
configurationType: ConfigurationType,
projectId: string,
workItemType: string
) {
if (workItemType === '' || workItemType === undefined) {
throw new Error('Work item type cannot be empty or undefined.');
}
public constructor(configurationType: ConfigurationType, projectId: string) {
this.storageService = new StorageService(
`${configurationType}|${projectId}|${workItemType}`,
`${configurationType}|${projectId}`,
ScopeType.Default
);
}
@ -75,9 +67,7 @@ class ConfigurationStorage {
return this.storageService.getData();
}
public async setConfiguration(
configuration: Object
): Promise<Object> {
public async setConfiguration(configuration: Object): Promise<Object> {
return this.storageService.setData(configuration) as Promise<Object>;
}
}

Просмотреть файл

@ -6,18 +6,13 @@ import {
HeaderTitleRow,
TitleSize,
} from 'azure-devops-ui/Header';
import { Dropdown } from 'azure-devops-ui/Dropdown';
import { IStatusProps, Status, Statuses, StatusSize } from 'azure-devops-ui/Status';
import * as React from 'react';
import styled from 'styled-components';
import { IListBoxItem } from 'azure-devops-ui/ListBox';
interface IHeaderProps {
title: string;
isStatusOk: boolean;
dropdownPlaceholder: string;
dropdownItems: IListBoxItem[];
onDropdownSelect: (event: React.SyntheticEvent<HTMLElement>, item: IListBoxItem) => void;
onSaveClick: () => void | Promise<void>;
}
@ -30,14 +25,7 @@ const HeaderSideContainer = styled.div`
}
`;
const Header = ({
title,
isStatusOk,
onSaveClick,
onDropdownSelect,
dropdownItems,
dropdownPlaceholder,
}: IHeaderProps) => {
const Header = ({ title, isStatusOk, onSaveClick }: IHeaderProps) => {
const statusProps: IStatusProps = isStatusOk ? Statuses.Success : Statuses.Failed;
return (
@ -48,12 +36,6 @@ const Header = ({
</HeaderTitleRow>
</HeaderTitleArea>
<HeaderSideContainer>
<Dropdown
width={250}
placeholder={dropdownPlaceholder}
items={dropdownItems}
onSelect={onDropdownSelect}
/>
<Button text='Save configuration' primary={true} onClick={onSaveClick} />
<Status {...statusProps} size={StatusSize.l} />
</HeaderSideContainer>

Просмотреть файл

@ -9,65 +9,62 @@ import { WorkItemType } from 'azure-devops-extension-api/WorkItemTracking/WorkIt
import { getClient } from 'azure-devops-extension-api';
import { ManifestService } from '../../common/manifest.service';
function useConfigurationStorage(
workItemTypeName: string
): [object, string, boolean, (value: string) => void, () => Promise<void>] {
function useConfigurationStorage(): [
string,
boolean,
(value: string) => void,
() => Promise<void>
] {
const [config, setConfig] = useState({});
const [configText, setConfigText] = useState('');
const [status, setStatus] = useState(true);
function saveDraft(value: string): void {
try {
const parsedConfig = JSON.parse(value);
setConfig(parsedConfig);
setStatus(true);
} catch (error) {
setStatus(false);
}
setConfigText(value);
}
async function publishConfig(): Promise<void> {
if (!status) {
throw new Error('Configuration is invalid');
}
const projectInfoService = await SDK.getService<IProjectPageService>(
CommonServiceIds.ProjectPageService
);
const project = await projectInfoService.getProject();
const manifest = await new ManifestService(project.id).updateManifest(config);
setConfig(manifest);
}
useEffect(() => {
(async function() {
const projectInfoService = await SDK.getService<IProjectPageService>(
CommonServiceIds.ProjectPageService
);
const project = await projectInfoService.getProject();
const manifestService = new ManifestService(project.id, workItemTypeName);
const manifestService = new ManifestService(project.id);
try {
const manifest = await manifestService.getManifest();
if (manifest === undefined) {
setConfig({});
setConfigText('');
saveDraft('');
} else {
setConfig(manifest);
setConfigText(JSON.stringify(manifest, null, 2));
saveDraft(JSON.stringify(manifest, null, 2));
}
} catch (error) {
setConfig({});
setConfigText('');
saveDraft('');
}
})();
}, [workItemTypeName]);
}, []);
async function updateConfigurationStorage() {
// TODO: make status validation within a hook rather that trust a component.
if (!status) {
throw new Error('Configuration is invalid');
}
const projectInfoService = await SDK.getService<IProjectPageService>(
CommonServiceIds.ProjectPageService
);
const project = await projectInfoService.getProject();
const manifestService = new ManifestService(project.id, workItemTypeName);
const manifest = await manifestService.updateManifest(config);
setConfig(manifest);
}
function saveConfig(value: string): void {
try {
const parsedConfig = JSON.parse(value);
setStatus(true);
setConfigText(value);
setConfig(parsedConfig);
} catch (error) {
setConfigText(value);
setStatus(false);
}
}
return [config, configText, status, saveConfig, updateConfigurationStorage];
return [configText, status, saveDraft, publishConfig];
}
function useFetchWorkItemTypes(): WorkItemType[] {

Просмотреть файл

@ -3,9 +3,7 @@ import MonacoEditor from 'react-monaco-editor';
import styled from 'styled-components';
import { Header } from '../components/Header';
import { useExternalToast } from '../hooks/toast';
import { useConfigurationStorage, useFetchWorkItemTypes } from './ConfigView.hooks';
import { IListBoxItem } from 'azure-devops-ui/ListBox';
import { useState, useEffect } from 'react';
import { useConfigurationStorage } from './ConfigView.hooks';
const EditorContainer = styled.div`
display: flex;
@ -25,44 +23,27 @@ const EditorOptions = {
};
const ConfigView = () => {
const [currentWorkItemType, setCurrentWorkItemType] = useState<string>('');
const workItemTypes = useFetchWorkItemTypes();
const [, configText, status, saveConfig, updateConfigurationStorage] = useConfigurationStorage(
currentWorkItemType
);
const [configText, status, saveConfig, updateConfigurationStorage] = useConfigurationStorage();
const showToast = useExternalToast();
useEffect(() => {
// TODO: update dropdown current value here
setCurrentWorkItemType(workItemTypes[0] ? workItemTypes[0].name : '');
}, [workItemTypes]);
function editorDidMount(editor) {
editor.getModel().updateOptions({ tabSize: 2 });
}
function onWorkItemSelect(event: React.SyntheticEvent<HTMLElement>, item: IListBoxItem) {
setCurrentWorkItemType(item.text);
async function onSaveButtonClick() {
try {
await updateConfigurationStorage();
await showToast('Configuration succesfully saved.', 2000);
} catch (error) {
await showToast('Error saving configuration.', 2000);
}
}
const dropdownItems = workItemTypes.map(workItemType => {
return { id: workItemType.referenceName, text: workItemType.name };
});
return (
<ConfigViewContainer>
<Header
title='Cascading list config'
onSaveClick={async () => {
try {
await updateConfigurationStorage();
await showToast('Configuration succesfully saved.', 2000);
} catch (error) {
await showToast('Error saving configuration.', 2000);
}
}}
dropdownPlaceholder=''
dropdownItems={dropdownItems}
onDropdownSelect={onWorkItemSelect}
title='Cascading List Config'
onSaveClick={onSaveButtonClick}
isStatusOk={status}
/>
<EditorContainer>

Просмотреть файл

@ -20,13 +20,11 @@ SDK.init({
const workItemFormService = await SDK.getService<IWorkItemFormService>(
WorkItemTrackingServiceIds.WorkItemFormService
);
const projectInfoService = await SDK.getService<IProjectPageService>(
CommonServiceIds.ProjectPageService
);
const project = await projectInfoService.getProject();
const workItemType = (await workItemFormService.getFieldValue('System.WorkItemType')) as string;
const manifestService = new ManifestService(project.id, workItemType);
const manifestService = new ManifestService(project.id);
const manifest = await manifestService.getManifest();
const cascadingService = new CascadingFieldsService(workItemFormService, manifest.cascades);