Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve stories load #817

Open
wants to merge 25 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
ee58a5f
Add support to on demand fetch
trizotti Nov 23, 2022
f79559f
Refactor action
trizotti Nov 23, 2022
a15e9d9
Switch from toggleStory to expandOrCallapse
trizotti Nov 23, 2022
fb82c5d
Add serializer
trizotti Nov 23, 2022
d03a36b
Add test to serializer
trizotti Nov 23, 2022
48ccfdc
Add error handling
trizotti Nov 24, 2022
8c6f24f
Add tests to new feature
trizotti Nov 24, 2022
29bd810
Refactor ruby code
trizotti Nov 25, 2022
fe56a7f
Fix new line error
trizotti Nov 25, 2022
26d5381
Refactor js code
trizotti Nov 25, 2022
8e3b8ea
One more refactoring bypass file lines limit
trizotti Nov 25, 2022
03db7a8
Refactor expandOrCollapse
trizotti Nov 25, 2022
a9a76b8
Fix trailing space
trizotti Nov 25, 2022
bc9cdfc
Refactor expandOrCollapse
trizotti Nov 25, 2022
6f182a2
Remove unnecesary code
trizotti Dec 6, 2022
d41e609
refactor: improving specs and code readbility
gabrielcicero45 Oct 16, 2023
6fbacad
improving stories query
gabrielcicero45 Oct 27, 2023
609667f
Removing select from read_all and adding to read
gabrielcicero45 Oct 31, 2023
34d58b8
Removes project_boards_serializer
gabrielcicero45 Nov 1, 2023
557b107
remove project_boards_serializer_specs
gabrielcicero45 Nov 3, 2023
9d03285
fix rubocop and eslint warnings
gabrielcicero45 Nov 7, 2023
e4826cd
fix import on StoryItem
gabrielcicero45 Nov 7, 2023
13685b0
refactor: Separate expandOrCollapseStory into two distinct actions
gabrielcicero45 Nov 9, 2023
89c0491
add scopes in story
gabrielcicero45 Nov 13, 2023
5be175c
rubocop and lint fixes
GabrielRMuller Aug 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion app/assets/javascripts/actions/actionTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@ export default keyMirror({
ERROR_REQUEST_PAST_STORIES: null,
CREATE_STORY: null,
ADD_STORY: null,
EXPAND_STORY: null,
COLLAPSE_STORY: null,
CLONE_STORY: null,
RECEIVE_HISTORY: null,
LOAD_HISTORY: null,
TOGGLE_STORY: null,
EDIT_STORY: null,
UPDATE_STORY: null,
RECEIVE_HISTORY_ERROR: null,
Expand Down
4 changes: 2 additions & 2 deletions app/assets/javascripts/actions/projectBoard.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import actionTypes from './actionTypes';
import { receiveUsers } from './user';
import { receiveStories, toggleStory } from './story';
import { receiveStories, expandStory } from './story';
import { receivePastIterations } from './pastIterations';
import { storyScopes } from '../libs/beta/constants';
import { sendErrorNotification } from './notifications';
Expand Down Expand Up @@ -57,7 +57,7 @@ export const expandStoryIfNeeded = (dispatch, getHash) => {
const storyId = getHash('#story-');

if (storyId) {
dispatch(toggleStory(parseInt(storyId)));
dispatch(expandStory(parseInt(storyId)));
window.history.pushState('', '/', window.location.pathname);
}
};
Expand Down
32 changes: 20 additions & 12 deletions app/assets/javascripts/actions/story.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import {
import { wait } from '../services/promises';
import { storyScopes } from '../libs/beta/constants';
import { storiesWithScope } from '../reducers/stories';
import projectStoriesService from '../services/stories';
import { isStoryLoading } from '../models/beta/story';

export const createStory = (attributes, from) => ({
type: actionTypes.CREATE_STORY,
Expand All @@ -20,6 +22,22 @@ export const addStory = (story, from) => ({
from,
});

export const expandStory = (storyId, from) => {
return {
type: actionTypes.EXPAND_STORY,
storyId,
from,
};
};

export const collapseStory = (storyId, from) => {
return {
type: actionTypes.COLLAPSE_STORY,
storyId,
from,
};
};

export const loadHistory = title => ({
type: actionTypes.LOAD_HISTORY,
title,
Expand Down Expand Up @@ -82,12 +100,6 @@ export const deleteStorySuccess = (id, from) => ({
from,
});

export const toggleStory = (id, from) => ({
type: actionTypes.TOGGLE_STORY,
id,
from,
});

export const editStory = (id, newAttributes, from) => ({
type: actionTypes.EDIT_STORY,
id,
Expand All @@ -111,7 +123,6 @@ export const fetchEpic =
try {
const { projectId } = getState().projectBoard;
const storiesByLabel = await Story.getByLabel(label, projectId);

dispatch(receiveStories(storiesByLabel, storyScopes.EPIC));
} catch {
dispatch(sendDefaultErrorNotification());
Expand Down Expand Up @@ -212,7 +223,7 @@ export const updateCollapsedStory =
);
};

export const dragDropStory =
export const dragDropStory =
(storyId, projectId, newAttributes, from) =>
async (dispatch, getState, { Story }) => {
const { stories } = getState();
Expand All @@ -229,9 +240,7 @@ export const dragDropStory =
try {
// Optimistic Update:
dispatch(sortStories(storiesWithUpdatedPositions, from));

const updatedStories = await Story.updatePosition(newStory);

await wait(300);
return dispatch(sortStories(updatedStories, from));
} catch (error) {
Expand Down Expand Up @@ -340,7 +349,7 @@ export const saveStory =
);
}

return dispatch(toggleStory(story.id, from));
return dispatch(collapseStory(story.id, from));
};

export const deleteStory =
Expand All @@ -356,7 +365,6 @@ export const deleteStory =
).title;

await Story.deleteStory(storyId, projectId);

dispatch(deleteStorySuccess(storyId, from));

return dispatch(
Expand Down
6 changes: 4 additions & 2 deletions app/assets/javascripts/components/story/StoryItem.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ export const StoryItem = ({

const childProps = {
story,
onToggle: () => toggleStory(story.id, from),
onToggle: () => {
toggleStory(story, from);
},
className,
title,
from,
Expand All @@ -62,4 +64,4 @@ StoryItem.propTypes = {
toggleStory: PropTypes.func.isRequired,
};

export default connect(null, { toggleStory, fetchEpic })(StoryItem);
export default connect(null, { fetchEpic, toggleStory })(StoryItem);
19 changes: 6 additions & 13 deletions app/assets/javascripts/models/beta/story.js
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,10 @@ export const search = async (queryParam, projectId) => {
return data.map(item => deserialize(item.story));
};

export const isStoryLoading = story => {
return story._editing?.loading;
};

export const getByLabel = async (label, projectId) => {
const { data } = await httpService.get(
`/projects/${projectId}/stories?label=${label}`,
Expand All @@ -199,18 +203,6 @@ export const storyFailure = (story, error) => ({
needsToSave: false,
});

export const toggleStory = story => {
const editing = story.collapsed
? { ...story, _isDirty: false, loading: false }
: null;

return {
...story,
_editing: editing,
collapsed: !story.collapsed,
};
};

const isUnscheduledState = (story, newAttributes) =>
isFeature(story._editing) &&
(isChangingWithoutEstimate(story, newAttributes) ||
Expand Down Expand Up @@ -303,7 +295,8 @@ export const deserialize = (data, options) => {
...story,
labels: Label.splitLabels(story.labels),
estimate: story.estimate || '',
collapsed,
documents: (story.documents ?? []).map(document => document.file),
collapsed
};
};

Expand Down
57 changes: 38 additions & 19 deletions app/assets/javascripts/reducers/stories.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import actionTypes from 'actions/actionTypes';
import {
toggleStory,
editStory,
addNewAttributes,
setLoadingStory,
setLoadingValue,
cloneStory,
storyFailure,
withoutNewStory,
createNewStory,
replaceOrAddNewStory,
} from 'models/beta/story';
Expand All @@ -16,7 +14,7 @@ import * as Task from 'models/beta/task';
import * as Label from 'models/beta/label';
import { updateIfSameId } from '../services/updateIfSameId';
import { storyScopes } from './../libs/beta/constants';
import { isEpic, isSearch, isNew } from '../models/beta/story';
import { isEpic, isSearch } from '../models/beta/story';

const initialState = {
[storyScopes.ALL]: {},
Expand Down Expand Up @@ -84,29 +82,50 @@ const storiesReducer = (state = initialState, action) => {
)
),
};
case actionTypes.CLONE_STORY:
const clonedStory = cloneStory(action.story);

case actionTypes.EXPAND_STORY:
return {
...state,
[action.from]: normalizeStories(
replaceOrAddNewStory(denormalizedStories, clonedStory)
),
[action.from]: {
stories: {
...state[action.from].stories,
byId: {
...state[action.from].stories.byId,
[action.storyId]: {
...state[action.from].stories.byId[action.storyId],
collapsed: false,
_editing: {
...state[action.from].stories.byId[action.storyId],
_isDirty: false,
loading: false,
},
},
},
},
},
};
case actionTypes.TOGGLE_STORY:
if (isNew(action)) {
return {
...state,
[action.from]: normalizeStories(
withoutNewStory(denormalizedStories, action.id)
),
};
}
case actionTypes.COLLAPSE_STORY:
return {
...state,
[action.from]: {
stories: {
...state[action.from].stories,
byId: {
...state[action.from].stories.byId,
[action.storyId]: {
...state[action.from].stories.byId[action.storyId],
collapsed: true,
},
},
},
},
};
case actionTypes.CLONE_STORY:
const clonedStory = cloneStory(action.story);

return {
...state,
[action.from]: normalizeStories(
denormalizedStories.map(updateIfSameId(action.id, toggleStory))
replaceOrAddNewStory(denormalizedStories, clonedStory)
),
};
case actionTypes.EDIT_STORY:
Expand Down
9 changes: 9 additions & 0 deletions app/assets/javascripts/services/stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import httpService from './httpService';

const ProjectStoriesService = {
async fetchStory(story) {
return httpService.get(`/projects/${story.projectId}/stories/${story.id}`);
},
};

export default ProjectStoriesService;
17 changes: 17 additions & 0 deletions app/models/story.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,23 @@ class Story < ApplicationRecord
start_date.beginning_of_day,
end_date.end_of_day)
}
scope :not_accepted_or_recently_accepted, lambda { |current_iteration_start|
where.not(state: 'accepted').or(where('accepted_at >= ?', current_iteration_start))
}

scope :collapsed_story, lambda {
select(
:id,
:title,
:description,
:estimate,
:story_type,
:state,
:requested_by_name,
:owned_by_initials,
:project_id
)
}

delegate :suppress_notifications, to: :project

Expand Down
34 changes: 30 additions & 4 deletions app/operations/beta/project_board_operations/read.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ module ProjectBoardOperations
class Read
include Operation

delegate :past_iterations, :current_iteration_start, to: :iterations

def initialize(project_id:, current_user:, current_flow: nil, projects_scope: Project)
@project_id = project_id
@current_user = current_user
Expand All @@ -22,6 +24,14 @@ def call

attr_reader :project_id, :current_user, :current_flow, :projects_scope

def iterations
@project_iterations ||= Iterations::ProjectIterations.new(project: project)
end

def project_iterations
Success(iterations)
end
gabrielcicero45 marked this conversation as resolved.
Show resolved Hide resolved

def create_project_board
project_users = project.users

Expand All @@ -40,9 +50,25 @@ def create_project_board
end

def stories_and_past_iterations
read_all_result = yield ::StoryOperations::ReadAll.call(project: project)
read_all_result[:stories] = read_all_result.delete(:active_stories)
read_all_result
yield active_stories
yield project_iterations

yield Success(
stories: @active_stories,
past_iterations: past_iterations
)
end

def active_stories
@active_stories ||= begin
project
.stories
.not_accepted_or_recently_accepted(current_iteration_start)
.collapsed_story
.order('updated_at DESC')
end

Success(@active_stories)
end

def project_labels
Expand All @@ -55,7 +81,7 @@ def project
@project ||= current_user
.projects
.friendly
.preload(:users, stories: %i[notes tasks])
.preload(:users)
.find(project_id)
end

Expand Down
12 changes: 6 additions & 6 deletions app/operations/story_operations/read_all.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@ def project_iterations

def active_stories
@active_stories ||= begin
project
.stories
.with_dependencies
.where("state != 'accepted' OR accepted_at >= ?", current_iteration_start)
.order('updated_at DESC')
end
project
.stories
.with_dependencies
.not_accepted_or_recently_accepted(current_iteration_start)
.order('updated_at DESC')
end

Success(@active_stories)
end
Expand Down
Loading
Loading