Commit bdec7baa authored by Martin Wortschack's avatar Martin Wortschack

Merge branch 'master' into 7427-track-navbar-clicks-on-gitlab-com

parents 516ad19d 1f5d50b1
No related merge requests found

Too many changes to show.

To preserve performance only 1000 of 1000+ files are displayed.

......@@ -29,8 +29,6 @@ rules:
import/no-useless-path-segments: off
lines-between-class-members: off
# Disabled for now, to make the plugin-vue 4.5 -> 5.0 update smoother
vue/html-closing-bracket-newline: off
vue/html-closing-bracket-spacing: off
vue/no-confusing-v-for-v-if: error
vue/no-unused-components: off
vue/no-use-v-if-with-v-for: off
......
This diff is collapsed.
### Background:
(Include problem, use cases, benefits, and/or goals)
**What questions are you trying to answer?**
**Are you looking to verify an existing hypothesis or uncover new issues you should be exploring?**
**What is the backstory of this project and how does it impact the approach?**
**What do you already know about the areas you are exploring?**
**What does success look like at the end of the project?**
### Links / references:
/label ~"UX research"
......@@ -64,7 +64,7 @@ Some features might be simple enough that they only involve one Component, while
more complex features could involve multiple or even all.
Example (from https://gitlab.com/gitlab-org/gitlab-ce/issues/50353):
* Respository is
* Repository is
* Intuitive
* It's easy to select the desired file template
* It doesn't require unnecessary actions to save the change
......@@ -93,4 +93,4 @@ When adding new automated tests, please keep [testing levels](https://docs.gitla
in mind.
-->
/label ~Quality ~"test plan"
\ No newline at end of file
/label ~Quality ~"test plan"
8.11.3
10.13.0
......@@ -50,7 +50,6 @@ Style/FrozenStringLiteralComment:
- 'danger/**/*'
- 'db/**/*'
- 'ee/**/*'
- 'lib/gitlab/**/*'
- 'lib/tasks/**/*'
- 'qa/**/*'
- 'rubocop/**/*'
......
2.4.5
2.5.3
Please view this file on the master branch, on stable branches it's out of date.
## 11.5.1 (2018-11-26)
### Security (6 changes)
- Sanitize tracing external_urls before saving to DB and when displaying the URL to prevent XSS issues.
- Prevent reporter roles from viewing the Jaeger tracing settings page.
- Fix IDOR at /drafts/publish.
- Authorize users when listing board users and milestones.
- Resolve: Guest can set weight of a new issue.
- Fixes XSS with merge request approvers selection.
## 11.5.0 (2018-11-22)
### Security (2 changes)
- Escape entity title while autocomplete template rendering to prevent XSS. !696
- Prevent templated services from being imported.
### Removed (1 change)
- Remove security report summary from pipelines view. !7844
### Fixed (25 changes, 3 of them are from the community)
- Geo: Remove connectivity check from primary to secondary from gitlab:geo:check rake task. !7821
- Include (closed) for closed epics in parsed text. !7946
- Add new state to the cluster application vue app. !7954
- Do not allow to assign an issue to an epic twice. !8004
- [Geo] Fix: Deleting a project leaves orphaned LFS objects and CI Job artifacts around. !8031
- Support `/client/features` Unleash endpoint. !8045
- Fix button rendering in license management in FF. !8046
- Geo: Handle orphaned Uploads records. !8054
- Geo - Redirect user back to the secondary after a logout & re-login via the primary. !8157
- Fix approver removal still being conducted even when "Cancel" is clicked in confirmation prompt. !8178
- Link project short SHA to commit url. !8214
- Update ops dashboard remove dropdown button. !8236 (George Tsiolis)
- Clear ops dashboard project search input on submit. !8239 (George Tsiolis)
- Fixes a dismissed vulnerability bug on the group security dashboard. !8343
- Fixes missing fields on the group security dashboard. !8360
- Fixes the view issue button in the Group Security Dashboard. !8385
- Ops Dashboard should be available for public projects on GitLab.com. !8399
- Update draft comments design to match new design. !8405
- Change issues analytics breadcrumb. !8414 (George Tsiolis)
- Include classification label in project API. !8426
- Fix Pod Log topbar position when perf bar is disabled.
- Always proxy reports downloads.
- Removes extra rigth margin from job page.
- Geo: Rails console message display primary/secondary state incorrectly.
- Disable Feature Flags and Packages if repository is disabled.
### Changed (13 changes, 1 of them is from the community)
- Add test button to Group SAML settings. !5622
- Group SAML status badges on members page. !5807
- Update related issues list styling to be more space efficient. !7784
- Refactor test reports to use new artifact architecture. !7827
- Add timeline icon for issue weights. !7847 (George Tsiolis)
- Added a search bar to `Admin > Geo > Projects`. !8079
- Geo: Deprecate source installations instructions. !8134
- Does not synchronize default branch for pull mirrors. !8138
- Adds split error states for the group security dashboard. !8208
- Geo: Improve read-only message in secondary nodes for actionable screens. !8238
- Improve error messages for operations dashboard. !8244
- Add documentation link to ops dashboard. !8296
- Issue board card design. !21229
### Added (24 changes, 1 of them is from the community)
- Group-level file templates. !7391
- Adds group-level Security Dashboard counts. !7564
- Parse SAST reports and store vulnerabilities in database. !7578
- elasticsearch 6 support - migrate from parent/child relationships to join. !7618
- Geo: Admin > Geo > Projects support for batch operations. !7806
- Create system notes for epic close and reopen. !7850
- Add Tracing landing and settings page. !7903
- Add modals and actions to the vulnerabilities in the Group security dashboard. !7910
- Assign code owner as approver. !7933
- Enable previewing of draft review comments. !7936
- Audit log: Add logging for project feature changes. !7962
- Add project operations dashboard. !7973
- Audit log: Add audit events for group setting changes. !7987
- Add approve quick action. !7989
- Show actual Milestone dates within tooltips for Milestones in Epics sidebar. !8048
- Allow filtering by weight in issues API. !8140 (Heinrich Lee Yu)
- Filter epics by state in API. !8179
- Support epics autocomplete for project objects. !8180
- Add 'l', 'r' and 'e' keyboard shortcuts support in Epic. !8203
- Configurable GitHub static context for statuses integration. !8235
- Send notifications for epic status change. !8247
- Support license management and performance using new reports syntax.
- Support reports: for project security dashboard.
- Add chart of issues created per month.
### Other (17 changes, 11 of them are from the community)
- Update boards list selector specs. !6266 (George Tsiolis)
- Write some Geo development documentation. !7452
- Connects the Group Security Dashboard API and Frontend. !7793
- Rails5: Fix epics finder count_key method In Rails5, the state enum value is passed instead of the database integer. !7822 (Jasper Maes)
- Rails 5: fix presence message validation for prometheus_alert. !7823 (Jasper Maes)
- Rails 5: fix mysql milliseconds problem in prometheus alert event spec. !7828 (Jasper Maes)
- Rails5: fix VulnerabilitySummaryEntity. !7893 (Jasper Maes)
- Update feature flags empty state. !7967 (George Tsiolis)
- Adds the security dashboard link. !7974
- Remove tooltip on sidebar text buttons. !8021 (George Tsiolis)
- Add a metric to the usage ping data to track the number of projects with at least one alert. !8058
- Remove unneeded permission checks from the mirror repositories partial. !8077
- Rails5: fix flaky mysql reset pipeline minutes spec. !8122 (Jasper Maes)
- Move `prepend` outside the `class` block for finders. !8192 (George Tsiolis)
- Rails5: fix operations controller spec nil parameter. !8209 (Jasper Maes)
- Update related issues title typography. !8267 (George Tsiolis)
- Geo: Clarify Geo HA documentation.
## 11.4.8 (2018-11-27)
### Security (5 changes)
- Escape entity title while autocomplete template rendering to prevent XSS. !707
- Authorize users when listing board users and milestones.
- Fix IDOR at /drafts/publish.
- Resolve: Guest can set weight of a new issue.
- Fixes XSS with merge request approvers selection.
## 11.4.7 (2018-11-20)
### Fixed (1 change)
- Fix code owner as merge request suggestion not available under Starter plan. !8248
## 11.4.6 (2018-11-18)
### Security (1 change)
- Prevent templated services from being imported.
## 11.4.5 (2018-11-04)
### Fixed (1 change)
......@@ -119,6 +259,23 @@ Please view this file on the master branch, on stable branches it's out of date.
- API: Allow issue weight parameter to be greater than or equal to zero.
## 11.3.11 (2018-11-26)
### Security (7 changes)
- Escape entity title while autocomplete template rendering to prevent XSS. !697
- Properly filter private references from system notes.
- Authorize users when listing board users and milestones.
- Project groups approvers no longer leak private groups info.
- Resolve: Guest can set weight of a new issue.
- Fixes XSS with merge request approvers selection.
- Protect against CSRF attacks when adding Slack app.
## 11.3.10 (2018-11-18)
- No changes.
## 11.3.9 (2018-10-31)
- No changes.
......
This diff is collapsed.
0.129.0
1.1.0
7.1.0
7.1.1
# --- Special code for migrating to Rails 5.0 ---
def rails5?
%w[1 true].include?(ENV["RAILS5"])
!%w[0 false].include?(ENV["RAILS5"])
end
gem_versions = {}
gem_versions['activerecord_sane_schema_dumper'] = rails5? ? '1.0' : '0.2'
gem_versions['default_value_for'] = rails5? ? '~> 3.0.5' : '~> 3.0.0'
gem_versions['rails'] = rails5? ? '5.0.7' : '4.2.10'
gem_versions['rails-i18n'] = rails5? ? '~> 5.1' : '~> 4.0.9'
gem_versions['activerecord_sane_schema_dumper'] = rails5? ? '1.0' : '0.2'
gem_versions['rails'] = rails5? ? '5.0.7' : '4.2.10'
gem_versions['rails-i18n'] = rails5? ? '~> 5.1' : '~> 4.0.9'
# --- The end of special code for migrating to Rails 5.0 ---
source 'https://rubygems.org'
......@@ -15,13 +14,20 @@ source 'https://rubygems.org'
gem 'rails', gem_versions['rails']
gem 'rails-deprecated_sanitizer', '~> 1.0.3'
# Improves copy-on-write performance for MRI
gem 'nakayoshi_fork', '~> 0.0.4'
# Responders respond_to and respond_with
gem 'responders', '~> 2.0'
gem 'sprockets', '~> 3.7.0'
# Default values for AR models
gem 'default_value_for', gem_versions['default_value_for']
if rails5?
gem 'gitlab-default_value_for', '~> 3.1.1', require: 'default_value_for'
else
gem 'default_value_for', '~> 3.0.0'
end
# Supported DBs
gem 'mysql2', '~> 0.4.10', group: :mysql
......@@ -143,7 +149,7 @@ gem 'rdoc', '~> 6.0'
gem 'org-ruby', '~> 0.9.12'
gem 'creole', '~> 0.5.0'
gem 'wikicloth', '0.8.1'
gem 'asciidoctor', '~> 1.5.6'
gem 'asciidoctor', '~> 1.5.8'
gem 'asciidoctor-plantuml', '0.0.8'
gem 'rouge', '~> 3.1'
gem 'truncato', '~> 0.7.9'
......@@ -233,13 +239,13 @@ gem 'slack-notifier', '~> 1.5.1'
gem 'hangouts-chat', '~> 0.0.5'
# Asana integration
gem 'asana', '~> 0.6.0'
gem 'asana', '~> 0.8.1'
# FogBugz integration
gem 'ruby-fogbugz', '~> 0.2.1'
# Kubernetes integration
gem 'kubeclient', '~> 3.1.0'
gem 'kubeclient', '~> 4.0.0'
# Sanitize user input
gem 'sanitize', '~> 4.6'
......@@ -326,8 +332,8 @@ group :development do
gem 'rblineprof', '~> 0.3.6', platform: :mri, require: false
# Better errors handler
gem 'better_errors', '~> 2.1.0'
gem 'binding_of_caller', '~> 0.7.2'
gem 'better_errors', '~> 2.5.0'
gem 'binding_of_caller', '~> 0.8.0'
# thin instead webrick
gem 'thin', '~> 1.7.0'
......@@ -354,7 +360,7 @@ group :development, :test do
gem 'minitest', '~> 5.7.0'
# Generate Fake data
gem 'ffaker', '~> 2.4'
gem 'ffaker', '~> 2.10'
gem 'capybara', '~> 2.15'
gem 'capybara-screenshot', '~> 1.0.0'
......@@ -369,14 +375,14 @@ group :development, :test do
gem 'rubocop-rspec', '~> 1.22.1'
gem 'scss_lint', '~> 0.56.0', require: false
gem 'haml_lint', '~> 0.26.0', require: false
gem 'haml_lint', '~> 0.28.0', require: false
gem 'simplecov', '~> 0.14.0', require: false
gem 'bundler-audit', '~> 0.5.0', require: false
gem 'benchmark-ips', '~> 2.3.0', require: false
gem 'license_finder', '~> 5.4', require: false
gem 'knapsack', '~> 1.16'
gem 'knapsack', '~> 1.17'
gem 'activerecord_sane_schema_dumper', gem_versions['activerecord_sane_schema_dumper']
......@@ -395,7 +401,7 @@ group :test do
gem 'rails-controller-testing' if rails5? # Rails5 only gem.
gem 'test_after_commit', '~> 1.1' unless rails5? # Remove this gem when migrated to rails 5.0. It's been integrated to rails 5.0.
gem 'sham_rack', '~> 1.3.6'
gem 'concurrent-ruby', '~> 1.0.5'
gem 'concurrent-ruby', '~> 1.1'
gem 'test-prof', '~> 0.2.5'
gem 'rspec_junit_formatter'
end
......@@ -434,7 +440,7 @@ group :ed25519 do
end
# Gitaly GRPC client
gem 'gitaly-proto', '~> 0.123.0', require: 'gitaly'
gem 'gitaly-proto', '~> 1.1.0', require: 'gitaly'
gem 'grpc', '~> 1.15.0'
gem 'google-protobuf', '~> 3.6'
......
This diff is collapsed.
# BUNDLE_GEMFILE=Gemfile.rails5 bundle install
# BUNDLE_GEMFILE=Gemfile.rails4 bundle install
ENV["RAILS5"] = "true"
ENV["RAILS5"] = "false"
gemfile = File.expand_path("../Gemfile", __FILE__)
......
This diff is collapsed.
This document is intended to communicate the product philosophy GitLab uses in creating GitLab Enterprise Edition. The principles can be found in the [Product Section of the GitLab Handbook](https://about.gitlab.com/handbook/product/#product-at-gitlab).
......@@ -103,6 +103,12 @@ picked into the stable branches) up to the 19th of the month. Such merge
requests should have the ~"feature flag" label assigned, and don't require a
corresponding exception request to be created.
In order to build the final package and present the feature for self-hosted
customers, the feature flag should be removed. This should happen before the
22nd, ideally _at least_ 2 days before. That means MRs with feature
flags being picked at the 19th would have a quite tight schedule, so picking
these _earlier_ is preferable.
While rare, release managers may decide to reject picking a change into a stable
branch, even when feature flags are used. This might be necessary if the changes
are deemed problematic, too invasive, or there simply isn't enough time to
......
11.5.0-pre
11.6.0-pre
app/assets/images/cluster_app_logos/cert_manager.png

1.26 KB

......@@ -10,10 +10,10 @@ const Api = {
projectsPath: '/api/:version/projects.json',
projectPath: '/api/:version/projects/:id',
projectLabelsPath: '/:namespace_path/:project_path/labels',
mergeRequestPath: '/api/:version/projects/:id/merge_requests/:mrid',
projectMergeRequestPath: '/api/:version/projects/:id/merge_requests/:mrid',
projectMergeRequestChangesPath: '/api/:version/projects/:id/merge_requests/:mrid/changes',
projectMergeRequestVersionsPath: '/api/:version/projects/:id/merge_requests/:mrid/versions',
mergeRequestsPath: '/api/:version/merge_requests',
mergeRequestChangesPath: '/api/:version/projects/:id/merge_requests/:mrid/changes',
mergeRequestVersionsPath: '/api/:version/projects/:id/merge_requests/:mrid/versions',
groupLabelsPath: '/groups/:namespace_path/-/labels',
ldapGroupsPath: '/api/:version/ldap/:provider/groups.json',
issuableTemplatePath: '/:namespace_path/:project_path/templates/:type/:key',
......@@ -101,36 +101,36 @@ const Api = {
},
// Return Merge Request for project
mergeRequest(projectPath, mergeRequestId, params = {}) {
const url = Api.buildUrl(Api.mergeRequestPath)
projectMergeRequest(projectPath, mergeRequestId, params = {}) {
const url = Api.buildUrl(Api.projectMergeRequestPath)
.replace(':id', encodeURIComponent(projectPath))
.replace(':mrid', mergeRequestId);
return axios.get(url, { params });
},
mergeRequests(params = {}) {
const url = Api.buildUrl(Api.mergeRequestsPath);
return axios.get(url, { params });
},
mergeRequestChanges(projectPath, mergeRequestId) {
const url = Api.buildUrl(Api.mergeRequestChangesPath)
projectMergeRequestChanges(projectPath, mergeRequestId) {
const url = Api.buildUrl(Api.projectMergeRequestChangesPath)
.replace(':id', encodeURIComponent(projectPath))
.replace(':mrid', mergeRequestId);
return axios.get(url);
},
mergeRequestVersions(projectPath, mergeRequestId) {
const url = Api.buildUrl(Api.mergeRequestVersionsPath)
projectMergeRequestVersions(projectPath, mergeRequestId) {
const url = Api.buildUrl(Api.projectMergeRequestVersionsPath)
.replace(':id', encodeURIComponent(projectPath))
.replace(':mrid', mergeRequestId);
return axios.get(url);
},
mergeRequests(params = {}) {
const url = Api.buildUrl(Api.mergeRequestsPath);
return axios.get(url, { params });
},
newLabel(namespacePath, projectPath, data, callback) {
let url;
......
<script>
import Icon from '~/vue_shared/components/icon.vue';
import Tooltip from '~/vue_shared/directives/tooltip';
import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
import { GlLoadingIcon, GlTooltipDirective } from '@gitlab/ui';
export default {
name: 'Badge',
components: {
Icon,
Tooltip,
GlLoadingIcon,
},
directives: {
Tooltip,
GlTooltip: GlTooltipDirective,
},
props: {
imageUrl: {
......@@ -65,12 +63,7 @@ export default {
<template>
<div>
<a
v-show="!isLoading && !hasError"
:href="linkUrl"
target="_blank"
rel="noopener noreferrer"
>
<a v-show="!isLoading && !hasError" :href="linkUrl" target="_blank" rel="noopener noreferrer">
<img
:src="imageUrlWithRetries"
class="project-badge"
......@@ -80,15 +73,9 @@ export default {
/>
</a>
<gl-loading-icon
v-show="isLoading"
:inline="true"
/>
<gl-loading-icon v-show="isLoading" :inline="true" />
<div
v-show="hasError"
class="btn-group"
>
<div v-show="hasError" class="btn-group">
<div class="btn btn-default btn-sm disabled">
<icon
:size="16"
......@@ -97,25 +84,20 @@ export default {
aria-hidden="true"
/>
</div>
<div
class="btn btn-default btn-sm disabled"
>
<div class="btn btn-default btn-sm disabled">
<span class="prepend-left-8 append-right-8">{{ s__('Badges|No badge image') }}</span>
</div>
</div>
<button
v-show="hasError"
v-tooltip
v-gl-tooltip.hover
:title="s__('Badges|Reload badge image')"
class="btn btn-transparent btn-sm text-primary"
type="button"
@click="reloadImage"
>
<icon
:size="16"
name="retry"
/>
<icon :size="16" name="retry" />
</button>
</div>
</template>
......@@ -4,7 +4,7 @@ import { mapActions, mapState } from 'vuex';
import createFlash from '~/flash';
import { s__, sprintf } from '~/locale';
import LoadingButton from '~/vue_shared/components/loading_button.vue';
import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
import { GlLoadingIcon } from '@gitlab/ui';
import createEmptyBadge from '../empty_badge';
import Badge from './badge.vue';
......@@ -155,10 +155,7 @@ export default {
@submit.prevent.stop="onSubmit"
>
<div class="form-group">
<label
for="badge-link-url"
class="label-bold"
>{{ s__('Badges|Link') }}</label>
<label for="badge-link-url" class="label-bold">{{ s__('Badges|Link') }}</label>
<p v-html="helpText"></p>
<input
id="badge-link-url"
......@@ -168,19 +165,12 @@ export default {
required
@input="debouncedPreview"
/>
<div class="invalid-feedback">
{{ s__('Badges|Please fill in a valid URL') }}
</div>
<span class="form-text text-muted">
{{ badgeLinkUrlExample }}
</span>
<div class="invalid-feedback">{{ s__('Badges|Please fill in a valid URL') }}</div>
<span class="form-text text-muted"> {{ badgeLinkUrlExample }} </span>
</div>
<div class="form-group">
<label
for="badge-image-url"
class="label-bold"
>{{ s__('Badges|Badge image URL') }}</label>
<label for="badge-image-url" class="label-bold">{{ s__('Badges|Badge image URL') }}</label>
<p v-html="helpText"></p>
<input
id="badge-image-url"
......@@ -190,12 +180,8 @@ export default {
required
@input="debouncedPreview"
/>
<div class="invalid-feedback">
{{ s__('Badges|Please fill in a valid URL') }}
</div>
<span class="form-text text-muted">
{{ badgeImageUrlExample }}
</span>
<div class="invalid-feedback">{{ s__('Badges|Please fill in a valid URL') }}</div>
<span class="form-text text-muted"> {{ badgeImageUrlExample }} </span>
</div>
<div class="form-group">
......@@ -206,37 +192,22 @@ export default {
:image-url="renderedImageUrl"
:link-url="renderedLinkUrl"
/>
<p v-show="isRendering">
<gl-loading-icon
:inline="true"
/>
<p v-show="isRendering"><gl-loading-icon :inline="true" /></p>
<p v-show="!renderedBadge && !isRendering" class="disabled-content">
{{ s__('Badges|No image to preview') }}
</p>
<p
v-show="!renderedBadge && !isRendering"
class="disabled-content"
>{{ s__('Badges|No image to preview') }}</p>
</div>
<div
v-if="isEditing"
class="row-content-block"
>
<div v-if="isEditing" class="row-content-block">
<loading-button
:loading="isSaving"
:label="s__('Badges|Save changes')"
type="submit"
container-class="btn btn-success"
/>
<button
class="btn btn-cancel"
type="button"
@click="onCancel"
>{{ __('Cancel') }}</button>
<button class="btn btn-cancel" type="button" @click="onCancel">{{ __('Cancel') }}</button>
</div>
<div
v-else
class="form-group"
>
<div v-else class="form-group">
<loading-button
:loading="isSaving"
:label="s__('Badges|Add badge')"
......
<script>
import { mapState } from 'vuex';
import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
import { GlLoadingIcon } from '@gitlab/ui';
import BadgeListRow from './badge_list_row.vue';
import { GROUP_BADGE } from '../constants';
......@@ -26,32 +26,15 @@ export default {
<div class="card">
<div class="card-header">
{{ s__('Badges|Your badges') }}
<span
v-show="!isLoading"
class="badge badge-pill"
>{{ badges.length }}</span>
<span v-show="!isLoading" class="badge badge-pill">{{ badges.length }}</span>
</div>
<gl-loading-icon
v-show="isLoading"
:size="2"
class="card-body"
/>
<div
v-if="hasNoBadges"
class="card-body"
>
<gl-loading-icon v-show="isLoading" :size="2" class="card-body" />
<div v-if="hasNoBadges" class="card-body">
<span v-if="isGroupBadge">{{ s__('Badges|This group has no badges') }}</span>
<span v-else>{{ s__('Badges|This project has no badges') }}</span>
</div>
<div
v-else
class="card-body"
>
<badge-list-row
v-for="badge in badges"
:key="badge.id"
:badge="badge"
/>
<div v-else class="card-body">
<badge-list-row v-for="badge in badges" :key="badge.id" :badge="badge" />
</div>
</div>
</template>
......@@ -2,7 +2,7 @@
import { mapActions, mapState } from 'vuex';
import { s__ } from '~/locale';
import Icon from '~/vue_shared/components/icon.vue';
import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
import { GlLoadingIcon } from '@gitlab/ui';
import { PROJECT_BADGE } from '../constants';
import Badge from './badge.vue';
......@@ -50,20 +50,14 @@ export default {
<span class="badge badge-pill">{{ badgeKindText }}</span>
</div>
<div class="table-section section-15 table-button-footer">
<div
v-if="canEditBadge"
class="table-action-buttons">
<div v-if="canEditBadge" class="table-action-buttons">
<button
:disabled="badge.isDeleting"
class="btn btn-default append-right-8"
type="button"
@click="editBadge(badge)"
@click="editBadge(badge);"
>
<icon
:size="16"
:aria-label="__('Edit')"
name="pencil"
/>
<icon :size="16" :aria-label="__('Edit')" name="pencil" />
</button>
<button
:disabled="badge.isDeleting"
......@@ -71,18 +65,11 @@ export default {
type="button"
data-toggle="modal"
data-target="#delete-badge-modal"
@click="updateBadgeInModal(badge)"
@click="updateBadgeInModal(badge);"
>
<icon
:size="16"
:aria-label="__('Delete')"
name="remove"
/>
<icon :size="16" :aria-label="__('Delete')" name="remove" />
</button>
<gl-loading-icon
v-show="badge.isDeleting"
:inline="true"
/>
<gl-loading-icon v-show="badge.isDeleting" :inline="true" />
</div>
</div>
</div>
......
......@@ -46,7 +46,8 @@ export default {
:header-title-text="s__('Badges|Delete badge?')"
:footer-primary-button-text="s__('Badges|Delete badge')"
footer-primary-button-variant="danger"
@submit="onSubmitModal">
@submit="onSubmitModal"
>
<div class="well">
<badge
:image-url="badgeInModal ? badgeInModal.renderedImageUrl : ''"
......@@ -56,15 +57,9 @@ export default {
<p v-html="deleteModalText"></p>
</gl-modal>
<badge-form
v-show="isEditing"
:is-editing="true"
/>
<badge-form v-show="isEditing" :is-editing="true" />
<badge-form
v-show="!isEditing"
:is-editing="false"
/>
<badge-form v-show="!isEditing" :is-editing="false" />
<badge-list v-show="!isEditing" />
</div>
</template>
import $ from 'jquery';
import { convertPermissionToBoolean } from '~/lib/utils/common_utils';
import { parseBoolean } from '~/lib/utils/common_utils';
import GfmAutoComplete from '~/gfm_auto_complete';
export default function initGFMInput() {
$('.js-gfm-input:not(.js-vue-textarea)').each((i, el) => {
const gfm = new GfmAutoComplete(gl.GfmAutoComplete && gl.GfmAutoComplete.dataSources);
const enableGFM = convertPermissionToBoolean(el.dataset.supportsAutocomplete);
const enableGFM = parseBoolean(el.dataset.supportsAutocomplete);
gfm.setup($(el), {
emojis: true,
......
import { n__ } from '../locale';
import { convertPermissionToBoolean } from '../lib/utils/common_utils';
import { parseBoolean } from '../lib/utils/common_utils';
export default class SecretValues {
constructor({
......@@ -16,7 +16,7 @@ export default class SecretValues {
this.revealButton = this.container.querySelector('.js-secret-value-reveal-button');
if (this.revealButton) {
const isRevealed = convertPermissionToBoolean(this.revealButton.dataset.secretRevealStatus);
const isRevealed = parseBoolean(this.revealButton.dataset.secretRevealStatus);
this.updateDom(isRevealed);
this.revealButton.addEventListener('click', this.onRevealButtonClicked.bind(this));
......@@ -24,9 +24,7 @@ export default class SecretValues {
}
onRevealButtonClicked() {
const previousIsRevealed = convertPermissionToBoolean(
this.revealButton.dataset.secretRevealStatus,
);
const previousIsRevealed = parseBoolean(this.revealButton.dataset.secretRevealStatus);
this.updateDom(!previousIsRevealed);
}
......
......@@ -4,6 +4,7 @@ import Mousetrap from 'mousetrap';
import axios from '../../lib/utils/axios_utils';
import { refreshCurrentPage, visitUrl } from '../../lib/utils/url_utility';
import findAndFollowLink from '../../lib/utils/navigation_utility';
import { parseBoolean } from '~/lib/utils/common_utils';
const defaultStopCallback = Mousetrap.stopCallback;
Mousetrap.stopCallback = (e, element, combo) => {
......@@ -61,7 +62,7 @@ export default class Shortcuts {
static onTogglePerfBar(e) {
e.preventDefault();
const performanceBarCookieName = 'perf_bar_enabled';
if (Cookies.get(performanceBarCookieName) === 'true') {
if (parseBoolean(Cookies.get(performanceBarCookieName))) {
Cookies.set(performanceBarCookieName, 'false', { path: '/' });
} else {
Cookies.set(performanceBarCookieName, 'true', { path: '/' });
......
......@@ -4,6 +4,7 @@ import _ from 'underscore';
import Sidebar from '../../right_sidebar';
import Shortcuts from './shortcuts';
import { CopyAsGFM } from '../markdown/copy_as_gfm';
import { getSelectedFragment } from '~/lib/utils/common_utils';
export default class ShortcutsIssuable extends Shortcuts {
constructor(isMergeRequest) {
......@@ -24,17 +25,43 @@ export default class ShortcutsIssuable extends Shortcuts {
static replyWithSelectedText() {
const $replyField = $('.js-main-target-form .js-vue-comment-form');
const documentFragment = window.gl.utils.getSelectedFragment();
if (!$replyField.length) {
if (!$replyField.length || $replyField.is(':hidden') /* Other tab selected in MR */) {
return false;
}
const documentFragment = getSelectedFragment(document.querySelector('#content-body'));
if (!documentFragment) {
$replyField.focus();
return false;
}
// Sanity check: Make sure the selected text comes from a discussion : it can either contain a message...
let foundMessage = !!documentFragment.querySelector('.md, .wiki');
// ... Or come from a message
if (!foundMessage) {
if (documentFragment.originalNodes) {
documentFragment.originalNodes.forEach(e => {
let node = e;
do {
// Text nodes don't define the `matches` method
if (node.matches && node.matches('.md, .wiki')) {
foundMessage = true;
}
node = node.parentNode;
} while (node && !foundMessage);
});
}
// If there is no message, just select the reply field
if (!foundMessage) {
$replyField.focus();
return false;
}
}
const el = CopyAsGFM.transformGFMSelection(documentFragment.cloneNode(true));
const selected = CopyAsGFM.nodeToGFM(el);
......
......@@ -124,7 +124,7 @@ export default class FileTemplateMediator {
selectTemplateFile(selector, query, data) {
selector.renderLoading();
// in case undo menu is already already there
// in case undo menu is already there
this.destroyUndoMenu();
this.fetchFileTemplate(selector.config.type, query, data)
.then(file => {
......
......@@ -23,10 +23,12 @@ export default class BlobViewer {
if (!viewer || !viewer.dataset.richType) return;
const initViewer = promise =>
promise.then(module => module.default(viewer)).catch(error => {
Flash('Error loading file viewer.');
throw error;
});
promise
.then(module => module.default(viewer))
.catch(error => {
Flash('Error loading file viewer.');
throw error;
});
switch (viewer.dataset.richType) {
case 'balsamiq':
......
......@@ -16,9 +16,17 @@ export default () => {
const filePath = editBlobForm.data('blobFilename');
const currentAction = $('.js-file-title').data('currentAction');
const projectId = editBlobForm.data('project-id');
const commitButton = $('.js-commit-button');
commitButton.on('click', () => {
window.onbeforeunload = null;
});
new EditBlob(`${urlRoot}${assetsPath}`, filePath, currentAction, projectId);
new NewCommitForm(editBlobForm);
// returning here blocks page navigation
window.onbeforeunload = () => '';
}
if (uploadBlobForm.length) {
......
......@@ -61,35 +61,25 @@ export default {
<template>
<div class="board-blank-state">
<p>
Add the following default lists to your Issue Board with one click:
</p>
<p>Add the following default lists to your Issue Board with one click:</p>
<ul class="board-blank-state-list">
<li
v-for="(label, index) in predefinedLabels"
:key="index"
>
<span
:style="{ backgroundColor: label.color }"
class="label-color">
</span>
<li v-for="(label, index) in predefinedLabels" :key="index">
<span :style="{ backgroundColor: label.color }" class="label-color"> </span>
{{ label.title }}
</li>
</ul>
<p>
Starting out with the default set of lists will get you
right on the way to making the most of your board.
Starting out with the default set of lists will get you right on the way to making the most of
your board.
</p>
<button
class="btn btn-success btn-inverted btn-block"
type="button"
@click.stop="addDefaultLists">
@click.stop="addDefaultLists"
>
Add default lists
</button>
<button
class="btn btn-default btn-block"
type="button"
@click.stop="clearBlankState">
<button class="btn btn-default btn-block" type="button" @click.stop="clearBlankState">
Nevermind, I'll use my own
</button>
</div>
......
......@@ -79,14 +79,15 @@ export default {
:class="{
'user-can-drag': !disabled && issue.id,
'is-disabled': disabled || !issue.id,
'is-active': issueDetailVisible
'is-active': issueDetailVisible,
}"
:index="index"
:data-issue-id="issue.id"
class="board-card"
@mousedown="mouseDown"
@mousemove="mouseMove"
@mouseup="showIssue($event)">
@mouseup="showIssue($event);"
>
<issue-card-inner
:list="list"
:issue="issue"
......
<script>
import Sortable from 'sortablejs';
import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
import { GlLoadingIcon } from '@gitlab/ui';
import boardNewIssue from './board_new_issue.vue';
import boardCard from './board_card.vue';
import eventHub from '../eventhub';
......@@ -222,23 +222,22 @@ export default {
<template>
<div class="board-list-component">
<div
v-if="loading"
class="board-list-loading text-center"
aria-label="Loading issues">
<div v-if="loading" class="board-list-loading text-center" aria-label="Loading issues">
<gl-loading-icon />
</div>
<board-new-issue
v-if="list.type !== 'closed' && showIssueForm"
:group-id="groupId"
:list="list"/>
:list="list"
/>
<ul
v-show="!loading"
ref="list"
:data-board="list.id"
:data-board-type="list.type"
:class="{ 'is-smaller': showIssueForm }"
class="board-list js-board-list">
class="board-list js-board-list"
>
<board-card
v-for="(issue, index) in issues"
ref="issue"
......@@ -249,25 +248,12 @@ export default {
:issue-link-base="issueLinkBase"
:group-id="groupId"
:root-path="rootPath"
:disabled="disabled" />
<li
v-if="showCount"
class="board-list-count text-center"
data-issue-id="-1">
<gl-loading-icon
v-show="list.loadingMore"
label="Loading more issues"
/>
<span
v-if="list.issues.length === list.issuesSize"
>
Showing all issues
</span>
<span
v-else
>
Showing {{ list.issues.length }} of {{ list.issuesSize }} issues
</span>
:disabled="disabled"
/>
<li v-if="showCount" class="board-list-count text-center" data-issue-id="-1">
<gl-loading-icon v-show="list.loadingMore" label="Loading more issues" />
<span v-if="list.issues.length === list.issuesSize"> Showing all issues </span>
<span v-else> Showing {{ list.issues.length }} of {{ list.issuesSize }} issues </span>
</li>
</ul>
</div>
......
<script>
import $ from 'jquery';
import { GlButton } from '@gitlab-org/gitlab-ui';
import { GlButton } from '@gitlab/ui';
import eventHub from '../eventhub';
import ProjectSelect from './project_select.vue';
import ListIssue from '../models/issue';
......@@ -99,21 +99,11 @@ export default {
<template>
<div class="board-new-issue-form">
<div class="board-card">
<form @submit="submit($event)">
<div
v-if="error"
class="flash-container"
>
<div class="flash-alert">
An error occurred. Please try again.
</div>
<form @submit="submit($event);">
<div v-if="error" class="flash-container">
<div class="flash-alert">An error occurred. Please try again.</div>
</div>
<label
:for="list.id + '-title'"
class="label-bold"
>
Title
</label>
<label :for="list.id + '-title'" class="label-bold"> Title </label>
<input
:id="list.id + '-title'"
ref="input"
......@@ -123,10 +113,7 @@ export default {
name="issue_title"
autocomplete="off"
/>
<project-select
v-if="groupId"
:group-id="groupId"
/>
<project-select v-if="groupId" :group-id="groupId" />
<div class="clearfix prepend-top-10">
<gl-button
ref="submit-button"
......@@ -137,12 +124,7 @@ export default {
>
Submit issue
</gl-button>
<gl-button
class="float-right"
type="button"
variant="default"
@click="cancel"
>
<gl-button class="float-right" type="button" variant="default" @click="cancel">
Cancel
</gl-button>
</div>
......
<script>
import { GlTooltipDirective } from '@gitlab-org/gitlab-ui';
import { GlTooltipDirective } from '@gitlab/ui';
import { sprintf, __ } from '~/locale';
import Icon from '~/vue_shared/components/icon.vue';
import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue';
......@@ -171,17 +171,12 @@ export default {
:title="__('Confidential')"
class="confidential-icon append-right-4"
:aria-label="__('Confidential')"
/><a
:href="issue.path"
:title="issue.title"
class="js-no-trigger"
@mousemove.stop>{{ issue.title }}</a>
/><a :href="issue.path" :title="issue.title" class="js-no-trigger" @mousemove.stop>{{
issue.title
}}</a>
</h4>
</div>
<div
v-if="showLabelFooter"
class="board-card-labels prepend-top-4 d-flex flex-wrap"
>
<div v-if="showLabelFooter" class="board-card-labels prepend-top-4 d-flex flex-wrap">
<button
v-for="label in issue.labels"
v-if="showLabel(label)"
......@@ -191,13 +186,15 @@ export default {
:title="label.description"
class="badge color-label append-right-4 prepend-top-4"
type="button"
@click="filterByLabel(label)"
@click="filterByLabel(label);"
>
{{ label.title }}
</button>
</div>
<div class="board-card-footer d-flex justify-content-between align-items-end">
<div class="d-flex align-items-start flex-wrap-reverse board-card-number-container js-board-card-number-container">
<div
class="d-flex align-items-start flex-wrap-reverse board-card-number-container js-board-card-number-container"
>
<span
v-if="issue.referencePath"
class="board-card-number d-flex append-right-8 prepend-top-8"
......@@ -207,19 +204,17 @@ export default {
:title="issueReferencePath"
placement="bottom"
class="board-issue-path block-truncated bold"
>{{ issueReferencePath }}</tooltip-on-truncate>#{{ issue.iid }}
>{{ issueReferencePath }}</tooltip-on-truncate
>#{{ issue.iid }}
</span>
<span class="board-info-items prepend-top-8 d-inline-block">
<issue-due-date
v-if="issue.dueDate"
:date="issue.dueDate"
/><issue-time-estimate
<issue-due-date v-if="issue.dueDate" :date="issue.dueDate" /><issue-time-estimate
v-if="issue.timeEstimate"
:estimate="issue.timeEstimate"
/><issue-card-weight
v-if="issue.weight"
:weight="issue.weight"
@click="filterByWeight(issue.weight)"
@click="filterByWeight(issue.weight);"
/>
</span>
</div>
......@@ -236,8 +231,7 @@ export default {
tooltip-placement="bottom"
>
<span class="js-assignee-tooltip">
<span class="bold d-block">Assignee</span>
{{ assignee.name }}
<span class="bold d-block">Assignee</span> {{ assignee.name }}
<span class="text-white-50">@{{ assignee.username }}</span>
</span>
</user-avatar-link>
......
<script>
import dateFormat from 'dateformat';
import { GlTooltip } from '@gitlab-org/gitlab-ui';
import { GlTooltip } from '@gitlab/ui';
import Icon from '~/vue_shared/components/icon.vue';
import { __ } from '~/locale';
import { getDayDifference, getTimeago, dateInWords } from '~/lib/utils/datetime_utility';
......@@ -66,25 +66,17 @@ export default {
<template>
<span>
<span
ref="issueDueDate"
class="board-card-info card-number"
>
<span ref="issueDueDate" class="board-card-info card-number">
<icon
:class="{'text-danger': isPastDue, 'board-card-info-icon': true}"
:class="{ 'text-danger': isPastDue, 'board-card-info-icon': true }"
name="calendar"
/><time
:class="{'text-danger': isPastDue}"
datetime="date"
class="board-card-info-text">{{ body }}</time>
/><time :class="{ 'text-danger': isPastDue }" datetime="date" class="board-card-info-text">{{
body
}}</time>
</span>
<gl-tooltip
:target="() => $refs.issueDueDate"
placement="bottom"
>
<span class="bold">{{ __('Due date') }}</span>
<br />
<span :class="{'text-danger-muted': isPastDue}">{{ title }}</span>
<gl-tooltip :target="() => $refs.issueDueDate" placement="bottom">
<span class="bold">{{ __('Due date') }}</span> <br />
<span :class="{ 'text-danger-muted': isPastDue }">{{ title }}</span>
</gl-tooltip>
</span>
</template>
<script>
import { GlTooltip } from '@gitlab-org/gitlab-ui';
import { GlTooltip } from '@gitlab/ui';
import Icon from '~/vue_shared/components/icon.vue';
import { parseSeconds, stringifyTime } from '~/lib/utils/datetime_utility';
......@@ -27,22 +27,18 @@ export default {
<template>
<span>
<span
ref="issueTimeEstimate"
class="board-card-info card-number"
>
<icon
name="hourglass"
css-classes="board-card-info-icon"
/><time class="board-card-info-text">{{ timeEstimate }}</time>
<span ref="issueTimeEstimate" class="board-card-info card-number">
<icon name="hourglass" css-classes="board-card-info-icon" /><time
class="board-card-info-text"
>{{ timeEstimate }}</time
>
</span>
<gl-tooltip
:target="() => $refs.issueTimeEstimate"
placement="bottom"
class="js-issue-time-estimate"
>
<span class="bold d-block">{{ __('Time estimate') }}</span>
{{ title }}
<span class="bold d-block">{{ __('Time estimate') }}</span> {{ title }}
</gl-tooltip>
</span>
</template>
......@@ -45,24 +45,20 @@ export default {
<section class="empty-state">
<div class="row">
<div class="col-12 col-md-6 order-md-last">
<aside class="svg-content"><img :src="emptyStateSvg"/></aside>
<aside class="svg-content"><img :src="emptyStateSvg" /></aside>
</div>
<div class="col-12 col-md-6 order-md-first">
<div class="text-content">
<h4>{{ contents.title }}</h4>
<p v-html="contents.content"></p>
<a
v-if="activeTab === 'all'"
:href="newIssuePath"
class="btn btn-success btn-inverted"
>
<a v-if="activeTab === 'all'" :href="newIssuePath" class="btn btn-success btn-inverted">
New issue
</a>
<button
v-if="activeTab === 'selected'"
class="btn btn-default"
type="button"
@click="changeTab('all')"
@click="changeTab('all');"
>
Open issues
</button>
......
......@@ -63,28 +63,15 @@ export default {
};
</script>
<template>
<footer
class="form-actions add-issues-footer"
>
<footer class="form-actions add-issues-footer">
<div class="float-left">
<button
:disabled="submitDisabled"
class="btn btn-success"
type="button"
@click="addIssues"
>
<button :disabled="submitDisabled" class="btn btn-success" type="button" @click="addIssues">
{{ submitText }}
</button>
<span class="inline add-issues-footer-to-list">
to list
</span>
<lists-dropdown/>
<span class="inline add-issues-footer-to-list"> to list </span>
<lists-dropdown />
</div>
<button
class="btn btn-default float-right"
type="button"
@click="toggleModal(false)"
>
<button class="btn btn-default float-right" type="button" @click="toggleModal(false);">
Cancel
</button>
</footer>
......
......@@ -58,16 +58,14 @@ export default {
class="close"
data-dismiss="modal"
aria-label="Close"
@click="toggleModal(false)"
@click="toggleModal(false);"
>
<span aria-hidden="true">×</span>
</button>
</h2>
</header>
<modal-tabs v-if="!loading && issuesCount > 0"/>
<div
v-if="showSearch"
class="add-issues-search append-bottom-10">
<modal-tabs v-if="!loading && issuesCount > 0" />
<div v-if="showSearch" class="add-issues-search append-bottom-10">
<modal-filters :store="filter" />
<button
ref="selectAllBtn"
......
......@@ -6,7 +6,7 @@ import ModalList from './list.vue';
import ModalFooter from './footer.vue';
import EmptyState from './empty_state.vue';
import ModalStore from '../../stores/modal_store';
import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
import { GlLoadingIcon } from '@gitlab/ui';
export default {
components: {
......@@ -143,9 +143,7 @@ export default {
};
</script>
<template>
<div
v-if="showAddIssuesModal"
class="add-issues-modal">
<div v-if="showAddIssuesModal" class="add-issues-modal">
<div class="add-issues-container">
<modal-header
:project-id="projectId"
......@@ -163,15 +161,10 @@ export default {
:new-issue-path="newIssuePath"
:empty-state-svg="emptyStateSvg"
/>
<section
v-if="loading || filterLoading"
class="add-issues-list text-center"
>
<div class="add-issues-list-loading">
<gl-loading-icon />
</div>
<section v-if="loading || filterLoading" class="add-issues-list text-center">
<div class="add-issues-list-loading"><gl-loading-icon /></div>
</section>
<modal-footer/>
<modal-footer />
</div>
</div>
</template>
......@@ -117,38 +117,22 @@ export default {
};
</script>
<template>
<section
ref="list"
class="add-issues-list add-issues-list-columns">
<section ref="list" class="add-issues-list add-issues-list-columns">
<div
v-if="issuesCount > 0 && issues.length === 0"
class="empty-state add-issues-empty-state-filter text-center">
<div class="svg-content">
<img :src="emptyStateSvg" />
</div>
<div class="text-content">
<h4>
There are no issues to show.
</h4>
</div>
class="empty-state add-issues-empty-state-filter text-center"
>
<div class="svg-content"><img :src="emptyStateSvg" /></div>
<div class="text-content"><h4>There are no issues to show.</h4></div>
</div>
<div
v-for="(group, index) in groupedIssues"
:key="index"
class="add-issues-list-column">
<div
v-for="issue in group"
v-if="showIssue(issue)"
:key="issue.id"
class="board-card-parent">
<div v-for="(group, index) in groupedIssues" :key="index" class="add-issues-list-column">
<div v-for="issue in group" v-if="showIssue(issue)" :key="issue.id" class="board-card-parent">
<div
:class="{ 'is-active': issue.selected }"
class="board-card"
@click="toggleIssue($event, issue)">
<issue-card-inner
:issue="issue"
:issue-link-base="issueLinkBase"
:root-path="rootPath"/>
@click="toggleIssue($event, issue);"
>
<issue-card-inner :issue="issue" :issue-link-base="issueLinkBase" :root-path="rootPath" />
<icon
v-if="issue.selected"
:aria-label="'Issue #' + issue.id + ' selected'"
......
<script>
import { GlLink } from '@gitlab-org/gitlab-ui';
import { GlLink } from '@gitlab/ui';
import Icon from '~/vue_shared/components/icon.vue';
import ModalStore from '../../stores/modal_store';
import boardsStore from '../../stores/boards_store';
......@@ -27,35 +27,20 @@ export default {
</script>
<template>
<div class="dropdown inline">
<button
class="dropdown-menu-toggle"
type="button"
data-toggle="dropdown"
aria-expanded="false">
<span
:style="{ backgroundColor: selected.label.color }"
class="dropdown-label-box">
</span>
{{ selected.title }}
<icon
name="chevron-down"
/>
<button class="dropdown-menu-toggle" type="button" data-toggle="dropdown" aria-expanded="false">
<span :style="{ backgroundColor: selected.label.color }" class="dropdown-label-box"> </span>
{{ selected.title }} <icon name="chevron-down" />
</button>
<div class="dropdown-menu dropdown-menu-selectable dropdown-menu-drop-up">
<ul>
<li
v-for="(list, i) in state.lists"
v-if="list.type == 'label'"
:key="i">
<li v-for="(list, i) in state.lists" v-if="list.type == 'label'" :key="i">
<gl-link
:class="{ 'is-active': list.id == selected.id }"
href="#"
role="button"
@click.prevent="modal.selectedList = list">
<span
:style="{ backgroundColor: list.label.color }"
class="dropdown-label-box">
</span>
@click.prevent="modal.selectedList = list;"
>
<span :style="{ backgroundColor: list.label.color }" class="dropdown-label-box"> </span>
{{ list.title }}
</gl-link>
</li>
......
......@@ -20,28 +20,14 @@ export default {
<template>
<div class="top-area prepend-top-10 append-bottom-10">
<ul class="nav-links issues-state-filters">
<li :class="{ 'active': activeTab == 'all' }">
<a
href="#"
role="button"
@click.prevent="changeTab('all')"
>
Open issues
<span class="badge badge-pill">
{{ issuesCount }}
</span>
<li :class="{ active: activeTab == 'all' }">
<a href="#" role="button" @click.prevent="changeTab('all');">
Open issues <span class="badge badge-pill"> {{ issuesCount }} </span>
</a>
</li>
<li :class="{ 'active': activeTab == 'selected' }">
<a
href="#"
role="button"
@click.prevent="changeTab('selected')"
>
Selected issues
<span class="badge badge-pill">
{{ selectedCount }}
</span>
<li :class="{ active: activeTab == 'selected' }">
<a href="#" role="button" @click.prevent="changeTab('selected');">
Selected issues <span class="badge badge-pill"> {{ selectedCount }} </span>
</a>
</li>
</ul>
......
......@@ -2,7 +2,7 @@
import $ from 'jquery';
import _ from 'underscore';
import Icon from '~/vue_shared/components/icon.vue';
import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
import { GlLoadingIcon } from '@gitlab/ui';
import eventHub from '../eventhub';
import Api from '../../api';
......@@ -48,10 +48,19 @@ export default {
selectable: true,
data: (term, callback) => {
this.loading = true;
return Api.groupProjects(this.groupId, term, { with_issues_enabled: true }, projects => {
this.loading = false;
callback(projects);
});
return Api.groupProjects(
this.groupId,
term,
{
with_issues_enabled: true,
with_shared: false,
include_subgroups: true,
},
projects => {
this.loading = false;
callback(projects);
},
);
},
renderRow(project) {
return `
......@@ -72,23 +81,15 @@ export default {
<template>
<div>
<label class="label-bold prepend-top-10">
Project
</label>
<div
ref="projectsDropdown"
class="dropdown"
>
<label class="label-bold prepend-top-10"> Project </label>
<div ref="projectsDropdown" class="dropdown">
<button
class="dropdown-menu-toggle wide"
type="button"
data-toggle="dropdown"
aria-expanded="false"
>
{{ selectedProjectName }}
<icon
name="chevron-down"
/>
{{ selectedProjectName }} <icon name="chevron-down" />
</button>
<div class="dropdown-menu dropdown-menu-selectable dropdown-menu-full-width">
<div class="dropdown-title">
......@@ -106,21 +107,11 @@ export default {
</button>
</div>
<div class="dropdown-input">
<input
class="dropdown-input-field"
type="search"
placeholder="Search projects"
/>
<icon
name="search"
class="dropdown-input-search"
data-hidden="true"
/>
<input class="dropdown-input-field" type="search" placeholder="Search projects" />
<icon name="search" class="dropdown-input-search" data-hidden="true" />
</div>
<div class="dropdown-content"></div>
<div class="dropdown-loading">
<gl-loading-icon />
</div>
<div class="dropdown-loading"><gl-loading-icon /></div>
</div>
</div>
</div>
......
......@@ -74,14 +74,8 @@ export default Vue.extend({
});
</script>
<template>
<div
class="block list"
>
<button
class="btn btn-default btn-block"
type="button"
@click="removeIssue"
>
<div class="block list">
<button class="btn btn-default btn-block" type="button" @click="removeIssue">
Remove from board
</button>
</div>
......
......@@ -21,13 +21,13 @@ import BoardSidebar from 'ee/boards/components/board_sidebar';
import initNewListDropdown from './components/new_list_dropdown';
import BoardAddIssuesModal from 'ee/boards/components/modal/index';
import '~/vue_shared/vue_resource_interceptor';
import { NavigationType } from '~/lib/utils/common_utils';
import { NavigationType, parseBoolean } from '~/lib/utils/common_utils';
import 'ee/boards/models/list';
import 'ee/boards/models/issue';
import 'ee/boards/models/project';
import BoardService from 'ee/boards/services/board_service';
import BoardsSelector from 'ee/boards/components/boards_selector';
import BoardsSelector from 'ee/boards/components/boards_selector.vue';
import collapseIcon from 'ee/boards/icons/fullscreen_collapse.svg';
import expandIcon from 'ee/boards/icons/fullscreen_expand.svg';
import tooltip from '~/vue_shared/directives/tooltip';
......@@ -67,7 +67,7 @@ export default () => {
boardsEndpoint: $boardApp.dataset.boardsEndpoint,
listsEndpoint: $boardApp.dataset.listsEndpoint,
boardId: $boardApp.dataset.boardId,
disabled: $boardApp.dataset.disabled === 'true',
disabled: parseBoolean($boardApp.dataset.disabled),
issueLinkBase: $boardApp.dataset.issueLinkBase,
rootPath: $boardApp.dataset.rootPath,
bulkUpdatePath: $boardApp.dataset.bulkUpdatePath,
......@@ -356,11 +356,34 @@ export default () => {
`,
});
const boardsSwitcherElement = document.getElementById('js-multiple-boards-switcher');
// eslint-disable-next-line no-new
new Vue({
el: '#js-multiple-boards-switcher',
el: boardsSwitcherElement,
components: {
BoardsSelector,
},
data() {
const { dataset } = boardsSwitcherElement;
const boardsSelectorProps = {
...dataset,
currentBoard: JSON.parse(dataset.currentBoard),
hasMissingBoards: parseBoolean(dataset.hasMissingBoards),
canAdminBoard: parseBoolean(dataset.canAdminBoard),
multipleIssueBoardsAvailable: parseBoolean(dataset.multipleIssueBoardsAvailable),
projectId: Number(dataset.projectId),
groupId: Number(dataset.groupId),
scopedIssueBoardFeatureEnabled: parseBoolean(dataset.scopedIssueBoardFeatureEnabled),
weights: JSON.parse(dataset.weights),
};
return { boardsSelectorProps };
},
render(createElement) {
return createElement(BoardsSelector, {
props: this.boardsSelectorProps,
});
},
});
};
......@@ -6,7 +6,7 @@ import _ from 'underscore';
import Vue from 'vue';
import Cookies from 'js-cookie';
import BoardsStoreEE from 'ee/boards/stores/boards_store_ee';
import { getUrlParamsArray } from '~/lib/utils/common_utils';
import { getUrlParamsArray, parseBoolean } from '~/lib/utils/common_utils';
const boardsStore = {
disabled: false,
......@@ -96,7 +96,7 @@ const boardsStore = {
});
},
welcomeIsHidden() {
return Cookies.get('issue_board_welcome_hidden') === 'true';
return parseBoolean(Cookies.get('issue_board_welcome_hidden'));
},
removeList(id, type = 'blank') {
const list = this.findList('id', id, type);
......
......@@ -2,7 +2,7 @@
import $ from 'jquery';
import { visitUrl } from './lib/utils/url_utility';
import { convertPermissionToBoolean } from './lib/utils/common_utils';
import { parseBoolean } from './lib/utils/common_utils';
export default class BuildArtifacts {
constructor() {
......@@ -22,7 +22,7 @@ export default class BuildArtifacts {
// eslint-disable-next-line class-methods-use-this
setupEntryClick() {
return $('.tree-holder').on('click', 'tr[data-link]', function() {
visitUrl(this.dataset.link, convertPermissionToBoolean(this.dataset.externalLink));
visitUrl(this.dataset.link, parseBoolean(this.dataset.externalLink));
});
}
// eslint-disable-next-line class-methods-use-this
......
......@@ -2,7 +2,7 @@ import _ from 'underscore';
import axios from '../lib/utils/axios_utils';
import { s__ } from '../locale';
import Flash from '../flash';
import { convertPermissionToBoolean } from '../lib/utils/common_utils';
import { parseBoolean } from '../lib/utils/common_utils';
import statusCodes from '../lib/utils/http_status';
import VariableList from './ci_variable_list';
......@@ -84,7 +84,7 @@ export default class AjaxVariableList {
.catch(() => {
loadingIcon.classList.toggle('hide', true);
this.variableList.toggleEnableRow(true);
Flash(s__('CiVariable|Error occured while saving variables'));
Flash(s__('CiVariable|Error occurred while saving variables'));
});
}
......@@ -101,7 +101,7 @@ export default class AjaxVariableList {
// If we submitted a row that was destroyed, remove it so we don't try
// to destroy it again which would cause a BE error
const destroyInput = row.querySelector('.js-ci-variable-input-destroy');
if (convertPermissionToBoolean(destroyInput.value)) {
if (parseBoolean(destroyInput.value)) {
row.remove();
// Update the ID input so any future edits and `_destroy` will apply on the BE
} else {
......
import $ from 'jquery';
import { convertPermissionToBoolean } from '../lib/utils/common_utils';
import { parseBoolean } from '../lib/utils/common_utils';
import { s__ } from '../locale';
import setupToggleButtons from '../toggle_buttons';
import CreateItemDropdown from '../create_item_dropdown';
......@@ -150,7 +150,7 @@ export default class VariableList {
removeRow(row) {
const $row = $(row);
const isPersisted = convertPermissionToBoolean($row.attr('data-is-persisted'));
const isPersisted = parseBoolean($row.attr('data-is-persisted'));
if (isPersisted) {
$row.hide();
......
import Visibility from 'visibilityjs';
import Vue from 'vue';
import initDismissableCallout from '~/dismissable_callout';
import PersistentUserCallout from '../persistent_user_callout';
import { s__, sprintf } from '../locale';
import Flash from '../flash';
import Poll from '../lib/utils/poll';
......@@ -26,6 +26,7 @@ export default class Clusters {
statusPath,
installHelmPath,
installIngressPath,
installCertManagerPath,
installRunnerPath,
installJupyterPath,
installKnativePath,
......@@ -48,6 +49,7 @@ export default class Clusters {
endpoint: statusPath,
installHelmEndpoint: installHelmPath,
installIngressEndpoint: installIngressPath,
installCertManagerEndpoint: installCertManagerPath,
installRunnerEndpoint: installRunnerPath,
installPrometheusEndpoint: installPrometheusPath,
installJupyterEndpoint: installJupyterPath,
......@@ -65,7 +67,7 @@ export default class Clusters {
this.showTokenButton = document.querySelector('.js-show-cluster-token');
this.tokenField = document.querySelector('.js-cluster-token');
initDismissableCallout('.js-cluster-security-warning');
Clusters.initDismissableCallout();
initSettingsPanels();
setupToggleButtons(document.querySelector('.js-cluster-enable-toggle-area'));
this.initApplications(clusterType);
......@@ -106,6 +108,12 @@ export default class Clusters {
});
}
static initDismissableCallout() {
const callout = document.querySelector('.js-cluster-security-warning');
if (callout) new PersistentUserCallout(callout); // eslint-disable-line no-new
}
addListeners() {
if (this.showTokenButton) this.showTokenButton.addEventListener('click', this.showToken);
eventHub.$on('installApplication', this.installApplication);
......
......@@ -164,35 +164,21 @@ export default {
:class="[
rowJsClass,
isInstalled && 'cluster-application-installed',
disabled && 'cluster-application-disabled'
disabled && 'cluster-application-disabled',
]"
class="cluster-application-row gl-responsive-table-row gl-responsive-table-row-col-span"
>
<div
class="gl-responsive-table-row-layout"
role="row"
>
<div
class="table-section append-right-8 section-align-top"
role="gridcell"
>
<div class="gl-responsive-table-row-layout" role="row">
<div class="table-section append-right-8 section-align-top" role="gridcell">
<img
v-if="hasLogo"
:src="logoUrl"
:alt="`${title} logo`"
class="cluster-application-logo avatar s40"
/>
<identicon
v-else
:entity-id="identiconId"
:entity-name="title"
size-class="s40"
/>
<identicon v-else :entity-id="identiconId" :entity-name="title" size-class="s40" />
</div>
<div
class="table-section cluster-application-description section-wrap"
role="gridcell"
>
<div class="table-section cluster-application-description section-wrap" role="gridcell">
<strong>
<a
v-if="titleLink"
......@@ -203,12 +189,7 @@ export default {
>
{{ title }}
</a>
<span
v-else
class="js-cluster-application-title"
>
{{ title }}
</span>
<span v-else class="js-cluster-application-title"> {{ title }} </span>
</strong>
<slot name="description"></slot>
<div
......@@ -219,16 +200,10 @@ export default {
{{ generalErrorDescription }}
</p>
<ul v-if="statusReason || requestReason">
<li
v-if="statusReason"
class="js-cluster-application-status-error-message"
>
<li v-if="statusReason" class="js-cluster-application-status-error-message">
{{ statusReason }}
</li>
<li
v-if="requestReason"
class="js-cluster-application-request-error-message"
>
<li v-if="requestReason" class="js-cluster-application-request-error-message">
{{ requestReason }}
</li>
</ul>
......@@ -239,15 +214,8 @@ export default {
class="table-section table-button-footer section-align-top"
role="gridcell"
>
<div
v-if="showManageButton"
class="btn-group table-action-buttons"
>
<a
:href="manageLink"
:class="{ disabled: disabled }"
class="btn"
>
<div v-if="showManageButton" class="btn-group table-action-buttons">
<a :href="manageLink" :class="{ disabled: disabled }" class="btn">
{{ manageButtonLabel }}
</a>
</div>
......
......@@ -6,6 +6,7 @@ export default class ClusterService {
this.appInstallEndpointMap = {
helm: this.options.installHelmEndpoint,
ingress: this.options.installIngressEndpoint,
cert_manager: this.options.installCertManagerEndpoint,
runner: this.options.installRunnerEndpoint,
prometheus: this.options.installPrometheusEndpoint,
jupyter: this.options.installJupyterEndpoint,
......
......@@ -24,6 +24,13 @@ export default class ClusterStore {
requestReason: null,
externalIp: null,
},
cert_manager: {
title: s__('ClusterIntegration|Cert-Manager'),
status: null,
statusReason: null,
requestStatus: null,
requestReason: null,
},
runner: {
title: s__('ClusterIntegration|GitLab Runner'),
status: null,
......@@ -53,6 +60,7 @@ export default class ClusterStore {
requestStatus: null,
requestReason: null,
hostname: null,
externalIp: null,
},
},
};
......@@ -104,6 +112,8 @@ export default class ClusterStore {
} else if (appId === KNATIVE) {
this.state.applications.knative.hostname =
serverAppEntry.hostname || this.state.applications.knative.hostname;
this.state.applications.knative.externalIp =
serverAppEntry.external_ip || this.state.applications.knative.externalIp;
}
});
}
......
......@@ -82,7 +82,6 @@ export default {
</script>
<template>
<div class="content-list pipelines">
<gl-loading-icon
v-if="isLoading"
:label="s__('Pipelines|Loading Pipelines')"
......@@ -93,14 +92,13 @@ export default {
<svg-blank-state
v-else-if="shouldRenderErrorState"
:svg-path="errorStateSvgPath"
:message="s__(`Pipelines|There was an error fetching the pipelines.
Try again in a few moments or contact your support team.`)"
:message="
s__(`Pipelines|There was an error fetching the pipelines.
Try again in a few moments or contact your support team.`)
"
/>
<div
v-else-if="shouldRenderTable"
class="table-holder"
>
<div v-else-if="shouldRenderTable" class="table-holder">
<pipelines-table-component
:pipelines="state.pipelines"
:update-graph-dropdown="updateGraphDropdown"
......
......@@ -2,6 +2,7 @@ import $ from 'jquery';
import Cookies from 'js-cookie';
import _ from 'underscore';
import bp from './breakpoints';
import { parseBoolean } from '~/lib/utils/common_utils';
export default class ContextualSidebar {
constructor() {
......@@ -78,7 +79,7 @@ export default class ContextualSidebar {
if (breakpoint === 'sm' || breakpoint === 'md') {
this.toggleCollapsedSidebar(true);
} else if (breakpoint === 'lg') {
const collapse = Cookies.get('sidebar_collapsed') === 'true';
const collapse = parseBoolean(Cookies.get('sidebar_collapsed'));
this.toggleCollapsedSidebar(collapse);
}
}
......
......@@ -32,30 +32,19 @@ export default {
type="button"
@click="dismissOverviewDialog"
>
<icon
name="close"
/>
<icon name="close" />
</button>
<div
class="svg-container"
v-html="iconCycleAnalyticsSplash"
>
</div>
<div class="svg-container" v-html="iconCycleAnalyticsSplash"></div>
<div class="inner-content">
<h4>
{{ __('Introducing Cycle Analytics') }}
</h4>
<h4>{{ __('Introducing Cycle Analytics') }}</h4>
<p>
{{ __(`Cycle Analytics gives an overview
of how much time it takes to go from idea to production in your project.`) }}
{{
__(`Cycle Analytics gives an overview
of how much time it takes to go from idea to production in your project.`)
}}
</p>
<p>
<a
:href="documentationLink"
target="_blank"
rel="nofollow"
class="btn"
>
<a :href="documentationLink" target="_blank" rel="nofollow" class="btn">
{{ __('Read more') }}
</a>
</p>
......
<script>
import tooltip from '../../vue_shared/directives/tooltip';
import { GlTooltipDirective } from '@gitlab/ui';
export default {
directives: {
tooltip,
GlTooltip: GlTooltipDirective,
},
props: {
count: {
......@@ -14,20 +14,14 @@ export default {
};
</script>
<template>
<span
v-if="count === 50"
class="events-info float-right"
>
<span v-if="count === 50" class="events-info float-right">
<i
v-tooltip
:title="n__(
'Limited to showing %d event at most',
'Limited to showing %d events at most',
50
)"
v-gl-tooltip
:title="
n__('Limited to showing %d event at most', 'Limited to showing %d events at most', 50)
"
class="fa fa-warning"
aria-hidden="true"
data-placement="top"
>
</i>
{{ n__('Showing %d event', 'Showing %d events', 50) }}
......
......@@ -28,45 +28,26 @@ export default {
<limit-warning :count="items.length" />
</div>
<ul class="stage-event-list">
<li
v-for="(mergeRequest, i) in items"
:key="i"
class="stage-event-item"
>
<li v-for="(mergeRequest, i) in items" :key="i" class="stage-event-item">
<div class="item-details">
<!-- FIXME: Pass an alt attribute here for accessibility -->
<user-avatar-image :img-src="mergeRequest.author.avatarUrl" />
<h5 class="item-title merge-merquest-title">
<a :href="mergeRequest.url">
{{ mergeRequest.title }}
</a>
<a :href="mergeRequest.url"> {{ mergeRequest.title }} </a>
</h5>
<a
:href="mergeRequest.url"
class="issue-link">
!{{ mergeRequest.iid }}
</a>
&middot;
<a :href="mergeRequest.url" class="issue-link"> !{{ mergeRequest.iid }} </a> &middot;
<span>
{{ s__('OpenedNDaysAgo|Opened') }}
<a
:href="mergeRequest.url"
class="issue-date">
{{ mergeRequest.createdAt }}
</a>
<a :href="mergeRequest.url" class="issue-date"> {{ mergeRequest.createdAt }} </a>
</span>
<span>
{{ s__('ByAuthor|by') }}
<a
:href="mergeRequest.author.webUrl"
class="issue-author-link">
<a :href="mergeRequest.author.webUrl" class="issue-author-link">
{{ mergeRequest.author.name }}
</a>
</span>
</div>
<div class="item-time">
<total-time :time="mergeRequest.totalTime" />
</div>
<div class="item-time"><total-time :time="mergeRequest.totalTime" /></div>
</li>
</ul>
</div>
......
......@@ -28,47 +28,24 @@ export default {
<limit-warning :count="items.length" />
</div>
<ul class="stage-event-list">
<li
v-for="(issue, i) in items"
:key="i"
class="stage-event-item"
>
<li v-for="(issue, i) in items" :key="i" class="stage-event-item">
<div class="item-details">
<!-- FIXME: Pass an alt attribute here for accessibility -->
<user-avatar-image :img-src="issue.author.avatarUrl"/>
<user-avatar-image :img-src="issue.author.avatarUrl" />
<h5 class="item-title issue-title">
<a
:href="issue.url"
class="issue-title"
>
{{ issue.title }}
</a>
<a :href="issue.url" class="issue-title"> {{ issue.title }} </a>
</h5>
<a
:href="issue.url"
class="issue-link"
>#{{ issue.iid }}</a>
&middot;
<a :href="issue.url" class="issue-link">#{{ issue.iid }}</a> &middot;
<span>
{{ s__('OpenedNDaysAgo|Opened') }}
<a
:href="issue.url"
class="issue-date"
>{{ issue.createdAt }}</a>
<a :href="issue.url" class="issue-date">{{ issue.createdAt }}</a>
</span>
<span>
{{ s__('ByAuthor|by') }}
<a
:href="issue.author.webUrl"
class="issue-author-link"
>
{{ issue.author.name }}
</a>
<a :href="issue.author.webUrl" class="issue-author-link"> {{ issue.author.name }} </a>
</span>
</div>
<div class="item-time">
<total-time :time="issue.totalTime" />
</div>
<div class="item-time"><total-time :time="issue.totalTime" /></div>
</li>
</ul>
</div>
......
......@@ -34,42 +34,25 @@ export default {
<limit-warning :count="items.length" />
</div>
<ul class="stage-event-list">
<li
v-for="(commit, i) in items"
:key="i"
class="stage-event-item"
>
<li v-for="(commit, i) in items" :key="i" class="stage-event-item">
<div class="item-details item-conmmit-component">
<!-- FIXME: Pass an alt attribute here for accessibility -->
<user-avatar-image :img-src="commit.author.avatarUrl" />
<h5 class="item-title commit-title">
<a :href="commit.commitUrl">
{{ commit.title }}
</a>
<a :href="commit.commitUrl"> {{ commit.title }} </a>
</h5>
<span>
{{ s__('FirstPushedBy|First') }}
<span
class="commit-icon"
v-html="iconCommit"
>
</span>
<a
:href="commit.commitUrl"
class="commit-hash-link commit-sha"
>{{ commit.shortSha }}</a>
{{ s__('FirstPushedBy|First') }} <span class="commit-icon" v-html="iconCommit"> </span>
<a :href="commit.commitUrl" class="commit-hash-link commit-sha">{{
commit.shortSha
}}</a>
{{ s__('FirstPushedBy|pushed by') }}
<a
:href="commit.author.webUrl"
class="commit-author-link"
>
<a :href="commit.author.webUrl" class="commit-author-link">
{{ commit.author.name }}
</a>
</span>
</div>
<div class="item-time">
<total-time :time="commit.totalTime" />
</div>
<div class="item-time"><total-time :time="commit.totalTime" /></div>
</li>
</ul>
</div>
......
......@@ -30,66 +30,37 @@ export default {
<limit-warning :count="items.length" />
</div>
<ul class="stage-event-list">
<li
v-for="(mergeRequest, i) in items"
:key="i"
class="stage-event-item"
>
<li v-for="(mergeRequest, i) in items" :key="i" class="stage-event-item">
<div class="item-details">
<!-- FIXME: Pass an alt attribute here for accessibility -->
<user-avatar-image :img-src="mergeRequest.author.avatarUrl" />
<h5 class="item-title merge-merquest-title">
<a :href="mergeRequest.url">
{{ mergeRequest.title }}
</a>
<a :href="mergeRequest.url"> {{ mergeRequest.title }} </a>
</h5>
<a
:href="mergeRequest.url"
class="issue-link"
>!{{ mergeRequest.iid }}</a>
&middot;
<a :href="mergeRequest.url" class="issue-link">!{{ mergeRequest.iid }}</a> &middot;
<span>
{{ s__('OpenedNDaysAgo|Opened') }}
<a
:href="mergeRequest.url"
class="issue-date"
>{{ mergeRequest.createdAt }}</a>
<a :href="mergeRequest.url" class="issue-date">{{ mergeRequest.createdAt }}</a>
</span>
<span>
{{ s__('ByAuthor|by') }}
<a
:href="mergeRequest.author.webUrl"
class="issue-author-link"
>{{ mergeRequest.author.name }}</a>
<a :href="mergeRequest.author.webUrl" class="issue-author-link">{{
mergeRequest.author.name
}}</a>
</span>
<template v-if="mergeRequest.state === 'closed'">
<span class="merge-request-state">
<i
class="fa fa-ban"
aria-hidden="true"
>
</i>
{{ mergeRequest.state.toUpperCase() }}
<i class="fa fa-ban" aria-hidden="true"> </i> {{ mergeRequest.state.toUpperCase() }}
</span>
</template>
<template v-else>
<span
v-if="mergeRequest.branch"
class="merge-request-branch"
>
<icon
:size="16"
name="fork"
/>
<a :href="mergeRequest.branch.url">
{{ mergeRequest.branch.name }}
</a>
<span v-if="mergeRequest.branch" class="merge-request-branch">
<icon :size="16" name="fork" />
<a :href="mergeRequest.branch.url"> {{ mergeRequest.branch.name }} </a>
</span>
</template>
</div>
<div class="item-time">
<total-time :time="mergeRequest.totalTime" />
</div>
<div class="item-time"><total-time :time="mergeRequest.totalTime" /></div>
</li>
</ul>
</div>
......
......@@ -36,62 +36,23 @@ export default {
<limit-warning :count="items.length" />
</div>
<ul class="stage-event-list">
<li
v-for="(build, i) in items"
:key="i"
class="stage-event-item item-build-component"
>
<li v-for="(build, i) in items" :key="i" class="stage-event-item item-build-component">
<div class="item-details">
<!-- FIXME: Pass an alt attribute here for accessibility -->
<user-avatar-image :img-src="build.author.avatarUrl"/>
<user-avatar-image :img-src="build.author.avatarUrl" />
<h5 class="item-title">
<a
:href="build.url"
class="pipeline-id"
>
#{{ build.id }}
</a>
<icon
:size="16"
name="fork"
/>
<a
:href="build.branch.url"
class="ref-name"
>
{{ build.branch.name }}
</a>
<span
class="icon-branch"
v-html="iconBranch"
>
</span>
<a
:href="build.commitUrl"
class="commit-sha"
>
{{ build.shortSha }}
</a>
<a :href="build.url" class="pipeline-id"> #{{ build.id }} </a>
<icon :size="16" name="fork" />
<a :href="build.branch.url" class="ref-name"> {{ build.branch.name }} </a>
<span class="icon-branch" v-html="iconBranch"> </span>
<a :href="build.commitUrl" class="commit-sha"> {{ build.shortSha }} </a>
</h5>
<span>
<a
:href="build.url"
class="build-date"
>
{{ build.date }}
</a>
{{ s__('ByAuthor|by') }}
<a
:href="build.author.webUrl"
class="issue-author-link"
>
{{ build.author.name }}
</a>
<a :href="build.url" class="build-date"> {{ build.date }} </a> {{ s__('ByAuthor|by') }}
<a :href="build.author.webUrl" class="issue-author-link"> {{ build.author.name }} </a>
</span>
</div>
<div class="item-time">
<total-time :time="build.totalTime" />
</div>
<div class="item-time"><total-time :time="build.totalTime" /></div>
</li>
</ul>
</div>
......
......@@ -38,63 +38,22 @@ export default {
<limit-warning :count="items.length" />
</div>
<ul class="stage-event-list">
<li
v-for="(build, i) in items"
:key="i"
class="stage-event-item item-build-component"
>
<li v-for="(build, i) in items" :key="i" class="stage-event-item item-build-component">
<div class="item-details">
<h5 class="item-title">
<span
class="icon-build-status"
v-html="iconBuildStatus"
>
</span>
<a
:href="build.url"
class="item-build-name"
>
{{ build.name }}
</a>
&middot;
<a
:href="build.url"
class="pipeline-id"
>
#{{ build.id }}
</a>
<icon
:size="16"
name="fork"
/>
<a
:href="build.branch.url"
class="ref-name"
>
{{ build.branch.name }}
</a>
<span
class="icon-branch"
v-html="iconBranch"
>
</span>
<a
:href="build.commitUrl"
class="commit-sha">
{{ build.shortSha }}
</a>
<span class="icon-build-status" v-html="iconBuildStatus"> </span>
<a :href="build.url" class="item-build-name"> {{ build.name }} </a> &middot;
<a :href="build.url" class="pipeline-id"> #{{ build.id }} </a>
<icon :size="16" name="fork" />
<a :href="build.branch.url" class="ref-name"> {{ build.branch.name }} </a>
<span class="icon-branch" v-html="iconBranch"> </span>
<a :href="build.commitUrl" class="commit-sha"> {{ build.shortSha }} </a>
</h5>
<span>
<a
:href="build.url"
class="issue-date">
{{ build.date }}
</a>
<a :href="build.url" class="issue-date"> {{ build.date }} </a>
</span>
</div>
<div class="item-time">
<total-time :time="build.totalTime" />
</div>
<div class="item-time"><total-time :time="build.totalTime" /></div>
</li>
</ul>
</div>
......
......@@ -18,28 +18,16 @@ export default {
<span class="total-time">
<template v-if="hasData">
<template v-if="time.days">
{{ time.days }}
<span>
{{ n__('day', 'days', time.days) }}
</span>
{{ time.days }} <span> {{ n__('day', 'days', time.days) }} </span>
</template>
<template v-if="time.hours">
{{ time.hours }}
<span>
{{ n__('Time|hr', 'Time|hrs', time.hours) }}
</span>
{{ time.hours }} <span> {{ n__('Time|hr', 'Time|hrs', time.hours) }} </span>
</template>
<template v-if="time.mins && !time.days">
{{ time.mins }}
<span>
{{ n__('Time|min', 'Time|mins', time.mins) }}
</span>
{{ time.mins }} <span> {{ n__('Time|min', 'Time|mins', time.mins) }} </span>
</template>
<template v-if="time.seconds && hasData === 1 || time.seconds === 0">
{{ time.seconds }}
<span>
{{ s__('Time|s') }}
</span>
<template v-if="(time.seconds && hasData === 1) || time.seconds === 0">
{{ time.seconds }} <span> {{ s__('Time|s') }} </span>
</template>
</template>
<template v-else>
......
<script>
import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
import { GlLoadingIcon } from '@gitlab/ui';
import eventHub from '../eventhub';
export default {
......@@ -43,11 +43,9 @@ export default {
:class="[{ disabled: isLoading }, btnCssClass]"
:disabled="isLoading"
class="btn"
@click="doAction">
@click="doAction"
>
<slot></slot>
<gl-loading-icon
v-if="isLoading"
:inline="true"
/>
<gl-loading-icon v-if="isLoading" :inline="true" />
</button>
</template>
......@@ -6,7 +6,7 @@ import eventHub from '../eventhub';
import DeployKeysService from '../service';
import DeployKeysStore from '../store';
import KeysPanel from './keys_panel.vue';
import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
import { GlLoadingIcon } from '@gitlab/ui';
export default {
components: {
......@@ -123,26 +123,10 @@ export default {
/>
<template v-else-if="hasKeys">
<div class="top-area scrolling-tabs-container inner-page-scroll-tabs">
<div class="fade-left">
<i
class="fa fa-angle-left"
aria-hidden="true"
>
</i>
</div>
<div class="fade-right">
<i
class="fa fa-angle-right"
aria-hidden="true"
>
</i>
</div>
<div class="fade-left"><i class="fa fa-angle-left" aria-hidden="true"> </i></div>
<div class="fade-right"><i class="fa fa-angle-right" aria-hidden="true"> </i></div>
<navigation-tabs
:tabs="tabs"
scope="deployKeys"
@onChangeTab="onChangeTab"
/>
<navigation-tabs :tabs="tabs" scope="deployKeys" @onChangeTab="onChangeTab" />
</div>
<keys-panel
:project-id="projectId"
......
......@@ -112,26 +112,14 @@ export default {
<template>
<div class="gl-responsive-table-row deploy-key">
<div class="table-section section-40">
<div
role="rowheader"
class="table-mobile-header">
{{ s__('DeployKeys|Deploy key') }}
</div>
<div role="rowheader" class="table-mobile-header">{{ s__('DeployKeys|Deploy key') }}</div>
<div class="table-mobile-content">
<strong class="title qa-key-title">
{{ deployKey.title }}
</strong>
<div class="fingerprint qa-key-fingerprint">
{{ deployKey.fingerprint }}
</div>
<strong class="title qa-key-title"> {{ deployKey.title }} </strong>
<div class="fingerprint qa-key-fingerprint">{{ deployKey.fingerprint }}</div>
</div>
</div>
<div class="table-section section-30 section-wrap">
<div
role="rowheader"
class="table-mobile-header">
{{ s__('DeployKeys|Project usage') }}
</div>
<div role="rowheader" class="table-mobile-header">{{ s__('DeployKeys|Project usage') }}</div>
<div class="table-mobile-content deploy-project-list">
<template v-if="projects.length > 0">
<a
......@@ -139,10 +127,8 @@ export default {
:title="projectTooltipTitle(firstProject)"
class="label deploy-project-label"
>
<span>
{{ firstProject.project.full_name }}
</span>
<icon :name="firstProject.can_push ? 'lock-open' : 'lock'"/>
<span> {{ firstProject.project.full_name }} </span>
<icon :name="firstProject.can_push ? 'lock-open' : 'lock'" />
</a>
<a
v-if="isExpandable"
......@@ -162,39 +148,24 @@ export default {
:title="projectTooltipTitle(deployKeysProject)"
class="label deploy-project-label"
>
<span>
{{ deployKeysProject.project.full_name }}
</span>
<icon :name="deployKeysProject.can_push ? 'lock-open' : 'lock'"/>
<span> {{ deployKeysProject.project.full_name }} </span>
<icon :name="deployKeysProject.can_push ? 'lock-open' : 'lock'" />
</a>
</template>
<span
v-else
class="text-secondary">{{ __('None') }}</span>
<span v-else class="text-secondary">{{ __('None') }}</span>
</div>
</div>
<div class="table-section section-15 text-right">
<div
role="rowheader"
class="table-mobile-header">
{{ __('Created') }}
</div>
<div role="rowheader" class="table-mobile-header">{{ __('Created') }}</div>
<div class="table-mobile-content text-secondary key-created-at">
<span
v-tooltip
:title="tooltipTitle(deployKey.created_at)">
<icon name="calendar"/>
<span>{{ timeFormated(deployKey.created_at) }}</span>
<span v-tooltip :title="tooltipTitle(deployKey.created_at)">
<icon name="calendar" /> <span>{{ timeFormated(deployKey.created_at) }}</span>
</span>
</div>
</div>
<div class="table-section section-15 table-button-footer deploy-key-actions">
<div class="btn-group table-action-buttons">
<action-btn
v-if="!isEnabled"
:deploy-key="deployKey"
type="enable"
>
<action-btn v-if="!isEnabled" :deploy-key="deployKey" type="enable">
{{ __('Enable') }}
</action-btn>
<a
......@@ -205,7 +176,7 @@ export default {
class="btn btn-default text-secondary"
data-container="body"
>
<icon name="pencil"/>
<icon name="pencil" />
</a>
<action-btn
v-if="isRemovable"
......@@ -216,7 +187,7 @@ export default {
type="remove"
data-container="body"
>
<icon name="remove"/>
<icon name="remove" />
</action-btn>
<action-btn
v-else-if="isEnabled"
......@@ -227,7 +198,7 @@ export default {
type="disable"
data-container="body"
>
<icon name="cancel"/>
<icon name="cancel" />
</action-btn>
</div>
</div>
......
......@@ -30,24 +30,14 @@ export default {
<template>
<div class="deploy-keys-panel table-holder">
<template v-if="keys.length > 0">
<div
role="row"
class="gl-responsive-table-row table-row-header">
<div
role="rowheader"
class="table-section section-40">
<div role="row" class="gl-responsive-table-row table-row-header">
<div role="rowheader" class="table-section section-40">
{{ s__('DeployKeys|Deploy key') }}
</div>
<div
role="rowheader"
class="table-section section-30">
<div role="rowheader" class="table-section section-30">
{{ s__('DeployKeys|Project usage') }}
</div>
<div
role="rowheader"
class="table-section section-15 text-right">
{{ __('Created') }}
</div>
<div role="rowheader" class="table-section section-15 text-right">{{ __('Created') }}</div>
</div>
<deploy-key
v-for="deployKey in keys"
......@@ -58,10 +48,7 @@ export default {
:project-id="projectId"
/>
</template>
<div
v-else
class="settings-message text-center"
>
<div v-else class="settings-message text-center">
{{ s__('DeployKeys|No deploy keys found. Create one with the form above.') }}
</div>
</div>
......
......@@ -112,7 +112,7 @@ const JumpToDiscussion = Vue.extend({
if (!hasDiscussionsToJumpTo) {
// If there are no discussions to jump to on the current page,
// switch to the notes tab and jump to the first disucssion there.
// switch to the notes tab and jump to the first discussion there.
window.mrTabs.activateTab('show');
activeTab = 'show';
jumpToFirstDiscussion = true;
......
......@@ -28,12 +28,10 @@ export default {
</script>
<template>
<div class="info-well prepend-top-default">
<div class="info-well w-100">
<div class="well-segment">
<ul class="blob-commit-info">
<commit-item
:commit="commit"
/>
<commit-item :commit="commit" />
</ul>
</div>
</div>
......
......@@ -39,7 +39,7 @@ export default {
return this.diffFile.viewer.name === 'text';
},
diffFileCommentForm() {
return this.getCommentFormForDiffFile(this.diffFile.fileHash);
return this.getCommentFormForDiffFile(this.diffFile.file_hash);
},
showNotesContainer() {
return this.diffFile.discussions.length || this.diffFileCommentForm;
......@@ -73,34 +73,31 @@ export default {
<inline-diff-view
v-if="isInlineView"
:diff-file="diffFile"
:diff-lines="diffFile.highlightedDiffLines || []"
:diff-lines="diffFile.highlighted_diff_lines || []"
/>
<parallel-diff-view
v-if="isParallelView"
:diff-file="diffFile"
:diff-lines="diffFile.parallelDiffLines || []"
:diff-lines="diffFile.parallel_diff_lines || []"
/>
</template>
<diff-viewer
v-else
:diff-mode="diffMode"
:new-path="diffFile.newPath"
:new-sha="diffFile.diffRefs.headSha"
:old-path="diffFile.oldPath"
:old-sha="diffFile.diffRefs.baseSha"
:file-hash="diffFile.fileHash"
:new-path="diffFile.new_path"
:new-sha="diffFile.diff_refs.head_sha"
:old-path="diffFile.old_path"
:old-sha="diffFile.diff_refs.base_sha"
:file-hash="diffFile.file_hash"
:project-path="projectPath"
>
<image-diff-overlay
slot="image-overlay"
:discussions="diffFile.discussions"
:file-hash="diffFile.fileHash"
:file-hash="diffFile.file_hash"
:can-comment="getNoteableData.current_user.can_create_note"
/>
<div
v-if="showNotesContainer"
class="note-container"
>
<div v-if="showNotesContainer" class="note-container">
<diff-discussions
v-if="diffFile.discussions.length"
class="diff-file-discussions"
......@@ -115,8 +112,8 @@ export default {
:save-button-title="__('Comment')"
class="diff-comment-form new-note discussion-form discussion-form-container"
@handleFormUpdate="handleSaveNote"
@cancelForm="closeDiffFileCommentForm(diffFile.fileHash)"
/>
@cancelForm="closeDiffFileCommentForm(diffFile.file_hash);"
/>
</div>
</diff-viewer>
</div>
......
......@@ -3,7 +3,7 @@ import { mapActions } from 'vuex';
import Icon from '~/vue_shared/components/icon.vue';
import { pluralize, truncate } from '~/lib/utils/text_utility';
import UserAvatarImage from '~/vue_shared/components/user_avatar/user_avatar_image.vue';
import { GlTooltipDirective } from '@gitlab-org/gitlab-ui';
import { GlTooltipDirective } from '@gitlab/ui';
import { COUNT_OF_AVATARS_IN_GUTTER, LENGTH_OF_AVATAR_TOOLTIP } from '../constants';
export default {
......@@ -75,10 +75,7 @@ export default {
class="diff-notes-collapse js-diff-comment-avatar js-diff-comment-button"
@click="toggleDiscussions"
>
<icon
:size="12"
name="collapse"
/>
<icon :size="12" name="collapse" />
</button>
<template v-else>
<user-avatar-image
......@@ -99,7 +96,8 @@ export default {
data-placement="top"
role="button"
@click="toggleDiscussions"
>+{{ moreCount }}</span>
>+{{ moreCount }}</span
>
</template>
</div>
</template>
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment