1
0
Fork 0
mirror of https://gitlab.com/bramw/baserow.git synced 2025-01-12 20:08:16 +00:00

RBAC Help Icons

This commit is contained in:
Alexander Haller 2022-12-29 13:59:10 +00:00
parent 2b9de4afdf
commit aa70d78614
23 changed files with 199 additions and 64 deletions

View file

@ -10,6 +10,7 @@ For example:
## Unreleased
### New Features
* Add various help icons to explain RBAC in the UI [#1318](https://gitlab.com/bramw/baserow/-/issues/1318)
### Bug Fixes
@ -21,7 +22,6 @@ For example:
* (Optional) - Regenerate the `card_cover` thumbnails to have better quality images in gallery views with: `./baserow regenerate_user_file_thumbnails card_cover`
### New Features
* (Enterprise Preview Feature) Database and Table level RBAC with Teams are now available as a preview feature for enterprise users, Add 'RBAC' to the FEATURE_FLAG env and restart var to enable.
* Possibility to disable password authentication if another authentication provider is enabled. [#1317](https://gitlab.com/bramw/baserow/-/issues/1317)
* Users with roles higher than viewer on tables and databases now counted as paid users

View file

@ -7,3 +7,4 @@
@import 'subject_sample_field';
@import 'member_roles';
@import 'select_list_footer';
@import 'manage_team_form';

View file

@ -0,0 +1,4 @@
.manage-team-form__role-title {
display: flex;
margin-bottom: 10px;
}

View file

@ -69,6 +69,10 @@
overflow: hidden;
}
.member-roles-members-list__role-selector {
display: flex;
}
.select-members-list__user-name {
max-width: 400px;
text-overflow: ellipsis;

View file

@ -27,6 +27,17 @@
role-value-column="role_uid"
@update-role="roleUpdate($event)"
></EditRoleContext>
<HelpIcon
v-if="roleUidSelected === 'NO_ACCESS'"
:tooltip="$t('membersRoleField.noAccessHelpText')"
class="margin-left-1"
/>
<HelpIcon
v-if="roleUidSelected === 'ADMIN'"
:tooltip="$t('membersRoleField.adminHelpText')"
class="margin-left-1"
is-warning
/>
</div>
</template>
@ -65,6 +76,9 @@ export default {
})
: []
},
roleUidSelected() {
return this.row[this.column.key]
},
...mapGetters({ userId: 'auth/getUserId' }),
},
methods: {

View file

@ -40,17 +40,24 @@
</div>
</div>
</div>
<RoleSelector
:disabled="
roleAssignment.subject.id === userId &&
roleAssignment.subject_type === 'auth.User'
"
:roles="getAvailableRoles(roles)"
:value="getRole(roleAssignment)"
:allow-removing-role="true"
@delete="$emit('role-updated', roleAssignment, null)"
@input="({ uid }) => $emit('role-updated', roleAssignment, uid)"
/>
<div class="member-roles-members-list__role-selector">
<HelpIcon
v-if="getRole(roleAssignment).uid === 'ADMIN'"
class="margin-right-1"
:tooltip="$t('memberRolesMembersList.adminHelpText')"
/>
<RoleSelector
:disabled="
roleAssignment.subject.id === userId &&
roleAssignment.subject_type === 'auth.User'
"
:roles="getAvailableRoles(roles)"
:value="getRole(roleAssignment)"
:allow-removing-role="true"
@delete="$emit('role-updated', roleAssignment, null)"
@input="({ uid }) => $emit('role-updated', roleAssignment, uid)"
/>
</div>
</li>
</ul>
</template>

View file

@ -6,12 +6,18 @@
$t(`memberRolesTab.${translationPrefix}.title`, { name: scope.name })
}}
</h2>
<a
:class="{ 'button--loading': loading }"
class="button button--ghost"
@click="loading ? null : $refs.roleAssignmentModal.show()"
>{{ $t(`memberRolesTab.${translationPrefix}.selectMembers`) }}</a
>
<div>
<HelpIcon
:tooltip="$t(`memberRolesTab.${translationPrefix}.headerTooltip`)"
class="margin-right-1"
></HelpIcon>
<a
:class="{ 'button--loading': loading }"
class="button button--ghost"
@click="loading ? null : $refs.roleAssignmentModal.show()"
>{{ $t(`memberRolesTab.${translationPrefix}.selectMembers`) }}</a
>
</div>
</div>
<div v-if="loading" class="loading"></div>
<div v-else>

View file

@ -6,17 +6,23 @@
<div v-if="showRoleSelector">
<RoleSelector v-model="roleSelected" :roles="roles" />
</div>
<a
class="button"
:class="{ disabled: !inviteEnabled }"
@click="inviteEnabled ? $emit('invite', roleSelected) : null"
>{{
$t('selectSubjectsListFooter.invite', {
count,
type: subjectTypeLabel,
})
}}
</a>
<div>
<HelpIcon
:tooltip="$t('selectSubjectsListFooter.helpTooltip')"
class="margin-right-1"
></HelpIcon>
<a
class="button"
:class="{ disabled: !inviteEnabled }"
@click="inviteEnabled ? $emit('invite', roleSelected) : null"
>{{
$t('selectSubjectsListFooter.invite', {
count,
type: subjectTypeLabel,
})
}}
</a>
</div>
</div>
</template>

View file

@ -31,7 +31,15 @@
</FormElement>
</div>
<div class="col col-5">
<h3>{{ $t('manageTeamForm.roleTitle') }}</h3>
<div class="manage-team-form__role-title">
<h3>
{{ $t('manageTeamForm.roleTitle') }}
<HelpIcon
class="margin-left-1"
:tooltip="$t('manageTeamForm.roleHelpText')"
/>
</h3>
</div>
<FormElement class="control">
<div class="control__elements">
<Dropdown v-model="values.default_role" :show-search="false">

View file

@ -134,7 +134,8 @@ export default {
{
roles: this.roles,
groupId: this.group.id,
}
},
this.$t('teamsTable.roleHelpText')
),
new CrudTableColumn(
'subject_sample',

View file

@ -34,7 +34,8 @@
"roleTitle": "Default role",
"inviteMembers": "Add members",
"membersTitle": "Members",
"noSubjectsSelected": "Click '{buttonLabel}' to optionally add team users."
"noSubjectsSelected": "Click '{buttonLabel}' to optionally add team users.",
"roleHelpText": "User specific roles will always override Team roles."
},
"editTeamContext": {
"edit": "Edit team",
@ -46,7 +47,8 @@
"nameColumn": "Name",
"createdColumn": "Created on",
"subjectsColumn": "Members",
"roleColumn": "Default role"
"roleColumn": "Default role",
"roleHelpText": "Can be overriden with roles on databases and tables."
},
"subjectSampleField": {
"titleAttr": "{subjectCount} members in this team."
@ -158,7 +160,8 @@
"everyoneHasAccess": "Everyone at {name} workspace can access this database.",
"onlyYouHaveAccess": "Only you can access this database.",
"warningTitle": "Other users might inherit access!",
"warningMessage": "Other users might inherit access via their respective roles on the parent group."
"warningMessage": "Other users might inherit access via their respective roles on the parent group.",
"headerTooltip": "Database roles will override group roles."
},
"table": {
"title": "{name} table",
@ -166,7 +169,8 @@
"everyoneHasAccess": "Everyone at {name} workspace can access this table.",
"onlyYouHaveAccess": "Only you can access this table.",
"warningTitle": "Other users might inherit access!",
"warningMessage": "Other users might inherit access via their respective roles on the parent database or group."
"warningMessage": "Other users might inherit access via their respective roles on the parent database or group.",
"headerTooltip": "Table roles will override group and database roles."
}
},
"memberRolesShareToggle": {
@ -181,7 +185,8 @@
},
"memberRolesMembersList": {
"remove": "Remove",
"teamMembersCount": "{count} team members"
"teamMembersCount": "{count} team members",
"adminHelpText": "Admins can restrict other admins roles."
},
"roleAssignmentModal": {
"membersTab": "Members",
@ -202,7 +207,15 @@
"types": {
"members": "members",
"teams": "teams"
}
},
"helpTooltip": "Member role assignments override team role assignments."
},
"membersRoleField": {
"noAccessHelpText": "This user requires explicit access to resources.",
"adminHelpText": "Admins can restrict other admins roles."
},
"membersPagePlugin": {
"roleHelpText": "Can be overriden with roles on databases and tables."
},
"oauthSettingsForm": {
"providerName": "Name",
@ -229,4 +242,4 @@
"userTeamsField": {
"no_records": "No teams"
}
}
}

View file

@ -68,7 +68,8 @@ export class EnterpriseMembersPagePluginType extends MembersPagePluginType {
false,
{
groupId: group.id,
}
},
this.app.i18n.t('membersPagePlugin.roleHelpText')
)
)
}

View file

@ -107,3 +107,5 @@
@import 'auth';
@import "expand_on_overflow_list";
@import 'list';
@import 'help_icon';
@import 'group_invite_form';

View file

@ -0,0 +1,8 @@
.group-invite-form__role-selector {
display: flex;
align-items: center;
}
.group-invite-form__role-selector-dropdown {
width: 100%;
}

View file

@ -0,0 +1,3 @@
.help-icon {
color: $color-neutral-600;
}

View file

@ -42,6 +42,7 @@
color: $white;
padding: 0 8px;
text-align: center;
white-space: nowrap;
@include fixed-height(26px, 12px);
}

View file

@ -0,0 +1,26 @@
<template>
<i v-tooltip="tooltip" class="help-icon fas" :class="iconClass"> </i>
</template>
<script>
export default {
name: 'HelpIcon',
props: {
tooltip: {
type: String,
required: false,
default: null,
},
isWarning: {
type: Boolean,
required: false,
default: false,
},
},
computed: {
iconClass() {
return this.isWarning ? 'fa-exclamation-circle' : 'fa-question-circle'
},
},
}
</script>

View file

@ -25,11 +25,14 @@
>
<div class="data-table__table-cell-head">
<template v-if="col.sortable">
<a
class="data-table__table-cell-head-link"
@click="toggleSort(col)"
>{{ col.header }}</a
>
<div>
<a
class="data-table__table-cell-head-link"
@click="toggleSort(col)"
>{{ col.header }}</a
>
<HelpIcon v-if="col.helpText" :tooltip="col.helpText" />
</div>
<div>
<template v-if="sorted(col)">
<i class="fas" :class="sortIcon(col)"></i>
@ -37,7 +40,14 @@
</template>
</div>
</template>
<template v-else>{{ col.header }}</template>
<template v-else>
<div>
{{ col.header }}
<HelpIcon
v-if="col.helpText"
:tooltip="col.helpText"
/></div
></template>
</div>
</th>
</tr>

View file

@ -22,15 +22,22 @@
<div class="col col-5">
<FormElement class="control">
<div class="control__elements">
<Dropdown v-model="values.permissions" :show-search="false">
<DropdownItem
v-for="role in roles"
:key="role.uid"
:name="role.name"
:value="role.uid"
:description="role.description"
></DropdownItem>
</Dropdown>
<div class="group-invite-form__role-selector">
<slot name="roleSelectorLabel"></slot>
<Dropdown
v-model="values.permissions"
class="group-invite-form__role-selector-dropdown"
:show-search="false"
>
<DropdownItem
v-for="role in roles"
:key="role.uid"
:name="role.name"
:value="role.uid"
:description="role.description"
></DropdownItem>
</Dropdown>
</div>
</div>
</FormElement>
</div>

View file

@ -9,15 +9,23 @@
:group="group"
@submitted="inviteSubmitted"
>
<div class="col col-12 align-right">
<button
:class="{ 'button--loading': inviteLoading }"
class="button"
:disabled="inviteLoading"
>
{{ $t('membersSettings.membersInviteModal.submit') }}
</button>
</div>
<template #default>
<div class="col col-12 align-right">
<button
:class="{ 'button--loading': inviteLoading }"
class="button"
:disabled="inviteLoading"
>
{{ $t('membersSettings.membersInviteModal.submit') }}
</button>
</div>
</template>
<template #roleSelectorLabel>
<HelpIcon
class="margin-right-1"
:tooltip="$t('membersSettings.membersInviteModal.helpIconText')"
/>
</template>
</GroupInviteForm>
</Modal>
</template>

View file

@ -25,7 +25,8 @@ export default class CrudTableColumn {
stickyLeft = false,
stickyRight = false,
additionalProps = {},
widthPerc = ''
widthPerc = '',
helpText = null
) {
this.key = key
this._header = header
@ -35,6 +36,7 @@ export default class CrudTableColumn {
this.stickyRight = stickyRight
this.additionalProps = additionalProps
this.widthPerc = widthPerc
this.helpText = helpText
}
get header() {

View file

@ -465,6 +465,7 @@
"membersInviteModal": {
"title": "Invite group members",
"submit": "Send invite",
"helpIconText": "The selected role will be the users default role in this group.",
"errors": {
"userAlreadyInGroup": {
"title": "User is already in the group.",

View file

@ -20,6 +20,7 @@ import Alert from '@baserow/modules/core/components/Alert'
import Tabs from '@baserow/modules/core/components/Tabs'
import Tab from '@baserow/modules/core/components/Tab'
import List from '@baserow/modules/core/components/List'
import HelpIcon from '@baserow/modules/core/components/HelpIcon'
import lowercase from '@baserow/modules/core/filters/lowercase'
import uppercase from '@baserow/modules/core/filters/uppercase'
@ -54,6 +55,7 @@ Vue.component('ProgressBar', ProgressBar)
Vue.component('Tab', Tab)
Vue.component('Tabs', Tabs)
Vue.component('List', List)
Vue.component('HelpIcon', HelpIcon)
Vue.filter('lowercase', lowercase)
Vue.filter('uppercase', uppercase)