Commit 0f90c929 authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/gitlab@master

parent f05aa6b55cca
......@@ -89,10 +89,9 @@ export default {
methods: {
...mapActions('environmentLogs', [
'setInitData',
'setSearch',
'showPodLogs',
'showEnvironment',
'fetchEnvironments',
'fetchLogs',
'fetchMoreLogsPrepend',
'dismissRequestEnvironmentsError',
'dismissInvalidTimeRangeWarning',
......@@ -191,13 +190,13 @@ export default {
<log-advanced-filters
v-if="showAdvancedFilters"
ref="log-advanced-filters"
class="d-md-flex flex-grow-1"
class="d-md-flex flex-grow-1 min-width-0"
:disabled="environments.isLoading"
/>
<log-simple-filters
v-else
ref="log-simple-filters"
class="d-md-flex flex-grow-1"
class="d-md-flex flex-grow-1 min-width-0"
:disabled="environments.isLoading"
/>
......@@ -205,7 +204,7 @@ export default {
ref="scrollButtons"
class="flex-grow-0 pr-2 mb-2 controllers"
:scroll-down-button-disabled="scrollDownButtonDisabled"
@refresh="showPodLogs(pods.current)"
@refresh="fetchLogs()"
@scrollDown="scrollDown"
/>
</div>
......
<script>
import { s__ } from '~/locale';
import DateTimePicker from '~/vue_shared/components/date_time_picker/date_time_picker.vue';
import { mapActions, mapState } from 'vuex';
import {
GlIcon,
GlDropdown,
GlDropdownHeader,
GlDropdownDivider,
GlDropdownItem,
GlSearchBoxByClick,
} from '@gitlab/ui';
import { GlFilteredSearch } from '@gitlab/ui';
import { __, s__ } from '~/locale';
import DateTimePicker from '~/vue_shared/components/date_time_picker/date_time_picker.vue';
import { timeRanges } from '~/vue_shared/constants';
import { TOKEN_TYPE_POD_NAME } from '../constants';
import TokenWithLoadingState from './tokens/token_with_loading_state.vue';
export default {
components: {
GlIcon,
GlDropdown,
GlDropdownHeader,
GlDropdownDivider,
GlDropdownItem,
GlSearchBoxByClick,
GlFilteredSearch,
DateTimePicker,
},
props: {
......@@ -32,11 +22,10 @@ export default {
data() {
return {
timeRanges,
searchQuery: '',
};
},
computed: {
...mapState('environmentLogs', ['timeRange', 'pods']),
...mapState('environmentLogs', ['timeRange', 'pods', 'logs']),
timeRangeModel: {
get() {
......@@ -46,75 +35,56 @@ export default {
this.setTimeRange(val);
},
},
/**
* Token options.
*
* Returns null when no pods are present, so suggestions are displayed in the token
*/
podOptions() {
if (this.pods.options.length) {
return this.pods.options.map(podName => ({ value: podName, title: podName }));
}
return null;
},
podDropdownText() {
return this.pods.current || s__('Environments|All pods');
tokens() {
return [
{
icon: 'pod',
type: TOKEN_TYPE_POD_NAME,
title: s__('Environments|Pod name'),
token: TokenWithLoadingState,
operators: [{ value: '=', description: __('is'), default: 'true' }],
unique: true,
options: this.podOptions,
loading: this.logs.isLoading,
noOptionsText: s__('Environments|No pods to display'),
},
];
},
},
methods: {
...mapActions('environmentLogs', ['setSearch', 'showPodLogs', 'setTimeRange']),
isCurrentPod(podName) {
return podName === this.pods.current;
...mapActions('environmentLogs', ['showFilteredLogs', 'setTimeRange']),
filteredSearchSubmit(filters) {
this.showFilteredLogs(filters);
},
},
};
</script>
<template>
<div>
<gl-dropdown
ref="podsDropdown"
:text="podDropdownText"
:disabled="disabled"
class="mb-2 gl-h-32 pr-2 d-flex d-md-block flex-grow-0 qa-pods-dropdown"
>
<gl-dropdown-header class="text-center">
{{ s__('Environments|Filter by pod') }}
</gl-dropdown-header>
<gl-dropdown-item v-if="!pods.options.length" disabled>
<span ref="noPodsMsg" class="text-muted">
{{ s__('Environments|No pods to display') }}
</span>
</gl-dropdown-item>
<template v-else>
<gl-dropdown-item ref="allPodsOption" key="all-pods" @click="showPodLogs(null)">
<div class="d-flex">
<gl-icon
:class="{ invisible: pods.current !== null }"
name="status_success_borderless"
/>
<div class="flex-grow-1">{{ s__('Environments|All pods') }}</div>
</div>
</gl-dropdown-item>
<gl-dropdown-divider />
<gl-dropdown-item
v-for="podName in pods.options"
:key="podName"
class="text-nowrap"
@click="showPodLogs(podName)"
>
<div class="d-flex">
<gl-icon
:class="{ invisible: !isCurrentPod(podName) }"
name="status_success_borderless"
/>
<div class="flex-grow-1">{{ podName }}</div>
</div>
</gl-dropdown-item>
</template>
</gl-dropdown>
<gl-search-box-by-click
ref="searchBox"
v-model.trim="searchQuery"
:disabled="disabled"
:placeholder="s__('Environments|Search')"
class="mb-2 pr-2 flex-grow-1"
type="search"
autofocus
@submit="setSearch(searchQuery)"
/>
<div class="mb-2 pr-2 flex-grow-1 min-width-0">
<gl-filtered-search
:placeholder="__('Search')"
:clear-button-title="__('Clear')"
:close-button-title="__('Close')"
class="gl-h-32"
:disabled="disabled || logs.isLoading"
:available-tokens="tokens"
@submit="filteredSearchSubmit"
/>
</div>
<date-time-picker
ref="dateTimePicker"
......
<script>
import { GlFilteredSearchToken, GlLoadingIcon } from '@gitlab/ui';
export default {
components: {
GlFilteredSearchToken,
GlLoadingIcon,
},
inheritAttrs: false,
props: {
config: {
type: Object,
required: true,
},
},
};
</script>
<template>
<gl-filtered-search-token :config="config" v-bind="{ ...$attrs }" v-on="$listeners">
<template #suggestions>
<div class="m-1">
<gl-loading-icon v-if="config.loading" />
<div v-else class="py-1 px-2 text-muted">
{{ config.noOptionsText }}
</div>
</div>
</template>
</gl-filtered-search-token>
</template>
export const dateFormatMask = 'UTC:mmm dd HH:MM:ss.l"Z"';
export const TOKEN_TYPE_POD_NAME = 'TOKEN_TYPE_POD_NAME';
......@@ -2,6 +2,7 @@ import { backOff } from '~/lib/utils/common_utils';
import httpStatusCodes from '~/lib/utils/http_status';
import axios from '~/lib/utils/axios_utils';
import { convertToFixedRange } from '~/lib/utils/datetime_range';
import { TOKEN_TYPE_POD_NAME } from '../constants';
import * as types from './mutation_types';
......@@ -49,19 +50,42 @@ const requestLogsUntilData = ({ commit, state }) => {
return requestUntilData(logs_api_path, params);
};
/**
* Converts filters emitted by the component, e.g. a filterered-search
* to parameters to be applied to the filters of the store
* @param {Array} filters - List of strings or objects to filter by.
* @returns {Object} - An object with `search` and `podName` keys.
*/
const filtersToParams = (filters = []) => {
// Strings become part of the `search`
const search = filters
.filter(f => typeof f === 'string')
.join(' ')
.trim();
// null podName to show all pods
const podName = filters.find(f => f?.type === TOKEN_TYPE_POD_NAME)?.value?.data ?? null;
return { search, podName };
};
export const setInitData = ({ commit }, { timeRange, environmentName, podName }) => {
commit(types.SET_TIME_RANGE, timeRange);
commit(types.SET_PROJECT_ENVIRONMENT, environmentName);
commit(types.SET_CURRENT_POD_NAME, podName);
};
export const showPodLogs = ({ dispatch, commit }, podName) => {
export const showFilteredLogs = ({ dispatch, commit }, filters = []) => {
const { podName, search } = filtersToParams(filters);
commit(types.SET_CURRENT_POD_NAME, podName);
commit(types.SET_SEARCH, search);
dispatch('fetchLogs');
};
export const setSearch = ({ dispatch, commit }, searchQuery) => {
commit(types.SET_SEARCH, searchQuery);
export const showPodLogs = ({ dispatch, commit }, podName) => {
commit(types.SET_CURRENT_POD_NAME, podName);
dispatch('fetchLogs');
};
......
import { secondsToMilliseconds } from '~/lib/utils/datetime_utility';
import dateFormat from 'dateformat';
const dateFormatMask = 'UTC:mmm dd HH:MM:ss.l"Z"';
import { dateFormatMask } from './constants';
/**
* Returns a time range (`start`, `end`) where `start` is the
......
......@@ -36,7 +36,7 @@ export default {
<template>
<div>
<div>
<div class="border-bottom pb-4">
<h3>{{ s__('StaticSiteEditor|Success!') }}</h3>
<p>
{{
......@@ -45,35 +45,37 @@ export default {
)
}}
</p>
<div>
<div class="d-flex justify-content-end">
<gl-new-button ref="returnToSiteButton" :href="returnUrl">{{
s__('StaticSiteEditor|Return to site')
}}</gl-new-button>
<gl-new-button ref="mergeRequestButton" :href="mergeRequest.url" variant="info">{{
s__('StaticSiteEditor|View merge request')
}}</gl-new-button>
<gl-new-button
ref="mergeRequestButton"
class="ml-2"
:href="mergeRequest.url"
variant="success"
>{{ s__('StaticSiteEditor|View merge request') }}</gl-new-button
>
</div>
</div>
<hr />
<div>
<div class="pt-2">
<h4>{{ s__('StaticSiteEditor|Summary of changes') }}</h4>
<ul>
<li>
{{ s__('StaticSiteEditor|A new branch was created:') }}
{{ s__('StaticSiteEditor|You created a new branch:') }}
<gl-link ref="branchLink" :href="branch.url">{{ branch.label }}</gl-link>
</li>
<li>
{{ s__('StaticSiteEditor|Your changes were committed to it:') }}
<gl-link ref="commitLink" :href="commit.url">{{ commit.label }}</gl-link>
</li>
<li>
{{ s__('StaticSiteEditor|A merge request was created:') }}
{{ s__('StaticSiteEditor|You created a merge request:') }}
<gl-link ref="mergeRequestLink" :href="mergeRequest.url">{{
mergeRequest.label
}}</gl-link>
</li>
<li>
{{ s__('StaticSiteEditor|You added a commit:') }}
<gl-link ref="commitLink" :href="commit.url">{{ commit.label }}</gl-link>
</li>
</ul>
</div>
</div>
......
......@@ -96,8 +96,8 @@
}
.name {
background-color: $filter-name-resting-color;
color: $filter-name-text-color;
background-color: $white-normal;
color: $gl-text-color-secondary;
border-radius: 2px 0 0 2px;
margin-right: 1px;
text-transform: capitalize;
......@@ -105,7 +105,7 @@
.operator {
background-color: $white-normal;
color: $filter-value-text-color;
color: $gl-text-color;
margin-right: 1px;
}
......@@ -113,7 +113,7 @@
display: flex;
align-items: center;
background-color: $white-normal;
color: $filter-value-text-color;
color: $gl-text-color;
border-radius: 0 2px 2px 0;
margin-right: 5px;
padding-right: 8px;
......@@ -152,7 +152,7 @@
.filtered-search-token .selected,
.filtered-search-term .selected {
.name {
background-color: $filter-name-selected-color;
background-color: $gray-200;
}
.operator {
......
......@@ -86,13 +86,13 @@
line-height: 10px;
color: $gl-gray-700;
vertical-align: middle;
background-color: $kdb-bg;
background-color: $gray-50;
border-width: 1px;
border-style: solid;
border-color: $gl-gray-200 $gl-gray-200 $kdb-border-bottom;
border-color: $gray-200 $gray-200 $gray-400;
border-image: none;
border-radius: 3px;
box-shadow: 0 -1px 0 $kdb-shadow inset;
box-shadow: 0 -1px 0 $gray-400 inset;
}
h1 {
......
......@@ -485,7 +485,7 @@ $line-removed-dark: #fac5cd;
$line-number-old: #f9d7dc;
$line-number-new: #ddfbe6;
$line-number-select: #fbf2da;
$line-target-blue: #f6faff;
$line-target-blue: $blue-50;
$line-select-yellow: #fcf8e7;
$line-select-yellow-dark: #f0e2bd;
$dark-diff-match-bg: rgba(255, 255, 255, 0.3);
......@@ -698,7 +698,7 @@ $logs-p-color: #333;
*/
$input-height: 34px;
$input-danger-bg: #f2dede;
$input-group-addon-bg: #f7f8fa;
$input-group-addon-bg: $gray-50;
$gl-field-focus-shadow: rgba(0, 0, 0, 0.075);
$gl-field-focus-shadow-error: rgba($red-500, 0.6);
$input-short-width: 200px;
......@@ -774,9 +774,6 @@ $select2-drop-shadow2: rgba(31, 37, 50, 0.317647);
/*
* Typography
*/
$kdb-bg: #fcfcfc;
$kdb-border-bottom: #bbb;
$kdb-shadow: #bbb;
$body-text-shadow: rgba(255, 255, 255, 0.01);
/*
......@@ -800,20 +797,6 @@ CI variable lists
*/
$ci-variable-remove-button-width: calc(1em + #{2 * $gl-padding});
/*
Filtered Search
*/
$filter-name-resting-color: #f8f8f8;
$filter-name-text-color: rgba(0, 0, 0, 0.55);
$filter-value-text-color: rgba(0, 0, 0, 0.85);
$filter-name-selected-color: #ebebeb;
$filter-value-selected-color: #d7d7d7;
/*
Animation Functions
*/
$dropdown-animation-timing: cubic-bezier(0.23, 1, 0.32, 1);
/*
GitLab Plans
*/
......
......@@ -54,6 +54,11 @@
.mh-50vh { max-height: 50vh; }
.min-width-0 {
// By default flex items don't shrink below their minimum content size. To change this, set the item's min-width
min-width: 0;
}
.font-size-inherit { font-size: inherit; }
.gl-w-8 { width: px-to-rem($grid-size); }
.gl-w-16 { width: px-to-rem($grid-size * 2); }
......
......@@ -475,6 +475,16 @@ def adjourned_deletion?
false
end
def wiki_access_level
# TODO: Remove this method once we implement group-level features.
# https://gitlab.com/gitlab-org/gitlab/-/issues/208412
if Feature.enabled?(:group_wiki, self)
ProjectFeature::ENABLED
else
ProjectFeature::DISABLED
end
end
private
def update_two_factor_requirement
......
# frozen_string_literal: true
class ProjectPolicy
module ClassMethods
module CrudPolicyHelpers
extend ActiveSupport::Concern
class_methods do
def create_read_update_admin_destroy(name)
[
:"read_#{name}",
......
# frozen_string_literal: true
class GroupPolicy < BasePolicy
include CrudPolicyHelpers
include FindGroupProjects
desc "Group is public"
......@@ -42,15 +43,23 @@ class GroupPolicy < BasePolicy
@subject.subgroup_creation_level == ::Gitlab::Access::MAINTAINER_SUBGROUP_ACCESS
end
desc "Group has wiki disabled"
condition(:wiki_disabled, score: 32) { !feature_available?(:wiki) }
rule { public_group }.policy do
enable :read_group
enable :read_package
enable :read_wiki
end
rule { logged_in_viewable }.enable :read_group
rule { logged_in_viewable }.policy do
enable :read_group
enable :read_wiki
end
rule { guest }.policy do
enable :read_group
enable :read_wiki
enable :upload_file
end
......@@ -78,10 +87,12 @@ class GroupPolicy < BasePolicy
enable :create_metrics_dashboard_annotation
enable :delete_metrics_dashboard_annotation
enable :update_metrics_dashboard_annotation
enable :create_wiki
end
rule { reporter }.policy do
enable :read_container_image
enable :download_wiki_code
enable :admin_label
enable :admin_list
enable :admin_issue
......@@ -100,6 +111,7 @@ class GroupPolicy < BasePolicy
enable :destroy_deploy_token
enable :read_deploy_token
enable :create_deploy_token
enable :admin_wiki
end
rule { owner }.policy do
......@@ -145,6 +157,11 @@ class GroupPolicy < BasePolicy
rule { maintainer & can?(:create_projects) }.enable :transfer_projects
rule { wiki_disabled }.policy do
prevent(*create_read_update_admin_destroy(:wiki))
prevent(:download_wiki_code)
end
def access_level
return GroupMember::NO_ACCESS if @user.nil?
......@@ -154,6 +171,21 @@ def access_level
def lookup_access_level!
@subject.max_member_access_for_user(@user)
end
# TODO: Extract this into a helper shared with ProjectPolicy, once we implement group-level features.
# https://gitlab.com/gitlab-org/gitlab/-/issues/208412
def feature_available?(feature)
return false unless feature == :wiki
case @subject.wiki_access_level
when ProjectFeature::DISABLED
false
when ProjectFeature::PRIVATE
admin? || access_level >= ProjectFeature.required_minimum_access_level(feature)
else
true
end
end
end
GroupPolicy.prepend_if_ee('EE::GroupPolicy')
......@@ -5,7 +5,7 @@ class IssuePolicy < IssuablePolicy
# Make sure to sync this class checks with issue.rb to avoid security problems.
# Check commit 002ad215818450d2cbbc5fa065850a953dc7ada8 for more information.
extend ProjectPolicy::ClassMethods
include CrudPolicyHelpers
desc "User can read confidential issues"
condition(:can_read_confidential) do
......
# frozen_string_literal: true
class ProjectPolicy < BasePolicy
extend