Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
a117cbcb
Commit
a117cbcb
authored
Jan 23, 2019
by
Kushal Pandya
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add epics sidebar shell
Add shell for Epic sidebar with Todo text and sidebar toggle button.
parent
7d9f342e
Changes
17
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
349 additions
and
5 deletions
+349
-5
ee/app/assets/javascripts/epic/components/epic_body.vue
ee/app/assets/javascripts/epic/components/epic_body.vue
+4
-0
ee/app/assets/javascripts/epic/components/epic_sidebar.vue
ee/app/assets/javascripts/epic/components/epic_sidebar.vue
+38
-0
ee/app/assets/javascripts/epic/components/sidebar_items/sidebar_header.vue
...ascripts/epic/components/sidebar_items/sidebar_header.vue
+31
-0
ee/app/assets/javascripts/epic/store/actions.js
ee/app/assets/javascripts/epic/store/actions.js
+13
-0
ee/app/assets/javascripts/epic/store/getters.js
ee/app/assets/javascripts/epic/store/getters.js
+2
-0
ee/app/assets/javascripts/epic/store/index.js
ee/app/assets/javascripts/epic/store/index.js
+1
-1
ee/app/assets/javascripts/epic/store/mutation_types.js
ee/app/assets/javascripts/epic/store/mutation_types.js
+2
-0
ee/app/assets/javascripts/epic/store/mutations.js
ee/app/assets/javascripts/epic/store/mutations.js
+4
-0
ee/app/assets/javascripts/epic/store/state.js
ee/app/assets/javascripts/epic/store/state.js
+3
-2
ee/app/assets/javascripts/epic/utils/epic_utils.js
ee/app/assets/javascripts/epic/utils/epic_utils.js
+18
-0
ee/spec/javascripts/epic/components/epic_header_spec.js
ee/spec/javascripts/epic/components/epic_header_spec.js
+1
-1
ee/spec/javascripts/epic/components/epic_sidebar_spec.js
ee/spec/javascripts/epic/components/epic_sidebar_spec.js
+48
-0
ee/spec/javascripts/epic/components/sidebar_items/sidebar_header_spec.js
...ipts/epic/components/sidebar_items/sidebar_header_spec.js
+47
-0
ee/spec/javascripts/epic/mock_data.js
ee/spec/javascripts/epic/mock_data.js
+4
-1
ee/spec/javascripts/epic/store/actions_spec.js
ee/spec/javascripts/epic/store/actions_spec.js
+62
-0
ee/spec/javascripts/epic/store/mutationts_spec.js
ee/spec/javascripts/epic/store/mutationts_spec.js
+11
-0
ee/spec/javascripts/epic/utils/epic_utils_spec.js
ee/spec/javascripts/epic/utils/epic_utils_spec.js
+60
-0
No files found.
ee/app/assets/javascripts/epic/components/epic_body.vue
View file @
a117cbcb
...
...
@@ -4,11 +4,14 @@ import { mapState } from 'vuex';
import
IssuableBody
from
'
~/issue_show/components/app.vue
'
;
import
RelatedItems
from
'
ee/related_issues/components/related_issues_root.vue
'
;
import
EpicSidebar
from
'
./epic_sidebar.vue
'
;
export
default
{
epicsPathIdSeparator
:
'
&
'
,
components
:
{
IssuableBody
,
RelatedItems
,
EpicSidebar
,
},
computed
:
{
...
mapState
([
...
...
@@ -76,5 +79,6 @@ export default {
css-class=
"js-related-issues-block"
path-id-separator=
"#"
/>
<epic-sidebar
/>
</div>
</
template
>
ee/app/assets/javascripts/epic/components/epic_sidebar.vue
0 → 100644
View file @
a117cbcb
<
script
>
import
{
mapState
,
mapGetters
,
mapActions
}
from
'
vuex
'
;
import
epicUtils
from
'
../utils/epic_utils
'
;
import
SidebarHeader
from
'
./sidebar_items/sidebar_header.vue
'
;
export
default
{
components
:
{
SidebarHeader
,
},
computed
:
{
...
mapState
([
'
epicId
'
,
'
sidebarCollapsed
'
]),
...
mapGetters
([
'
isUserSignedIn
'
]),
},
mounted
()
{
this
.
toggleSidebarFlag
(
epicUtils
.
getCollapsedGutter
());
},
methods
:
{
...
mapActions
([
'
toggleSidebarFlag
'
]),
},
};
</
script
>
<
template
>
<aside
:class=
"
{
'right-sidebar-expanded': !sidebarCollapsed,
'right-sidebar-collapsed': sidebarCollapsed,
}"
:data-signed-in="isUserSignedIn"
class="right-sidebar epic-sidebar"
>
<div
class=
"issuable-sidebar js-issuable-update"
>
<sidebar-header
:sidebar-collapsed=
"sidebarCollapsed"
/>
</div>
</aside>
</
template
>
ee/app/assets/javascripts/epic/components/sidebar_items/sidebar_header.vue
0 → 100644
View file @
a117cbcb
<
script
>
import
{
mapActions
}
from
'
vuex
'
;
import
ToggleSidebar
from
'
~/vue_shared/components/sidebar/toggle_sidebar.vue
'
;
export
default
{
components
:
{
ToggleSidebar
,
},
props
:
{
sidebarCollapsed
:
{
type
:
Boolean
,
required
:
true
,
},
},
methods
:
{
...
mapActions
([
'
toggleSidebar
'
]),
},
};
</
script
>
<
template
>
<div
class=
"block issuable-sidebar-header"
>
<span
class=
"issuable-header-text hide-collapsed float-left"
>
{{
__
(
'
Todo
'
)
}}
</span>
<toggle-sidebar
:collapsed=
"sidebarCollapsed"
css-classes=
"float-right"
@
toggle=
"toggleSidebar(
{ sidebarCollapsed })"
/>
</div>
</
template
>
ee/app/assets/javascripts/epic/store/actions.js
View file @
a117cbcb
...
...
@@ -50,5 +50,18 @@ export const toggleEpicStatus = ({ state, dispatch }, isEpicOpen) => {
});
};
export
const
toggleSidebarFlag
=
({
commit
},
sidebarCollapsed
)
=>
commit
(
types
.
TOGGLE_SIDEBAR
,
sidebarCollapsed
);
export
const
toggleContainerClassAndCookie
=
(
_
,
sidebarCollapsed
)
=>
{
epicUtils
.
toggleContainerClass
(
'
right-sidebar-expanded
'
);
epicUtils
.
toggleContainerClass
(
'
right-sidebar-collapsed
'
);
epicUtils
.
setCollapsedGutter
(
sidebarCollapsed
);
};
export
const
toggleSidebar
=
({
dispatch
},
{
sidebarCollapsed
})
=>
{
dispatch
(
'
toggleContainerClassAndCookie
'
,
!
sidebarCollapsed
);
dispatch
(
'
toggleSidebarFlag
'
,
!
sidebarCollapsed
);
};
// prevent babel-plugin-rewire from generating an invalid default during karma tests
export
default
()
=>
{};
ee/app/assets/javascripts/epic/store/getters.js
View file @
a117cbcb
...
...
@@ -2,5 +2,7 @@ import { statusType } from '../constants';
export
const
isEpicOpen
=
state
=>
state
.
state
===
statusType
.
open
;
export
const
isUserSignedIn
=
()
=>
!!
gon
.
current_user_id
;
// prevent babel-plugin-rewire from generating an invalid default during karma tests
export
default
()
=>
{};
ee/app/assets/javascripts/epic/store/index.js
View file @
a117cbcb
...
...
@@ -10,10 +10,10 @@ Vue.use(Vuex);
const
createStore
=
()
=>
new
Vuex
.
Store
({
state
:
state
(),
actions
,
getters
,
mutations
,
state
,
});
export
default
createStore
;
ee/app/assets/javascripts/epic/store/mutation_types.js
View file @
a117cbcb
...
...
@@ -5,3 +5,5 @@ export const REQUEST_EPIC_STATUS_CHANGE = 'REQUEST_EPIC_STATUS_CHANGE';
export
const
REQUEST_EPIC_STATUS_CHANGE_SUCCESS
=
'
REQUEST_EPIC_STATUS_CHANGE_SUCCESS
'
;
export
const
REQUEST_EPIC_STATUS_CHANGE_FAILURE
=
'
REQUEST_EPIC_STATUS_CHANGE_FAILURE
'
;
export
const
TRIGGER_ISSUABLE_EVENTS
=
'
TRIGGER_ISSUABLE_EVENTS
'
;
export
const
TOGGLE_SIDEBAR
=
'
TOGGLE_SIDEBAR
'
;
ee/app/assets/javascripts/epic/store/mutations.js
View file @
a117cbcb
...
...
@@ -19,4 +19,8 @@ export default {
[
types
.
REQUEST_EPIC_STATUS_CHANGE_FAILURE
](
state
)
{
state
.
epicStatusChangeInProgress
=
false
;
},
[
types
.
TOGGLE_SIDEBAR
](
state
,
isSidebarCollapsed
)
{
state
.
sidebarCollapsed
=
isSidebarCollapsed
;
},
};
ee/app/assets/javascripts/epic/store/state.js
View file @
a117cbcb
export
default
{
export
default
()
=>
(
{
// API Paths to Send/Receive Data
endpoint
:
''
,
updateEndpoint
:
''
,
...
...
@@ -51,4 +51,5 @@ export default {
// UI status flags
epicStatusChangeInProgress
:
false
,
epicDeleteInProgress
:
false
,
};
sidebarCollapsed
:
false
,
});
ee/app/assets/javascripts/epic/utils/epic_utils.js
View file @
a117cbcb
import
$
from
'
jquery
'
;
import
Cookies
from
'
js-cookie
'
;
import
{
parseBoolean
}
from
'
~/lib/utils/common_utils
'
;
const
triggerDocumentEvent
=
(
eventName
,
eventParam
)
=>
{
$
(
document
).
trigger
(
eventName
,
eventParam
);
...
...
@@ -8,6 +11,18 @@ const bindDocumentEvent = (eventName, callback) => {
$
(
document
).
on
(
eventName
,
callback
);
};
const
toggleContainerClass
=
className
=>
{
const
containerEl
=
document
.
querySelector
(
'
.page-with-contextual-sidebar
'
);
if
(
containerEl
)
{
containerEl
.
classList
.
toggle
(
className
);
}
};
const
getCollapsedGutter
=
()
=>
parseBoolean
(
Cookies
.
get
(
'
collapsed_gutter
'
));
const
setCollapsedGutter
=
value
=>
Cookies
.
set
(
'
collapsed_gutter
'
,
value
);
// This is for mocking methods from this
// file within tests using `spyOnDependency`
// which requires first param to always
...
...
@@ -16,6 +31,9 @@ const bindDocumentEvent = (eventName, callback) => {
const
epicUtils
=
{
triggerDocumentEvent
,
bindDocumentEvent
,
toggleContainerClass
,
getCollapsedGutter
,
setCollapsedGutter
,
};
export
default
epicUtils
;
ee/spec/javascripts/epic/components/epic_header_spec.js
View file @
a117cbcb
...
...
@@ -7,7 +7,7 @@ import { statusType } from 'ee/epic/constants';
import
{
mountComponentWithStore
}
from
'
spec/helpers/vue_mount_component_helper
'
;
import
{
mockEpicMeta
,
mockEpicData
}
from
'
../mock_data
'
;
describe
(
'
Epic
Body
Component
'
,
()
=>
{
describe
(
'
Epic
Header
Component
'
,
()
=>
{
let
vm
;
let
store
;
...
...
ee/spec/javascripts/epic/components/epic_sidebar_spec.js
0 → 100644
View file @
a117cbcb
import
Vue
from
'
vue
'
;
import
EpicSidebar
from
'
ee/epic/components/epic_sidebar.vue
'
;
import
createStore
from
'
ee/epic/store
'
;
import
{
mountComponentWithStore
}
from
'
spec/helpers/vue_mount_component_helper
'
;
import
{
mockEpicMeta
,
mockEpicData
}
from
'
../mock_data
'
;
describe
(
'
EpicSidebarComponent
'
,
()
=>
{
let
vm
;
let
store
;
beforeEach
(
done
=>
{
const
Component
=
Vue
.
extend
(
EpicSidebar
);
store
=
createStore
();
store
.
dispatch
(
'
setEpicMeta
'
,
mockEpicMeta
);
store
.
dispatch
(
'
setEpicData
'
,
mockEpicData
);
vm
=
mountComponentWithStore
(
Component
,
{
store
,
});
setTimeout
(
done
);
});
afterEach
(()
=>
{
vm
.
$destroy
();
});
describe
(
'
template
'
,
()
=>
{
it
(
'
renders component container element with classes `right-sidebar-expanded`, `right-sidebar` & `epic-sidebar`
'
,
done
=>
{
store
.
dispatch
(
'
toggleSidebarFlag
'
,
false
);
vm
.
$nextTick
()
.
then
(()
=>
{
expect
(
vm
.
$el
.
classList
.
contains
(
'
right-sidebar-expanded
'
)).
toBe
(
true
);
expect
(
vm
.
$el
.
classList
.
contains
(
'
right-sidebar
'
)).
toBe
(
true
);
expect
(
vm
.
$el
.
classList
.
contains
(
'
epic-sidebar
'
)).
toBe
(
true
);
})
.
then
(
done
)
.
catch
(
done
.
fail
);
});
it
(
'
renders header container element with classes `issuable-sidebar` & `js-issuable-update`
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.issuable-sidebar.js-issuable-update
'
)).
not
.
toBeNull
();
});
});
});
ee/spec/javascripts/epic/components/sidebar_items/sidebar_header_spec.js
0 → 100644
View file @
a117cbcb
import
Vue
from
'
vue
'
;
import
SidebarHeader
from
'
ee/epic/components/sidebar_items/sidebar_header.vue
'
;
import
createStore
from
'
ee/epic/store
'
;
import
{
mountComponentWithStore
}
from
'
spec/helpers/vue_mount_component_helper
'
;
import
{
mockEpicMeta
,
mockEpicData
}
from
'
../../mock_data
'
;
describe
(
'
SidebarHeaderComponent
'
,
()
=>
{
let
vm
;
beforeEach
(
done
=>
{
const
Component
=
Vue
.
extend
(
SidebarHeader
);
const
store
=
createStore
();
store
.
dispatch
(
'
setEpicMeta
'
,
mockEpicMeta
);
store
.
dispatch
(
'
setEpicData
'
,
mockEpicData
);
vm
=
mountComponentWithStore
(
Component
,
{
store
,
props
:
{
sidebarCollapsed
:
false
},
});
setTimeout
(
done
);
});
afterEach
(()
=>
{
vm
.
$destroy
();
});
describe
(
'
template
'
,
()
=>
{
it
(
'
renders component container element with classes `block` & `issuable-sidebar-header`
'
,
()
=>
{
expect
(
vm
.
$el
.
classList
.
contains
(
'
block
'
)).
toBe
(
true
);
expect
(
vm
.
$el
.
classList
.
contains
(
'
issuable-sidebar-header
'
)).
toBe
(
true
);
});
it
(
'
renders Todo text element
'
,
()
=>
{
const
todoEl
=
vm
.
$el
.
querySelector
(
'
.issuable-header-text.hide-collapsed.float-left
'
);
expect
(
todoEl
).
not
.
toBeNull
();
expect
(
todoEl
.
innerText
.
trim
()).
toBe
(
'
Todo
'
);
});
it
(
'
renders toggle sidebar button element
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
button.btn-sidebar-action
'
)).
not
.
toBeNull
();
});
});
});
ee/spec/javascripts/epic/mock_data.js
View file @
a117cbcb
...
...
@@ -11,6 +11,9 @@ export const mockEpicMeta = convertObjectPropsToCamelCase(meta, {
});
export
const
mockEpicData
=
convertObjectPropsToCamelCase
(
Object
.
assign
({},
getJSONFixture
(
'
epic/mock_data.json
'
),
initial
,
{
endpoint
:
TEST_HOST
}),
Object
.
assign
({},
getJSONFixture
(
'
epic/mock_data.json
'
),
initial
,
{
endpoint
:
TEST_HOST
,
sidebarCollapsed
:
false
,
}),
{
deep
:
true
},
);
ee/spec/javascripts/epic/store/actions_spec.js
View file @
a117cbcb
...
...
@@ -185,4 +185,66 @@ describe('Epic Store Actions', () => {
});
});
});
describe
(
'
toggleSidebarFlag
'
,
()
=>
{
it
(
'
should call `TOGGLE_SIDEBAR` mutation with param `sidebarCollapsed`
'
,
done
=>
{
const
sidebarCollapsed
=
true
;
testAction
(
actions
.
toggleSidebarFlag
,
sidebarCollapsed
,
state
,
[{
type
:
'
TOGGLE_SIDEBAR
'
,
payload
:
sidebarCollapsed
}],
[],
done
,
);
});
});
describe
(
'
toggleContainerClassAndCookie
'
,
()
=>
{
const
sidebarCollapsed
=
true
;
beforeEach
(()
=>
{
spyOn
(
epicUtils
,
'
toggleContainerClass
'
).
and
.
stub
();
spyOn
(
epicUtils
,
'
setCollapsedGutter
'
).
and
.
stub
();
});
it
(
'
should call `epicUtils.toggleContainerClass` with classes `right-sidebar-expanded` & `right-sidebar-collapsed`
'
,
()
=>
{
actions
.
toggleContainerClassAndCookie
({},
sidebarCollapsed
);
expect
(
epicUtils
.
toggleContainerClass
).
toHaveBeenCalledTimes
(
2
);
expect
(
epicUtils
.
toggleContainerClass
).
toHaveBeenCalledWith
(
'
right-sidebar-expanded
'
);
expect
(
epicUtils
.
toggleContainerClass
).
toHaveBeenCalledWith
(
'
right-sidebar-collapsed
'
);
});
it
(
'
should call `epicUtils.setCollapsedGutter` with param `isSidebarCollapsed`
'
,
()
=>
{
actions
.
toggleContainerClassAndCookie
({},
sidebarCollapsed
);
expect
(
epicUtils
.
setCollapsedGutter
).
toHaveBeenCalledWith
(
sidebarCollapsed
);
});
});
describe
(
'
toggleSidebar
'
,
()
=>
{
it
(
'
dispatches toggleContainerClassAndCookie and toggleSidebarFlag actions with opposite value of `isSidebarCollapsed` param
'
,
done
=>
{
const
sidebarCollapsed
=
true
;
testAction
(
actions
.
toggleSidebar
,
{
sidebarCollapsed
},
state
,
[],
[
{
type
:
'
toggleContainerClassAndCookie
'
,
payload
:
!
sidebarCollapsed
,
},
{
type
:
'
toggleSidebarFlag
'
,
payload
:
!
sidebarCollapsed
,
},
],
done
,
);
});
});
});
ee/spec/javascripts/epic/store/mutationts_spec.js
View file @
a117cbcb
...
...
@@ -51,4 +51,15 @@ describe('Epic Store Mutations', () => {
expect
(
state
.
epicStatusChangeInProgress
).
toBe
(
false
);
});
});
describe
(
'
TOGGLE_SIDEBAR
'
,
()
=>
{
it
(
'
Should set `sidebarCollapsed` flag on state with value of provided `sidebarCollapsed` param
'
,
()
=>
{
const
state
=
{};
const
sidebarCollapsed
=
true
;
mutations
[
types
.
TOGGLE_SIDEBAR
](
state
,
sidebarCollapsed
);
expect
(
state
.
sidebarCollapsed
).
toBe
(
sidebarCollapsed
);
});
});
});
ee/spec/javascripts/epic/utils/epic_utils_spec.js
0 → 100644
View file @
a117cbcb
import
Cookies
from
'
js-cookie
'
;
import
epicUtils
from
'
ee/epic/utils/epic_utils
'
;
describe
(
'
epicUtils
'
,
()
=>
{
describe
(
'
toggleContainerClass
'
,
()
=>
{
beforeEach
(()
=>
{
setFixtures
(
'
<div class="page-with-contextual-sidebar"></div>
'
);
});
it
(
'
toggles provided class on containerEl
'
,
()
=>
{
const
className
=
'
my-class
'
;
const
containerEl
=
document
.
querySelector
(
'
.page-with-contextual-sidebar
'
);
containerEl
.
classList
.
add
(
className
);
epicUtils
.
toggleContainerClass
(
className
);
expect
(
containerEl
.
classList
.
contains
(
className
)).
toBe
(
false
);
});
});
describe
(
'
getCollapsedGutter
'
,
()
=>
{
let
originalCollapsedGutter
;
beforeAll
(()
=>
{
originalCollapsedGutter
=
Cookies
.
get
(
'
collapsed_gutter
'
);
});
afterAll
(()
=>
{
Cookies
.
set
(
'
collapsed_gutter
'
,
originalCollapsedGutter
);
});
it
(
'
gets value of Cookie flag `collapsed_gutter` as boolean
'
,
()
=>
{
const
collapsedGutterVal
=
true
;
Cookies
.
set
(
'
collapsed_gutter
'
,
collapsedGutterVal
);
expect
(
epicUtils
.
getCollapsedGutter
()).
toBe
(
collapsedGutterVal
);
});
});
describe
(
'
setCollapsedGutter
'
,
()
=>
{
let
originalCollapsedGutter
;
beforeAll
(()
=>
{
originalCollapsedGutter
=
Cookies
.
get
(
'
collapsed_gutter
'
);
});
afterAll
(()
=>
{
Cookies
.
set
(
'
collapsed_gutter
'
,
originalCollapsedGutter
);
});
it
(
'
sets value of Cookie flag `collapsed_gutter` with provided `value` param
'
,
()
=>
{
const
collapsedGutterVal
=
true
;
epicUtils
.
setCollapsedGutter
(
collapsedGutterVal
);
expect
(
Cookies
.
get
(
'
collapsed_gutter
'
)).
toBe
(
`
${
collapsedGutterVal
}
`
);
// Cookie value will always be string
});
});
});
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment