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
0
Merge Requests
0
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
Boxiang Sun
gitlab-ce
Commits
f59bdbf0
Commit
f59bdbf0
authored
Aug 07, 2017
by
Regis Boudinot
Committed by
Jacob Schatz
Aug 07, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
33874 confidential issue redesign
parent
1bed998e
Changes
14
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
434 additions
and
28 deletions
+434
-28
app/assets/javascripts/sidebar/components/confidential/confidential_issue_sidebar.vue
...ar/components/confidential/confidential_issue_sidebar.vue
+82
-0
app/assets/javascripts/sidebar/components/confidential/edit_form.vue
...javascripts/sidebar/components/confidential/edit_form.vue
+47
-0
app/assets/javascripts/sidebar/components/confidential/edit_form_buttons.vue
...pts/sidebar/components/confidential/edit_form_buttons.vue
+45
-0
app/assets/javascripts/sidebar/sidebar_bundle.js
app/assets/javascripts/sidebar/sidebar_bundle.js
+17
-1
app/assets/stylesheets/pages/issuable.scss
app/assets/stylesheets/pages/issuable.scss
+24
-0
app/assets/stylesheets/pages/note_form.scss
app/assets/stylesheets/pages/note_form.scss
+32
-21
app/views/projects/_md_preview.html.haml
app/views/projects/_md_preview.html.haml
+7
-5
app/views/projects/issues/show.html.haml
app/views/projects/issues/show.html.haml
+2
-1
app/views/shared/issuable/_sidebar.html.haml
app/views/shared/issuable/_sidebar.html.haml
+4
-0
changelogs/unreleased/33874_confi.yml
changelogs/unreleased/33874_confi.yml
+5
-0
spec/features/issues_spec.rb
spec/features/issues_spec.rb
+26
-0
spec/javascripts/sidebar/confidential_edit_buttons_spec.js
spec/javascripts/sidebar/confidential_edit_buttons_spec.js
+39
-0
spec/javascripts/sidebar/confidential_edit_form_buttons_spec.js
...avascripts/sidebar/confidential_edit_form_buttons_spec.js
+39
-0
spec/javascripts/sidebar/confidential_issue_sidebar_spec.js
spec/javascripts/sidebar/confidential_issue_sidebar_spec.js
+65
-0
No files found.
app/assets/javascripts/sidebar/components/confidential/confidential_issue_sidebar.vue
0 → 100644
View file @
f59bdbf0
<
script
>
/* global Flash */
import
editForm
from
'
./edit_form.vue
'
;
export
default
{
components
:
{
editForm
,
},
props
:
{
isConfidential
:
{
required
:
true
,
type
:
Boolean
,
},
isEditable
:
{
required
:
true
,
type
:
Boolean
,
},
service
:
{
required
:
true
,
type
:
Object
,
},
},
data
()
{
return
{
edit
:
false
,
};
},
computed
:
{
faEye
()
{
const
eye
=
this
.
isConfidential
?
'
fa-eye-slash
'
:
'
fa-eye
'
;
return
{
[
eye
]:
true
,
};
},
},
methods
:
{
toggleForm
()
{
this
.
edit
=
!
this
.
edit
;
},
updateConfidentialAttribute
(
confidential
)
{
this
.
service
.
update
(
'
issue
'
,
{
confidential
})
.
then
(()
=>
location
.
reload
())
.
catch
(()
=>
new
Flash
(
'
Something went wrong trying to change the confidentiality of this issue
'
));
},
},
};
</
script
>
<
template
>
<div
class=
"block confidentiality"
>
<div
class=
"sidebar-collapsed-icon"
>
<i
class=
"fa"
:class=
"faEye"
aria-hidden=
"true"
data-hidden=
"true"
></i>
</div>
<div
class=
"title hide-collapsed"
>
Confidentiality
<a
v-if=
"isEditable"
class=
"pull-right confidential-edit"
href=
"#"
@
click.prevent=
"toggleForm"
>
Edit
</a>
</div>
<div
class=
"value confidential-value hide-collapsed"
>
<editForm
v-if=
"edit"
:toggle-form=
"toggleForm"
:is-confidential=
"isConfidential"
:update-confidential-attribute=
"updateConfidentialAttribute"
/>
<div
v-if=
"!isConfidential"
class=
"no-value confidential-value"
>
<i
class=
"fa fa-eye is-not-confidential"
></i>
None
</div>
<div
v-else
class=
"value confidential-value hide-collapsed"
>
<i
aria-hidden=
"true"
data-hidden=
"true"
class=
"fa fa-eye-slash is-confidential"
></i>
This issue is confidential
</div>
</div>
</div>
</
template
>
app/assets/javascripts/sidebar/components/confidential/edit_form.vue
0 → 100644
View file @
f59bdbf0
<
script
>
import
editFormButtons
from
'
./edit_form_buttons.vue
'
;
export
default
{
components
:
{
editFormButtons
,
},
props
:
{
isConfidential
:
{
required
:
true
,
type
:
Boolean
,
},
toggleForm
:
{
required
:
true
,
type
:
Function
,
},
updateConfidentialAttribute
:
{
required
:
true
,
type
:
Function
,
},
},
};
</
script
>
<
template
>
<div
class=
"dropdown open"
>
<div
class=
"dropdown-menu confidential-warning-message"
>
<div>
<p
v-if=
"!isConfidential"
>
You are going to turn on the confidentiality. This means that only team members with
<strong>
at least Reporter access
</strong>
are able to see and leave comments on the issue.
</p>
<p
v-else
>
You are going to turn off the confidentiality. This means
<strong>
everyone
</strong>
will be able to see and leave a comment on this issue.
</p>
<edit-form-buttons
:is-confidential=
"isConfidential"
:toggle-form=
"toggleForm"
:update-confidential-attribute=
"updateConfidentialAttribute"
/>
</div>
</div>
</div>
</
template
>
app/assets/javascripts/sidebar/components/confidential/edit_form_buttons.vue
0 → 100644
View file @
f59bdbf0
<
script
>
export
default
{
props
:
{
isConfidential
:
{
required
:
true
,
type
:
Boolean
,
},
toggleForm
:
{
required
:
true
,
type
:
Function
,
},
updateConfidentialAttribute
:
{
required
:
true
,
type
:
Function
,
},
},
computed
:
{
onOrOff
()
{
return
this
.
isConfidential
?
'
Turn Off
'
:
'
Turn On
'
;
},
updateConfidentialBool
()
{
return
!
this
.
isConfidential
;
},
},
};
</
script
>
<
template
>
<div
class=
"confidential-warning-message-actions"
>
<button
type=
"button"
class=
"btn btn-default append-right-10"
@
click=
"toggleForm"
>
Cancel
</button>
<button
type=
"button"
class=
"btn btn-close"
@
click.prevent=
"updateConfidentialAttribute(updateConfidentialBool)"
>
{{
onOrOff
}}
</button>
</div>
</
template
>
app/assets/javascripts/sidebar/sidebar_bundle.js
View file @
f59bdbf0
import
Vue
from
'
vue
'
;
import
Vue
from
'
vue
'
;
import
sidebarTimeTracking
from
'
./components/time_tracking/sidebar_time_tracking
'
;
import
sidebarTimeTracking
from
'
./components/time_tracking/sidebar_time_tracking
'
;
import
sidebarAssignees
from
'
./components/assignees/sidebar_assignees
'
;
import
sidebarAssignees
from
'
./components/assignees/sidebar_assignees
'
;
import
confidential
from
'
./components/confidential/confidential_issue_sidebar.vue
'
;
import
Mediator
from
'
./sidebar_mediator
'
;
import
Mediator
from
'
./sidebar_mediator
'
;
...
@@ -10,13 +11,28 @@ function domContentLoaded() {
...
@@ -10,13 +11,28 @@ function domContentLoaded() {
mediator
.
fetch
();
mediator
.
fetch
();
const
sidebarAssigneesEl
=
document
.
querySelector
(
'
#js-vue-sidebar-assignees
'
);
const
sidebarAssigneesEl
=
document
.
querySelector
(
'
#js-vue-sidebar-assignees
'
);
const
confidentialEl
=
document
.
querySelector
(
'
#js-confidential-entry-point
'
);
// Only create the sidebarAssignees vue app if it is found in the DOM
// Only create the sidebarAssignees vue app if it is found in the DOM
// We currently do not use sidebarAssignees for the MR page
// We currently do not use sidebarAssignees for the MR page
if
(
sidebarAssigneesEl
)
{
if
(
sidebarAssigneesEl
)
{
new
Vue
(
sidebarAssignees
).
$mount
(
sidebarAssigneesEl
);
new
Vue
(
sidebarAssignees
).
$mount
(
sidebarAssigneesEl
);
}
}
if
(
confidentialEl
)
{
const
dataNode
=
document
.
getElementById
(
'
js-confidential-issue-data
'
);
const
initialData
=
JSON
.
parse
(
dataNode
.
innerHTML
);
const
ConfidentialComp
=
Vue
.
extend
(
confidential
);
new
ConfidentialComp
({
propsData
:
{
isConfidential
:
initialData
.
is_confidential
,
isEditable
:
initialData
.
is_editable
,
service
:
mediator
.
service
,
},
}).
$mount
(
confidentialEl
);
}
new
Vue
(
sidebarTimeTracking
).
$mount
(
'
#issuable-time-tracker
'
);
new
Vue
(
sidebarTimeTracking
).
$mount
(
'
#issuable-time-tracker
'
);
}
}
...
...
app/assets/stylesheets/pages/issuable.scss
View file @
f59bdbf0
...
@@ -5,6 +5,30 @@
...
@@ -5,6 +5,30 @@
margin-right
:
auto
;
margin-right
:
auto
;
}
}
.is-confidential
{
color
:
$orange-600
;
background-color
:
$orange-50
;
border-radius
:
3px
;
padding
:
5px
;
margin
:
0
3px
0
-4px
;
}
.is-not-confidential
{
border-radius
:
3px
;
padding
:
5px
;
margin
:
0
3px
0
-4px
;
}
.confidentiality
{
.is-not-confidential
{
margin
:
auto
;
}
.is-confidential
{
margin
:
auto
;
}
}
.limit-container-width
{
.limit-container-width
{
.detail-page-header
,
.detail-page-header
,
.page-content-header
,
.page-content-header
,
...
...
app/assets/stylesheets/pages/note_form.scss
View file @
f59bdbf0
...
@@ -104,40 +104,51 @@
...
@@ -104,40 +104,51 @@
}
}
.confidential-issue-warning
{
.confidential-issue-warning
{
background-color
:
$gray-normal
;
color
:
$orange-600
;
border-radius
:
3px
;
background-color
:
$orange-50
;
border-radius
:
$border-radius-default
$border-radius-default
0
0
;
border
:
1px
solid
$border-gray-normal
;
padding
:
3px
12px
;
padding
:
3px
12px
;
margin
:
auto
;
margin
:
auto
;
margin-top
:
0
;
text-align
:
center
;
font-size
:
12px
;
align-items
:
center
;
align-items
:
center
;
}
@media
(
max-width
:
$screen-md-max
)
{
.confidential-value
{
// On smaller devices the warning becomes the fourth item in the list,
.fa
{
// rather than centering, and grows to span the full width of the
background-color
:
inherit
;
// comment area.
order
:
4
;
margin
:
6px
auto
;
width
:
100%
;
}
}
}
.fa
{
.confidential-warning-message
{
margin-right
:
8px
;
line-height
:
1
.5
;
padding
:
16px
;
.confidential-warning-message-actions
{
display
:
flex
;
button
{
flex-grow
:
1
;
}
}
}
}
}
.not-confidential
{
padding
:
0
;
border-top
:
none
;
}
.right-sidebar-expanded
{
.right-sidebar-expanded
{
.confidential-issue-warning
{
.md-area
{
// When the sidebar is open the warning becomes the fourth item in the list,
border-radius
:
0
;
// rather than centering, and grows to span the full width of the
border-top
:
none
;
// comment area.
order
:
4
;
margin
:
6px
auto
;
width
:
100%
;
}
}
}
}
.right-sidebar-collapsed
{
.confidential-issue-warning
{
border-bottom
:
none
;
}
}
.discussion-form
{
.discussion-form
{
padding
:
$gl-padding-top
$gl-padding
$gl-padding
;
padding
:
$gl-padding-top
$gl-padding
$gl-padding
;
...
...
app/views/projects/_md_preview.html.haml
View file @
f59bdbf0
-
referenced_users
=
local_assigns
.
fetch
(
:referenced_users
,
nil
)
-
referenced_users
=
local_assigns
.
fetch
(
:referenced_users
,
nil
)
-
if
defined?
(
@issue
)
&&
@issue
.
confidential?
%li
.confidential-issue-warning
=
confidential_icon
(
@issue
)
%span
This is a confidential issue. Your comment will not be visible to the public.
-
else
%li
.confidential-issue-warning.not-confidential
.md-area
.md-area
.md-header
.md-header
%ul
.nav-links.clearfix
%ul
.nav-links.clearfix
...
@@ -10,11 +17,6 @@
...
@@ -10,11 +17,6 @@
%a
.js-md-preview-button
{
href:
"#md-preview-holder"
,
tabindex:
-
1
}
%a
.js-md-preview-button
{
href:
"#md-preview-holder"
,
tabindex:
-
1
}
Preview
Preview
-
if
defined?
(
@issue
)
&&
@issue
.
confidential?
%li
.confidential-issue-warning
=
icon
(
'warning'
)
%span
This is a confidential issue. Your comment will not be visible to the public.
%li
.pull-right
%li
.pull-right
.toolbar-group
.toolbar-group
=
markdown_toolbar_button
({
icon:
"bold fw"
,
data:
{
"md-tag"
=>
"**"
},
title:
"Add bold text"
})
=
markdown_toolbar_button
({
icon:
"bold fw"
,
data:
{
"md-tag"
=>
"**"
},
title:
"Add bold text"
})
...
...
app/views/projects/issues/show.html.haml
View file @
f59bdbf0
...
@@ -19,7 +19,8 @@
...
@@ -19,7 +19,8 @@
=
icon
(
'angle-double-left'
)
=
icon
(
'angle-double-left'
)
.issuable-meta
.issuable-meta
=
confidential_icon
(
@issue
)
-
if
@issue
.
confidential
=
icon
(
'eye-slash'
,
class:
'is-confidential'
)
=
issuable_meta
(
@issue
,
@project
,
"Issue"
)
=
issuable_meta
(
@issue
,
@project
,
"Issue"
)
.issuable-actions
.issuable-actions
...
...
app/views/shared/issuable/_sidebar.html.haml
View file @
f59bdbf0
...
@@ -115,6 +115,10 @@
...
@@ -115,6 +115,10 @@
-
if
can?
current_user
,
:admin_label
,
@project
and
@project
-
if
can?
current_user
,
:admin_label
,
@project
and
@project
=
render
partial:
"shared/issuable/label_page_create"
=
render
partial:
"shared/issuable/label_page_create"
-
if
issuable
.
has_attribute?
(
:confidential
)
%script
#js-confidential-issue-data
{
type:
"application/json"
}=
{
is_confidential:
@issue
.
confidential
,
is_editable:
can_edit_issuable
}.
to_json
.
html_safe
#js-confidential-entry-point
=
render
"shared/issuable/participants"
,
participants:
issuable
.
participants
(
current_user
)
=
render
"shared/issuable/participants"
,
participants:
issuable
.
participants
(
current_user
)
-
if
current_user
-
if
current_user
-
subscribed
=
issuable
.
subscribed?
(
current_user
,
@project
)
-
subscribed
=
issuable
.
subscribed?
(
current_user
,
@project
)
...
...
changelogs/unreleased/33874_confi.yml
0 → 100644
View file @
f59bdbf0
---
title
:
Update confidential issue UI - add confidential visibility and settings to
sidebar
merge_request
:
author
:
spec/features/issues_spec.rb
View file @
f59bdbf0
...
@@ -706,4 +706,30 @@ describe 'Issues' do
...
@@ -706,4 +706,30 @@ describe 'Issues' do
expect
(
page
).
to
have_text
(
"updated title"
)
expect
(
page
).
to
have_text
(
"updated title"
)
end
end
end
end
describe
'confidential issue#show'
,
js:
true
do
it
'shows confidential sibebar information as confidential and can be turned off'
do
issue
=
create
(
:issue
,
:confidential
,
project:
project
)
visit
project_issue_path
(
project
,
issue
)
expect
(
page
).
to
have_css
(
'.confidential-issue-warning'
)
expect
(
page
).
to
have_css
(
'.is-confidential'
)
expect
(
page
).
not_to
have_css
(
'.is-not-confidential'
)
find
(
'.confidential-edit'
).
click
expect
(
page
).
to
have_css
(
'.confidential-warning-message'
)
within
(
'.confidential-warning-message'
)
do
find
(
'.btn-close'
).
click
end
wait_for_requests
visit
project_issue_path
(
project
,
issue
)
expect
(
page
).
not_to
have_css
(
'.is-confidential'
)
expect
(
page
).
to
have_css
(
'.is-not-confidential'
)
end
end
end
end
spec/javascripts/sidebar/confidential_edit_buttons_spec.js
0 → 100644
View file @
f59bdbf0
import
Vue
from
'
vue
'
;
import
editFormButtons
from
'
~/sidebar/components/confidential/edit_form_buttons.vue
'
;
describe
(
'
Edit Form Buttons
'
,
()
=>
{
let
vm1
;
let
vm2
;
beforeEach
(()
=>
{
const
Component
=
Vue
.
extend
(
editFormButtons
);
const
toggleForm
=
()
=>
{
};
const
updateConfidentialAttribute
=
()
=>
{
};
vm1
=
new
Component
({
propsData
:
{
isConfidential
:
true
,
toggleForm
,
updateConfidentialAttribute
,
},
}).
$mount
();
vm2
=
new
Component
({
propsData
:
{
isConfidential
:
false
,
toggleForm
,
updateConfidentialAttribute
,
},
}).
$mount
();
});
it
(
'
renders on or off text based on confidentiality
'
,
()
=>
{
expect
(
vm1
.
$el
.
innerHTML
.
includes
(
'
Turn Off
'
),
).
toBe
(
true
);
expect
(
vm2
.
$el
.
innerHTML
.
includes
(
'
Turn On
'
),
).
toBe
(
true
);
});
});
spec/javascripts/sidebar/confidential_edit_form_buttons_spec.js
0 → 100644
View file @
f59bdbf0
import
Vue
from
'
vue
'
;
import
editForm
from
'
~/sidebar/components/confidential/edit_form.vue
'
;
describe
(
'
Edit Form Dropdown
'
,
()
=>
{
let
vm1
;
let
vm2
;
beforeEach
(()
=>
{
const
Component
=
Vue
.
extend
(
editForm
);
const
toggleForm
=
()
=>
{
};
const
updateConfidentialAttribute
=
()
=>
{
};
vm1
=
new
Component
({
propsData
:
{
isConfidential
:
true
,
toggleForm
,
updateConfidentialAttribute
,
},
}).
$mount
();
vm2
=
new
Component
({
propsData
:
{
isConfidential
:
false
,
toggleForm
,
updateConfidentialAttribute
,
},
}).
$mount
();
});
it
(
'
renders on the appropriate warning text
'
,
()
=>
{
expect
(
vm1
.
$el
.
innerHTML
.
includes
(
'
You are going to turn off the confidentiality.
'
),
).
toBe
(
true
);
expect
(
vm2
.
$el
.
innerHTML
.
includes
(
'
You are going to turn on the confidentiality.
'
),
).
toBe
(
true
);
});
});
spec/javascripts/sidebar/confidential_issue_sidebar_spec.js
0 → 100644
View file @
f59bdbf0
import
Vue
from
'
vue
'
;
import
confidentialIssueSidebar
from
'
~/sidebar/components/confidential/confidential_issue_sidebar.vue
'
;
describe
(
'
Confidential Issue Sidebar Block
'
,
()
=>
{
let
vm1
;
let
vm2
;
beforeEach
(()
=>
{
const
Component
=
Vue
.
extend
(
confidentialIssueSidebar
);
const
service
=
{
update
:
()
=>
new
Promise
((
resolve
,
reject
)
=>
{
resolve
(
true
);
reject
(
'
failed!
'
);
}),
};
vm1
=
new
Component
({
propsData
:
{
isConfidential
:
true
,
isEditable
:
true
,
service
,
},
}).
$mount
();
vm2
=
new
Component
({
propsData
:
{
isConfidential
:
false
,
isEditable
:
false
,
service
,
},
}).
$mount
();
});
it
(
'
shows if confidential and/or editable
'
,
()
=>
{
expect
(
vm1
.
$el
.
innerHTML
.
includes
(
'
Edit
'
),
).
toBe
(
true
);
expect
(
vm1
.
$el
.
innerHTML
.
includes
(
'
This issue is confidential
'
),
).
toBe
(
true
);
expect
(
vm2
.
$el
.
innerHTML
.
includes
(
'
None
'
),
).
toBe
(
true
);
});
it
(
'
displays the edit form when editable
'
,
(
done
)
=>
{
expect
(
vm1
.
edit
).
toBe
(
false
);
vm1
.
$el
.
querySelector
(
'
.confidential-edit
'
).
click
();
expect
(
vm1
.
edit
).
toBe
(
true
);
setTimeout
(()
=>
{
expect
(
vm1
.
$el
.
innerHTML
.
includes
(
'
You are going to turn off the confidentiality.
'
),
).
toBe
(
true
);
done
();
});
});
});
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