diff --git a/lib/cql/index.html b/lib/cql/index.html index 40b980b..b0c7b0e 100644 --- a/lib/cql/index.html +++ b/lib/cql/index.html @@ -23,9 +23,8 @@ } body { - max-width: 1280px; margin: 0 auto; - padding: 2rem; + padding: 1rem; } /* @@ -89,7 +88,7 @@ /* End reset */ #cql-input-container { - margin: 10px 0; + margin: 0 0 20px 0; border-radius: 5px; background-color: #333; } @@ -99,6 +98,10 @@ align-items: center; } + .Page__header h1 { + margin-top: 0; + } + .Page__repo-link { display: flex; align-items: center; @@ -106,6 +109,35 @@ margin-left: auto; } + .Page__InputLayout { + display: flex; + gap: 20px; + } + + .Page__InputDebug { + border: 2px solid #333; + padding: 10px; + border-radius: 5px; + flex-basis: 50%; + min-width: 0; + overflow-x: scroll; + } + + .Page__InputContent { + flex-basis: 50%; + } + + .Page__Config { + display: flex; + flex-direction: column; + gap: 10px; + } + + .Page__Config input, + .Page__Config select { + min-width: 300px; + } + .Page__repo-link:visited { color: #ccc; } @@ -231,10 +263,6 @@ display: flex; } - .CqlSandbox { - margin-top: 30px; - } - .CqlSandbox__query-results { display: flex; } @@ -243,6 +271,10 @@ flex-grow: 1; } + .CqlSandbox__query-results h2 { + margin-top: 0; + } + input { position: relative; padding: 5px; @@ -366,7 +398,9 @@ outline: none; } - .CqlToken__STRING, .CqlToken__PLUS, .CqlToken__MINUS { + .CqlToken__STRING, + .CqlToken__PLUS, + .CqlToken__MINUS { color: lightblue; } @@ -410,264 +444,75 @@

Rich query sandbox

-
- - -
-
- -
-
-

Press + to select a specific field to search.

-

- Join search terms with OR and - AND. Consecutive search terms, e.g. - this that, are implicitly joined with - OR. -

-

- Group expressions with parenthesis, e.g. - one (two - AND three) -

-
- -
-
-
-
-

CQL

-
+
+
+
+
-
-

API query

-
+
+

Press + to select a specific field to search.

+

+ Join search terms with OR and + AND. Consecutive search terms, e.g. + this that, are implicitly joined + with OR. +

+

+ Group expressions with parenthesis, e.g. + one (two + AND three) +

+ +

Config

+
+
+ +
+
+ +
+
+ +
-

Config

-
- +
+
+
+

CQL

+
+
+
+

API query

+
+
+
-

Todos

-
    -
  • Scanning
  • -
  • Parsing
  • -
  • Query string builder
  • -
  • Add group and binary syntax
  • -
  • String ranges in scanned tokens
  • -
  • Parse hints for typeahead
  • -
  • - - ScalaJS to provide parser in web env ScalaJS adds 180kb to - your bundle as the price of entry? Yeah we're not doing that -
  • -
  • - Add a language server for funsies -
  • -
  • - Web component - environment and first - pass at component infra -
  • -
  • - Web component - syntax highlighting -
      -
    • - Ensure untokenised string - components still display, we're getting 500s and invisible - characters on trailing + chars -
    • -
    -
  • -
  • - Web component - typeahead -
      -
    • - First pass at implementation -
    • -
    • - Handle typing on the trailing edge - (off by one) -
    • -
    -
  • -
  • - Web component - async lookup -
      -
    • - Implement async lookup in language - server -
    • -
    • Add loading state
    • -
    -
  • -
  • - Bug: open parentheses crashes the - server 🙃 -
  • -
  • Fix tests
  • -
  • Fix input scrolling
  • -
  • - Bug: fix crash on adding query meta - within parentheses or after binary operators (with useful error state) -
  • -
  • - Add '@' syntax for content - return format (e.g. show-fields) -
      -
    • - Fix issue with incomplete binaries - and output modifiers -
    • -
    -
  • -
  • - Fill out additional fields: -
      -
    • - Dates! -
        -
      • - Add type property - to suggestion envelope to ensure correct interface is displayed - (NB: Circe wraps sealed trait in object with single key as name - of class) -
      • -
      • - Correct focus when date - appears -
      • -
      • - What do we do when users want - to navigate through the string without focus being stolen? - Perhaps we don't need to autofocus? Solution for now: - autofocus on first input, keydown or tab to focus input when - value is already present (to allow user to scrub through dates - unimpeded) -
      • -
      • - Parse to correct format for query -
      • -
      -
    • -
    • Other, less fancy fields
    • -
    -
  • -
  • Fix crash on empty parens
  • -
  • - Fix crash on leading colon when key is - not valid query or output key -
  • -
  • - Move to contenteditable (ProseMirror) - (issues with scrolling in Chrome, e.g. - https://issues.chromium.org/issues/41081857, make syncing scroll state of overlay difficult) -
  • -
  • - Handle keyboard navigation on - typeahead menu -
  • -
  • - Handle selection on typeahead menu - (including clicks) -
  • -
  • - Correctly display typeahead menu when - there's no content in a chip key or value -
  • -
  • Serialise to CQL string on copy
  • -
  • - Deletion pattern for chips on - backspace -
  • -
  • Deletion handle for chips UI
  • -
  • Add good testing story
  • -
  • - 🐛 Suggestions are off by one for - consecutive chips -
  • -
  • Date suggestions
  • -
  • Relative date suggestions as options
  • -
  • Chip polarity
  • -
  • Add typeahead for binaries
  • -
  • - Error handling, with position, when - the query is malformed -
  • -
  • - Error handling for >>399 codes -
  • -
  • - Cursor movement: -
      -
    • - Ctrl-a, Ctrl-e to move to start - and end of doc -
    • -
    • ...
    • -
    -
  • -
  • Display labels, not values, in chips?
  • -
  • - Move language server to client: -
      -
    • Move code and tests
    • -
    -
  • -
  • - Align typeahead interfaces with server, - simplifying structure -
  • -
  • - Accessibility: -
      -
    • ...
    • -
    -
  • -
  • - Telemetry: -
      -
    • Create chip
    • -
    • Autocomplete key, value selection
    • -
    • Remove chip – mouse
    • -
    • Remove chip – backspace
    • -
    • Tab behaviour?
    • -
    • Paste?
    • -
    • ...
    • -
    -
  • -
  • ...
  • -
-

Infra

-
    -
  • Configure CI for lambda
  • -
  • Add handler for lambda
  • -
  • Add CI for static site
  • -
  • Add configuration for CAPI key
  • -
  • ...
  • -
diff --git a/lib/cql/src/cqlInput/editor/utils.spec.ts b/lib/cql/src/cqlInput/editor/utils.spec.ts index a23c660..74f61a3 100644 --- a/lib/cql/src/cqlInput/editor/utils.spec.ts +++ b/lib/cql/src/cqlInput/editor/utils.spec.ts @@ -47,16 +47,19 @@ describe("utils", () => { */ const assertCqlStrPosFromDocPos = async ( query: string, - expectedIndexForQuery: number, getPos: (node: Node) => number, + expectedIndexForQuery: number, ) => { const tokens = queryToProseMirrorTokens(query); - const mapping = createProseMirrorTokenToDocumentMapping(tokens); + const mapping = createProseMirrorTokenToDocumentMapping(tokens).invert(); const node = tokensToDoc(tokens); node.check(); - expect(mapping.map(expectedIndexForQuery)).toBe(getPos(node)); + expect( + mapping.map(getPos(node)), + `Expected ProseMirror document position ${getPos(node)} to map to CQL position ${expectedIndexForQuery} ('${query[expectedIndexForQuery]}')`, + ).toBe(expectedIndexForQuery); }; describe("tokensToDoc", () => { @@ -170,9 +173,7 @@ describe("utils", () => { }); it("should preserve whitespace within values that have whitespace", async () => { - const tokens = queryToProseMirrorTokens( - 'example +key:"1 2" example', - ); + const tokens = queryToProseMirrorTokens('example +key:"1 2" example'); const node = tokensToDoc(tokens); const expected = doc( @@ -279,7 +280,7 @@ describe("utils", () => { }); it("with polarity symbols", async () => { - const text = await getTextFromTokenRanges('+example -example'); + const text = await getTextFromTokenRanges("+example -example"); expect(text).toEqual(["+", "example", "-", "example", ""]); }); @@ -323,11 +324,27 @@ describe("utils", () => { }); it("with selection in an empty chip key", () => { - assertCqlStrPosFromDocPos("+:", 1, node => findNodeAt(0, node, schema.nodes.chipKey) + 1) + assertCqlStrPosFromDocPos( + "+:", + (node) => findNodeAt(0, node, schema.nodes.chipKey) + 1, + 1, + ); }); it("with selection in an empty chip value", () => { - assertCqlStrPosFromDocPos("+a:", 2, node => findNodeAt(0, node, schema.nodes.chipValue) + 1) + assertCqlStrPosFromDocPos( + "+a:", + (node) => findNodeAt(0, node, schema.nodes.chipValue) + 1, + 2, + ); + }); + + it("with selection at the end of a chip value", () => { + assertCqlStrPosFromDocPos( + "+a:b", + (node) => findNodeAt(0, node, schema.nodes.chipValue) + 2, + 4, + ); }); }); });