@@ -20,7 +20,7 @@ exports[`ClickToCode renders all children 1`] = `
exports[`ClickToCode renders children as code if no code is provided 1`] = `
hellohi!
@@ -30,7 +30,7 @@ exports[`ClickToCode renders children as code if no code is provided 1`] = `
exports[`ClickToCode renders code as the code when code is available 1`] = `
hello
diff --git a/src/browser/modules/GuideCarousel/GuideCarousel.tsx b/src/browser/modules/GuideCarousel/GuideCarousel.tsx
index dab2a198811..408fccfd5bc 100644
--- a/src/browser/modules/GuideCarousel/GuideCarousel.tsx
+++ b/src/browser/modules/GuideCarousel/GuideCarousel.tsx
@@ -25,10 +25,9 @@ import {
GuideNavButton,
GuideUl,
StyledCarousel,
- GuideProgressContainer,
- StyledProgressCount,
- CarouselIndicator
+ GuideProgressContainer
} from '../Sidebar/styled'
+import Pagination from './Pagination'
type GuideCarouselProps = {
slides: JSX.Element[]
@@ -66,32 +65,31 @@ function GuidesCarousel({
const moreThanOneSlide = slides.length > 1
return (
-
+
{moreThanOneSlide && (
-
+
Previous
-
- {`${currentSlideIndex + 1} / ${slides.length}`}
-
- {slides.slice(0, 25).map((_, i) => (
- gotoSlide(i)}
- active={i === currentSlideIndex}
- >
-
-
- ))}
- {slides.length >= 25 && '...'}
+
-
+
Next
diff --git a/src/browser/modules/GuideCarousel/Pagination.test.ts b/src/browser/modules/GuideCarousel/Pagination.test.ts
new file mode 100644
index 00000000000..23cc5bbb1fa
--- /dev/null
+++ b/src/browser/modules/GuideCarousel/Pagination.test.ts
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+import { paginationHelper } from './Pagination'
+
+const D = '...'
+describe('Pagination', () => {
+ test('paginationHelper', () => {
+ // doesn't crash on out of bounds
+ expect(paginationHelper(0, 1)).toEqual([])
+
+ // Handles simple cases
+ expect(paginationHelper(0, 0)).toEqual([])
+ expect(paginationHelper(3, 0)).toEqual([0, 1, 2])
+ expect(paginationHelper(6, 4)).toEqual([0, 1, 2, 3, 4, 5])
+
+ // Same for list of 7 regardless of selection
+ Array.from({ length: 7 }).forEach((_a, i) => {
+ expect(paginationHelper(7, i)).toEqual([0, 1, 2, 3, 4, 5, 6])
+ })
+
+ // Handles all cases length 8
+ expect(paginationHelper(8, 0)).toEqual([0, 1, 2, 3, 4, D, 7])
+ expect(paginationHelper(8, 1)).toEqual([0, 1, 2, 3, 4, D, 7])
+ expect(paginationHelper(8, 2)).toEqual([0, 1, 2, 3, 4, D, 7])
+ expect(paginationHelper(8, 3)).toEqual([0, 1, 2, 3, 4, D, 7])
+ expect(paginationHelper(8, 4)).toEqual([0, D, 3, 4, 5, 6, 7])
+ expect(paginationHelper(8, 5)).toEqual([0, D, 3, 4, 5, 6, 7])
+ expect(paginationHelper(8, 6)).toEqual([0, D, 3, 4, 5, 6, 7])
+ expect(paginationHelper(8, 7)).toEqual([0, D, 3, 4, 5, 6, 7])
+
+ // Handles all cases length 9
+ expect(paginationHelper(9, 0)).toEqual([0, 1, 2, 3, 4, D, 8])
+ expect(paginationHelper(9, 1)).toEqual([0, 1, 2, 3, 4, D, 8])
+ expect(paginationHelper(9, 2)).toEqual([0, 1, 2, 3, 4, D, 8])
+ expect(paginationHelper(9, 3)).toEqual([0, 1, 2, 3, 4, D, 8])
+ expect(paginationHelper(9, 4)).toEqual([0, D, 3, 4, 5, D, 8])
+ expect(paginationHelper(9, 5)).toEqual([0, D, 4, 5, 6, 7, 8])
+ expect(paginationHelper(9, 6)).toEqual([0, D, 4, 5, 6, 7, 8])
+ expect(paginationHelper(9, 7)).toEqual([0, D, 4, 5, 6, 7, 8])
+ expect(paginationHelper(9, 8)).toEqual([0, D, 4, 5, 6, 7, 8])
+ })
+})
diff --git a/src/browser/modules/GuideCarousel/Pagination.tsx b/src/browser/modules/GuideCarousel/Pagination.tsx
new file mode 100644
index 00000000000..2da5848c126
--- /dev/null
+++ b/src/browser/modules/GuideCarousel/Pagination.tsx
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+import React from 'react'
+import { PaginationItem } from './styled'
+type PaginationProps = {
+ gotoIndex: (index: number) => void
+ itemCount: number
+ selectedIndex: number
+}
+const DOTS = '...'
+type DotDotDot = typeof DOTS
+
+const range = (from: number, to: number) =>
+ Array.from({ length: from ? to - from + 1 : to }, (_, i) => i + from)
+
+export function paginationHelper(
+ itemCount: number,
+ selectedIndex: number
+): (number | DotDotDot)[] {
+ /* We aim to always show 7 symbols
+ Pagination example (C denotes current index and D denotes dots)
+ C 2 3 4 5 D 9
+ 1 C 3 4 5 D 9
+ 1 2 C 4 5 D 9
+ 1 2 3 C 5 D 9
+ 1 D 4 C 6 D 9
+ 1 D 5 C 7 8 9
+ 1 D 5 6 C 8 9
+ 1 D 5 6 7 C 9
+ 1 D 5 6 7 8 C
+*/
+ const lastIndex = itemCount - 1
+ const outOfBounds = selectedIndex < 0 || selectedIndex > lastIndex
+ if (outOfBounds) {
+ return []
+ }
+
+ const baseNumbers = range(0, itemCount)
+
+ // no split
+ if (itemCount <= 7) {
+ return baseNumbers
+ }
+
+ // early splits
+ if (selectedIndex < 4) {
+ return [...range(0, 5), DOTS, lastIndex]
+ }
+
+ // late splits
+ const isInlastFiveItems = itemCount - selectedIndex < 5
+ if (isInlastFiveItems) {
+ return [0, DOTS, ...range(itemCount - 5, lastIndex)]
+ }
+
+ // two splits
+ return [
+ 0,
+ DOTS,
+ selectedIndex - 1,
+ selectedIndex,
+ selectedIndex + 1,
+ DOTS,
+ lastIndex
+ ]
+}
+
+function Pagination({
+ gotoIndex,
+ itemCount,
+ selectedIndex
+}: PaginationProps): JSX.Element {
+ return (
+ <>
+ {paginationHelper(itemCount, selectedIndex).map(
+ (slideIndexOrDots, index) => {
+ if (slideIndexOrDots === DOTS) {
+ return …
+ } else {
+ const displayNumber = slideIndexOrDots + 1
+ return (
+ gotoIndex(slideIndexOrDots)}
+ data-testid={`pagination-${displayNumber}`}
+ >
+ {displayNumber}
+
+ )
+ }
+ }
+ )}
+ >
+ )
+}
+export default Pagination
diff --git a/src/browser/modules/GuideCarousel/styled.tsx b/src/browser/modules/GuideCarousel/styled.tsx
new file mode 100644
index 00000000000..bbc8ecd98a2
--- /dev/null
+++ b/src/browser/modules/GuideCarousel/styled.tsx
@@ -0,0 +1,7 @@
+import styled from 'styled-components'
+
+export const PaginationItem = styled.span<{ active: boolean }>`
+ padding: 0 3px;
+ ${props => (props.active ? 'color: white;' : null)}
+ cursor: pointer;
+`
diff --git a/src/browser/modules/Sidebar/GuidesDrawer.tsx b/src/browser/modules/Sidebar/GuidesDrawer.tsx
index 539c56c3e8d..b98a8c0131e 100644
--- a/src/browser/modules/Sidebar/GuidesDrawer.tsx
+++ b/src/browser/modules/Sidebar/GuidesDrawer.tsx
@@ -54,10 +54,14 @@ function GuidesDrawer({
const scrollRef = useRef(null)
return (
-
+
{!isDefaultGuide(guide) && (
-
+
)}
diff --git a/src/browser/modules/Sidebar/NewSavedScript.tsx b/src/browser/modules/Sidebar/NewSavedScript.tsx
index c43c6a55d35..e5e912841fa 100644
--- a/src/browser/modules/Sidebar/NewSavedScript.tsx
+++ b/src/browser/modules/Sidebar/NewSavedScript.tsx
@@ -19,7 +19,7 @@ import React, { useState } from 'react'
import styled from 'styled-components'
const StyledHeaderText = styled.div`
- font-family: 'Open Sans';
+ font-family: ${props => props.theme.drawerHeaderFontFamily};
color: white;
`
diff --git a/src/browser/modules/Sidebar/styled.tsx b/src/browser/modules/Sidebar/styled.tsx
index c7ecf4c42ec..02af335ce06 100644
--- a/src/browser/modules/Sidebar/styled.tsx
+++ b/src/browser/modules/Sidebar/styled.tsx
@@ -128,7 +128,7 @@ export const StyledCommand = styled(DrawerBrowserCommand)`
export const StyledCarousel = styled.div`
height: 100%;
- padding-bottom: 20px;
+ padding-bottom: 50px;
width: 100%;
outline: none;
diff --git a/src/browser/modules/Stream/CypherFrame/__snapshots__/ErrorsView.test.tsx.snap b/src/browser/modules/Stream/CypherFrame/__snapshots__/ErrorsView.test.tsx.snap
index 9f56e1c40d2..2289f6b263b 100644
--- a/src/browser/modules/Stream/CypherFrame/__snapshots__/ErrorsView.test.tsx.snap
+++ b/src/browser/modules/Stream/CypherFrame/__snapshots__/ErrorsView.test.tsx.snap
@@ -6,11 +6,11 @@ exports[`ErrorsViews ErrorsStatusbar displays error 1`] = `
class="sc-bdVaJa kwzqrW"
>
Test.Error: Test error description
@@ -26,42 +26,42 @@ exports[`ErrorsViews ErrorsView displays nothing if no errors 1`] = ``;
exports[`ErrorsViews ErrorsView displays procedure link if unknown procedure 1`] = `
ERROR
Neo.ClientError.Procedure.ProcedureNotFound
not found
List available procedures
@@ -74,30 +74,30 @@ exports[`ErrorsViews ErrorsView displays procedure link if unknown procedure 1`]
exports[`ErrorsViews ErrorsView does displays an error 1`] = `
ERROR
Test.Error
Test error description
diff --git a/src/browser/modules/Stream/CypherFrame/__snapshots__/VisualizationView.test.tsx.snap b/src/browser/modules/Stream/CypherFrame/__snapshots__/VisualizationView.test.tsx.snap
index 65b8a3f3330..53d957c852f 100644
--- a/src/browser/modules/Stream/CypherFrame/__snapshots__/VisualizationView.test.tsx.snap
+++ b/src/browser/modules/Stream/CypherFrame/__snapshots__/VisualizationView.test.tsx.snap
@@ -137,7 +137,7 @@ exports[`Visualization renders with result and escapes any HTML 1`] = `
class="sc-cvbbAY cqXpvD faded zoom-in"
>
@@ -145,7 +145,7 @@ exports[`Visualization renders with result and escapes any HTML 1`] = `
class="sc-cvbbAY cqXpvD zoom-out"
>
diff --git a/src/browser/modules/Stream/__snapshots__/SchemaFrame.test.tsx.snap b/src/browser/modules/Stream/__snapshots__/SchemaFrame.test.tsx.snap
index 280e749a22e..49cf3307542 100644
--- a/src/browser/modules/Stream/__snapshots__/SchemaFrame.test.tsx.snap
+++ b/src/browser/modules/Stream/__snapshots__/SchemaFrame.test.tsx.snap
@@ -10,13 +10,13 @@ exports[`SchemaFrame renders empty 1`] = `
class="sc-ibxdXY lnvWNA"
>
Indexes
@@ -24,10 +24,10 @@ exports[`SchemaFrame renders empty 1`] = `
None
@@ -35,13 +35,13 @@ exports[`SchemaFrame renders empty 1`] = `
Constraints
@@ -49,10 +49,10 @@ exports[`SchemaFrame renders empty 1`] = `
None
@@ -92,43 +92,43 @@ exports[`SchemaFrame renders empty for Neo4j >= 4.0 1`] = `
class="sc-ibxdXY lnvWNA"
>
Index Name
Type
Uniqueness
EntityType
LabelsOrTypes
Properties
State
@@ -136,42 +136,42 @@ exports[`SchemaFrame renders empty for Neo4j >= 4.0 1`] = `
None
Constraints
@@ -179,10 +179,10 @@ exports[`SchemaFrame renders empty for Neo4j >= 4.0 1`] = `
None
@@ -222,13 +222,13 @@ exports[`SchemaFrame renders results for Neo4j < 4.0 1`] = `
class="sc-ibxdXY lnvWNA"
>
Indexes
@@ -236,10 +236,10 @@ exports[`SchemaFrame renders results for Neo4j < 4.0 1`] = `
ON :Movie(released) ONLINE
@@ -247,13 +247,13 @@ exports[`SchemaFrame renders results for Neo4j < 4.0 1`] = `
Constraints
@@ -261,10 +261,10 @@ exports[`SchemaFrame renders results for Neo4j < 4.0 1`] = `
ON ( book:Book ) ASSERT book.isbn IS UNIQUE
diff --git a/src/shared/services/dom-helpers.ts b/src/shared/services/dom-helpers.ts
index d3452a90513..a3ba69069f4 100644
--- a/src/shared/services/dom-helpers.ts
+++ b/src/shared/services/dom-helpers.ts
@@ -18,7 +18,6 @@
* along with this program. If not, see .
*/
-/* global HTMLElement */
const addClass = (node: any, className: any) => {
if (!(node instanceof HTMLElement && typeof className === 'string')) {
return
@@ -31,11 +30,19 @@ const addClass = (node: any, className: any) => {
}
}
-const prependIcon = (element: any, classname: any) => {
+const prependIcon = (element: any, classname: string, onClick: () => void) => {
const icon = document.createElement('i')
addClass(icon, classname)
icon.setAttribute('style', 'padding-right:4px')
element.insertBefore(icon, element.firstChild)
+
+ if (onClick) {
+ icon.onclick = e => {
+ // prevent populating the editor as well
+ e.stopPropagation()
+ onClick()
+ }
+ }
}
export { addClass, prependIcon }