...
 
Commits (12)
......@@ -144,6 +144,7 @@ export default {
if (left || right) {
return {
...line,
left: line.left ? mapDiscussions(line.left) : null,
right: line.right ? mapDiscussions(line.right, () => !left) : null,
};
......
......@@ -161,6 +161,7 @@ export function addContextLines(options) {
const normalizedParallelLines = contextLines.map(line => ({
left: line,
right: line,
line_code: line.line_code,
}));
if (options.bottom) {
......
---
title: 'API: Expose full commit title'
merge_request: 25189
author: Robert Schilling
type: fixed
......@@ -112,7 +112,7 @@ table_display_block: true
## Emphasis
- Use double asterisks (`**`) to mark a word or text in bold (`**bold**`).
- Use undescore (`_`) for text in italics (`_italic_`).
- Use underscore (`_`) for text in italics (`_italic_`).
- Use greater than (`>`) for blockquotes.
## Punctuation
......
# Frontend Development Guidelines
> **Notice:**
We are currently in the process of re-writing our development guide to make it easier to find information. The new guide is still WIP but viewable in [development/new_fe_guide](../new_fe_guide/index.md)
> We are currently in the process of re-writing our development guide to make it easier to find information. The new guide is still WIP but viewable in [development/new_fe_guide](../new_fe_guide/index.md)
This document describes various guidelines to ensure consistency and quality
across GitLab's frontend team.
......@@ -32,32 +32,41 @@ For our currently-supported browsers, see our [requirements][requirements].
---
## [Development Process](development_process.md)
How we plan and execute the work on the frontend.
## [Architecture](architecture.md)
How we go about making fundamental design decisions in GitLab's frontend team
or make changes to our frontend development guidelines.
## [Testing](../testing_guide/frontend_testing.md)
How we write frontend tests, run the GitLab test suite, and debug test related
issues.
## [Design Patterns](design_patterns.md)
Common JavaScript design patterns in GitLab's codebase.
## [Vue.js Best Practices](vue.md)
Vue specific design patterns and practices.
## [Vuex](vuex.md)
Vuex specific design patterns and practices.
## [Axios](axios.md)
Axios specific practices and gotchas.
## [GraphQL](graphql.md)
How to use GraphQL
## [Icons and Illustrations](icons.md)
How we use SVG for our Icons and Illustrations.
## [Components](components.md)
......@@ -70,7 +79,7 @@ How we use UI components.
### [JavaScript Style Guide](style_guide_js.md)
We use eslint to enforce our JavaScript style guides. Our guide is based on
We use eslint to enforce our JavaScript style guides. Our guide is based on
the excellent [Airbnb][airbnb-js-style-guide] style guide with a few small
changes.
......@@ -81,23 +90,26 @@ Our SCSS conventions which are enforced through [scss-lint][scss-lint].
---
## [Performance](performance.md)
Best practices for monitoring and maximizing frontend performance.
---
## [Security](security.md)
Frontend security practices.
---
## [Accessibility](accessibility.md)
Our accessibility standards and resources.
## [Internationalization (i18n) and Translations](../i18n/externalization.md)
Frontend internationalization support is described in [this document](../i18n/).
The [externalization part of the guide](../i18n/externalization.md) explains the helpers/methods available.
[rails]: http://rubyonrails.org/
[haml]: http://haml.info/
[hamlit]: https://github.com/k0kubun/hamlit
......@@ -116,6 +128,7 @@ The [externalization part of the guide](../i18n/externalization.md) explains the
---
## [DropLab](droplab/droplab.md)
Our internal `DropLab` dropdown library.
- [DropLab](droplab/droplab.md)
......
# Event Tracking
We use [Snowplow](https://github.com/snowplow/snowplow) for tracking custom events.
## Generic tracking function
In addition to Snowplow's built-in method for tracking page views, we use a generic tracking function which enables us to selectively apply listeners to events.
The generic tracking function can be imported in EE-specific JS files as follows:
```javascript
import { trackEvent } from `ee/stats`;
```
This gives the user access to the `trackEvent` method, which takes the following parameters:
| parameter | type | description | required |
| ---------------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `category` | string | Describes the page that you're capturing click events on. Unless infeasible, please use the Rails page attribute `document.body.dataset.page` by default. | true |
| `eventName` | string | Describes the action the user is taking. The first word should always describe the action. For example, clicks should be `click` and activations should be `activate`. Use underscores to describe what was acted on. For example, activating a form field would be `activate_form_input`. Clicking on a dropdown is `click_dropdown`. | true |
| `additionalData` | object | Additional data such as `label`, `property`, and `value` as described [in our Feature Instrumentation taxonomy](https://about.gitlab.com/handbook/product/feature-instrumentation/#taxonomy). | false |
Read more about instrumentation and the taxonomy in the [Product Handbook](https://about.gitlab.com/handbook/product/feature-instrumentation).
### Tracking in `.js` and `.vue` files
The most simple use case is to add tracking programmatically to an event of interest in Javascript.
The following example demonstrates how to track a click on a button in Javascript by calling the `trackEvent` method explicitly:
```javascript
import { trackEvent } from `ee/stats`;
trackEvent('dashboard:projects:index', 'click_button', {
label: 'create_from_template',
property: 'template_preview',
value: 'rails',
});
```
### Tracking in HAML templates
Sometimes we want to track clicks for multiple elements on a page. Creating event handlers for all elements could soon turn into a tedious task.
There's a more convenient solution to this problem. When working with HAML templates, we can add `data-track-*` attributes to elements of interest. This way, all elements that have both `data-track-label` and `data-track-event` attributes assigned get marked for event tracking. All we have to do is call the `bindTrackableContainer` method on a container which allows for better scoping.
Below is an example of `data-track-*` attributes assigned to a button in HAML:
```ruby
%button.btn{ data: { track_label: "create_from_template", track_property: "template_preview", track_event: "click_button", track_value: "my-template" } }
```
By calling `bindTrackableContainer('.my-container')`, click handlers get bound to all elements located in `.my-container` provided that they have the necessary `data-track-*` attributes assigned to them.
```javascript
import Stats from 'ee/stats';
document.addEventListener('DOMContentLoaded', () => {
Stats.bindTrackableContainer('.my-container', 'category');
});
```
The second parameter in `bindTrackableContainer` is optional. If omitted, the value of `document.body.dataset.page` will be used as category instead.
Below is a list of supported `data-track-*` attributes:
| attribute | description | required |
| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `data-track-label` | The `label` in `trackEvent` | true |
| `data-track-event` | The `eventName` in `trackEvent` | true |
| `data-track-property` | The `property` in `trackEvent`. If omitted, an empty string will be used as a default value. | false |
| `data-track-value` | The `value` in `trackEvent`. If omitted, this will be `target.value` or empty string. For checkboxes, the default value being tracked will be the element's checked attribute if `data-track-value` is omitted. | false |
Since Snowplow is an Enterprise Edition feature, it's necessary to create a CE backport when adding `data-track-*` attributes to HAML templates in most cases.
......@@ -27,6 +27,10 @@ Learn about all the internal JavaScript modules that make up our frontend.
Style guides to keep our code consistent.
## [Event Tracking with Snowplow](event_tracking.md)
How we use Snowplow to track custom events.
## [Tips](tips.md)
Tips from our frontend team to develop more efficiently and effectively.
......@@ -66,7 +66,7 @@ publish any website written directly in plain HTML, CSS, and JavaScript.</p>
If you're using GitLab.com, your website will be publicly available to the internet.
If you're using self-managed instances (Core, Starter, Premium, or Ultimate),
your websites will be published on your own server, according to the
[Pages admin settings](../../../administration/pages/index.md) chosen by your sysdamin,
[Pages admin settings](../../../administration/pages/index.md) chosen by your sysadmin,
who can opt for making them public or internal to your server.
### How it works
......
......@@ -50,7 +50,7 @@ review the list of changed files. Click on each file to review the changes and
click the tick icon to stage the file.
Once you have staged some changes, you can add a commit message and commit the
staged changes. Unstaged changes will not be commited.
staged changes. Unstaged changes will not be committed.
![Commit changes](img/commit_changes.png)
......
......@@ -369,8 +369,9 @@ module API
end
class Commit < Grape::Entity
expose :id, :short_id, :title, :created_at
expose :id, :short_id, :created_at
expose :parent_ids
expose :full_title, as: :title
expose :safe_message, as: :message
expose :author_name, :author_email, :authored_date
expose :committer_name, :committer_email, :committed_date
......
......@@ -14,7 +14,7 @@ import { MERGE_REQUEST_NOTEABLE_TYPE } from '~/notes/constants';
import diffFileMockData from '../mock_data/diff_file';
import { noteableDataMock } from '../../notes/mock_data';
const getDiffFileMock = () => Object.assign({}, diffFileMockData);
const getDiffFileMock = () => JSON.parse(JSON.stringify(diffFileMockData));
describe('DiffsStoreUtils', () => {
describe('findDiffFile', () => {
......@@ -80,30 +80,44 @@ describe('DiffsStoreUtils', () => {
});
describe('addContextLines', () => {
it('should add context lines properly with bottom parameter', () => {
it('should add context lines', () => {
const diffFile = getDiffFileMock();
const inlineLines = diffFile.highlighted_diff_lines;
const parallelLines = diffFile.parallel_diff_lines;
const lineNumbers = { oldLineNumber: 3, newLineNumber: 5 };
const contextLines = [{ lineNumber: 42 }];
const options = { inlineLines, parallelLines, contextLines, lineNumbers, bottom: true };
const contextLines = [{ lineNumber: 42, line_code: '123' }];
const options = { inlineLines, parallelLines, contextLines, lineNumbers };
const inlineIndex = utils.findIndexInInlineLines(inlineLines, lineNumbers);
const parallelIndex = utils.findIndexInParallelLines(parallelLines, lineNumbers);
const normalizedParallelLine = {
left: options.contextLines[0],
right: options.contextLines[0],
line_code: '123',
};
utils.addContextLines(options);
expect(inlineLines[inlineLines.length - 1]).toEqual(contextLines[0]);
expect(parallelLines[parallelLines.length - 1]).toEqual(normalizedParallelLine);
expect(inlineLines[inlineIndex]).toEqual(contextLines[0]);
expect(parallelLines[parallelIndex]).toEqual(normalizedParallelLine);
});
it('should add context lines properly with bottom parameter', () => {
const diffFile = getDiffFileMock();
const inlineLines = diffFile.highlighted_diff_lines;
const parallelLines = diffFile.parallel_diff_lines;
const lineNumbers = { oldLineNumber: 3, newLineNumber: 5 };
const contextLines = [{ lineNumber: 42, line_code: '123' }];
const options = { inlineLines, parallelLines, contextLines, lineNumbers, bottom: true };
const normalizedParallelLine = {
left: options.contextLines[0],
right: options.contextLines[0],
line_code: '123',
};
delete options.bottom;
utils.addContextLines(options);
expect(inlineLines[inlineIndex]).toEqual(contextLines[0]);
expect(parallelLines[parallelIndex]).toEqual(normalizedParallelLine);
expect(inlineLines[inlineLines.length - 1]).toEqual(contextLines[0]);
expect(parallelLines[parallelLines.length - 1]).toEqual(normalizedParallelLine);
});
});
......
......@@ -237,7 +237,7 @@ describe API::Commits do
end
describe 'create' do
let(:message) { 'Created file' }
let(:message) { 'Created a new file with a very very looooooooooooooooooooooooooooooooooooooooooooooong commit message' }
let(:invalid_c_params) do
{
branch: 'master',
......