]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-12886 Update LTS handling in static documentation
authorWouter Admiraal <wouter.admiraal@sonarsource.com>
Thu, 2 Jan 2020 14:20:29 +0000 (15:20 +0100)
committerSonarTech <sonartech@sonarsource.com>
Wed, 8 Jan 2020 19:46:11 +0000 (20:46 +0100)
server/sonar-docs/src/@types/types.d.ts
server/sonar-docs/src/components/Sidebar.tsx
server/sonar-docs/src/components/VersionSelect.tsx
server/sonar-docs/src/components/__tests__/Sidebar-test.tsx
server/sonar-docs/src/components/__tests__/VersionSelect-test.tsx [new file with mode: 0644]
server/sonar-docs/src/components/__tests__/__snapshots__/Sidebar-test.tsx.snap
server/sonar-docs/src/components/__tests__/__snapshots__/VersionSelect-test.tsx.snap [new file with mode: 0644]
server/sonar-docs/src/layouts/layout.css
server/sonar-docs/static/DocsVersions.json

index a4a11275bbbe994f426e6b95b3bac02b00fe8a6c..b27e9f9f0295556dba75fb325919eddb3ba09b90 100644 (file)
@@ -21,6 +21,7 @@ export type Dict<T> = { [key: string]: T };
 
 export interface DocVersion {
   current: boolean;
+  lts?: boolean;
   value: string;
 }
 
index 309206dfd3a719e55522d931e82ecc1f549e9bf7..c27bd513186bb31670061fa06da05c75011c66b5 100644 (file)
@@ -165,10 +165,16 @@ export default class Sidebar extends React.PureComponent<Props, State> {
 
   render() {
     const { versions } = this.state;
+    const { version } = this.props;
+
     const currentVersion = versions.find(v => v.current);
+    const ltsVersion = versions.find(v => v.lts);
+
     const selectedVersionValue =
-      currentVersion && this.props.version === 'latest' ? currentVersion.value : this.props.version;
+      currentVersion && version === 'latest' ? currentVersion.value : version;
     const isOnCurrentVersion = !currentVersion || selectedVersionValue === currentVersion.value;
+    const isOnLTSVersion = ltsVersion && version === ltsVersion.value;
+
     return (
       <div className="page-sidebar">
         <div className="sidebar-header">
@@ -176,7 +182,7 @@ export default class Sidebar extends React.PureComponent<Props, State> {
             <img
               alt="Continuous Code Quality"
               className="sidebar-logo"
-              src={`/${this.props.version}/images/SonarQubeIcon.svg`}
+              src={`/${version}/images/SonarQubeIcon.svg`}
               title="Continuous Code Quality"
               width="160"
             />
@@ -186,11 +192,10 @@ export default class Sidebar extends React.PureComponent<Props, State> {
             selectedVersionValue={selectedVersionValue}
             versions={versions}
           />
-          {this.state.loaded && !isOnCurrentVersion && (
+          {this.state.loaded && !isOnCurrentVersion && !isOnLTSVersion && (
             <div className="alert alert-warning">
-              This is an archived version of the doc for{' '}
-              <b>SonarQube version {this.props.version}</b>. <a href="/">See Documentation</a> for
-              current functionnality.
+              This is an archived version of the doc for <b>SonarQube version {version}</b>.{' '}
+              <a href="/">See Documentation</a> for current functionnality.
             </div>
           )}
         </div>
@@ -207,21 +212,21 @@ export default class Sidebar extends React.PureComponent<Props, State> {
             <DownloadIcon /> SonarQube
           </a>
           <a href="https://community.sonarsource.com/" rel="noopener noreferrer" target="_blank">
-            <img alt="Community" src={`/${this.props.version}/images/community.svg`} /> Community
+            <img alt="Community" src={`/${version}/images/community.svg`} /> Community
           </a>
           <a
             className="icon-only"
             href="https://twitter.com/SonarQube"
             rel="noopener noreferrer"
             target="_blank">
-            <img alt="Twitter" src={`/${this.props.version}/images/twitter.svg`} />
+            <img alt="Twitter" src={`/${version}/images/twitter.svg`} />
           </a>
           <a
             className="icon-only"
             href="https://www.sonarqube.org/whats-new/"
             rel="noopener noreferrer"
             target="_blank">
-            <img alt="Product News" src={`/${this.props.version}/images/newspaper.svg`} />
+            <img alt="Product News" src={`/${version}/images/newspaper.svg`} />
             <span className="tooltip">Product News</span>
           </a>
         </div>
index 15ec735b8ad9b1b293f48780ac8401c534f1eb54..3f9f61ccfcafce3ed57611936036fa917ca2ad00 100644 (file)
@@ -62,7 +62,9 @@ export default class VersionSelect extends React.PureComponent<Props, State> {
                 return (
                   <li key={version.value}>
                     <a href={version.current ? '/' : '/' + version.value}>
-                      <span className={version.current ? 'current' : ''}>{version.value}</span>
+                      <span className={version.current || version.lts ? 'current' : ''}>
+                        {version.value + (version.lts ? ' LTS' : '')}
+                      </span>
                     </a>
                   </li>
                 );
index 4ea1e61dcb2fda503fdecf25cb5285501425ac17..0bc43821e0dd5532e9211982a8252b3151a70d27 100644 (file)
@@ -59,18 +59,23 @@ jest.mock('../navTreeUtils', () => {
 beforeEach(() => {
   (fetch as FetchMock).resetMocks();
   (fetch as FetchMock).mockResponse(`[
-    { "value": "2.0", "current": true },
+    { "value": "3.0", "current": true },
+    { "value": "2.0", "current": false, "lts": true },
     { "value": "1.0", "current": false }
   ]`);
 });
 
-it('should render correctly', () => {
+it('should render correctly', async () => {
   const wrapper = shallowRender();
-  expect(wrapper).toMatchSnapshot();
+  await new Promise(setImmediate);
+
+  expect(wrapper).toMatchSnapshot('default');
+  expect(wrapper.setProps({ version: '1.0' })).toMatchSnapshot('show warning');
+  expect(wrapper.setProps({ version: '2.0' })).toMatchSnapshot('lts');
 });
 
 function shallowRender(props: Partial<Sidebar['props']> = {}) {
-  return shallow(
+  return shallow<Sidebar>(
     <Sidebar
       location={{ pathname: '/2.0/foo/baz/foo/bar' } as Location}
       pages={[
@@ -99,7 +104,7 @@ function shallowRender(props: Partial<Sidebar['props']> = {}) {
           }
         } as MarkdownRemark
       ]}
-      version="2.0"
+      version="3.0"
       {...props}
     />
   );
diff --git a/server/sonar-docs/src/components/__tests__/VersionSelect-test.tsx b/server/sonar-docs/src/components/__tests__/VersionSelect-test.tsx
new file mode 100644 (file)
index 0000000..a0fef76
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2020 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import { shallow } from 'enzyme';
+import * as React from 'react';
+import { click } from 'sonar-ui-common/helpers/testUtils';
+import OutsideClickHandler from '../OutsideClickHandler';
+import VersionSelect from '../VersionSelect';
+
+it('should render correctly', () => {
+  expect(shallowRender()).toMatchSnapshot('default');
+
+  const wrapper = shallowRender();
+  wrapper.setState({ open: true });
+  expect(wrapper).toMatchSnapshot('open');
+
+  expect(shallowRender({ isOnCurrentVersion: true })).toMatchSnapshot('on current version');
+});
+
+it('should handle open/closing the list', () => {
+  const wrapper = shallowRender();
+
+  click(wrapper.find('button'));
+  expect(wrapper.state().open).toBe(true);
+  click(wrapper.find('button'));
+  expect(wrapper.state().open).toBe(false);
+
+  wrapper.setState({ open: true });
+  wrapper.find(OutsideClickHandler).prop('onClickOutside')();
+  expect(wrapper.state().open).toBe(false);
+});
+
+function shallowRender(props: Partial<VersionSelect['props']> = {}) {
+  return shallow<VersionSelect>(
+    <VersionSelect
+      isOnCurrentVersion={false}
+      selectedVersionValue="1.0"
+      versions={[
+        { value: '3.0', current: true },
+        { value: '2.0', current: false, lts: true },
+        { value: '1.0', current: false }
+      ]}
+      {...props}
+    />
+  );
+}
index 5a05f9b2671be08c31a449facab8fc47642f06dc..0fec9f778a070615fdb64380f24c7f6ce838865a 100644 (file)
@@ -1,6 +1,6 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
-exports[`should render correctly 1`] = `
+exports[`should render correctly: default 1`] = `
 <div
   className="page-sidebar"
 >
@@ -13,15 +13,294 @@ exports[`should render correctly 1`] = `
       <img
         alt="Continuous Code Quality"
         className="sidebar-logo"
-        src="/2.0/images/SonarQubeIcon.svg"
+        src="/3.0/images/SonarQubeIcon.svg"
         title="Continuous Code Quality"
         width="160"
       />
     </ForwardRef>
     <VersionSelect
       isOnCurrentVersion={true}
+      selectedVersionValue="3.0"
+      versions={
+        Array [
+          Object {
+            "current": true,
+            "value": "3.0",
+          },
+          Object {
+            "current": false,
+            "lts": true,
+            "value": "2.0",
+          },
+          Object {
+            "current": false,
+            "value": "1.0",
+          },
+        ]
+      }
+    />
+  </div>
+  <div
+    className="page-indexes"
+  >
+    <Search
+      navigation={
+        Array [
+          "/foo/",
+          Object {
+            "children": Array [
+              "/foo/bar/",
+              "/foo/baz/",
+              Object {
+                "children": Array [
+                  "/foo/baz/bar/",
+                  "/foo/baz/foo/",
+                  Object {
+                    "children": Array [
+                      "/foo/baz/foo/bar/",
+                      "/foo/baz/foo/baz",
+                    ],
+                    "title": "Foo Baz Foo subs",
+                  },
+                ],
+                "title": "Foo Baz subs",
+              },
+            ],
+            "title": "Foo subs",
+          },
+          "/bar/",
+          Object {
+            "children": Array [
+              Object {
+                "title": "External link 1",
+                "url": "http://example.com/1",
+              },
+              "/bar/foo/",
+            ],
+            "title": "Bar subs",
+          },
+          Object {
+            "title": "External link 2",
+            "url": "http://example.com/2",
+          },
+        ]
+      }
+      onResultsChange={[Function]}
+      pages={
+        Array [
+          Object {
+            "fields": Object {
+              "slug": "/foo/",
+            },
+            "frontmatter": Object {
+              "title": "Foo",
+            },
+          },
+          Object {
+            "fields": Object {
+              "slug": "/foo/baz/bar",
+            },
+            "frontmatter": Object {
+              "title": "Foo Baz Bar",
+            },
+          },
+          Object {
+            "fields": Object {
+              "slug": "/bar/",
+            },
+            "frontmatter": Object {
+              "title": "Bar",
+            },
+          },
+        ]
+      }
+    />
+    <nav>
+      <PageLink
+        className="page-indexes-link"
+        key="/foo/"
+        location={
+          Object {
+            "pathname": "/2.0/foo/baz/foo/bar",
+          }
+        }
+        node={
+          Object {
+            "fields": Object {
+              "slug": "/foo/",
+            },
+            "frontmatter": Object {
+              "title": "Foo",
+            },
+          }
+        }
+      />
+      <CategoryLink
+        key="Foo subs"
+        location={
+          Object {
+            "pathname": "/2.0/foo/baz/foo/bar",
+          }
+        }
+        openByDefault={true}
+        title="Foo subs"
+      >
+        <CategoryLink
+          key="Foo Baz subs"
+          location={
+            Object {
+              "pathname": "/2.0/foo/baz/foo/bar",
+            }
+          }
+          openByDefault={true}
+          title="Foo Baz subs"
+        >
+          <Component />
+          <CategoryLink
+            key="Foo Baz Foo subs"
+            location={
+              Object {
+                "pathname": "/2.0/foo/baz/foo/bar",
+              }
+            }
+            openByDefault={true}
+            title="Foo Baz Foo subs"
+          />
+        </CategoryLink>
+      </CategoryLink>
+      <PageLink
+        className="page-indexes-link"
+        key="/bar/"
+        location={
+          Object {
+            "pathname": "/2.0/foo/baz/foo/bar",
+          }
+        }
+        node={
+          Object {
+            "fields": Object {
+              "slug": "/bar/",
+            },
+            "frontmatter": Object {
+              "title": "Bar",
+            },
+          }
+        }
+      />
+      <CategoryLink
+        key="Bar subs"
+        location={
+          Object {
+            "pathname": "/2.0/foo/baz/foo/bar",
+          }
+        }
+        openByDefault={false}
+        title="Bar subs"
+      >
+        <ExternalLink
+          external="http://example.com/1"
+          key="External link 1"
+          title="External link 1"
+        />
+      </CategoryLink>
+      <ExternalLink
+        external="http://example.com/2"
+        key="External link 2"
+        title="External link 2"
+      />
+    </nav>
+  </div>
+  <div
+    className="sidebar-footer"
+  >
+    <a
+      href="https://www.sonarqube.org/"
+      rel="noopener noreferrer"
+      target="_blank"
+    >
+      <DownloadIcon />
+       SonarQube
+    </a>
+    <a
+      href="https://community.sonarsource.com/"
+      rel="noopener noreferrer"
+      target="_blank"
+    >
+      <img
+        alt="Community"
+        src="/3.0/images/community.svg"
+      />
+       Community
+    </a>
+    <a
+      className="icon-only"
+      href="https://twitter.com/SonarQube"
+      rel="noopener noreferrer"
+      target="_blank"
+    >
+      <img
+        alt="Twitter"
+        src="/3.0/images/twitter.svg"
+      />
+    </a>
+    <a
+      className="icon-only"
+      href="https://www.sonarqube.org/whats-new/"
+      rel="noopener noreferrer"
+      target="_blank"
+    >
+      <img
+        alt="Product News"
+        src="/3.0/images/newspaper.svg"
+      />
+      <span
+        className="tooltip"
+      >
+        Product News
+      </span>
+    </a>
+  </div>
+</div>
+`;
+
+exports[`should render correctly: lts 1`] = `
+<div
+  className="page-sidebar"
+>
+  <div
+    className="sidebar-header"
+  >
+    <ForwardRef
+      to="/"
+    >
+      <img
+        alt="Continuous Code Quality"
+        className="sidebar-logo"
+        src="/2.0/images/SonarQubeIcon.svg"
+        title="Continuous Code Quality"
+        width="160"
+      />
+    </ForwardRef>
+    <VersionSelect
+      isOnCurrentVersion={false}
       selectedVersionValue="2.0"
-      versions={Array []}
+      versions={
+        Array [
+          Object {
+            "current": true,
+            "value": "3.0",
+          },
+          Object {
+            "current": false,
+            "lts": true,
+            "value": "2.0",
+          },
+          Object {
+            "current": false,
+            "value": "1.0",
+          },
+        ]
+      }
     />
   </div>
   <div
@@ -246,3 +525,283 @@ exports[`should render correctly 1`] = `
   </div>
 </div>
 `;
+
+exports[`should render correctly: show warning 1`] = `
+<div
+  className="page-sidebar"
+>
+  <div
+    className="sidebar-header"
+  >
+    <ForwardRef
+      to="/"
+    >
+      <img
+        alt="Continuous Code Quality"
+        className="sidebar-logo"
+        src="/1.0/images/SonarQubeIcon.svg"
+        title="Continuous Code Quality"
+        width="160"
+      />
+    </ForwardRef>
+    <VersionSelect
+      isOnCurrentVersion={false}
+      selectedVersionValue="1.0"
+      versions={
+        Array [
+          Object {
+            "current": true,
+            "value": "3.0",
+          },
+          Object {
+            "current": false,
+            "lts": true,
+            "value": "2.0",
+          },
+          Object {
+            "current": false,
+            "value": "1.0",
+          },
+        ]
+      }
+    />
+    <div
+      className="alert alert-warning"
+    >
+      This is an archived version of the doc for 
+      <b>
+        SonarQube version 
+        1.0
+      </b>
+      .
+       
+      <a
+        href="/"
+      >
+        See Documentation
+      </a>
+       for current functionnality.
+    </div>
+  </div>
+  <div
+    className="page-indexes"
+  >
+    <Search
+      navigation={
+        Array [
+          "/foo/",
+          Object {
+            "children": Array [
+              "/foo/bar/",
+              "/foo/baz/",
+              Object {
+                "children": Array [
+                  "/foo/baz/bar/",
+                  "/foo/baz/foo/",
+                  Object {
+                    "children": Array [
+                      "/foo/baz/foo/bar/",
+                      "/foo/baz/foo/baz",
+                    ],
+                    "title": "Foo Baz Foo subs",
+                  },
+                ],
+                "title": "Foo Baz subs",
+              },
+            ],
+            "title": "Foo subs",
+          },
+          "/bar/",
+          Object {
+            "children": Array [
+              Object {
+                "title": "External link 1",
+                "url": "http://example.com/1",
+              },
+              "/bar/foo/",
+            ],
+            "title": "Bar subs",
+          },
+          Object {
+            "title": "External link 2",
+            "url": "http://example.com/2",
+          },
+        ]
+      }
+      onResultsChange={[Function]}
+      pages={
+        Array [
+          Object {
+            "fields": Object {
+              "slug": "/foo/",
+            },
+            "frontmatter": Object {
+              "title": "Foo",
+            },
+          },
+          Object {
+            "fields": Object {
+              "slug": "/foo/baz/bar",
+            },
+            "frontmatter": Object {
+              "title": "Foo Baz Bar",
+            },
+          },
+          Object {
+            "fields": Object {
+              "slug": "/bar/",
+            },
+            "frontmatter": Object {
+              "title": "Bar",
+            },
+          },
+        ]
+      }
+    />
+    <nav>
+      <PageLink
+        className="page-indexes-link"
+        key="/foo/"
+        location={
+          Object {
+            "pathname": "/2.0/foo/baz/foo/bar",
+          }
+        }
+        node={
+          Object {
+            "fields": Object {
+              "slug": "/foo/",
+            },
+            "frontmatter": Object {
+              "title": "Foo",
+            },
+          }
+        }
+      />
+      <CategoryLink
+        key="Foo subs"
+        location={
+          Object {
+            "pathname": "/2.0/foo/baz/foo/bar",
+          }
+        }
+        openByDefault={true}
+        title="Foo subs"
+      >
+        <CategoryLink
+          key="Foo Baz subs"
+          location={
+            Object {
+              "pathname": "/2.0/foo/baz/foo/bar",
+            }
+          }
+          openByDefault={true}
+          title="Foo Baz subs"
+        >
+          <Component />
+          <CategoryLink
+            key="Foo Baz Foo subs"
+            location={
+              Object {
+                "pathname": "/2.0/foo/baz/foo/bar",
+              }
+            }
+            openByDefault={true}
+            title="Foo Baz Foo subs"
+          />
+        </CategoryLink>
+      </CategoryLink>
+      <PageLink
+        className="page-indexes-link"
+        key="/bar/"
+        location={
+          Object {
+            "pathname": "/2.0/foo/baz/foo/bar",
+          }
+        }
+        node={
+          Object {
+            "fields": Object {
+              "slug": "/bar/",
+            },
+            "frontmatter": Object {
+              "title": "Bar",
+            },
+          }
+        }
+      />
+      <CategoryLink
+        key="Bar subs"
+        location={
+          Object {
+            "pathname": "/2.0/foo/baz/foo/bar",
+          }
+        }
+        openByDefault={false}
+        title="Bar subs"
+      >
+        <ExternalLink
+          external="http://example.com/1"
+          key="External link 1"
+          title="External link 1"
+        />
+      </CategoryLink>
+      <ExternalLink
+        external="http://example.com/2"
+        key="External link 2"
+        title="External link 2"
+      />
+    </nav>
+  </div>
+  <div
+    className="sidebar-footer"
+  >
+    <a
+      href="https://www.sonarqube.org/"
+      rel="noopener noreferrer"
+      target="_blank"
+    >
+      <DownloadIcon />
+       SonarQube
+    </a>
+    <a
+      href="https://community.sonarsource.com/"
+      rel="noopener noreferrer"
+      target="_blank"
+    >
+      <img
+        alt="Community"
+        src="/1.0/images/community.svg"
+      />
+       Community
+    </a>
+    <a
+      className="icon-only"
+      href="https://twitter.com/SonarQube"
+      rel="noopener noreferrer"
+      target="_blank"
+    >
+      <img
+        alt="Twitter"
+        src="/1.0/images/twitter.svg"
+      />
+    </a>
+    <a
+      className="icon-only"
+      href="https://www.sonarqube.org/whats-new/"
+      rel="noopener noreferrer"
+      target="_blank"
+    >
+      <img
+        alt="Product News"
+        src="/1.0/images/newspaper.svg"
+      />
+      <span
+        className="tooltip"
+      >
+        Product News
+      </span>
+    </a>
+  </div>
+</div>
+`;
diff --git a/server/sonar-docs/src/components/__tests__/__snapshots__/VersionSelect-test.tsx.snap b/server/sonar-docs/src/components/__tests__/__snapshots__/VersionSelect-test.tsx.snap
new file mode 100644 (file)
index 0000000..b91c29e
--- /dev/null
@@ -0,0 +1,109 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly: default 1`] = `
+<div
+  className="version-select"
+>
+  <button
+    onClick={[Function]}
+    type="button"
+  >
+    Docs 
+    <span
+      className=""
+    >
+      1.0
+    </span>
+    <ChevronDownIcon
+      size={10}
+    />
+  </button>
+</div>
+`;
+
+exports[`should render correctly: on current version 1`] = `
+<div
+  className="version-select"
+>
+  <button
+    onClick={[Function]}
+    type="button"
+  >
+    Docs 
+    <span
+      className="current"
+    >
+      1.0
+    </span>
+    <ChevronDownIcon
+      size={10}
+    />
+  </button>
+</div>
+`;
+
+exports[`should render correctly: open 1`] = `
+<div
+  className="version-select"
+>
+  <button
+    onClick={[Function]}
+    type="button"
+  >
+    Docs 
+    <span
+      className=""
+    >
+      1.0
+    </span>
+    <ChevronUpIcon
+      size={10}
+    />
+  </button>
+  <OutsideClickHandler
+    onClickOutside={[Function]}
+  >
+    <ul>
+      <li
+        key="3.0"
+      >
+        <a
+          href="/"
+        >
+          <span
+            className="current"
+          >
+            3.0
+          </span>
+        </a>
+      </li>
+      <li
+        key="2.0"
+      >
+        <a
+          href="/2.0"
+        >
+          <span
+            className="current"
+          >
+            2.0 LTS
+          </span>
+        </a>
+      </li>
+      <li
+        key="1.0"
+      >
+        <a
+          href="/1.0"
+        >
+          <span
+            className=""
+          >
+            1.0
+          </span>
+        </a>
+      </li>
+    </ul>
+  </OutsideClickHandler>
+</div>
+`;
index 25d06883f9fdab2702b8883a27fe4ac35307c90b..6696f42a55d68a398b2970935eae9f4207de5b0f 100644 (file)
@@ -493,8 +493,9 @@ a.search-result .note {
   font-size: 15px;
   margin: 0;
   padding: 4px 16px;
-  text-align: center;
+  text-align: left;
   transition: all 0.2s ease;
+  white-space: nowrap;
 }
 
 .version-select ul li:hover {
index 19772b03b16f9851f747d8549314b01fdd2a47b7..501eab58d1eae270380771aeec3ca56be370f8ab 100644 (file)
@@ -1,6 +1,6 @@
 [
   { "value": "7.3", "current": true },
   { "value": "7.2", "current": false },
-  { "value": "7.1", "current": false },
+  { "value": "7.1", "current": false, "lts": true },
   { "value": "7.0", "current": false }
 ]