Merge pull request #3 from microsoft/ByAgenT/wit-type-scoping-remove
Remove work item type scoping
This commit is contained in:
Коммит
c95cce60b1
|
@ -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);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче