This commit is contained in:
Navneet Gupta 2018-07-18 19:55:11 -07:00
Родитель 5457e07fc3
Коммит 86342174ad
21 изменённых файлов: 3848 добавлений и 11065 удалений

14312
package-lock.json сгенерированный

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -28,52 +28,51 @@
],
"dependencies": {
"es6-promise": "^4.2.4",
"npm": "^6.0.1",
"office-ui-fabric-react": "^5.68.0",
"rc-input-number": "^4.0.10",
"react": "^16.2.0",
"immer": "^1.3.1",
"office-ui-fabric-react": "^5.117.0",
"rc-input-number": "^4.0.12",
"react": "^16.4.1",
"react-dnd": "^2.6.0",
"react-dnd-html5-backend": "^2.6.0",
"react-dom": "^16.2.0",
"react-dom": "^16.4.1",
"react-redux": "^5.0.7",
"react-splitter-layout": "^3.0.0",
"redux": "^3.7.2",
"redux-logger": "^3.0.6",
"redux-saga": "^0.16.0",
"reselect": "^3.0.1",
"vss-web-extension-sdk": "^5.131.0"
"vss-web-extension-sdk": "^5.134.0"
},
"devDependencies": {
"@types/jest": "^22.2.2",
"@types/jquery": "^2.0.41",
"@types/react": "^15.0.21",
"@types/react": "^15.6.18",
"@types/react-dom": "^0.14.23",
"@types/react-redux": "^5.0.15",
"awesome-typescript-loader": "^4.0.1",
"copy-webpack-plugin": "^4.0.1",
"copy-webpack-plugin": "^4.5.2",
"css-loader": "^0.28.0",
"extract-text-webpack-plugin": "^3.0.2",
"jest": "^22.4.3",
"node-sass": "^4.8.3",
"prettier": "^1.12.1",
"jest": "^22.4.4",
"node-sass": "^4.9.2",
"prettier": "^1.13.7",
"prettier-webpack-plugin": "^1.0.0",
"redux-devtools": "^3.4.1",
"rimraf": "^2.6.1",
"sass-loader": "^6.0.7",
"source-map-loader": "^0.2.3",
"style-loader": "^0.16.1",
"tfx-cli": "^0.4.5",
"tfx-cli": "^0.5.14",
"ts-jest": "^22.4.2",
"ts-loader": "^4.0.1",
"tslint": "^5.10.0",
"ts-loader": "^4.4.2",
"tslint": "^5.11.0",
"tslint-react": "^3.6.0",
"typescript": "^2.7.2",
"typescript": "^2.9.2",
"typings": "^2.1.0",
"uglifyjs-webpack-plugin": "^0.4.2",
"webpack": "^4.2.0",
"webpack-bundle-analyzer": "^2.11.1",
"webpack-cli": "^2.1.3",
"webpack-dev-server": "^3.1.1"
"uglifyjs-webpack-plugin": "^1.2.7",
"webpack": "^4.16.1",
"webpack-bundle-analyzer": "^2.13.1",
"webpack-cli": "^3.0.8",
"webpack-dev-server": "^3.1.4"
},
"jest": {
"transform": {

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

@ -510,7 +510,6 @@ export class FeatureTimelineGrid extends React.Component<IFeatureTimelineGridPro
}
private _onViewChanged = (text: string) => {
debugger;
const {
projectId,
teamId

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

@ -46,6 +46,8 @@ class WorkItemList extends React.Component<IWorkItemListProps, IWorkItemListStat
if (workItems.length === 0) {
message = <MessageBar>Only top 100 Proposed features are available.</MessageBar>;
}
debugger;
return (
<div className="work-item-list-container">
<TextField

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

@ -79,7 +79,6 @@ export function* handleInitialize(action: InitializeAction) {
const teamFieldValues: Contracts.TeamFieldValues = tfv;
// For now show only lowest level of portfolio backlog
backlogConfig.portfolioBacklogs.sort((b1, b2) => b1.rank - b2.rank);
const workItemTypeNames = [];
backlogConfig.portfolioBacklogs.reduce((workItemTypeNames, backlog) => {
workItemTypeNames.push(...backlog.workItemTypes.map(w => w.name));

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

@ -77,7 +77,6 @@ export const planFeatureStateSelector = () => {
if (!state || !state.planFeaturesState) {
return getDefaultPlanFeaturesPaneState();
}
return state.planFeaturesState;
})
}

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

@ -1,6 +1,7 @@
import { Reducer } from 'redux';
import { IBacklogConfigurationState } from './types';
import { BacklogConfigurationActions, BacklogConfigurationReceivedType, BacklogConfigurationReceivedAction } from './actions';
import produce from "immer";
// Type-safe initialState!
const getInitialState = () => {
@ -10,27 +11,27 @@ const getInitialState = () => {
};
const reducer: Reducer<IBacklogConfigurationState> = (state: IBacklogConfigurationState = getInitialState(), action: BacklogConfigurationActions) => {
switch (action.type) {
case BacklogConfigurationReceivedType:
return handleBacklogConfigurationReceived(state, action as BacklogConfigurationReceivedAction);
default:
return state;
}
return produce(state, draft => {
switch (action.type) {
case BacklogConfigurationReceivedType:
return handleBacklogConfigurationReceived(draft, action as BacklogConfigurationReceivedAction);
}
});
};
function handleBacklogConfigurationReceived(state: IBacklogConfigurationState, action: BacklogConfigurationReceivedAction): IBacklogConfigurationState {
let newState = { ...state };
const {
projectId,
teamId,
backlogConfiguration
} = action.payload;
const projectData = newState.backlogConfigurations[projectId] ? { ...newState.backlogConfigurations[projectId] } : {};
backlogConfiguration.portfolioBacklogs.sort((b1, b2) => b1.rank - b2.rank);
const projectData = state.backlogConfigurations[projectId] || {};
projectData[teamId] = backlogConfiguration;
newState.backlogConfigurations[projectId] = projectData;
state.backlogConfigurations[projectId] = projectData;
return newState;
return state;
}
export default reducer;

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

@ -1,14 +1,14 @@
import { Reducer } from 'redux';
import { ToggleFeatureStateAction, ToggleFeatureStateType } from './actions';
import produce from "immer";
const reducer: Reducer<IDictionaryStringTo<boolean>> = (state: IDictionaryStringTo<boolean> = {}, action: ToggleFeatureStateAction) => {
switch (action.type) {
case ToggleFeatureStateType:
const newState = {...state};
newState[action.payload.featureName] = action.payload.isEnabled
return newState;
default:
return state;
}
return produce(state, draft => {
switch (action.type) {
case ToggleFeatureStateType:
draft[action.payload.featureName] = action.payload.isEnabled
}
});
};
export default reducer;

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

@ -1,14 +1,18 @@
import { Reducer } from 'redux';
import { CommonActions, ShowDetailsType, CloseDetailsType } from './actions';
import produce from "immer";
const reducer: Reducer<number[]> = (state: number[] = [], action: CommonActions) => {
switch (action.type) {
case ShowDetailsType:
return [...state, action.payload.id];
case CloseDetailsType:
return state.filter(id => id !== action.payload.id);
default:
return state;
}
return produce(state, draft => {
switch (action.type) {
case ShowDetailsType:
draft.push(action.payload.id);;
break;
case CloseDetailsType:
return draft.filter(id => id !== action.payload.id);
break;
}
});
};
export default reducer;

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

@ -1,7 +1,7 @@
import { Reducer } from 'redux';
import { ISettingsState, ProgressTrackingCriteria } from '../types';
import { SettingsActions, ToggleShowWorkitemDetailsType, ChangeProgressTrackingCriteriaType, RestoreSettingsType, ChangeShowClosedSinceDaysType } from './actions';
import produce from "immer";
export const getDefaultSettingsState = (): ISettingsState => {
return {
@ -15,22 +15,22 @@ const reducer: Reducer<ISettingsState> = (state: ISettingsState = getDefaultSett
type,
payload
} = action;
const newState = { ...state };
switch (type) {
case ToggleShowWorkitemDetailsType:
newState.showWorkItemDetails = payload as boolean;
return newState;
case ChangeProgressTrackingCriteriaType:
newState.progressTrackingCriteria = payload as ProgressTrackingCriteria;
return newState;
case ChangeShowClosedSinceDaysType:
newState.showClosedSinceDays = payload as number;
return newState;
case RestoreSettingsType:
return payload as ISettingsState;
default:
return state;
if(type === RestoreSettingsType) {
return payload as ISettingsState;
}
return produce(state, draft => {
switch (type) {
case ToggleShowWorkitemDetailsType:
draft.showWorkItemDetails = payload as boolean;
break;
case ChangeProgressTrackingCriteriaType:
draft.progressTrackingCriteria = payload as ProgressTrackingCriteria;
break;
case ChangeShowClosedSinceDaysType:
draft.showClosedSinceDays = payload as number;
break;
}
});
};
export default reducer;

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

@ -1,6 +1,8 @@
import { Reducer } from 'redux';
import { TogglePlanFeaturesPaneType, PlanFeaturesPaneFilterChangedType, PlanFeaturesPaneActions, PlanFeaturesPaneWidthChangedType } from './actions';
import { IPlanFeaturesState } from '../types';
import produce from "immer";
export const getDefaultPlanFeaturesPaneState = (): IPlanFeaturesState => {
return {
show: false,
@ -13,20 +15,20 @@ const reducer: Reducer<IPlanFeaturesState> = (state: IPlanFeaturesState = getDef
type,
payload
} = action;
const newState = { ...state };
switch (type) {
case TogglePlanFeaturesPaneType:
newState.show = payload as boolean;
return newState;
case PlanFeaturesPaneFilterChangedType:
newState.filter = payload as string;
return newState;
case PlanFeaturesPaneWidthChangedType:
newState.paneWidth = payload as number;
return newState;
default:
return state;
}
return produce(state, draft => {
switch (type) {
case TogglePlanFeaturesPaneType:
draft.show = payload as boolean;
break;
case PlanFeaturesPaneFilterChangedType:
draft.filter = payload as string;
break;
case PlanFeaturesPaneWidthChangedType:
draft.paneWidth = payload as number;
break;
}
});
};
export default reducer;

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

@ -1,5 +1,6 @@
import { Reducer } from 'redux';
import { ErrorActions, GenericErrorType } from './actions';
const reducer: Reducer<string> = (state: string = "", action: ErrorActions) => {
switch (action.type) {
case GenericErrorType:

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

@ -1,29 +1,29 @@
import { Reducer } from 'redux';
import { OverrideIterationActions, OverrideIterationHoverOverIterationType, OverrideIterationStartType, OverrideIterationCleanupType } from './actions';
import { IWorkItemOverrideIteration } from '../types';
const reducer: Reducer<IWorkItemOverrideIteration> = (state: IWorkItemOverrideIteration = null, action: OverrideIterationActions) => {
switch (action.type) {
case OverrideIterationStartType:
return { ...action.payload };
case OverrideIterationCleanupType:
return null;
case OverrideIterationHoverOverIterationType: {
if (!state) {
return state;
}
const newState = { ...state };
newState.iterationDuration = { ...state.iterationDuration }
if (newState.changingStart) {
newState.iterationDuration.startIterationId = action.payload;
} else {
newState.iterationDuration.endIterationId = action.payload;
}
import produce from "immer";
return newState;
}
default:
return state;
}
const reducer: Reducer<IWorkItemOverrideIteration> = (state: IWorkItemOverrideIteration = null, action: OverrideIterationActions) => {
return produce(state, draft => {
switch (action.type) {
case OverrideIterationStartType:
return { ...action.payload };
case OverrideIterationCleanupType:
return null;
case OverrideIterationHoverOverIterationType: {
if (!state) {
return state;
}
draft.iterationDuration = { ...state.iterationDuration }
if (state.changingStart) {
draft.iterationDuration.startIterationId = action.payload;
} else {
draft.iterationDuration.endIterationId = action.payload;
}
}
}
});
};
export default reducer;

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

@ -1,6 +1,7 @@
import { Reducer } from 'redux';
import { ITeamSettingState } from './types';
import { TeamSettingActions, TeamSettingReceivedType, TeamSettingReceivedAction } from './actions';
import produce from "immer";
// Type-safe initialState!
const getInitialState = () => {
@ -19,18 +20,18 @@ const reducer: Reducer<ITeamSettingState> = (state: ITeamSettingState = getIniti
};
function handleTeamSettingReceived(state: ITeamSettingState, action: TeamSettingReceivedAction): ITeamSettingState {
let newState = { ...state };
const {
projectId,
teamId,
teamSetting
} = action.payload;
return produce(state, draft => {
const {
projectId,
teamId,
teamSetting
} = action.payload;
const projectData = newState.teamSetting[projectId] ? { ...newState.teamSetting[projectId] } : {};
projectData[teamId] = teamSetting;
newState.teamSetting[projectId] = projectData;
const projectData = draft.teamSetting[projectId] || {};
projectData[teamId] = teamSetting;
draft.teamSetting[projectId] = projectData;
return newState;
});
}
export default reducer;

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

@ -2,6 +2,7 @@ import { Reducer } from 'redux';
import { ITeamSettingsIterationState } from './types';
import { TeamSettingsIterationActions, TeamSettingsIterationReceivedType, TeamSettingsIterationReceivedAction, DisplayAllIterationsActionType, ShiftDisplayIterationLeftActionType, ShiftDisplayIterationRightActionType, ChangeDisplayIterationCountActionType, ShiftDisplayIterationLeftAction, ShiftDisplayIterationRightAction, ChangeDisplayIterationCountAction, RestoreDisplayIterationCountActionType, RestoreDisplayIterationCountAction } from './actions';
import { getCurrentIterationIndex } from '../../helpers/iterationComparer';
import produce from "immer";
// Type-safe initialState!
export const getInitialState = (): ITeamSettingsIterationState => {
@ -32,27 +33,26 @@ const reducer: Reducer<ITeamSettingsIterationState> = (state: ITeamSettingsItera
};
function handleRestoreDisplayIterationCountAction(state: ITeamSettingsIterationState, action: RestoreDisplayIterationCountAction) {
let newState = { ...state };
return produce(state, draft => {
try {
newState.iterationDisplayOptions = { ...action.payload };
let { count } = action.payload;
const iterations = state.teamSettingsIterations[action.payload.projectId][action.payload.teamId] || [];
newState.iterationDisplayOptions.totalIterations = iterations.length;
try {
draft.iterationDisplayOptions = { ...action.payload };
let { count } = action.payload;
const iterations = state.teamSettingsIterations[action.payload.projectId][action.payload.teamId] || [];
draft.iterationDisplayOptions.totalIterations = iterations.length;
// Handle incase if the team iterations changed before restore
// Handle incase if the team iterations changed before restore
if (iterations.length === 0 || !count || count > iterations.length || action.payload.endIndex >= iterations.length) {
console.log("Ignoring restore display options as iterations changed.");
newState.iterationDisplayOptions = null;
if (iterations.length === 0 || !count || count > iterations.length || action.payload.endIndex >= iterations.length) {
console.log("Ignoring restore display options as iterations changed.");
draft.iterationDisplayOptions = null;
}
}
}
catch (error) {
newState = state;
console.log('Can not restore display options: ', error, action);
}
return newState;
catch (error) {
console.log('Can not restore display options: ', error, action);
}
});
}
function handleChangeDisplayIterationCountAction(state: ITeamSettingsIterationState, action: ChangeDisplayIterationCountAction) {
@ -62,89 +62,88 @@ function handleChangeDisplayIterationCountAction(state: ITeamSettingsIterationSt
projectId
} = action.payload;
const originalCount = count;
return produce(state, draft => {
const iterations = state.teamSettingsIterations[projectId][teamId];
const currentIterationIndex = getCurrentIterationIndex(iterations);
const originalCount = count;
if (count > iterations.length) {
count = iterations.length;
}
const iterations = draft.teamSettingsIterations[projectId][teamId];
const currentIterationIndex = getCurrentIterationIndex(iterations);
const displayOptions = {
count,
originalCount,
teamId,
projectId,
startIndex: 0,
endIndex: 0,
totalIterations: iterations.length
};
if (count > iterations.length) {
count = iterations.length;
}
let startIndex = currentIterationIndex - Math.floor((count / 2));
if (startIndex < 0) {
startIndex = 0;
}
const endIndex = startIndex + (count - 1);
const displayOptions = {
count,
originalCount,
teamId,
projectId,
startIndex: 0,
endIndex: 0,
totalIterations: iterations.length
};
displayOptions.startIndex = startIndex;
displayOptions.endIndex = endIndex;
let startIndex = currentIterationIndex - Math.floor((count / 2));
if (startIndex < 0) {
startIndex = 0;
}
const endIndex = startIndex + (count - 1);
const newState = { ...state };
newState.iterationDisplayOptions = displayOptions;
return newState;
displayOptions.startIndex = startIndex;
displayOptions.endIndex = endIndex;
draft.iterationDisplayOptions = displayOptions;
});
}
function handleShiftDisplayIterationLeft(state: ITeamSettingsIterationState, action: ShiftDisplayIterationLeftAction) {
if (state.iterationDisplayOptions) {
const newState = { ...state };
const displayOptions = { ...newState.iterationDisplayOptions };
if ((displayOptions.startIndex - action.payload.count) >= 0) {
displayOptions.startIndex -= action.payload.count;
displayOptions.endIndex = displayOptions.startIndex + state.iterationDisplayOptions.count - 1;
return produce(state, draft => {
if (draft.iterationDisplayOptions) {
const displayOptions = draft.iterationDisplayOptions;
if ((displayOptions.startIndex - action.payload.count) >= 0) {
displayOptions.startIndex -= action.payload.count;
displayOptions.endIndex = displayOptions.startIndex + draft.iterationDisplayOptions.count - 1;
}
draft.iterationDisplayOptions = displayOptions
}
newState.iterationDisplayOptions = displayOptions
return newState;
}
return state;
});
}
function handleShiftDisplayIterationRight(state: ITeamSettingsIterationState, action: ShiftDisplayIterationRightAction) {
if (state.iterationDisplayOptions) {
const newState = { ...state };
const iterationCount = state.teamSettingsIterations[state.iterationDisplayOptions.projectId][state.iterationDisplayOptions.teamId].length;
const displayOptions = { ...newState.iterationDisplayOptions };
if ((displayOptions.endIndex + action.payload.count) < iterationCount) {
displayOptions.endIndex += action.payload.count;
displayOptions.startIndex = displayOptions.endIndex - state.iterationDisplayOptions.count + 1;
return produce(state, draft => {
if (draft.iterationDisplayOptions) {
const iterationCount = draft.teamSettingsIterations[draft.iterationDisplayOptions.projectId][draft.iterationDisplayOptions.teamId].length;
const displayOptions = draft.iterationDisplayOptions;
if ((displayOptions.endIndex + action.payload.count) < iterationCount) {
displayOptions.endIndex += action.payload.count;
displayOptions.startIndex = displayOptions.endIndex - draft.iterationDisplayOptions.count + 1;
}
draft.iterationDisplayOptions = displayOptions;
}
newState.iterationDisplayOptions = displayOptions;
return newState;
}
return state;
});
}
function handleDisplayAllIterations(state: ITeamSettingsIterationState) {
const newState = { ...state };
newState.iterationDisplayOptions = null;
return newState;
return produce(state, draft => {
draft.iterationDisplayOptions = null;
});
}
function handleTeamSettingsIterationReceived(state: ITeamSettingsIterationState, action: TeamSettingsIterationReceivedAction): ITeamSettingsIterationState {
let newState = { ...state };
const {
projectId,
teamId,
TeamSettingsIterations
} = action.payload;
return produce(state, draft => {
const {
projectId,
teamId,
TeamSettingsIterations
} = action.payload;
const projectData = newState.teamSettingsIterations[projectId] ? { ...newState.teamSettingsIterations[projectId] } : {};
projectData[teamId] = TeamSettingsIterations;
newState.teamSettingsIterations[projectId] = projectData;
const projectData = draft.teamSettingsIterations[projectId] || {};
projectData[teamId] = TeamSettingsIterations;
draft.teamSettingsIterations[projectId] = projectData;
return newState;
});
}
export default reducer;

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

@ -1,7 +1,7 @@
import { Reducer } from 'redux';
import { IWorkItemMetadataState, IWorkItemMetadata } from './types';
import { WorkItemTypesReceivedActionType, MetaDataActions, WorkItemTypesReceivedAction, WorkItemStateColorsReceivedAction, WorkItemStateColorsReceivedActionType } from './actions';
import produce from "immer";
// Type-safe initialState!
export const getInitialState = (): IWorkItemMetadataState => {
return {
@ -22,29 +22,29 @@ const reducer: Reducer<IWorkItemMetadataState> = (state: IWorkItemMetadataState
};
function handleWorkItemTypesReceived(state: IWorkItemMetadataState, action: WorkItemTypesReceivedAction): IWorkItemMetadataState {
let newState = { ...state };
const {
projectId,
workItemTypes
} = action.payload;
return produce(state, draft => {
const {
projectId,
workItemTypes
} = action.payload;
const projectData: IWorkItemMetadata = newState.metadata[projectId] ? { ...newState.metadata[projectId] } : {} as IWorkItemMetadata;
projectData.workItemTypes = workItemTypes;
newState.metadata[projectId] = projectData;
return newState;
const projectData: IWorkItemMetadata = draft.metadata[projectId] || {} as IWorkItemMetadata;
projectData.workItemTypes = workItemTypes;
draft.metadata[projectId] = projectData;
});
}
function handleWorkItemStateColorsReceived(state: IWorkItemMetadataState, action: WorkItemStateColorsReceivedAction): IWorkItemMetadataState {
let newState = { ...state };
const {
projectId,
workItemTypeStateColors
} = action.payload;
return produce(state, draft => {
const {
projectId,
workItemTypeStateColors
} = action.payload;
const projectData: IWorkItemMetadata = newState.metadata[projectId] ? { ...newState.metadata[projectId] } : {} as IWorkItemMetadata;
projectData.workItemStateColors = workItemTypeStateColors;
newState.metadata[projectId] = projectData;
return newState;
const projectData: IWorkItemMetadata = draft.metadata[projectId] || {} as IWorkItemMetadata;
projectData.workItemStateColors = workItemTypeStateColors;
draft.metadata[projectId] = projectData;
});
}
export default reducer;

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

@ -1,29 +1,24 @@
import { Reducer } from 'redux';
import { IOverriddenIterationDuration } from '../types';
import { SetOverrideIterationType, ClearOverrideIterationType, OverrideIterationActions } from './actions';
import produce from "immer";
const reducer: Reducer<IDictionaryNumberTo<IOverriddenIterationDuration>> =
(state: IDictionaryNumberTo<IOverriddenIterationDuration> = {}, action: OverrideIterationActions) => {
switch (action.type) {
case SetOverrideIterationType:
const newState = { ...state };
newState[Number(action.payload.workItemId)] = {
startIterationId: action.payload.startIterationId,
endIterationId: action.payload.endIterationId,
user: action.payload.user
};
return newState;
case ClearOverrideIterationType: {
if (!state) {
return state;
return produce(state, draft => {
switch (action.type) {
case SetOverrideIterationType:
draft[Number(action.payload.workItemId)] = {
startIterationId: action.payload.startIterationId,
endIterationId: action.payload.endIterationId,
user: action.payload.user
};
break;
case ClearOverrideIterationType: {
delete draft[action.payload]
}
const newState = { ...state };
delete newState[action.payload]
return newState;
}
default:
return state;
}
});
};
export default reducer;

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

@ -14,6 +14,7 @@ import {
import { IWorkItemsState, WorkItemLevel, StateCategory } from './types';
import { Reducer } from 'redux';
import { getWorkItemStateCategory } from '../../helpers/getWorkItemStateCategory';
import produce from "immer";
// Type-safe initialState!
const getIntialState = () => {
@ -45,13 +46,12 @@ function handleStartUpdateWorkItemIteration(state: IWorkItemsState, action: Star
teamIteration
} = action.payload;
const newState = { ...state };
const workItemObject = newState.workItemInfos[workItem];
if (workItemObject) {
workItemObject.workItem.fields = { ...workItemObject.workItem.fields };
workItemObject.workItem.fields["System.IterationPath"] = teamIteration.path;
}
return newState;
return produce(state, draft => {
const workItemObject = draft.workItemInfos[workItem];
if (workItemObject) {
workItemObject.workItem.fields["System.IterationPath"] = teamIteration.path;
}
});
}
function handleStartMarkInProgress(workItemState: IWorkItemsState, action: StartMarkInProgressAction): IWorkItemsState {
@ -60,16 +60,13 @@ function handleStartMarkInProgress(workItemState: IWorkItemsState, action: Start
teamIteration
} = action.payload;
const newState = { ...workItemState };
let workItemObject = newState.workItemInfos[workItem];
if (workItemObject) {
workItemObject = { ...workItemObject };
workItemObject.workItem.fields = { ...workItemObject.workItem.fields };
workItemObject.workItem.fields["System.IterationPath"] = teamIteration.path;
workItemObject.stateCategory = StateCategory.InProgress;
newState.workItemInfos[workItem]= workItemObject;
}
return newState;
return produce(workItemState, draft => {
let workItemObject = draft.workItemInfos[workItem];
if (workItemObject) {
workItemObject.workItem.fields["System.IterationPath"] = teamIteration.path;
workItemObject.stateCategory = StateCategory.InProgress;
}
});
}
@ -79,51 +76,42 @@ function handleChangeParent(state: IWorkItemsState, action: ChangeParentAction):
newParentId
} = action.payload;
const newState = { ...state };
for (const childId of workItems) {
changeParent(newState, childId, newParentId);
}
return newState;
return produce(state, draft => {
for (const childId of workItems) {
changeParent(draft, childId, newParentId);
}
});
}
function changeParent(newState: IWorkItemsState, childId: number, parentId: number) {
const info = newState.workItemInfos[childId];
function changeParent(draft: IWorkItemsState, childId: number, parentId: number) {
const info = draft.workItemInfos[childId];
const oldParentId = info.parent;
if (parentId === oldParentId) {
return;
}
const newParentInfo = newState.workItemInfos[parentId];
const newParentInfo = draft.workItemInfos[parentId];
// Remove work item from old parent
if (oldParentId) {
const oldParentInfo = newState[oldParentId];
newState.workItemInfos[oldParentId] = {
...oldParentInfo
};
newState.workItemInfos[oldParentId].children = oldParentInfo.children.filter((id) => id !== childId);
const oldParentInfo = draft[oldParentId];
draft.workItemInfos[oldParentId] = oldParentInfo;
draft.workItemInfos[oldParentId].children = oldParentInfo.children.filter((id) => id !== childId);
}
if (parentId) {
//Add workItem as child of new parent
newState.workItemInfos[parentId] = {
...newParentInfo
};
newState.workItemInfos[parentId].children = [...newParentInfo.children, childId];
draft.workItemInfos[parentId] = newParentInfo;
draft.workItemInfos[parentId].children.push(childId);
};
//Set parent id
newState.workItemInfos[childId] = {
...newState.workItemInfos[childId],
parent: parentId
};
draft.workItemInfos[childId].parent = parentId;
}
function handleWorkItemsReceived(state: IWorkItemsState, action: WorkItemsReceivedAction): IWorkItemsState {
const newState = { ...state };
const {
workItems,
parentWorkItemIds,
@ -131,49 +119,49 @@ function handleWorkItemsReceived(state: IWorkItemsState, action: WorkItemsReceiv
workItemTypeStateInfo
} = action.payload;
for (const workItem of workItems) {
return produce(state, draft => {
for (const workItem of workItems) {
let level = WorkItemLevel.Child;
if (parentWorkItemIds.some(parentId => parentId === workItem.id)) {
level = WorkItemLevel.Parent;
} else if (currentLevelWorkItemIds.some(currentId => currentId === workItem.id)) {
level = WorkItemLevel.Current;
let level = WorkItemLevel.Child;
if (parentWorkItemIds.some(parentId => parentId === workItem.id)) {
level = WorkItemLevel.Parent;
} else if (currentLevelWorkItemIds.some(currentId => currentId === workItem.id)) {
level = WorkItemLevel.Current;
}
const stateCategory = getWorkItemStateCategory(workItem.fields["System.WorkItemType"], workItem.fields["System.State"], workItemTypeStateInfo);
draft.workItemInfos[workItem.id] = {
workItem,
children: [],
parent: 0,
level,
stateCategory
};
}
const stateCategory = getWorkItemStateCategory(workItem.fields["System.WorkItemType"], workItem.fields["System.State"], workItemTypeStateInfo);
newState.workItemInfos[workItem.id] = {
workItem,
children: [],
parent: 0,
level,
stateCategory
};
}
return newState;
});
}
function handleWorkItemLinksReceived(state: IWorkItemsState, action: WorkItemLinksReceivedAction): IWorkItemsState {
let newState = state;
const children = action.payload.workItemLinks.filter((link) => link.source);
for (const relation of children) {
let parentId = 0;
let childId = 0;
if (relation.rel === "System.LinkTypes.Hierarchy-Forward") {
parentId = relation.source.id;
childId = relation.target.id;
} else if (!relation.rel || relation.rel === "System.LinkTypes.Hierarchy-Reverse") {
parentId = relation.target.id;
childId = relation.source.id;
}
return produce(state, draft => {
const children = action.payload.workItemLinks.filter((link) => link.source);
for (const relation of children) {
let parentId = 0;
let childId = 0;
if (relation.rel === "System.LinkTypes.Hierarchy-Forward") {
parentId = relation.source.id;
childId = relation.target.id;
} else if (!relation.rel || relation.rel === "System.LinkTypes.Hierarchy-Reverse") {
parentId = relation.target.id;
childId = relation.source.id;
}
if (childId > 0) {
newState = { ...state };
changeParent(newState, childId, parentId);
if (childId > 0) {
changeParent(draft, childId, parentId);
}
}
}
return newState;
});
}
export default reducer;

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

@ -5,6 +5,7 @@
"noUnusedLocals": true,
"jsx": "react",
"experimentalDecorators": true,
"noFallthroughCasesInSwitch": true,
"lib": [
"es2015",
"es2015.promise",

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

@ -1,7 +1,7 @@
{
"manifestVersion": 1,
"id": "workitem-feature-timeline-extension",
"version": "0.0.258",
"version": "0.0.262",
"name": "Feature timeline",
"description": "Feature timeline of your in-progress features.",
"publisher": "ms-devlabs",

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

@ -55,14 +55,7 @@ const plugins = [
];
if (mode !== "development") {
plugins.unshift(new UglifyJSPlugin({
compress: {
warnings: false
},
output: {
comments: false
}
}));
plugins.unshift(new UglifyJSPlugin());
plugins.unshift(new BundleAnalyzerPlugin({
analyzerMode: "static",
generateStatsFile: true