Files
teleport/web/packages/shared/components/Notification/Notification.story.tsx
T
Grzegorz ZdunekandRafał Cieślak 4830ea16e5 Connect: Enable keyboard shortcuts configuration (#22194)
* Use event.code for non A-z keys

Without this fix, shortcuts like "Shift+1" can't work, because the reported character is "!".

* Add Zod schema to validate keyboard shortcuts

* Render better formatted error notification, add a link to docs

* Notify about duplicated accelerators

* Improve the error message for re-parsing failure (it can happen when a default value does not pass validation)

* A bunch of renames

* Allow spaces in accelerators

* Rename `isContentAnObject`

* Allow `Notification` to render links and lists

* Split by optional whitespace and "+"

* Allow lowercase letters

* Require a modifier for non-function keys

* Move VALID_SHORTCUT_MESSAGE to `initUi`

* Always return from `getDuplicateAccelerators`

* Use 'Cmd' and 'Ctrl' for mac

* Add comments

* Fix notification not rendering content

* Add more comments, rename `getKeyCode` to `getKeyName`

* Fix incorrect size of <Link> text

* Remove "expected" prefix

* Revert `typeof content === 'object'` in `Notification`

* Remove a comment about disabled keys in `ConfigService`, add a note about `keymap.` prefix

* Improve `getKeyName` comment

* Extract an inline object to a variable in `getKeyName`

* Fix notification list padding

* Change text for doc link & description for config error

* Improve comment for `getKeyName`

* Remove special formatting for list === 1 in `Notification`

* Print valid modifiers

* Call `getKeyboardShortcutSchema()` once

* Collect issues from all validations, run `invalidModifiers` through a set

* Change error message for `missingModifierIssue`

* Convert duplicates warning to error

* Define ALLOWED_KEY_CODES in a more concise way

* Support both `IntlBackslash` and `Backquote`

* Restore modifiers for mac to full spelling, sort them in order recommended by platform guidelines

* Fix old comment about the shortcuts order

---------

Co-authored-by: Rafał Cieślak <rafal.cieslak@goteleport.com>
2023-03-03 14:05:38 +00:00

326 lines
9.4 KiB
TypeScript

/*
Copyright 2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import React, { useState } from 'react';
import { Info, Warning } from 'design/Icon';
import Flex from 'design/Flex';
import { Notification } from './Notification';
export default {
title: 'Shared/Notification',
};
export const Notifications = () => {
return (
<div
css={`
display: grid;
grid-gap: ${props => props.theme.space[8]}px;
grid-template-columns: auto auto auto;
`}
>
<Flex flexDirection="column" gap={4}>
<Notification
item={{
id: crypto.randomUUID(),
severity: 'info',
content: {
title: 'Info with title and description',
description: loremIpsum,
},
}}
Icon={Info}
getColor={theme => theme.colors.info}
onRemove={() => {}}
isAutoRemovable={false}
/>
<Notification
item={{
id: crypto.randomUUID(),
severity: 'warn',
content: {
title: 'Warning with title and description',
description: loremIpsum,
},
}}
Icon={Warning}
getColor={theme => theme.colors.warning}
onRemove={() => {}}
isAutoRemovable={false}
/>
<Notification
item={{
id: crypto.randomUUID(),
severity: 'error',
content: {
title: 'Error with title and description',
description: loremIpsum,
},
}}
Icon={Warning}
getColor={theme => theme.colors.danger}
onRemove={() => {}}
isAutoRemovable={false}
/>
</Flex>
<Flex flexDirection="column" gap={4}>
<Notification
item={{
id: crypto.randomUUID(),
severity: 'info',
content: 'Multiline info without title. ' + loremIpsum,
}}
Icon={Info}
getColor={theme => theme.colors.info}
onRemove={() => {}}
isAutoRemovable={false}
/>
<Notification
item={{
id: crypto.randomUUID(),
severity: 'warn',
content: 'Multiline warning without title. ' + loremIpsum,
}}
Icon={Warning}
getColor={theme => theme.colors.warning}
onRemove={() => {}}
isAutoRemovable={false}
/>
<Notification
item={{
id: crypto.randomUUID(),
severity: 'error',
content: 'Multiline error without title. ' + loremIpsum,
}}
Icon={Warning}
getColor={theme => theme.colors.danger}
onRemove={() => {}}
isAutoRemovable={false}
/>
</Flex>
<Flex flexDirection="column" gap={4}>
<Notification
item={{
id: crypto.randomUUID(),
severity: 'info',
content: 'Info without title',
}}
Icon={Info}
getColor={theme => theme.colors.info}
onRemove={() => {}}
isAutoRemovable={false}
/>
<Notification
item={{
id: crypto.randomUUID(),
severity: 'warn',
content: 'Warning without title',
}}
Icon={Warning}
getColor={theme => theme.colors.warning}
onRemove={() => {}}
isAutoRemovable={false}
/>
<Notification
item={{
id: crypto.randomUUID(),
severity: 'error',
content: 'Error without title',
}}
Icon={Warning}
getColor={theme => theme.colors.danger}
onRemove={() => {}}
isAutoRemovable={false}
/>
</Flex>
<Flex flexDirection="column" gap={4}>
<Notification
item={{
id: crypto.randomUUID(),
severity: 'info',
content: {
title: 'Info with link',
description: loremIpsum,
link: {
href: 'https://goteleport.com',
text: 'goteleport.com',
},
},
}}
Icon={Info}
getColor={theme => theme.colors.info}
onRemove={() => {}}
isAutoRemovable={false}
/>
<Notification
item={{
id: crypto.randomUUID(),
severity: 'warn',
content: {
title: 'Warning with link',
description: loremIpsum,
link: {
href: 'https://goteleport.com',
text: 'goteleport.com',
},
},
}}
Icon={Warning}
getColor={theme => theme.colors.warning}
onRemove={() => {}}
isAutoRemovable={false}
/>
<Notification
item={{
id: crypto.randomUUID(),
severity: 'error',
content: {
title: 'Error with link',
description: loremIpsum,
link: {
href: 'https://goteleport.com',
text: 'goteleport.com',
},
},
}}
Icon={Warning}
getColor={theme => theme.colors.danger}
onRemove={() => {}}
isAutoRemovable={false}
/>
</Flex>
<Flex flexDirection="column" gap={4}>
<Notification
item={{
id: crypto.randomUUID(),
severity: 'info',
content: {
title: 'Info with list',
list: [loremIpsum, loremIpsum],
},
}}
Icon={Info}
getColor={theme => theme.colors.info}
onRemove={() => {}}
isAutoRemovable={false}
/>
<Notification
item={{
id: crypto.randomUUID(),
severity: 'warn',
content: {
title: 'Warning with list',
list: [loremIpsum, loremIpsum],
},
}}
Icon={Warning}
getColor={theme => theme.colors.warning}
onRemove={() => {}}
isAutoRemovable={false}
/>
<Notification
item={{
id: crypto.randomUUID(),
severity: 'error',
content: {
title: 'Error with list',
list: [loremIpsum, loremIpsum],
},
}}
Icon={Warning}
getColor={theme => theme.colors.danger}
onRemove={() => {}}
isAutoRemovable={false}
/>
</Flex>
</div>
);
};
export const AutoRemovable = () => {
const [showInfo, setShowInfo] = useState(true);
const [showWarning, setShowWarning] = useState(true);
const [showError, setShowError] = useState(true);
return (
<Flex flexDirection="column" gap={4}>
{showInfo ? (
<Notification
item={{
id: crypto.randomUUID(),
severity: 'info',
content:
"This will be automatically removed after 5 seconds. Click to expand it. Mouseover it to restart the timer. Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s.",
}}
onRemove={() => setShowInfo(false)}
Icon={Info}
getColor={theme => theme.colors.info}
isAutoRemovable={true}
autoRemoveDurationMs={5000}
/>
) : (
<div>Info notification has been removed</div>
)}
{showWarning ? (
<Notification
item={{
id: crypto.randomUUID(),
severity: 'warn',
content:
"This will be automatically removed after 5 seconds. Click to expand it. Mouseover it to restart the timer. Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s.",
}}
onRemove={() => setShowWarning(false)}
Icon={Warning}
getColor={theme => theme.colors.warning}
isAutoRemovable={true}
autoRemoveDurationMs={5000}
/>
) : (
<div>Warning notification has been removed</div>
)}
{showError ? (
<Notification
item={{
id: crypto.randomUUID(),
severity: 'error',
content:
"This can only be removed by clicking on the X. Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s.",
}}
onRemove={() => setShowError(false)}
Icon={Warning}
getColor={theme => theme.colors.danger}
isAutoRemovable={false}
/>
) : (
<div>Error notification has been removed</div>
)}
</Flex>
);
};
const loremIpsum =
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut non ipsum dignissim, dignissim est vitae, facilisis nunc.';