mirror of
				https://github.com/gristlabs/grist-core.git
				synced 2025-06-13 20:53:59 +00:00 
			
		
		
		
	(core) Updating flow and UI for shortcut warnings
Summary: - Popup looks different (better shadow, order and alignment) - Warnings need to be dismissed by checking "Don't show again" button, pressing Esc/Enter or clicking away just hides the popup, but it will be opened once again. - Dismissing one warning popup (about zoom keys), dismisses them all Test Plan: Updated Reviewers: georgegevoian Reviewed By: georgegevoian Differential Revision: https://phab.getgrist.com/D3683
This commit is contained in:
		
							parent
							
								
									64710b60f3
								
							
						
					
					
						commit
						fb16c3de56
					
				@ -63,28 +63,46 @@ export class DeprecatedCommands extends Disposable {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private _handleCommand(c: Command) {
 | 
			
		||||
    const seenWarnings = this._gristDoc.docPageModel.appModel.deprecatedWarnings;
 | 
			
		||||
    if (!this._hasSeenWarning(c.name)) {
 | 
			
		||||
      markAsSeen(seenWarnings, c.name);
 | 
			
		||||
      this._showWarning(c.desc);
 | 
			
		||||
      this._showWarning(c);
 | 
			
		||||
      return false; // Stop processing.
 | 
			
		||||
    } else {
 | 
			
		||||
      return true; // Continue processing.
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private _showWarning(desc: string) {
 | 
			
		||||
  private _showWarning(c: Command) {
 | 
			
		||||
    // Try to figure out where to show the message. If we have active view, we can try
 | 
			
		||||
    // to find the selected cell and show the message there. Otherwise, we show it in the
 | 
			
		||||
    // bottom right corner as a warning.
 | 
			
		||||
    const selectedCell = this._gristDoc.currentView.get()?.viewPane.querySelector(".selected_cursor");
 | 
			
		||||
    const seenWarnings = this._gristDoc.docPageModel.appModel.deprecatedWarnings;
 | 
			
		||||
    function onClose(checked: boolean) {
 | 
			
		||||
      if (checked) {
 | 
			
		||||
        // For deprecated zoom commands we have the same messages, so mark them as seen.
 | 
			
		||||
        const zoomCommands: DeprecationWarning[] = [
 | 
			
		||||
          'deprecatedDeleteRecords',
 | 
			
		||||
          'deprecatedInsertRecordAfter',
 | 
			
		||||
          'deprecatedInsertRowBefore',
 | 
			
		||||
        ];
 | 
			
		||||
        if (zoomCommands.includes(c.name as any)) {
 | 
			
		||||
          zoomCommands.forEach((name) => markAsSeen(seenWarnings, name));
 | 
			
		||||
        } else {
 | 
			
		||||
          markAsSeen(seenWarnings, c.name);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    if (!selectedCell) {
 | 
			
		||||
      reportMessage(() => dom('div', this._createMessage(desc)), {
 | 
			
		||||
      reportMessage(() => dom('div', this._createMessage(c.desc)), {
 | 
			
		||||
        level: 'info',
 | 
			
		||||
        key: 'deprecated-command',
 | 
			
		||||
      });
 | 
			
		||||
    } else {
 | 
			
		||||
      showDeprecatedWarning(selectedCell, this._createMessage(desc));
 | 
			
		||||
      showDeprecatedWarning(
 | 
			
		||||
        selectedCell,
 | 
			
		||||
        this._createMessage(c.desc),
 | 
			
		||||
        onClose
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -103,7 +121,7 @@ export class DeprecatedCommands extends Disposable {
 | 
			
		||||
      if (part[0] === '{') {
 | 
			
		||||
        const otherCommand = commands.allCommands[part.slice(1, -1)];
 | 
			
		||||
        if (otherCommand) {
 | 
			
		||||
          elements.push(otherCommand.getKeysDom());
 | 
			
		||||
          elements.push(otherCommand.getKeysDom(() => dom('span', 'or')));
 | 
			
		||||
        }
 | 
			
		||||
      } else {
 | 
			
		||||
        elements.push(cssTallerText(part));
 | 
			
		||||
 | 
			
		||||
@ -159,9 +159,10 @@ Command.prototype.getDesc = function() {
 | 
			
		||||
/**
 | 
			
		||||
 * Returns DOM for the keyboard shortcuts, wrapped in cute boxes that look like keyboard keys.
 | 
			
		||||
 */
 | 
			
		||||
Command.prototype.getKeysDom = function() {
 | 
			
		||||
Command.prototype.getKeysDom = function(separator) {
 | 
			
		||||
  return dom('span.shortcut_keys',
 | 
			
		||||
    this.humanKeys.map(key => dom('span.shortcut_key_image', key))
 | 
			
		||||
    separator ? this.humanKeys.map((key, i) => [i ? separator() : null, dom('span.shortcut_key_image', key)])
 | 
			
		||||
              : this.humanKeys.map(key => dom('span.shortcut_key_image', key))
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -35,16 +35,16 @@ export function buildConfirmDelete(
 | 
			
		||||
      dom('div', `Are you sure you want to delete ${single ? 'this' : 'these'} record${single ? '' : 's'}?`,
 | 
			
		||||
        dom.style('margin-bottom', '10px'),
 | 
			
		||||
      ),
 | 
			
		||||
      dom('div',
 | 
			
		||||
        labeledSquareCheckbox(remember, "Don't ask again.", testId('confirm-remember')),
 | 
			
		||||
        dom.style('margin-bottom', '10px'),
 | 
			
		||||
      ),
 | 
			
		||||
      cssButtons(
 | 
			
		||||
        dom.style('margin-bottom', '12px'),
 | 
			
		||||
        primaryButton('Delete', testId('confirm-save'), dom.on('click', () => {
 | 
			
		||||
          onSave(remember.get());
 | 
			
		||||
          ctl.close();
 | 
			
		||||
        })),
 | 
			
		||||
        basicButton('Cancel', testId('confirm-cancel'), dom.on('click', () => ctl.close()))
 | 
			
		||||
      ),
 | 
			
		||||
      dom('div',
 | 
			
		||||
        labeledSquareCheckbox(remember, "Don't ask again.", testId('confirm-remember')),
 | 
			
		||||
      )
 | 
			
		||||
    ), {}
 | 
			
		||||
  );
 | 
			
		||||
@ -60,21 +60,29 @@ export function buildConfirmDelete(
 | 
			
		||||
 | 
			
		||||
export function showDeprecatedWarning(
 | 
			
		||||
  refElement: Element,
 | 
			
		||||
  content: DomContents
 | 
			
		||||
  content: DomContents,
 | 
			
		||||
  onClose: (checked: boolean) => void,
 | 
			
		||||
) {
 | 
			
		||||
  const remember = observable(false);
 | 
			
		||||
  const tooltip = modalTooltip(refElement, (ctl) =>
 | 
			
		||||
    cssWideContainer(
 | 
			
		||||
      testId('popup-warning-deprecated'),
 | 
			
		||||
      elem => { FocusLayer.create(ctl, {defaultFocusElem: elem, pauseMousetrap: true}); },
 | 
			
		||||
      dom.onKeyDown({
 | 
			
		||||
        Escape: () => ctl.close(),
 | 
			
		||||
        Enter: () => ctl.close(),
 | 
			
		||||
        Escape: () => { ctl.close(); onClose(remember.get()); },
 | 
			
		||||
        Enter: () => { ctl.close(); onClose(remember.get()); },
 | 
			
		||||
      }),
 | 
			
		||||
      content,
 | 
			
		||||
      cssButtons(
 | 
			
		||||
        dom.style('margin-top', '12px'),
 | 
			
		||||
        dom.style('justify-content', 'right'),
 | 
			
		||||
        basicButton('Close', testId('confirm-cancel'), dom.on('click', () => ctl.close()))
 | 
			
		||||
        dom.style('justify-content', 'space-between'),
 | 
			
		||||
        dom.style('align-items', 'center'),
 | 
			
		||||
        dom('div',
 | 
			
		||||
          labeledSquareCheckbox(remember, "Don't show again.", testId('confirm-remember')),
 | 
			
		||||
        ),
 | 
			
		||||
        basicButton('Dismiss', testId('confirm-save'),
 | 
			
		||||
          dom.on('click', () => { ctl.close(); onClose(remember.get()); })
 | 
			
		||||
        )
 | 
			
		||||
      ),
 | 
			
		||||
    )
 | 
			
		||||
  );
 | 
			
		||||
@ -133,7 +141,7 @@ const cssButtons = styled('div', `
 | 
			
		||||
`);
 | 
			
		||||
 | 
			
		||||
const cssContainer = styled(cssTheme, `
 | 
			
		||||
  max-width: 210px;
 | 
			
		||||
  max-width: 270px;
 | 
			
		||||
`);
 | 
			
		||||
 | 
			
		||||
const cssWideContainer = styled(cssTheme, `
 | 
			
		||||
 | 
			
		||||
@ -9,6 +9,7 @@ import {waitGrainObs} from 'app/common/gutil';
 | 
			
		||||
import {IOpenController, IPopupDomCreator, IPopupOptions, PopupControl, popupOpen} from 'popweasel';
 | 
			
		||||
import {Computed, Disposable, dom, DomContents, DomElementArg, input, keyframes,
 | 
			
		||||
  MultiHolder, Observable, styled} from 'grainjs';
 | 
			
		||||
import {cssMenuElem} from 'app/client/ui2018/menus';
 | 
			
		||||
 | 
			
		||||
// IModalControl is passed into the function creating the body of the modal.
 | 
			
		||||
export interface IModalControl {
 | 
			
		||||
@ -492,11 +493,10 @@ export function modalTooltip(
 | 
			
		||||
 | 
			
		||||
/* CSS styled components */
 | 
			
		||||
 | 
			
		||||
const cssModalTooltip = styled('div', `
 | 
			
		||||
  padding: 16px;
 | 
			
		||||
const cssModalTooltip = styled(cssMenuElem, `
 | 
			
		||||
  padding: 16px 24px;
 | 
			
		||||
  background: ${theme.modalBg};
 | 
			
		||||
  border-radius: 3px;
 | 
			
		||||
  box-shadow: 0 2px 18px 0 ${theme.modalInnerShadow}, 0 0 1px 0 ${theme.modalOuterShadow};
 | 
			
		||||
  outline: none;
 | 
			
		||||
  & > div {
 | 
			
		||||
    outline: none;
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user