@stack-spot/portal-components 0.0.18 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/BannerWarning.d.ts +6 -0
- package/dist/components/BannerWarning.d.ts.map +1 -1
- package/dist/components/BannerWarning.js +6 -0
- package/dist/components/BannerWarning.js.map +1 -1
- package/dist/components/Breadcrumb/index.d.ts +7 -8
- package/dist/components/Breadcrumb/index.d.ts.map +1 -1
- package/dist/components/Breadcrumb/index.js +7 -6
- package/dist/components/Breadcrumb/index.js.map +1 -1
- package/dist/components/Breadcrumb/styled.d.ts +1 -1
- package/dist/components/Breadcrumb/styled.d.ts.map +1 -1
- package/dist/components/Breadcrumb/styled.js +1 -0
- package/dist/components/Breadcrumb/styled.js.map +1 -1
- package/dist/components/ChatBot.d.ts +7 -0
- package/dist/components/ChatBot.d.ts.map +1 -1
- package/dist/components/ChatBot.js +13 -6
- package/dist/components/ChatBot.js.map +1 -1
- package/dist/components/ErrorFeedback.d.ts +23 -0
- package/dist/components/ErrorFeedback.d.ts.map +1 -0
- package/dist/components/ErrorFeedback.js +73 -0
- package/dist/components/ErrorFeedback.js.map +1 -0
- package/dist/components/SelectionList.d.ts +123 -0
- package/dist/components/SelectionList.d.ts.map +1 -0
- package/dist/components/SelectionList.js +149 -0
- package/dist/components/SelectionList.js.map +1 -0
- package/dist/components/{tour → Tour}/StepContainer.d.ts +16 -0
- package/dist/components/Tour/StepContainer.d.ts.map +1 -0
- package/dist/components/{tour → Tour}/StepContainer.js +4 -0
- package/dist/components/Tour/StepContainer.js.map +1 -0
- package/dist/components/Tour/StepNavigation.d.ts +29 -0
- package/dist/components/Tour/StepNavigation.d.ts.map +1 -0
- package/dist/components/{tour → Tour}/StepNavigation.js +4 -0
- package/dist/components/Tour/StepNavigation.js.map +1 -0
- package/dist/components/Tour/StepTitle.d.ts +17 -0
- package/dist/components/Tour/StepTitle.d.ts.map +1 -0
- package/dist/components/{tour → Tour}/StepTitle.js +4 -0
- package/dist/components/Tour/StepTitle.js.map +1 -0
- package/dist/components/{tour → Tour}/context.d.ts +11 -0
- package/dist/components/Tour/context.d.ts.map +1 -0
- package/dist/components/{tour → Tour}/context.js +11 -0
- package/dist/components/Tour/context.js.map +1 -0
- package/dist/components/{tour → Tour}/index.d.ts +1 -1
- package/dist/components/Tour/index.d.ts.map +1 -0
- package/dist/components/{tour → Tour}/index.js +1 -1
- package/dist/components/Tour/index.js.map +1 -0
- package/dist/components/Tour/utils.d.ts +51 -0
- package/dist/components/Tour/utils.d.ts.map +1 -0
- package/dist/components/Tour/utils.js +60 -0
- package/dist/components/Tour/utils.js.map +1 -0
- package/dist/context/anchor.d.ts +28 -0
- package/dist/context/anchor.d.ts.map +1 -0
- package/dist/context/anchor.js +23 -0
- package/dist/context/anchor.js.map +1 -0
- package/dist/hooks/keyboard.d.ts +33 -0
- package/dist/hooks/keyboard.d.ts.map +1 -0
- package/dist/hooks/keyboard.js +59 -0
- package/dist/hooks/keyboard.js.map +1 -0
- package/dist/hooks/service-now.d.ts +30 -1
- package/dist/hooks/service-now.d.ts.map +1 -1
- package/dist/hooks/service-now.js +54 -15
- package/dist/hooks/service-now.js.map +1 -1
- package/dist/hooks/text.d.ts +10 -0
- package/dist/hooks/text.d.ts.map +1 -0
- package/dist/hooks/text.js +24 -0
- package/dist/hooks/text.js.map +1 -0
- package/dist/hooks/title.d.ts +13 -0
- package/dist/hooks/title.d.ts.map +1 -1
- package/dist/hooks/title.js +13 -0
- package/dist/hooks/title.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -3
- package/dist/index.js.map +1 -1
- package/dist/svg/AI.d.ts +9 -0
- package/dist/svg/AI.d.ts.map +1 -0
- package/dist/svg/AI.js +12 -0
- package/dist/svg/AI.js.map +1 -0
- package/dist/svg/EDP.d.ts +9 -0
- package/dist/svg/EDP.d.ts.map +1 -0
- package/dist/svg/EDP.js +8 -0
- package/dist/svg/EDP.js.map +1 -0
- package/dist/svg/Forbidden.d.ts +6 -0
- package/dist/svg/Forbidden.d.ts.map +1 -0
- package/dist/svg/Forbidden.js +4 -0
- package/dist/svg/Forbidden.js.map +1 -0
- package/dist/svg/HUB.d.ts +9 -0
- package/dist/svg/HUB.d.ts.map +1 -0
- package/dist/svg/HUB.js +8 -0
- package/dist/svg/HUB.js.map +1 -0
- package/dist/svg/Logo.d.ts +5 -0
- package/dist/svg/Logo.d.ts.map +1 -0
- package/dist/svg/Logo.js +7 -0
- package/dist/svg/Logo.js.map +1 -0
- package/dist/svg/MiniLogo.d.ts +9 -0
- package/dist/svg/MiniLogo.d.ts.map +1 -0
- package/dist/{components → svg}/MiniLogo.js +3 -0
- package/dist/svg/MiniLogo.js.map +1 -0
- package/dist/{components/MiniLogo.d.ts → svg/NotFound.d.ts} +2 -2
- package/dist/svg/NotFound.d.ts.map +1 -0
- package/dist/svg/NotFound.js +4 -0
- package/dist/svg/NotFound.js.map +1 -0
- package/dist/svg/ServerError.d.ts +6 -0
- package/dist/svg/ServerError.d.ts.map +1 -0
- package/dist/svg/ServerError.js +4 -0
- package/dist/svg/ServerError.js.map +1 -0
- package/dist/svg/Unauthenticated.d.ts +6 -0
- package/dist/svg/Unauthenticated.d.ts.map +1 -0
- package/dist/svg/Unauthenticated.js +4 -0
- package/dist/svg/Unauthenticated.js.map +1 -0
- package/dist/svg/index.d.ts +10 -0
- package/dist/svg/index.d.ts.map +1 -0
- package/dist/svg/index.js +10 -0
- package/dist/svg/index.js.map +1 -0
- package/dist/utils/accessibility.d.ts +73 -0
- package/dist/utils/accessibility.d.ts.map +1 -0
- package/dist/utils/accessibility.js +131 -0
- package/dist/utils/accessibility.js.map +1 -0
- package/dist/utils/cookie.d.ts +34 -0
- package/dist/utils/cookie.d.ts.map +1 -0
- package/dist/utils/cookie.js +64 -0
- package/dist/utils/cookie.js.map +1 -0
- package/package.json +23 -12
- package/readme.md +58 -13
- package/src/components/BannerWarning.tsx +6 -0
- package/src/components/Breadcrumb/index.tsx +15 -13
- package/src/components/Breadcrumb/styled.ts +2 -1
- package/src/components/ChatBot.tsx +15 -7
- package/src/components/ErrorFeedback.tsx +135 -0
- package/src/components/SelectionList.tsx +361 -0
- package/src/components/{tour → Tour}/StepContainer.tsx +16 -0
- package/src/components/{tour → Tour}/StepNavigation.tsx +26 -2
- package/src/components/{tour → Tour}/StepTitle.tsx +11 -1
- package/src/components/{tour → Tour}/context.tsx +11 -0
- package/src/components/{tour → Tour}/index.ts +1 -1
- package/src/components/Tour/utils.tsx +100 -0
- package/src/context/anchor.tsx +37 -0
- package/src/hooks/keyboard.tsx +80 -0
- package/src/hooks/service-now.tsx +60 -16
- package/src/hooks/text.tsx +30 -0
- package/src/hooks/title.tsx +13 -0
- package/src/index.ts +4 -3
- package/src/svg/AI.tsx +41 -0
- package/src/svg/EDP.tsx +39 -0
- package/src/svg/Forbidden.tsx +22 -0
- package/src/svg/HUB.tsx +39 -0
- package/src/svg/Logo.tsx +38 -0
- package/src/{components → svg}/MiniLogo.tsx +3 -0
- package/src/svg/NotFound.tsx +16 -0
- package/src/svg/ServerError.tsx +33 -0
- package/src/svg/Unauthenticated.tsx +16 -0
- package/src/svg/index.ts +9 -0
- package/src/utils/accessibility.ts +141 -0
- package/src/utils/cookie.ts +66 -0
- package/dist/components/Login.d.ts +0 -26
- package/dist/components/Login.d.ts.map +0 -1
- package/dist/components/Login.js +0 -100
- package/dist/components/Login.js.map +0 -1
- package/dist/components/MiniLogo.d.ts.map +0 -1
- package/dist/components/MiniLogo.js.map +0 -1
- package/dist/components/tour/StepContainer.d.ts.map +0 -1
- package/dist/components/tour/StepContainer.js.map +0 -1
- package/dist/components/tour/StepNavigation.d.ts +0 -13
- package/dist/components/tour/StepNavigation.d.ts.map +0 -1
- package/dist/components/tour/StepNavigation.js.map +0 -1
- package/dist/components/tour/StepTitle.d.ts +0 -7
- package/dist/components/tour/StepTitle.d.ts.map +0 -1
- package/dist/components/tour/StepTitle.js.map +0 -1
- package/dist/components/tour/context.d.ts.map +0 -1
- package/dist/components/tour/context.js.map +0 -1
- package/dist/components/tour/index.d.ts.map +0 -1
- package/dist/components/tour/index.js.map +0 -1
- package/dist/components/tour/utils.d.ts +0 -13
- package/dist/components/tour/utils.d.ts.map +0 -1
- package/dist/components/tour/utils.js +0 -43
- package/dist/components/tour/utils.js.map +0 -1
- package/src/components/Login.tsx +0 -157
- package/src/components/tour/utils.tsx +0 -65
package/package.json
CHANGED
|
@@ -1,22 +1,31 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stack-spot/portal-components",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./dist/index.js",
|
|
9
|
+
"./Breadcrumb": "./dist/components/Breadcrumb/index.js",
|
|
10
|
+
"./ErrorFeedback": "./dist/components/ErrorFeedback.js",
|
|
11
|
+
"./SelectionList": "./dist/components/SelectionList.js",
|
|
12
|
+
"./Tour": "./dist/components/Tour/index.js",
|
|
13
|
+
"./svg": "./dist/svg/index.js",
|
|
14
|
+
"./anchor": "./dist/context/anchor.js"
|
|
15
|
+
},
|
|
7
16
|
"scripts": {
|
|
8
|
-
"build": "tsc && tsc-esm-fix --target='dist'",
|
|
9
|
-
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0"
|
|
17
|
+
"build": "rimraf dist && tsc && tsc-esm-fix --target='dist'",
|
|
18
|
+
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
|
19
|
+
"check-tree-shaking": "agadoo"
|
|
10
20
|
},
|
|
11
21
|
"peerDependencies": {
|
|
12
|
-
"@citric/core": "
|
|
13
|
-
"@citric/icons": "
|
|
14
|
-
"@citric/ui": "
|
|
15
|
-
"@stack-spot/portal-theme": "
|
|
16
|
-
"@stack-spot/portal-translate": "
|
|
17
|
-
"react": "
|
|
18
|
-
"react-dom": "
|
|
19
|
-
"styled-components": ">=6.1.10"
|
|
22
|
+
"@citric/core": "^6.0.0",
|
|
23
|
+
"@citric/icons": "^5.4.0 || ^6.0.0",
|
|
24
|
+
"@citric/ui": "^5.4.0 || ^6.0.0",
|
|
25
|
+
"@stack-spot/portal-theme": "^1.0.0",
|
|
26
|
+
"@stack-spot/portal-translate": "^1.0.0",
|
|
27
|
+
"react": "^18.2.0",
|
|
28
|
+
"react-dom": "^18.2.0"
|
|
20
29
|
},
|
|
21
30
|
"devDependencies": {
|
|
22
31
|
"@types/lodash": "^4.14.202",
|
|
@@ -25,6 +34,7 @@
|
|
|
25
34
|
"@types/reactour": "^1.18.5",
|
|
26
35
|
"@typescript-eslint/eslint-plugin": "^6.10.0",
|
|
27
36
|
"@typescript-eslint/parser": "^6.10.0",
|
|
37
|
+
"agadoo": "^3.0.0",
|
|
28
38
|
"eslint": "^8.53.0",
|
|
29
39
|
"eslint-plugin-filenames": "^1.3.2",
|
|
30
40
|
"eslint-plugin-import": "^2.29.0",
|
|
@@ -33,12 +43,13 @@
|
|
|
33
43
|
"eslint-plugin-react": "^7.33.2",
|
|
34
44
|
"eslint-plugin-react-hooks": "^4.6.0",
|
|
35
45
|
"eslint-plugin-react-refresh": "^0.4.4",
|
|
46
|
+
"rimraf": "^5.0.7",
|
|
47
|
+
"styled-components": "6.1.10",
|
|
36
48
|
"tsc-esm-fix": "^2.20.26",
|
|
37
49
|
"typescript": "^5.2.2"
|
|
38
50
|
},
|
|
39
51
|
"dependencies": {
|
|
40
52
|
"lodash": "^4.17.21",
|
|
41
|
-
"react-toastify": "^9.1.3",
|
|
42
53
|
"reactour": "^1.19.3"
|
|
43
54
|
}
|
|
44
55
|
}
|
package/readme.md
CHANGED
|
@@ -1,24 +1,69 @@
|
|
|
1
1
|
# Components
|
|
2
|
-
|
|
2
|
+
A collection of UI components, hooks, SVG images, utilities and variables shared among Stackspot web projects.
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
What about the Design System (DS)? Some components here may be upgraded to the design system level eventually. But this is a place where we can have any kind of component, despite it belonging to a DS or not.
|
|
4
|
+
What about the Design System (DS)? Some components here may be upgraded to the design system level eventually. But this is a place where we
|
|
5
|
+
can have any kind of component, despite it belonging to a DS or not.
|
|
7
6
|
|
|
8
7
|
## Presentation components
|
|
9
8
|
These are pure functions, i.e. they rely only in their inputs to render the UI. Furthermore, they don't have any collateral effect.
|
|
10
9
|
|
|
11
|
-
Exceptions: translations are the only exception here. These components can access the current language without having it passed as
|
|
12
|
-
|
|
13
|
-
- BreadcrumbList: renders a list of breadcrumb navigation items.
|
|
14
|
-
|
|
15
|
-
## Containers
|
|
16
|
-
Containers are components that can access more than what has been passed as parameter. They can also have collateral effects.
|
|
10
|
+
Exceptions: translations are the only exception here. These components can access the current language without having it passed as
|
|
11
|
+
parameter.
|
|
17
12
|
|
|
18
|
-
|
|
13
|
+
- `BreadcrumbList`: renders a list of breadcrumb navigation items. Must be imported from `@stack-spot/portal-components/Breadcrumb`.
|
|
14
|
+
- `StepContainer`, `TourProvider`, `TourStep`: components related to React Tour, i.e. the tutorial engine used by Stackspot. Must be imported
|
|
15
|
+
from `@stack-spot/portal-components/Tour`.
|
|
16
|
+
- `BannerWarning`: a yellow alert box with an exclamation icon and the content passed as parameter. Used for warning messages.
|
|
17
|
+
- `ChatBot`: an orange circular button that can toggle the chat window from Service Now. The button has a chat icon when the window is
|
|
18
|
+
closed and a close icon when it's open.
|
|
19
|
+
- `ErrorFeedback`: a box with an icon and an error message. This is used for giving error feedbacks to the user.
|
|
20
|
+
- `SelectionList`: a selection UI that allows the selection of one single item. These items can be divided in sections (groups). This
|
|
21
|
+
component is highly customizable and has lots of accessibility features implemented.
|
|
22
|
+
- `AnchorProvider`: a way to provide an anchor component (links) to be used by Stackspot libraries. This allows these libraries not to be
|
|
23
|
+
coupled with an specific React navigators. To retrieve the component, use `useLinkComponent`. Must be imported from
|
|
24
|
+
`@stack-spot/portal-components/anchor`.
|
|
19
25
|
|
|
20
26
|
## Hooks
|
|
21
27
|
These are useful react hooks shared among the StackSpot portals.
|
|
22
28
|
|
|
23
|
-
- `useEffectOnce()`: runs an effect only once, when the component is mounted. This prevents React from running the effect twice when in
|
|
24
|
-
|
|
29
|
+
- `useEffectOnce()`: runs an effect only once, when the component is mounted. This prevents React from running the effect twice when in
|
|
30
|
+
development mode.
|
|
31
|
+
- `useTitleEffect(title)`: changes the title for the current page. The title is returned to its original value as soon as the component is
|
|
32
|
+
unmounted.
|
|
33
|
+
- `useCheckTextOverflow()`: checks if the text fits completely in the space available.
|
|
34
|
+
- `useLinkComponent()`: retrieves the anchor component declared at the closest `AnchorProvider`. If no component was provided, returns a
|
|
35
|
+
component that renders the HTML `<a>` tag directly. This is useful for integration with navigators for React. Must be imported from
|
|
36
|
+
`@stack-spot/portal-components/anchor`.
|
|
37
|
+
- `useKeyboardControls(options)`: creates listeners for controlling a Menu UI through the keyboard (up, down, tab, esc, enter).
|
|
38
|
+
- `useServiceNowEffect(options)`, `useServiceNowChatButtonVisibility()`: Service Now hooks (chat capabilities).
|
|
39
|
+
- `useTour()`: retrieves data related to the current step of React Tour (tutorial). Must be imported from
|
|
40
|
+
`@stack-spot/portal-components/Tour`.
|
|
41
|
+
|
|
42
|
+
## SVG images
|
|
43
|
+
Some SVG images are exported as React components at `@stack-spot/portal-components/svg`.
|
|
44
|
+
|
|
45
|
+
## Utilities and variables
|
|
46
|
+
These are useful functions shared among the StackSpot portals.
|
|
47
|
+
|
|
48
|
+
#### Accessibility
|
|
49
|
+
- `focusNextIgnoringChildren(element)`: focus the next element in the hierarchy, ignoring the children of the element passed as parameter.
|
|
50
|
+
- `focusFirstChild(element, options)`: focus the first child of element that is focusable according to the options.
|
|
51
|
+
- `isFocusable(element)`: checks if the element can receive focus.
|
|
52
|
+
- `focusAccessibleElement(element)`: tries to focus the element passed as parameter, but if it's not focusable, finds another element to
|
|
53
|
+
focus according to accessibility rules.
|
|
54
|
+
|
|
55
|
+
#### Cookie
|
|
56
|
+
- `setupCookies(domainRegex)`: setup a domain regex for the cookies. Use this if the domain is different than localhost or *.stackspot.com.
|
|
57
|
+
- `getCookies()`: retrieves an object with all the cookies.
|
|
58
|
+
- `getCookie(name)`: same as `getCookies()[name]`.
|
|
59
|
+
- `setCookie(name, value)`: sets the value of a cookie.
|
|
60
|
+
- `removeCookie(name)`: removes a cookie.
|
|
61
|
+
|
|
62
|
+
#### Other
|
|
63
|
+
- `isNewTourStep(step)`, `hasFinishedTourStep(key)`, `tourStepBuilder(options)`, `defaultTourConfig`: related to React Tour (tutorial).
|
|
64
|
+
- `openServiceNowChat()`, `serviceNowDictionary`: related to Service Now chat service.
|
|
65
|
+
|
|
66
|
+
# Developer notes
|
|
67
|
+
- Since not every component in this library will be used by every project. This library must be tree-shakeable! Before committing, make sure
|
|
68
|
+
`pnpm check-tree-shaking` passes.
|
|
69
|
+
|
|
@@ -2,6 +2,12 @@ import { Flex, IconBox, Text } from '@citric/core'
|
|
|
2
2
|
import { ExclamationTriangle } from '@citric/icons'
|
|
3
3
|
import { Alert } from '@citric/ui'
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* A styled and non-dismissible alert box for showing important warnings for the user.
|
|
7
|
+
*
|
|
8
|
+
* This renders a yellow box with an exclamation icon. The content passed as parameter is placed on the right of the icon.
|
|
9
|
+
* @param props an object containing the content (children) to show inside the alert box.
|
|
10
|
+
*/
|
|
5
11
|
export const BannerWarning = ({ children }: { children: React.ReactNode }) => (
|
|
6
12
|
<Flex sx={{ position: 'fixed', top: 0, zIndex: '999', w: 12, left: 0 }}>
|
|
7
13
|
<Alert colorScheme="warning" sx={{ p: 2, w: 12, justifyContent: 'center', height: ['60px', '100px'] }}>
|
|
@@ -2,6 +2,7 @@ import { Text } from '@citric/core'
|
|
|
2
2
|
import { Skeleton } from '@citric/ui'
|
|
3
3
|
import { last } from 'lodash'
|
|
4
4
|
import { useEffect, useMemo } from 'react'
|
|
5
|
+
import { useAnchorTag } from '../../context/anchor'
|
|
5
6
|
import { titleEffect } from '../../hooks/title'
|
|
6
7
|
import { Box } from './styled'
|
|
7
8
|
|
|
@@ -20,10 +21,6 @@ interface BreadcrumbItem {
|
|
|
20
21
|
* If this route is accessible, the link to it.
|
|
21
22
|
*/
|
|
22
23
|
href?: string,
|
|
23
|
-
/**
|
|
24
|
-
* Anchor from Citron to be used
|
|
25
|
-
*/
|
|
26
|
-
anchorTag?: AnchorComponent,
|
|
27
24
|
}
|
|
28
25
|
|
|
29
26
|
interface Props {
|
|
@@ -45,16 +42,20 @@ interface Props {
|
|
|
45
42
|
*/
|
|
46
43
|
shouldUpdatePageTitle?: boolean,
|
|
47
44
|
/**
|
|
48
|
-
*
|
|
45
|
+
* Key of the current page. If an item has this key, it won't be rendered as a link and will be marked as active.
|
|
49
46
|
*/
|
|
50
|
-
|
|
47
|
+
currentPageKey?: string,
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
interface ItemProps extends Pick<Props, 'currentPageKey'> {
|
|
51
|
+
item: BreadcrumbItem,
|
|
51
52
|
}
|
|
52
53
|
|
|
53
|
-
const BreadcrumbItem = ({ label, href,
|
|
54
|
+
const BreadcrumbItem = ({ item: { label, href, key }, currentPageKey }: ItemProps) => {
|
|
54
55
|
const text = <Text appearance="breadcrumb">{label}</Text>
|
|
55
|
-
const
|
|
56
|
-
const
|
|
57
|
-
return
|
|
56
|
+
const Link = useAnchorTag()
|
|
57
|
+
const shouldBeLink = href && currentPageKey != key
|
|
58
|
+
return <li>{shouldBeLink ? <Link href={href}>{text}</Link> : text}</li>
|
|
58
59
|
}
|
|
59
60
|
|
|
60
61
|
/**
|
|
@@ -62,9 +63,10 @@ const BreadcrumbItem = ({ label, href, anchorTag }: BreadcrumbItem) => {
|
|
|
62
63
|
*
|
|
63
64
|
* If the breadcrumb is obtained asynchronously, pass `isLoading = true` in order to show a loading feedback.
|
|
64
65
|
*/
|
|
65
|
-
export const BreadcrumbList = ({ items, isLoading, shouldUpdatePageTitle,
|
|
66
|
-
const listItems = useMemo(
|
|
67
|
-
<
|
|
66
|
+
export const BreadcrumbList = ({ items, isLoading, shouldUpdatePageTitle, currentPageKey }: Props) => {
|
|
67
|
+
const listItems = useMemo(
|
|
68
|
+
() => items.map(item => <BreadcrumbItem key={item.key || item.label} item={item} currentPageKey={currentPageKey} />),
|
|
69
|
+
[items],
|
|
68
70
|
)
|
|
69
71
|
useEffect(() => {
|
|
70
72
|
const title = last(items)?.label
|
|
@@ -2,7 +2,8 @@ import { getFontAppearance } from '@citric/core/dist/utils/theme'
|
|
|
2
2
|
import { theme } from '@stack-spot/portal-theme'
|
|
3
3
|
import { styled } from 'styled-components'
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
// the type below should be inferred, but a bug in TS+PNPM prevents it: https://github.com/microsoft/TypeScript/issues/42873
|
|
6
|
+
export const Box: React.FC<React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>> = styled.nav`
|
|
6
7
|
margin-bottom: 24px;
|
|
7
8
|
|
|
8
9
|
ul {
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { Button, Flex, IconBox, Styles } from '@citric/core'
|
|
2
2
|
import { QuestionAnswer, Times } from '@citric/icons'
|
|
3
|
-
import {
|
|
3
|
+
import { getServiceNowLauncher, hideChatWindow, showChatWindow } from '../hooks/service-now'
|
|
4
|
+
|
|
5
|
+
export const CHAT_BUTTON_ID = 'service-now-button'
|
|
6
|
+
export const CHAT_BUTTON_WRAPPER_ID = 'service-now-content'
|
|
4
7
|
|
|
5
8
|
const styles: Styles = {
|
|
6
9
|
content: {
|
|
@@ -44,24 +47,29 @@ const styles: Styles = {
|
|
|
44
47
|
},
|
|
45
48
|
}
|
|
46
49
|
|
|
50
|
+
/**
|
|
51
|
+
* A button for opening or closing the service-now chat window.
|
|
52
|
+
*
|
|
53
|
+
* This is a circular orange button with a chat icon if the chat window is closed or a close icon if the chat window is open.
|
|
54
|
+
*/
|
|
47
55
|
export const ChatBot = () => {
|
|
48
56
|
const handleOpenChatBot = () => {
|
|
49
57
|
const chatIframe = getServiceNowLauncher()
|
|
50
58
|
if (chatIframe) {
|
|
51
|
-
const
|
|
52
|
-
if (
|
|
53
|
-
|
|
59
|
+
const isVisible = chatIframe.classList.contains('show')
|
|
60
|
+
if (isVisible) {
|
|
61
|
+
hideChatWindow()
|
|
54
62
|
} else {
|
|
55
|
-
|
|
63
|
+
showChatWindow()
|
|
56
64
|
}
|
|
57
65
|
}
|
|
58
66
|
}
|
|
59
67
|
|
|
60
68
|
return (
|
|
61
|
-
<Flex id=
|
|
69
|
+
<Flex id={CHAT_BUTTON_WRAPPER_ID} sx={styles.content}>
|
|
62
70
|
<Button
|
|
63
71
|
onClick={handleOpenChatBot}
|
|
64
|
-
id=
|
|
72
|
+
id={CHAT_BUTTON_ID}
|
|
65
73
|
sx={styles.button}
|
|
66
74
|
>
|
|
67
75
|
<IconBox
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { Box, Button, Container, Flex, LinkBox, Text } from '@citric/core'
|
|
2
|
+
import { Dictionary, useTranslate } from '@stack-spot/portal-translate'
|
|
3
|
+
import { useState } from 'react'
|
|
4
|
+
import { Forbidden } from '../svg/Forbidden'
|
|
5
|
+
import { Logo } from '../svg/Logo'
|
|
6
|
+
import { NotFound } from '../svg/NotFound'
|
|
7
|
+
import { ServerError } from '../svg/ServerError'
|
|
8
|
+
import { Unauthenticated } from '../svg/Unauthenticated'
|
|
9
|
+
|
|
10
|
+
const imageStyle: React.CSSProperties = {
|
|
11
|
+
width: '200px',
|
|
12
|
+
height: '200px',
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const imageMap: Record<number, React.ReactElement> = {
|
|
16
|
+
401: <Unauthenticated style={imageStyle} />,
|
|
17
|
+
403: <Forbidden style={imageStyle} />,
|
|
18
|
+
404: <NotFound style={imageStyle} />,
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface ErrorDescription {
|
|
22
|
+
/**
|
|
23
|
+
* The HTTP Error code if this is a network error.
|
|
24
|
+
*/
|
|
25
|
+
code?: number,
|
|
26
|
+
/**
|
|
27
|
+
* The error message.
|
|
28
|
+
*/
|
|
29
|
+
message?: string,
|
|
30
|
+
/**
|
|
31
|
+
* Whether or not the application is in debug mode.
|
|
32
|
+
*/
|
|
33
|
+
debug?: boolean,
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* A box with an icon and an error message. This is used for giving error feedbacks to the user.
|
|
38
|
+
*
|
|
39
|
+
* If the application is in debug mode, a button is rendered to show the error message.
|
|
40
|
+
*
|
|
41
|
+
* @param options the error code, the error message and whether or not the application is in debug mode.
|
|
42
|
+
*/
|
|
43
|
+
export const ErrorFeedback = ({ code = 0, message, debug }: ErrorDescription) => {
|
|
44
|
+
const t = useTranslate(dictionary) as Record<string, string>
|
|
45
|
+
const [showDetails, setShowDetails] = useState(false)
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<Box bg="light.400">
|
|
49
|
+
<Container>
|
|
50
|
+
<Flex alignItems="center" sx={{ padding: 12 }}>
|
|
51
|
+
<Box width={5} sx={{ display: ['block', 'none'] }}>
|
|
52
|
+
<Flex justifyContent="flex-end" pr={20}>
|
|
53
|
+
{imageMap[code] ?? <ServerError style={imageStyle} />}
|
|
54
|
+
</Flex>
|
|
55
|
+
</Box>
|
|
56
|
+
<Box width={[7, 12]}>
|
|
57
|
+
<LinkBox href="/">
|
|
58
|
+
<Logo style={{ width: '130px', height: '30px' }} />
|
|
59
|
+
</LinkBox>
|
|
60
|
+
<Box w={[7, 12]}>
|
|
61
|
+
<Text appearance="h4" mt={5} colorScheme="inverse">
|
|
62
|
+
{code ? `${code}. ` : ''}
|
|
63
|
+
<Text appearance="h4" as="span" colorScheme="light.700">
|
|
64
|
+
{t[`${code}.title`]}
|
|
65
|
+
</Text>
|
|
66
|
+
</Text>
|
|
67
|
+
|
|
68
|
+
<Text appearance="body1" mt={5} colorScheme="inverse">
|
|
69
|
+
{t[`${code}.description`]}
|
|
70
|
+
</Text>
|
|
71
|
+
|
|
72
|
+
<Text appearance="body1" colorScheme="light.700" mt={1}>
|
|
73
|
+
{t[`${code}.help`]}
|
|
74
|
+
</Text>
|
|
75
|
+
{debug && message && (
|
|
76
|
+
<Button appearance="outlined" colorScheme="inverse" onClick={() => setShowDetails(v => !v)}>
|
|
77
|
+
{showDetails ? t.hideDetails : t.showDetails}
|
|
78
|
+
</Button>
|
|
79
|
+
)}
|
|
80
|
+
{showDetails && (
|
|
81
|
+
<Box bg="danger" mt={8} p={4} sx={{ borderRadius: '5px' }}>
|
|
82
|
+
<Text appearance="microtext1" colorScheme="danger.contrastText">{message}</Text>
|
|
83
|
+
</Box>
|
|
84
|
+
)}
|
|
85
|
+
</Box>
|
|
86
|
+
</Box>
|
|
87
|
+
</Flex>
|
|
88
|
+
</Container>
|
|
89
|
+
</Box>
|
|
90
|
+
)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const dictionary = {
|
|
94
|
+
en: {
|
|
95
|
+
altLogo: 'Logo Stackspot',
|
|
96
|
+
'0.title': 'Unknown client error',
|
|
97
|
+
'0.description': 'An unknown error happened while trying to load the resource.',
|
|
98
|
+
'0.help': 'Reload the page and, if it still doesn\'t work, report the error the Stackspot team.',
|
|
99
|
+
'401.title': 'Not authorized',
|
|
100
|
+
'401.description': 'There was a failure loading credentials for this page.',
|
|
101
|
+
'401.help': 'Check if the URL is correct or clear your cache and cookies from your browser and try again.',
|
|
102
|
+
'403.title': 'Private access',
|
|
103
|
+
'403.description': 'The page you have tried to visit is private.',
|
|
104
|
+
'403.help': 'Log in with another account or request access from the person who manages your organization.',
|
|
105
|
+
'404.title': 'Resource not found',
|
|
106
|
+
'404.description': 'This resource no longer exists.',
|
|
107
|
+
'404.help': 'Please try again or request a new URL from the person who manages your organization.',
|
|
108
|
+
'500.title': 'Server error',
|
|
109
|
+
'500.description':
|
|
110
|
+
"We have identified a problem with the server, but don't worry. We are already investigating what happened.",
|
|
111
|
+
'500.help': 'Please try again after a few minutes.',
|
|
112
|
+
showDetails: 'Show Details',
|
|
113
|
+
hideDetails: 'Hide Details',
|
|
114
|
+
},
|
|
115
|
+
pt: {
|
|
116
|
+
altLogo: 'Logo Stackspot',
|
|
117
|
+
'0.title': 'Erro desconhecido (cliente)',
|
|
118
|
+
'0.description': 'Um erro desconhecido aconteceu ao carregar o recurso',
|
|
119
|
+
'0.help': 'Recarregue a página e, se ainda não funcionar, reporte o problema para o time da Stackspot.',
|
|
120
|
+
'401.title': 'Não autorizado',
|
|
121
|
+
'401.description': 'Houve uma falha no carregamento de credenciais dessa página.',
|
|
122
|
+
'401.help': 'Verifique se a URL está correta ou limpe o cache e os cookies de seu navegador e tente novamente.',
|
|
123
|
+
'403.title': 'Acesso privado',
|
|
124
|
+
'403.description': '"A página que você tentou visualizar é particular."',
|
|
125
|
+
'403.help': 'Solicite acesso com o administrador da sua organização.',
|
|
126
|
+
'404.title': 'Recurso não encontrado',
|
|
127
|
+
'404.description': 'Este recurso não existe mais.',
|
|
128
|
+
'404.help': 'Tente novamente ou fale com o administrador da sua organização.',
|
|
129
|
+
'500.title': 'Erro ao exibir o recurso',
|
|
130
|
+
'500.description': 'Mas não se preocupe, já estamos investigando o que aconteceu.',
|
|
131
|
+
'500.help': 'Tente novamente após alguns minutos.',
|
|
132
|
+
showDetails: 'Ver Detalhes',
|
|
133
|
+
hideDetails: 'Esconder Detalhes',
|
|
134
|
+
},
|
|
135
|
+
} satisfies Dictionary
|