Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(console,phrases): add test sample code editor #5475

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 { 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 @@
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,40 +85,43 @@
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

Check warning on line 124 in packages/console/src/pages/JwtClaims/MonacoCodeEditor/index.tsx

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

packages/console/src/pages/JwtClaims/MonacoCodeEditor/index.tsx#L124

[no-warning-comments] Unexpected 'todo' comment: 'TODO: need to check on the usage of...'.
defaultValue={activeModel?.defaultValue}
path={activeModel?.name}
theme="logto-dark"
Expand Down
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

Check warning on line 24 in packages/console/src/pages/JwtClaims/ScriptPanel.tsx

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

packages/console/src/pages/JwtClaims/ScriptPanel.tsx#L24

[no-warning-comments] Unexpected 'todo' comment: 'TODO: API integration, read/write the...'.
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
Loading