Atlaskit Modal Dialog in Server Environment

Hi Everyone,

We have some issues using the Atlaskit Modal Dialog in a server environment and maybe someone else had these issues. Maybe there is a documented way around it that I didn’t found yet.

  • Atlaskit Modal Dialog will not disable keyboard events (e.g. j/k navigation, edit mask)
  • Attach File to issue is still active with an open Dialog
  • as the atlaskit dialog has a fixed z-index of 510 it is behind many atlassian dialogs (e.g. edit issue) as they have a z-index of around 3000
1 Like

Hi @m.herrmann,

I don’t have a clear answer for making the z-indexes for Atlaskit, AUI, and Jira modals work together, unfortunately.

As for the keyboard shortcuts, you could disable Jira shortcuts while your modal is open. Assuming you’re keeping track of the open state of your modal with component state, the solution might look like the following:

import React, { useState, useEffect } from 'react';
import Modal from '@atlaskit/modal-dialog';

const MyApp = () => {
  const [modalOpen, setModalOpen] = useState(false);
  
  useEffect(() => {
    // create a function that returns true if the modal is open.
    const isModalOpen = () => modalOpen;
    // this will register a function that's checked before executing all keyboard shortcuts.
    // if any of these function returns `true`, the shortcut will not be executed.
    // be sure to add a web-resource dependency on `jira.webresources:key-commands`
    // to guarantee this global variable exists before your code runs!
    AJS.KeyboardShortcuts.addIgnoreCondition(isModalOpen);
    // if your component is removed, ensure you don't accidentally disable keyboard shortcuts forever!
    return () => setModalOpen(false);
  });

  return (
    <>
      {modalOpen && <Modal ... />}
    </>
  );
}

Hope that helps!

Cheers,
Daz

5 Likes

Hi @daz ,

Thanks for the example code and your effort to document it to this extend.
My current workaround work something like this:

import React, { useEffect, useState, useCallback } from 'react';
import Modal from '@atlaskit/modal-dialog';
import Button from '@atlaskit/button';

export const TestModal = () => {
	const [modalOpen, setModalOpen] = useState(false);

	useEffect(() => {
		// create a function that returns true if the modal is open.
		const isModalOpen = () => modalOpen;
		// this will register a function that's checked before executing all keyboard shortcuts.
		// if any of these function returns `true`, the shortcut will not be executed.
		// be sure to add a web-resource dependency on `jira.webresources:key-commands`
		// to guarantee this global variable exists before your code runs!
		AJS.KeyboardShortcut.addIgnoreCondition(isModalOpen);
		// if your component is removed, ensure you don't accidentally disable keyboard shortcuts forever!
		return () => setModalOpen(false);
	}, []);
	const zIndexParentFixRef = useCallback((node) => {
		// check if reference node is an existing html element
		if (node === null || !(node instanceof HTMLElement)) {
			return;
		}
		// get the parent element with the atlaskit-portal css class.
		// this is where the z-index should be modified in the current version,
		// which is not stable and may change in the future
		const atlasKitPortalParent = node.closest('.atlaskit-portal');
		if (!atlasKitPortalParent || !(atlasKitPortalParent instanceof HTMLElement)) {
			return;
		}
		// set z-index to a higher value than the default edit issue dialog
		atlasKitPortalParent.style.zIndex = '3100';
	}, []);

	return (
		<>
			<Button appearance="primary" onClick={() => setModalOpen(true)}>
				Open modal
			</Button>
			{modalOpen && (
				<Modal onClose={() => setModalOpen(false)}>
					<div ref={zIndexParentFixRef}>This is some Modal content</div>
				</Modal>
			)}
		</>
	);
};

As soon as the div inside the modal is rendered, it will use the callback reference to find the atlaskit parent with the z-index and set it to a new value.
Maybe this will help someone who has the same issue.

Hey @m.herrmann ,

thank you for sharing your solution to that problem. We encountered the same problem when using Atlaskit components inside a Confluence macro editor. To give users the usual look and feel of the dialog itself, we use a normal AJS.dialog2 and render our React form inside of that dialog.

To make Atlaskit selects etc work, we added this nasty bit of code to where we open the dialog:

let portalFixerIntervalId = setInterval(()=>{
          if ($(".atlaskit-portal-container").length < 1) return;
          $(".atlaskit-portal-container").css({zIndex: 5000, position: "relative"});
          clearInterval(portalFixerIntervalId);
        }, 250);

It waits for the first use of a portal and then bumps the z-index of the (reused) atlaskit-portal-container wrapping all portals. It’s so dirty it feels like I need to shower after doing that, but it fixes the problem without cluttering our cross-platform components with workaround-effects.

1 Like

Hello, @daz @m.herrmann !

Can you help me with this point?

How add web-resource dependency for webpack config?

Trying something like this, but it is not working:

 new WrmPlugin({
            pluginKey: 'key',
            contextMap: {
                'key': ['atl.general']
            },
            providedDependencies: {
                'jira.webresources:key-commands': {
                    dependency: 'jira.webresources:key-commands',
                    import: 'jira.webresources:key-commands'
                }
            },
            locationPrefix: ...,
            watch : ...,
            xmlDescriptors: path.resolve(..., 'wr-defs.xml')
        }),

Hi,

I haven’t tried to do it using the WrmPlugin. We currently have a web resource defined in out atlassian-plugin xml, which have the dependencies for the app like this

<web-resource key="our-vendor-app-key-iframe" name="some-vendor-key-iframe">
		<dependency>jira.webresources:almond</dependency>
		<dependency>com.atlassian.auiplugin:ajs</dependency>
		<dependency>jira.webresources:jira-global</dependency>
		<dependency>jira.webresources:momentjs</dependency>
		<dependency>our.vendor.app.key:entrypoint-main</dependency>
	</web-resource>
1 Like

And how you import, or declare AJS in your code?

In my case (using modal with issue create screen), shortcuts still works(

AJS should be available without an import, with the exception of iframes / servlets without the atlassian header.
We defined an AJS Type ourself for the functions we need to use, but it seems that now there is a npm package for it from seibert media.

But as far as I know there is nothing official from atlassian

1 Like

@m.herrmann thank you!

And how about disabling AJS shortcuts? Does this code works for you?

	useEffect(() => {
		// create a function that returns true if the modal is open.
		const isModalOpen = () => modalOpen;
		// this will register a function that's checked before executing all keyboard shortcuts.
		// if any of these function returns `true`, the shortcut will not be executed.
		// be sure to add a web-resource dependency on `jira.webresources:key-commands`
		// to guarantee this global variable exists before your code runs!
		AJS.KeyboardShortcut.addIgnoreCondition(isModalOpen);
		// if your component is removed, ensure you don't accidentally disable keyboard shortcuts forever!
		return () => setModalOpen(false);
	}, []);

In my case (modal on issue create screen), shortcuts still working, and “Esc” for example closes issue create screen at first button press (at second – closes modal window)

I think “Esc” is a special case not related to the keyboard shortcuts as it’s handled by the create issue modal.
Maybe registering an event handler for escape will work with something like stopPropagation, but I’m not sure about the order. If that is not working, you may need to look into the Jira Source Code (from the atlassian account that bought at least one jira license) to check if there is another way.
It’s possible that the Modal Dialog Object for the Create Issue Dialog is somewhere in window.JIRA and may have a property / function to temporary disable the key handler.

1 Like