Skip to content

Commit

Permalink
feat(console,phrases): add test sample code editor (#5475)
Browse files Browse the repository at this point in the history
* feat(console,phrases): add test sample code editor

add test sample code editor

* fix(console): remove unused styles

remove unused styles

* refactor(console): refactor the components structure

erfactor the components structure

* refactor(console): clean up the root component

clean up the root component
  • Loading branch information
simeng-li authored Mar 7, 2024
1 parent 4e27e34 commit 2d98982
Show file tree
Hide file tree
Showing 35 changed files with 564 additions and 294 deletions.
5 changes: 5 additions & 0 deletions packages/console/src/assets/icons/token-file-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions packages/console/src/assets/icons/user-file-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 3 additions & 2 deletions packages/console/src/assets/icons/user.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,6 @@ export const defaultOptions: EditorProps['options'] = {
renderLineHighlight: 'none',
fontFamily: 'Roboto Mono, monospace',
fontSize: 14,
automaticLayout: true,
tabSize: 2,
};
Original file line number Diff line number Diff line change
Expand Up @@ -22,27 +22,28 @@
gap: _.unit(2);

.tab {
padding: _.unit(1.5) _.unit(3);
font: var(--font-label-2);
font-family: 'Roboto Mono', monospace;
color: var(--color-code-grey);
cursor: pointer;

&.active,
&:hover {
color: var(--color-code-white);
background-color: var(--color-code-tab-active-bg);
border-radius: 8px;
padding: _.unit(1.5) _.unit(3);
color: var(--color-code-white);
display: flex;
align-items: center;
gap: _.unit(1);

&.tabButton {
color: var(--color-code-grey);
cursor: pointer;

&.active,
&:hover {
color: var(--color-code-white);
background-color: var(--color-code-tab-active-bg);
border-radius: 8px;
}
}
}
}

.title {
font: var(--font-label-2);
font-family: 'Roboto Mono', monospace;
color: var(--color-code-white);
}

.actions {
display: flex;
gap: _.unit(2);
Expand All @@ -53,6 +54,5 @@
.editorContainer {
position: relative;
flex-grow: 1;
padding-bottom: _.unit(4);
}
}
57 changes: 34 additions & 23 deletions packages/console/src/pages/JwtClaims/MonacoCodeEditor/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ import { onKeyDownHandler } from '@/utils/a11y';
import { logtoDarkTheme, defaultOptions } from './config.js';
import * as styles from './index.module.scss';
import type { IStandaloneCodeEditor, Model } from './type.js';
import useEditorHeight from './use-editor-height.js';

export type { Model } from './type.js';

type Props = {
className?: string;
Expand All @@ -25,11 +28,16 @@ function MonacoCodeEditor({ className, actions, models }: Props) {
const editorRef = useRef<Nullable<IStandaloneCodeEditor>>(null);

const [activeModelName, setActiveModelName] = useState<string>();

const activeModel = useMemo(
() => models.find((model) => model.name === activeModelName),
[activeModelName, models]
);

const isMultiModals = useMemo(() => models.length > 1, [models]);

const { containerRef, editorHeight } = useEditorHeight();

// Set the first model as the active model
useEffect(() => {
setActiveModelName(models[0]?.name);
Expand Down Expand Up @@ -77,39 +85,42 @@ function MonacoCodeEditor({ className, actions, models }: Props) {
return (
<div className={classNames(className, styles.codeEditor)}>
<header>
{models.length > 1 ? (
<div className={styles.tabList}>
{models.map(({ name }) => (
<div
key={name}
className={classNames(styles.tab, name === activeModelName && styles.active)}
role="button"
tabIndex={0}
onClick={() => {
<div className={styles.tabList}>
{models.map(({ name, title, icon }) => (
<div
key={name}
className={classNames(
styles.tab,
isMultiModals && styles.tabButton,
name === activeModelName && styles.active
)}
{...(isMultiModals && {
role: 'button',
tabIndex: 0,
onClick: () => {
setActiveModelName(name);
}}
onKeyDown={onKeyDownHandler(() => {
},
onKeyDown: onKeyDownHandler(() => {
setActiveModelName(name);
})}
>
{name}
</div>
))}
</div>
) : (
<div className={styles.title}>{activeModel?.title}</div>
)}
}),
})}
>
{icon}
{title}
</div>
))}
</div>
<div className={styles.actions}>
{actions}
<IconButton size="small" onClick={handleCodeCopy}>
<Copy />
</IconButton>
</div>
</header>
<div className={styles.editorContainer}>
<div ref={containerRef} className={styles.editorContainer}>
<Editor
height="100%"
language="typescript"
height={editorHeight}
language={activeModel?.language ?? 'typescript'}
// TODO: need to check on the usage of value and defaultValue
defaultValue={activeModel?.defaultValue}
path={activeModel?.name}
Expand Down
2 changes: 2 additions & 0 deletions packages/console/src/pages/JwtClaims/MonacoCodeEditor/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ export type IStandaloneCodeEditor = Parameters<OnMount>[0];
export type Model = {
/** Used as the unique key for the monaco editor model @see {@link https://github.com/suren-atoyan/monaco-react?tab=readme-ov-file#multi-model-editor} */
name: string;
/** The icon of the model, will be displayed on the tab */
icon?: React.ReactNode;
/** The title of the model */
title: string;
defaultValue: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { useRef, useState, useLayoutEffect } from 'react';

// Recalculate the height of the editor when the container size changes
// This is to avoid the code editor's height shaking when the content is updated.
// @see {@link https://github.com/react-monaco-editor/react-monaco-editor/issues/391}
const useEditorHeight = () => {
const containerRef = useRef<HTMLDivElement>(null);

const [editorHeight, setEditorHeight] = useState<number | string>('100%');
const safeArea = 16;

useLayoutEffect(() => {
const handleResize = () => {
if (containerRef.current) {
setEditorHeight(containerRef.current.clientHeight - safeArea);
}
};

handleResize();

const resizeObserver = new ResizeObserver(handleResize);

if (containerRef.current) {
resizeObserver.observe(containerRef.current);
}

return () => {
resizeObserver.disconnect();
};
}, []);

return { containerRef, editorHeight };
};

export default useEditorHeight;
129 changes: 0 additions & 129 deletions packages/console/src/pages/JwtClaims/RightPanel/index.tsx

This file was deleted.

41 changes: 41 additions & 0 deletions packages/console/src/pages/JwtClaims/ScriptPanel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/* Code Editor for the custom JWT claims script. */
import { useMemo } from 'react';
import { useFormContext } from 'react-hook-form';
import { useTranslation } from 'react-i18next';

import Card from '@/ds-components/Card';

import MonacoCodeEditor, { type Model } from './MonacoCodeEditor';
import { userJwtFile, machineToMachineJwtFile, JwtTokenType } from './config';
import * as styles from './index.module.scss';
import { type JwtClaimsFormType } from './type';

const titlePhrases = Object.freeze({
[JwtTokenType.UserAccessToken]: 'user_jwt',
[JwtTokenType.MachineToMachineAccessToken]: 'machine_to_machine_jwt',
});

function ScriptPanel() {
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });

const { watch } = useFormContext<JwtClaimsFormType>();
const tokenType = watch('tokenType');

// TODO: API integration, read/write the custom claims code value
const activeModel = useMemo<Model>(() => {
return tokenType === JwtTokenType.UserAccessToken ? userJwtFile : machineToMachineJwtFile;
}, [tokenType]);

return (
<Card className={styles.codePanel}>
<div className={styles.cardTitle}>
{t('jwt_claims.code_editor_title', {
token: t(`jwt_claims.${titlePhrases[tokenType]}`),
})}
</div>
<MonacoCodeEditor className={styles.flexGrow} models={[activeModel]} />
</Card>
);
}

export default ScriptPanel;
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ function GuideCard({ name, children }: GuardCardProps) {
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console.jwt_claims' });

return (
<Card className={classNames(styles.card, expanded && styles.expanded)}>
<Card className={classNames(styles.card, styles.collapsible, expanded && styles.expanded)}>
<div
className={styles.headerRow}
role="button"
Expand Down
Loading

0 comments on commit 2d98982

Please sign in to comment.