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
4490af8c
Commit
4490af8c
authored
Aug 07, 2017
by
Jacob Schatz
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch '33874_confi' into 'master'
33874 confidential issue redesign See merge request !12801
parents
1bed998e
f59bdbf0
Changes
14
Show 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 @
4490af8c
<
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 @
4490af8c
<
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 @
4490af8c
<
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 @
4490af8c
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 @
4490af8c
...
@@ -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 @
4490af8c
...
@@ -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 @
4490af8c
-
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 @
4490af8c
...
@@ -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 @
4490af8c
...
@@ -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 @
4490af8c
---
title
:
Update confidential issue UI - add confidential visibility and settings to
sidebar
merge_request
:
author
:
spec/features/issues_spec.rb
View file @
4490af8c
...
@@ -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 @
4490af8c
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 @
4490af8c
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 @
4490af8c
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