UBER-159: popup dialog for deleting with message if not enough permissions (#3224)

Signed-off-by: Vyacheslav Tumanov <me@slavatumanov.me>
This commit is contained in:
Vyacheslav Tumanov 2023-05-23 15:20:11 +05:00 committed by GitHub
parent 237ae709ac
commit 14fbe03d9f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 99 additions and 8 deletions

View File

@ -0,0 +1,77 @@
<!--
// Copyright © 2023 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
-->
<script lang="ts">
import { Card, createQuery } from '@hcengineering/presentation'
import { AccountRole, Doc, getCurrentAccount, Ref, SortingOrder } from '@hcengineering/core'
import view from '@hcengineering/view-resources/src/plugin'
import { createEventDispatcher } from 'svelte'
import contact, { Employee, EmployeeAccount } from '@hcengineering/contact'
import EmployeePresenter from './EmployeePresenter.svelte'
import { employeeAccountByIdStore } from '../utils'
import ui, { Label } from '@hcengineering/ui'
export let object: Doc | Doc[]
export let deleteAction: () => void
const objectArray = Array.isArray(object) ? object : [object]
let owners: Ref<Employee>[] = []
const query = createQuery()
query.query(
contact.class.EmployeeAccount,
{ role: AccountRole.Owner },
(res) => {
owners = res.map((account) => account.employee)
},
{
sort: { name: SortingOrder.Descending }
}
)
const dispatch = createEventDispatcher()
const creators = [
...new Set(objectArray.map((obj) => $employeeAccountByIdStore.get(obj.createdBy as Ref<EmployeeAccount>)?.employee))
]
const me = $employeeAccountByIdStore.get(getCurrentAccount()._id as Ref<EmployeeAccount>)?.employee
const canDelete = (creators.length === 1 && creators.includes(me)) || (me && owners.includes(me))
const label = canDelete ? view.string.DeleteObject : view.string.DeletePopupNoPermissionTitle
</script>
<Card {label} okAction={deleteAction} canSave={canDelete} okLabel={ui.string.Ok} on:close={() => dispatch('close')}>
<div class="flex-grow flex-col">
{#if canDelete}
<div class="mb-2">
<Label label={view.string.DeleteObjectConfirm} params={{ count: objectArray.length }} />
</div>
{:else}
<div class="mb-2">
<Label label={view.string.DeletePopupNoPermissionLabel} />
</div>
<div class="mb-2">
<Label label={view.string.DeletePopupCreatorLabel} />
{#each creators as employee}
<div class="my-2">
<EmployeePresenter value={employee} />
</div>
{/each}
</div>
<div class="mb-2">
<Label label={view.string.DeletePopupOwnerLabel} />
{#each owners as employee}
<div class="my-2">
<EmployeePresenter value={employee} />
</div>
{/each}
</div>
{/if}
</div>
</Card>

View File

@ -78,6 +78,7 @@ import UserBoxItems from './components/UserBoxItems.svelte'
import EmployeeFilter from './components/EmployeeFilter.svelte'
import EmployeeFilterValuePresenter from './components/EmployeeFilterValuePresenter.svelte'
import EmployeeAccountFilterValuePresenter from './components/EmployeeAccountFilterValuePresenter.svelte'
import DeleteConfirmationPopup from './components/DeleteConfirmationPopup.svelte'
import contact from './plugin'
import {
@ -298,7 +299,8 @@ export default async (): Promise<Resources> => ({
UserBoxItems,
EmployeeFilter,
EmployeeFilterValuePresenter,
EmployeeAccountFilterValuePresenter
EmployeeAccountFilterValuePresenter,
DeleteConfirmationPopup
},
completion: {
EmployeeQuery: async (

View File

@ -194,7 +194,8 @@ export const contactPlugin = plugin(contactId, {
Avatar: '' as AnyComponent,
UserBoxList: '' as AnyComponent,
ChannelPresenter: '' as AnyComponent,
SpaceMembers: '' as AnyComponent
SpaceMembers: '' as AnyComponent,
DeleteConfirmationPopup: '' as AnyComponent
},
channelProvider: {
Email: '' as Ref<ChannelProvider>,

View File

@ -13,7 +13,11 @@
"Table": "Table",
"Role": "Role",
"DeleteObject": "Delete object",
"DeleteObjectConfirm": "Do you want to delete this {count, plural, =1 {object} other {# objects}}?",
"DeleteObjectConfirm": "Do you want to delete {count, plural, =1 {this object} other {these # objects}}?",
"DeletePopupNoPermissionTitle": "Not enough permissions to delete.",
"DeletePopupNoPermissionLabel": "Please contact people from the list below for them to do so.",
"DeletePopupCreatorLabel": "Creators (can delete only ones that were created by them):",
"DeletePopupOwnerLabel": "Owners (can delete all of them):",
"Archive": "Archive",
"ArchiveConfirm": "Do you want to archive this {count, plural, =1 {object} other {# objects}}?",
"Open": "Open",

View File

@ -14,6 +14,10 @@
"Role": "Роль",
"DeleteObject": "Удалить объект",
"DeleteObjectConfirm": "Вы действительно хотите удалить {count, plural, =1 {этот объект} other {эти # объекта}}?",
"DeletePopupNoPermissionTitle": "Недостаточно прав для удаления.",
"DeletePopupNoPermissionLabel": "Пожалуйста обратитесь к людям из списка ниже, чтобы они это сделали.",
"DeletePopupCreatorLabel": "Создатели объектов (могут удалить лишь те, что были созданы ими):",
"DeletePopupOwnerLabel": "Владельцы (могут удалить все):",
"Archive": "Архивировать",
"ArchiveConfirm": "Вы действительно хотите заархивировать {count, plural, =1 {этот объект} other {эти # объекта}}?",
"Open": "Открыть",

View File

@ -17,6 +17,7 @@ import { ContextStore, contextStore } from './context'
import view from './plugin'
import { FocusSelection, SelectDirection, focusStore, previewDocument, selectionStore } from './selection'
import { deleteObjects, getObjectLinkFragment } from './utils'
import contact from '@hcengineering/contact'
/**
* Action to be used for copying text to clipboard.
@ -55,12 +56,10 @@ async function CopyTextToClipboard (
function Delete (object: Doc | Doc[]): void {
showPopup(
MessageBox,
contact.component.DeleteConfirmationPopup,
{
label: view.string.DeleteObject,
message: view.string.DeleteObjectConfirm,
params: { count: Array.isArray(object) ? object.length : 1 },
action: async () => {
object,
deleteAction: async () => {
const objs = Array.isArray(object) ? object : [object]
await deleteObjects(getClient(), objs).catch((err) => console.error(err))
}

View File

@ -36,6 +36,10 @@ export default mergeIds(viewId, view, {
ChooseAColor: '' as IntlString,
DeleteObject: '' as IntlString,
DeleteObjectConfirm: '' as IntlString,
DeletePopupNoPermissionTitle: '' as IntlString,
DeletePopupNoPermissionLabel: '' as IntlString,
DeletePopupCreatorLabel: '' as IntlString,
DeletePopupOwnerLabel: '' as IntlString,
Archive: '' as IntlString,
ArchiveConfirm: '' as IntlString,
Assignees: '' as IntlString,