MauroDataMapper/mdm-ui

Create internal links when editing long text more easily with a shortcut

Closed this issue · 8 comments

A bit like in an IDE where you can press e.g. Ctrl+Space, and start typing, and it will give you suggestions for appropriate content. It would be very handy to be able to do this here, using a Lucene prefix search (a suitable endpoint may need to be created if one doesn't already exist).
See also #417

Related

@jamesrwelch @olliefreeman Is there an endpoint that exists which can act as a quick search for this autocomplete feature?

this is dependent on work on the API branch feature/addtl-search-endpoints

I believe the endpoints required for this are now merged in mdm-core. It feels like to have an autocomplete style search, the following endpoint should be used:

POST /api/catalogueItems/search

{
   "searchTerm": <autocomplete input>,
   "labelOnly" : true,
   "max": 20, // Or some suitable number
   "offset: 0,
   "sort": "label",
   "order": "asc"
}

@olliefreeman - can you confirm if this is correct?

See https://metadatacatalogue.myjetbrains.com/youtrack/issue/MC-9843 for further details on front/back end features.

I've been experimenting with the UI concepts of this "autocomplete" component with Jodit and the markdown editor. My initial thoughts were that this was going to look like an inline, popup-based component that appears as (and where) you type, like this:

image

In fact, Jodit has a plugin just for this: https://xdsoft.net/jodit/pro/docs/plugin/autocomplete. But I'm coming up against a number of issues.

Jodit Pro

The Jodit Autocomplete plugin is for the Pro version of the Jodit editor only. Given the price and restrictions, it is not feasible to use this. Plus, this only affects the Jodit HTML editor, an equivalent would have to be found for the Markdown editor.

Custom Jodit plugin

The next alternative is to write out own version of an autocomplete plugin. There I was faced with new issues:

  1. The type definitions exported by the jodit library end up producing compiler errors, I'm not sure why
  2. I can't seem to access the global Jodit JavaScript object from an Angular component, this is required to add to the plugins list via Jodit.plugins.add().
  3. Again, this would only work with the Jodit HTML editor, not our Markdown editor.

Custom JavaScript UI

The next alternative I thought of was to manually handle input triggers to both the Jodit and Markdown editors, then figure out how to display our own <div> inline popup with a list of eventual search results. This involves:

  1. Identifying the keydown event where the Ctrl+Space key is pressed together
  2. Locating the caret position/co-ordinates of the currently focused input field
  3. Use the co-ordinates to manually set the display of some <div> that was previously hidden, setting the top and left of the div as well for absolute positioning.
  4. Respond to further events to handle re-positioning, hiding the autocomplete, key inputs to send further search requests etc

This is actually incredibly complex (probably why 3rd party controls exist for this kind of thing). In my experiments I could sometimes get the caret position, but sometimes not depending on whitespace. Then handling further interactions would make this a lot of code to maintain.

Simplification

Complex JavaScript and DOM manipulation is a bit outside of my skillset. However, to get something like this working for both the Markdown and HTML editors, the best solution I can think of for now is to follow the existing pattern used by generating links:

image

In the above screenshot, a custom editor toolbar button is used to trigger own own MatDialog containing a small wizard for selecting a model directly from a tree search.

My simplified proposal would be:

  1. Still respond to keyboard events to capture the Ctrl+Space shortcut (or trigger via a custom toolbar button too)
  2. Display a new MatDialog containing the autocomplete search
  3. The dialog would contain a search field. Once enough characters have been entered, a prefix label search will be triggered to show a small number of results (e.g. 10)
  4. Typing in the search field would automatically adjust the search results - no manual button clicks required
  5. Once a result was selected, the details are sent back to the editor to construct a suitable link (HTML or Markdown style) to that item. The editors already do something similar.

Forcing a MatDialog to contain the "autocomplete" would simplify this feature and get something available out sooner. In the future, someone else could then look into updating to be more inline if possible.

@pjmonks Yep, I agree, let's not worry about it appearing at the caret position. If we can ensure it disappears / cancels with an 'esc' key press (I think this is the default behaviour), then that would be lovely.

Endpoints

Reading https://metadatacatalogue.myjetbrains.com/youtrack/issue/MC-9843 and looking at the source code for mdm-core, it seems like this is the endpoint we need for autocomplete search:

Request

POST api/{catalogueItemdomainType}/{cataloguetItemid}/search

{
  "searchTerm": "text",
  "max": 10,
  "offset": 0,
  "sort": null // or label?
  "order": null // or "asc"?
}

Response

{
  "count": 10,
  "items": [
    {
      "id": "1234-5678",
      "label": "item",
      "domainType": "DataModel",
      "breadcrumbs": [...]
    }
  ]
}

Questions

For @jamesrwelch:

This endpoint assumes we know a catalogue item acting as a parent/root for the search, but the content editors could be used in various places where you might not know a suitable parent. Is the intention for this autocomplete to be for descriptions of models? If so, it feels like the autocomplete feature will only work in the scenario of editing a model, so would be an editing feature enabled when a parentModel is passed through an @Input.

@pjmonks I think we'd want it whenever we're editing any model item / catalogue item (Data Element, Data Class, Term, etc). In those cases we'd know the Catalogue Item domain / id, because that would be the thing we'd pass the submission to?
In other cases (API Properties, etc) we could make this functionality unavailable?