CB-5181 Display User Notification Pop-up When Copy/Paste Functionality is Disabled by Administrator (#2730)

* CB-5181 adds copy event handler for data viewer (cells, value panel)

* CB-5181 makes edit/copy settings independent from each other

* CB-5181 adds disable copy case for read state JsonLine (pre)

* CB-5181 changes message text for popup

* CB-5181 changes message text for popup 2

* СB-5181 fixes rus locale for copy message

---------

Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
This commit is contained in:
sergeyteleshev
2024-06-25 18:17:40 +03:00
committed by GitHub
co-authored by Evgenia Bezborodova
parent 4078b6aa16
commit 4842cba903
13 changed files with 73 additions and 29 deletions
@@ -22,7 +22,7 @@ export interface IReactCodeMirrorProps extends React.PropsWithChildren {
getValue?: () => string;
extensions?: Map<Compartment, Extension>;
readonly?: boolean;
disableCopy?: boolean;
copyEventHandler?: (event: ClipboardEvent) => boolean;
autoFocus?: boolean;
onChange?: (value: string, update: ViewUpdate) => void;
onCursorChange?: (selection: SelectionRange, update: ViewUpdate) => void;
@@ -31,7 +31,7 @@ export const ReactCodemirror = observer<IReactCodeMirrorProps, IEditorRef>(
incomingValue,
extensions = new Map<Compartment, Extension>(),
readonly,
disableCopy,
copyEventHandler,
autoFocus,
onChange,
onCursorChange,
@@ -45,11 +45,9 @@ export const ReactCodemirror = observer<IReactCodeMirrorProps, IEditorRef>(
const eventHandlers = useMemo(
() =>
EditorView.domEventHandlers({
copy() {
return disableCopy;
},
copy: copyEventHandler,
}),
[disableCopy],
[copyEventHandler],
);
extensions = useCodemirrorExtensions(extensions, [readOnlyFacet, eventHandlers]);
const [container, setContainer] = useState<HTMLDivElement | null>(null);
@@ -17,6 +17,7 @@ import {
IResultSetElementKey,
ResultSetDataKeysUtils,
ResultSetSelectAction,
useDataViewerCopyHandler,
} from '@cloudbeaver/plugin-data-viewer';
import type { IDataGridSelectionContext } from './DataGridSelection/DataGridSelectionContext';
@@ -71,6 +72,7 @@ export function useGridSelectedCellsCopy(
) {
const dataViewerService = useService(DataViewerService);
const props = useObjectRef({ tableData, selectionContext, resultSetSelectAction });
const copyEventHandler = useDataViewerCopyHandler();
const onKeydownHandler = useCallback((event: React.KeyboardEvent) => {
if ((event.ctrlKey || event.metaKey) && event.nativeEvent.code === EVENT_KEY_CODE.C) {
@@ -98,6 +100,8 @@ export function useGridSelectedCellsCopy(
copyToClipboard(value);
}
}
copyEventHandler(event);
}
}, []);
@@ -14,11 +14,7 @@ import { DataViewerSettingsService } from './DataViewerSettingsService';
@injectable()
export class DataViewerService {
get canCopyData() {
if (this.sessionPermissionsResource.has(EAdminPermission.admin)) {
return true;
}
return !this.dataViewerSettingsService.disableCopyData;
return this.sessionPermissionsResource.has(EAdminPermission.admin) || !this.dataViewerSettingsService.disableCopyData;
}
constructor(
@@ -8,10 +8,9 @@
import { observer } from 'mobx-react-lite';
import { useMemo } from 'react';
import { useService } from '@cloudbeaver/core-di';
import { EditorLoader, useCodemirrorExtensions } from '@cloudbeaver/plugin-codemirror6';
import { DataViewerService } from '../../DataViewerService';
import { useDataViewerCopyHandler } from '../../useDataViewerCopyHandler';
import { getTypeExtension } from './getTypeExtension';
interface Props {
@@ -27,7 +26,7 @@ export const TextValueEditor = observer<Props>(function TextValueEditor({ conten
const typeExtension = useMemo(() => getTypeExtension(contentType!) ?? [], [contentType]);
const extensions = useCodemirrorExtensions(undefined, typeExtension);
const dataViewerService = useService(DataViewerService);
const copyEventHandler = useDataViewerCopyHandler();
return (
<EditorLoader
@@ -35,7 +34,7 @@ export const TextValueEditor = observer<Props>(function TextValueEditor({ conten
lineWrapping={lineWrapping}
readonly={readonly}
extensions={extensions}
disableCopy={!dataViewerService.canCopyData}
copyEventHandler={copyEventHandler}
onChange={onChange}
/>
);
@@ -85,5 +85,6 @@ export * from './ResultSetDataSource';
export * from './DataPresentationService';
export * from './DataViewerDataChangeConfirmationService';
export * from './ValuePanelPresentation/BooleanValue/isBooleanValuePresentationAvailable';
export * from './useDataViewerCopyHandler';
export * from './DataViewerSettingsService';
export * from './DATA_EDITOR_SETTINGS_GROUP';
@@ -34,6 +34,8 @@ export default [
['data_viewer_script_preview_error_title', 'Kann das Skript nicht bekommen'],
['data_viewer_total_count_tooltip', 'Totalzahl erhalten'],
['data_viewer_model_not_loaded', 'Das Tabellenmodell ist nicht geladen'],
['data_viewer_copy_not_allowed', 'An ability to copy data is disabled'],
['data_viewer_copy_not_allowed_message', 'If this was unexpected, contact the administrator'],
['settings_data_editor', 'Dateneditor'],
['settings_data_editor_disable_edit_name', 'Bearbeiten deaktivieren'],
['settings_data_editor_disable_edit_description', 'Deaktivieren Sie die Bearbeitung von Daten in Data Viewer für Nicht-Admin-Benutzer'],
@@ -57,6 +57,8 @@ export default [
['data_viewer_total_count_canceled_message', 'Statement was cancelled due to user request'],
['data_viewer_total_count_failed', 'Failed to get total count'],
['data_viewer_model_not_loaded', 'Table model is not loaded'],
['data_viewer_copy_not_allowed', 'An ability to copy data is disabled'],
['data_viewer_copy_not_allowed_message', 'If this was unexpected, contact the administrator'],
['settings_data_editor', 'Data Editor'],
['settings_data_editor_disable_edit_name', 'Disable Edit'],
['settings_data_editor_disable_edit_description', 'Disable editing of data in Data Viewer for non-admin users'],
@@ -8,7 +8,7 @@
export default [
['plugin_data_viewer_data_viewer_settings_group', 'Affichage des données'],
['table_header_sql_expression', 'Entrez une expression SQL pour filtrer les résultats, par exemple column_name=10'],
['table_header_sql_expression_not_supported', 'Le filtrage des données n\'est pas supporté'],
['table_header_sql_expression_not_supported', "Le filtrage des données n'est pas supporté"],
['data_viewer_tab_title', 'Données'],
['data_viewer_value_edit', 'Modifier'],
['data_viewer_value_apply', 'Appliquer'],
@@ -20,16 +20,16 @@ export default [
['data_viewer_statistics_updated_rows', 'Lignes mises à jour :'],
['data_viewer_action_refresh', 'Actualiser'],
['data_viewer_action_auto_refresh', 'Actualisation automatique'],
['data_viewer_action_auto_refresh_stop', 'Arrêter l\'actualisation automatique'],
['data_viewer_action_auto_refresh_stop', "Arrêter l'actualisation automatique"],
['data_viewer_action_edit_delete', 'Supprimer la sélection'],
['data_viewer_action_edit_add', 'Ajouter'],
['data_viewer_action_edit_add_copy', 'Dupliquer'],
['data_viewer_action_edit_revert', 'Annuler la sélection'],
['data_viewer_result_edited_title', 'Enregistrer les modifications'],
['data_viewer_result_edited_message', 'Le jeu de résultats a été modifié. Voulez-vous enregistrer les modifications dans la base de données ?'],
['data_viewer_data_save_error_title', 'Erreur lors de l\'enregistrement des modifications'],
['data_viewer_auto_refresh_settings', 'Paramètres d\'actualisation automatique'],
['data_viewer_auto_refresh_settings_stop_on_error', 'Arrêter en cas d\'erreur'],
['data_viewer_data_save_error_title', "Erreur lors de l'enregistrement des modifications"],
['data_viewer_auto_refresh_settings', "Paramètres d'actualisation automatique"],
['data_viewer_auto_refresh_settings_stop_on_error', "Arrêter en cas d'erreur"],
['data_viewer_presentation_value_title', 'Valeur'],
['data_viewer_presentation_value_text_line_wrapping_wrap', 'Retour à la ligne'],
['data_viewer_presentation_value_text_line_wrapping_no_wrap', 'Ne pas revenir à la ligne'],
@@ -42,25 +42,30 @@ export default [
['data_viewer_presentation_value_text_base64_title', 'Base64'],
['data_viewer_presentation_value_image_title', 'Image'],
['data_viewer_presentation_value_image_fit', 'Ajuster à la fenêtre'],
['data_viewer_presentation_value_image_original_size', 'Taille d\'origine'],
['data_viewer_presentation_value_boolean_placeholder', 'Impossible d\'afficher la valeur actuelle en tant que booléen'],
['data_viewer_presentation_value_image_original_size', "Taille d'origine"],
['data_viewer_presentation_value_boolean_placeholder', "Impossible d'afficher la valeur actuelle en tant que booléen"],
['data_viewer_presentation_value_content_truncated_placeholder', 'La valeur a été tronquée en raison de la'],
['data_viewer_presentation_value_content_download_error', 'Échec du téléchargement'],
['data_viewer_presentation_value_content_paste_error', 'Impossible de charger le texte complet'],
['data_viewer_script_preview', 'Script'],
['data_viewer_script_preview_dialog_title', 'Aperçu des modifications'],
['data_viewer_script_preview_error_title', 'Impossible d\'obtenir le script'],
['data_viewer_script_preview_error_title', "Impossible d'obtenir le script"],
['data_viewer_refresh_result_set', 'Actualiser le jeu de résultats'],
['data_viewer_total_count_tooltip', 'Obtenir le compte total'],
['data_viewer_total_count_canceled_title', 'Total annulé'],
['data_viewer_total_count_canceled_message', 'La déclaration a été annulée à la demande de l\'utilisateur'],
['data_viewer_total_count_failed', 'Échec de l\'obtention du compte total'],
['data_viewer_model_not_loaded', 'Le modèle de la table n\'est pas chargé'],
['data_viewer_total_count_canceled_message', "La déclaration a été annulée à la demande de l'utilisateur"],
['data_viewer_total_count_failed', "Échec de l'obtention du compte total"],
['data_viewer_model_not_loaded', "Le modèle de la table n'est pas chargé"],
['data_viewer_copy_not_allowed', 'An ability to copy data is disabled'],
['data_viewer_copy_not_allowed_message', 'If this was unexpected, contact the administrator'],
['settings_data_editor', 'Éditeur de données'],
['settings_data_editor_disable_edit_name', 'Désactiver l\'édition'],
['settings_data_editor_disable_edit_description', 'Désactiver l\'édition des données dans le Data Viewer pour les utilisateurs non administrateurs'],
['settings_data_editor_disable_edit_name', "Désactiver l'édition"],
['settings_data_editor_disable_edit_description', "Désactiver l'édition des données dans le Data Viewer pour les utilisateurs non administrateurs"],
['settings_data_editor_disable_data_copy_name', 'Désactiver la copie'],
['settings_data_editor_disable_data_copy_description', 'Désactiver la copie des données dans le Data Viewer pour les utilisateurs non administrateurs'],
[
'settings_data_editor_disable_data_copy_description',
'Désactiver la copie des données dans le Data Viewer pour les utilisateurs non administrateurs',
],
['settings_data_editor_fetch_min_name', 'Taille de récupération minimale'],
['settings_data_editor_fetch_min_description', 'Nombre minimal de lignes à récupérer'],
['settings_data_editor_fetch_max_name', 'Taille de récupération maximale'],
@@ -50,6 +50,8 @@ export default [
['data_viewer_total_count_canceled_message', 'Statement was cancelled due to user request'],
['data_viewer_total_count_failed', 'Failed to get total count'],
['data_viewer_model_not_loaded', 'Table model is not loaded'],
['data_viewer_copy_not_allowed', 'An ability to copy data is disabled'],
['data_viewer_copy_not_allowed_message', 'If this was unexpected, contact the administrator'],
['settings_data_editor', 'Data Editor'],
['settings_data_editor_disable_edit_name', 'Disable Edit'],
['settings_data_editor_disable_edit_description', 'Disable editing of data in Data Viewer for non-admin users'],
@@ -51,6 +51,8 @@ export default [
['data_viewer_total_count_canceled_message', 'Запрос был отменен пользователем'],
['data_viewer_total_count_failed', 'Не удалось получить количество записей'],
['data_viewer_model_not_loaded', 'Не удалось загрузить модель таблицы'],
['data_viewer_copy_not_allowed', 'Копирование отключено'],
['data_viewer_copy_not_allowed_message', 'Если это не ожидаемо, обратитесь к администратору'],
['settings_data_editor', 'Редактор данных'],
['settings_data_editor_disable_edit_name', 'Отключить редактирование'],
['settings_data_editor_disable_edit_description', 'Отключить редактирование данных для пользователей без прав администратора'],
@@ -57,6 +57,8 @@ export default [
['data_viewer_total_count_canceled_title', 'Total count canceled'],
['data_viewer_total_count_canceled_message', 'Statement was cancelled due to user request'],
['data_viewer_model_not_loaded', 'Table model is not loaded'],
['data_viewer_copy_not_allowed', 'An ability to copy data is disabled'],
['data_viewer_copy_not_allowed_message', 'If this was unexpected, contact the administrator'],
['settings_data_editor', 'Data Editor'],
['settings_data_editor_disable_edit_name', 'Disable Edit'],
['settings_data_editor_disable_edit_description', 'Disable editing of data in Data Viewer for non-admin users'],
@@ -0,0 +1,31 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import type React from 'react';
import { useService } from '@cloudbeaver/core-di';
import { NotificationService } from '@cloudbeaver/core-events';
import { DataViewerService } from './DataViewerService';
export function useDataViewerCopyHandler() {
const notificationService = useService(NotificationService);
const dataViewerService = useService(DataViewerService);
return function (event?: ClipboardEvent | React.KeyboardEvent | React.ClipboardEvent) {
if (!dataViewerService.canCopyData) {
event?.preventDefault();
notificationService.logError({
title: 'data_viewer_copy_not_allowed',
message: 'data_viewer_copy_not_allowed_message',
});
}
return !dataViewerService.canCopyData;
};
}