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
3512898e
Commit
3512898e
authored
Jun 03, 2019
by
GitLab Bot
Browse files
Options
Browse Files
Download
Plain Diff
Automatic merge of gitlab-org/gitlab-ce master
parents
589e7f3b
44f53d46
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
120 additions
and
110 deletions
+120
-110
app/assets/javascripts/gfm_auto_complete.js
app/assets/javascripts/gfm_auto_complete.js
+1
-0
app/assets/javascripts/monitoring/components/dashboard.vue
app/assets/javascripts/monitoring/components/dashboard.vue
+1
-1
app/assets/javascripts/notes/components/noteable_note.vue
app/assets/javascripts/notes/components/noteable_note.vue
+6
-3
app/assets/javascripts/notes/components/notes_app.vue
app/assets/javascripts/notes/components/notes_app.vue
+4
-0
changelogs/unreleased/62092-missing-padding-next-to-time-windows-dropdown-on-metrics-dashboard.yml
...ng-next-to-time-windows-dropdown-on-metrics-dashboard.yml
+5
-0
spec/frontend/helpers/jquery.js
spec/frontend/helpers/jquery.js
+6
-0
spec/frontend/notes/components/note_app_spec.js
spec/frontend/notes/components/note_app_spec.js
+97
-106
No files found.
app/assets/javascripts/gfm_auto_complete.js
View file @
3512898e
import
$
from
'
jquery
'
;
import
'
at.js
'
;
import
_
from
'
underscore
'
;
import
glRegexp
from
'
./lib/utils/regexp
'
;
...
...
app/assets/javascripts/monitoring/components/dashboard.vue
View file @
3512898e
...
...
@@ -248,7 +248,7 @@ export default {
>
</gl-dropdown>
</div>
<div
v-if=
"showTimeWindowDropdown"
class=
"d-flex align-items-center"
>
<div
v-if=
"showTimeWindowDropdown"
class=
"d-flex align-items-center
prepend-left-8
"
>
<strong>
{{
s__
(
'
Metrics|Show last
'
)
}}
</strong>
<gl-dropdown
class=
"prepend-left-10 js-time-window-dropdown"
...
...
app/assets/javascripts/notes/components/noteable_note.vue
View file @
3512898e
...
...
@@ -10,7 +10,7 @@ import Flash from '../../flash';
import
userAvatarLink
from
'
../../vue_shared/components/user_avatar/user_avatar_link.vue
'
;
import
noteHeader
from
'
./note_header.vue
'
;
import
noteActions
from
'
./note_actions.vue
'
;
import
n
oteBody
from
'
./note_body.vue
'
;
import
N
oteBody
from
'
./note_body.vue
'
;
import
eventHub
from
'
../event_hub
'
;
import
noteable
from
'
../mixins/noteable
'
;
import
resolvable
from
'
../mixins/resolvable
'
;
...
...
@@ -21,7 +21,7 @@ export default {
userAvatarLink
,
noteHeader
,
noteActions
,
n
oteBody
,
N
oteBody
,
TimelineEntryItem
,
},
mixins
:
[
noteable
,
resolvable
,
draftMixin
],
...
...
@@ -209,7 +209,10 @@ export default {
// we need to do this to prevent noteForm inconsistent content warning
// this is something we intentionally do so we need to recover the content
this
.
note
.
note
=
noteText
;
this
.
$refs
.
noteBody
.
note
.
note
=
noteText
;
const
{
noteBody
}
=
this
.
$refs
;
if
(
noteBody
)
{
noteBody
.
note
.
note
=
noteText
;
}
},
},
};
...
...
app/assets/javascripts/notes/components/notes_app.vue
View file @
3512898e
...
...
@@ -127,6 +127,9 @@ export default {
initUserPopovers
(
this
.
$el
.
querySelectorAll
(
'
.js-user-link
'
));
});
},
beforeDestroy
()
{
this
.
stopPolling
();
},
methods
:
{
...
mapActions
([
'
setLoadingState
'
,
...
...
@@ -144,6 +147,7 @@ export default {
'
expandDiscussion
'
,
'
startTaskList
'
,
'
convertToDiscussion
'
,
'
stopPolling
'
,
]),
fetchNotes
()
{
if
(
this
.
isFetching
)
return
null
;
...
...
changelogs/unreleased/62092-missing-padding-next-to-time-windows-dropdown-on-metrics-dashboard.yml
0 → 100644
View file @
3512898e
---
title
:
Added padding to time window dropdown in monitor dashboard
merge_request
:
28897
author
:
type
:
fixed
spec/frontend/helpers/jquery.js
0 → 100644
View file @
3512898e
import
$
from
'
jquery
'
;
global
.
$
=
$
;
global
.
jQuery
=
$
;
export
default
$
;
spec/
javascripts
/notes/components/note_app_spec.js
→
spec/
frontend
/notes/components/note_app_spec.js
View file @
3512898e
import
$
from
'
jquery
'
;
import
_
from
'
underscore
'
;
import
$
from
'
helpers/jquery
'
;
import
Vue
from
'
vue
'
;
import
{
mount
,
createLocalVue
}
from
'
@vue/test-utils
'
;
import
NotesApp
from
'
~/notes/components/notes_app.vue
'
;
import
service
from
'
~/notes/services/notes_service
'
;
import
createStore
from
'
~/notes/stores
'
;
import
'
~/behaviors/markdown/render_gfm
'
;
import
*
as
mockData
from
'
../mock_data
'
;
import
{
setTestTimeout
}
from
'
helpers/timeout
'
;
// TODO: use generated fixture (https://gitlab.com/gitlab-org/gitlab-ce/issues/62491)
import
*
as
mockData
from
'
../../../javascripts/notes/mock_data
'
;
const
originalInterceptors
=
[...
Vue
.
http
.
interceptors
];
const
emptyResponseInterceptor
=
(
request
,
next
)
=>
{
next
(
request
.
respondWith
(
JSON
.
stringify
([]),
{
status
:
200
,
}),
);
};
setTestTimeout
(
1000
);
describe
(
'
note_app
'
,
()
=>
{
let
mountComponent
;
let
wrapper
;
let
store
;
/**
* waits for fetchNotes() to complete
*/
const
waitForDiscussionsRequest
=
()
=>
new
Promise
(
resolve
=>
{
const
{
vm
}
=
wrapper
.
find
(
NotesApp
);
const
unwatch
=
vm
.
$watch
(
'
isFetching
'
,
isFetching
=>
{
if
(
isFetching
)
{
return
;
}
unwatch
();
resolve
();
});
});
beforeEach
(()
=>
{
$
(
'
body
'
).
attr
(
'
data-page
'
,
'
projects:merge_requests:show
'
);
...
...
@@ -33,6 +62,7 @@ describe('note_app', () => {
template
:
'
<div class="js-vue-notes-event"><notes-app v-bind="$attrs" /></div>
'
,
},
{
attachToDocument
:
true
,
propsData
,
store
,
localVue
,
...
...
@@ -44,24 +74,14 @@ describe('note_app', () => {
afterEach
(()
=>
{
wrapper
.
destroy
();
Vue
.
http
.
interceptors
=
[...
originalInterceptors
];
});
describe
(
'
set data
'
,
()
=>
{
const
responseInterceptor
=
(
request
,
next
)
=>
{
next
(
request
.
respondWith
(
JSON
.
stringify
([]),
{
status
:
200
,
}),
);
};
beforeEach
(()
=>
{
Vue
.
http
.
interceptors
.
push
(
r
esponseInterceptor
);
Vue
.
http
.
interceptors
.
push
(
emptyR
esponseInterceptor
);
wrapper
=
mountComponent
();
});
afterEach
(()
=>
{
Vue
.
http
.
interceptors
=
_
.
without
(
Vue
.
http
.
interceptors
,
responseInterceptor
);
return
waitForDiscussionsRequest
();
});
it
(
'
should set notes data
'
,
()
=>
{
...
...
@@ -87,29 +107,23 @@ describe('note_app', () => {
Vue
.
http
.
interceptors
.
push
(
mockData
.
individualNoteInterceptor
);
wrapper
=
mountComponent
();
return
waitForDiscussionsRequest
();
});
afterEach
(()
=>
{
Vue
.
http
.
interceptors
=
_
.
without
(
Vue
.
http
.
interceptors
,
mockData
.
individualNoteInterceptor
);
});
it
(
'
should render list of notes
'
,
done
=>
{
it
(
'
should render list of notes
'
,
()
=>
{
const
note
=
mockData
.
INDIVIDUAL_NOTE_RESPONSE_MAP
.
GET
[
'
/gitlab-org/gitlab-ce/issues/26/discussions.json
'
][
0
].
notes
[
0
];
setTimeout
(()
=>
{
expect
(
wrapper
.
find
(
'
.main-notes-list .note-header-author-name
'
)
.
text
()
.
trim
(),
).
toEqual
(
note
.
author
.
name
);
expect
(
wrapper
.
find
(
'
.main-notes-list .note-header-author-name
'
)
.
text
()
.
trim
(),
).
toEqual
(
note
.
author
.
name
);
expect
(
wrapper
.
find
(
'
.main-notes-list .note-text
'
).
html
()).
toContain
(
note
.
note_html
);
done
();
},
0
);
expect
(
wrapper
.
find
(
'
.main-notes-list .note-text
'
).
html
()).
toContain
(
note
.
note_html
);
});
it
(
'
should render form
'
,
()
=>
{
...
...
@@ -120,37 +134,42 @@ describe('note_app', () => {
});
it
(
'
should not render form when commenting is disabled
'
,
()
=>
{
wrapper
.
destroy
();
store
.
state
.
commentsDisabled
=
true
;
wrapper
=
mountComponent
();
expect
(
wrapper
.
find
(
'
.js-main-target-form
'
).
exists
()).
toBe
(
false
);
return
waitForDiscussionsRequest
().
then
(()
=>
{
expect
(
wrapper
.
find
(
'
.js-main-target-form
'
).
exists
()).
toBe
(
false
);
});
});
it
(
'
should render discussion filter note `commentsDisabled` is true
'
,
()
=>
{
wrapper
.
destroy
();
store
.
state
.
commentsDisabled
=
true
;
wrapper
=
mountComponent
();
expect
(
wrapper
.
find
(
'
.js-discussion-filter-note
'
).
exists
()).
toBe
(
true
);
return
waitForDiscussionsRequest
().
then
(()
=>
{
expect
(
wrapper
.
find
(
'
.js-discussion-filter-note
'
).
exists
()).
toBe
(
true
);
});
});
it
(
'
should render form comment button as disabled
'
,
()
=>
{
expect
(
wrapper
.
find
(
'
.js-note-new-discussion
'
).
attributes
(
'
disabled
'
)).
toEqual
(
'
disabled
'
);
});
it
(
'
updates discussions badge
'
,
done
=>
{
setTimeout
(()
=>
{
expect
(
document
.
querySelector
(
'
.js-discussions-count
'
).
textContent
).
toEqual
(
'
2
'
);
done
();
});
it
(
'
updates discussions badge
'
,
()
=>
{
expect
(
document
.
querySelector
(
'
.js-discussions-count
'
).
textContent
).
toEqual
(
'
2
'
);
});
});
describe
(
'
while fetching data
'
,
()
=>
{
beforeEach
(()
=>
{
Vue
.
http
.
interceptors
.
push
(
emptyResponseInterceptor
);
wrapper
=
mountComponent
();
});
afterEach
(()
=>
waitForDiscussionsRequest
());
it
(
'
renders skeleton notes
'
,
()
=>
{
expect
(
wrapper
.
find
(
'
.animation-container
'
).
exists
()).
toBe
(
true
);
});
...
...
@@ -165,78 +184,55 @@ describe('note_app', () => {
describe
(
'
update note
'
,
()
=>
{
describe
(
'
individual note
'
,
()
=>
{
beforeEach
(
done
=>
{
beforeEach
(
()
=>
{
Vue
.
http
.
interceptors
.
push
(
mockData
.
individualNoteInterceptor
);
spyOn
(
service
,
'
updateNote
'
).
and
.
callThrough
(
);
jest
.
spyOn
(
service
,
'
updateNote
'
);
wrapper
=
mountComponent
();
setTimeout
(()
=>
{
return
waitForDiscussionsRequest
().
then
(()
=>
{
wrapper
.
find
(
'
.js-note-edit
'
).
trigger
(
'
click
'
);
Vue
.
nextTick
(
done
);
},
0
);
});
afterEach
(()
=>
{
Vue
.
http
.
interceptors
=
_
.
without
(
Vue
.
http
.
interceptors
,
mockData
.
individualNoteInterceptor
,
);
});
});
it
(
'
renders edit form
'
,
()
=>
{
expect
(
wrapper
.
find
(
'
.js-vue-issue-note-form
'
).
exists
()).
toBe
(
true
);
});
it
(
'
calls the service to update the note
'
,
done
=>
{
it
(
'
calls the service to update the note
'
,
()
=>
{
wrapper
.
find
(
'
.js-vue-issue-note-form
'
).
value
=
'
this is a note
'
;
wrapper
.
find
(
'
.js-vue-issue-save
'
).
trigger
(
'
click
'
);
expect
(
service
.
updateNote
).
toHaveBeenCalled
();
// Wait for the requests to finish before destroying
setTimeout
(()
=>
{
done
();
});
});
});
describe
(
'
discussion note
'
,
()
=>
{
beforeEach
(
done
=>
{
beforeEach
(
()
=>
{
Vue
.
http
.
interceptors
.
push
(
mockData
.
discussionNoteInterceptor
);
spyOn
(
service
,
'
updateNote
'
).
and
.
callThrough
(
);
jest
.
spyOn
(
service
,
'
updateNote
'
);
wrapper
=
mountComponent
();
setTimeout
(()
=>
{
return
waitForDiscussionsRequest
().
then
(()
=>
{
wrapper
.
find
(
'
.js-note-edit
'
).
trigger
(
'
click
'
);
Vue
.
nextTick
(
done
);
},
0
);
});
afterEach
(()
=>
{
Vue
.
http
.
interceptors
=
_
.
without
(
Vue
.
http
.
interceptors
,
mockData
.
discussionNoteInterceptor
,
);
});
});
it
(
'
renders edit form
'
,
()
=>
{
expect
(
wrapper
.
find
(
'
.js-vue-issue-note-form
'
).
exists
()).
toBe
(
true
);
});
it
(
'
updates the note and resets the edit form
'
,
done
=>
{
it
(
'
updates the note and resets the edit form
'
,
()
=>
{
wrapper
.
find
(
'
.js-vue-issue-note-form
'
).
value
=
'
this is a note
'
;
wrapper
.
find
(
'
.js-vue-issue-save
'
).
trigger
(
'
click
'
);
expect
(
service
.
updateNote
).
toHaveBeenCalled
();
// Wait for the requests to finish before destroying
setTimeout
(()
=>
{
done
();
});
});
});
});
describe
(
'
new note form
'
,
()
=>
{
beforeEach
(()
=>
{
Vue
.
http
.
interceptors
.
push
(
mockData
.
individualNoteInterceptor
);
wrapper
=
mountComponent
();
return
waitForDiscussionsRequest
();
});
it
(
'
should render markdown docs url
'
,
()
=>
{
...
...
@@ -266,43 +262,37 @@ describe('note_app', () => {
beforeEach
(()
=>
{
Vue
.
http
.
interceptors
.
push
(
mockData
.
individualNoteInterceptor
);
wrapper
=
mountComponent
();
return
waitForDiscussionsRequest
();
});
afterEach
(
()
=>
{
Vue
.
http
.
interceptors
=
_
.
without
(
Vue
.
http
.
interceptors
,
mockData
.
individualNoteInterceptor
);
})
;
it
(
'
should render markdown docs url
'
,
()
=>
{
wrapper
.
find
(
'
.js-note-edit
'
).
trigger
(
'
click
'
);
const
{
markdownDocsPath
}
=
mockData
.
notesDataMock
;
it
(
'
should render markdown docs url
'
,
done
=>
{
setTimeout
(()
=>
{
wrapper
.
find
(
'
.js-note-edit
'
).
trigger
(
'
click
'
);
const
{
markdownDocsPath
}
=
mockData
.
notesDataMock
;
Vue
.
nextTick
(()
=>
{
expect
(
wrapper
.
find
(
`.edit-note a[href="
${
markdownDocsPath
}
"]`
)
.
text
()
.
trim
(),
).
toEqual
(
'
Markdown is supported
'
);
done
();
});
},
0
);
return
Vue
.
nextTick
().
then
(()
=>
{
expect
(
wrapper
.
find
(
`.edit-note a[href="
${
markdownDocsPath
}
"]`
)
.
text
()
.
trim
(),
).
toEqual
(
'
Markdown is supported
'
);
});
});
it
(
'
should not render quick actions docs url
'
,
done
=>
{
setTimeout
(()
=>
{
wrapper
.
find
(
'
.js-note-edit
'
).
trigger
(
'
click
'
);
const
{
quickActionsDocsPath
}
=
mockData
.
notesDataMock
;
Vue
.
nextTick
(()
=>
{
expect
(
wrapper
.
find
(
`.edit-note a[href="
${
quickActionsDocsPath
}
"]`
).
exists
()).
toBe
(
false
);
done
();
});
},
0
);
it
(
'
should not render quick actions docs url
'
,
()
=>
{
wrapper
.
find
(
'
.js-note-edit
'
).
trigger
(
'
click
'
);
const
{
quickActionsDocsPath
}
=
mockData
.
notesDataMock
;
expect
(
wrapper
.
find
(
`.edit-note a[href="
${
quickActionsDocsPath
}
"]`
).
exists
()).
toBe
(
false
);
});
});
describe
(
'
emoji awards
'
,
()
=>
{
beforeEach
(()
=>
{
Vue
.
http
.
interceptors
.
push
(
emptyResponseInterceptor
);
wrapper
=
mountComponent
();
return
waitForDiscussionsRequest
();
});
it
(
'
dispatches toggleAward after toggleAward event
'
,
()
=>
{
const
toggleAwardEvent
=
new
CustomEvent
(
'
toggleAward
'
,
{
detail
:
{
...
...
@@ -310,17 +300,18 @@ describe('note_app', () => {
noteId
:
1
,
},
});
const
toggleAwardAction
=
j
asmine
.
createSpy
(
'
toggleAward
'
);
const
toggleAwardAction
=
j
est
.
fn
().
mockName
(
'
toggleAward
'
);
wrapper
.
vm
.
$store
.
hotUpdate
({
actions
:
{
toggleAward
:
toggleAwardAction
,
stopPolling
()
{},
},
});
wrapper
.
vm
.
$parent
.
$el
.
dispatchEvent
(
toggleAwardEvent
);
expect
(
toggleAwardAction
).
toHaveBeenCalledTimes
(
1
);
const
[,
payload
]
=
toggleAwardAction
.
calls
.
argsFor
(
0
)
;
const
[,
payload
]
=
toggleAwardAction
.
mock
.
calls
[
0
]
;
expect
(
payload
).
toEqual
({
awardName
:
'
test
'
,
...
...
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