Switching to immer
This commit is contained in:
Родитель
5457e07fc3
Коммит
86342174ad
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
41
package.json
41
package.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
|
||||
|
|
Загрузка…
Ссылка в новой задаче