Skip to content

Commit

Permalink
Add descriptions for project settings (#171)
Browse files Browse the repository at this point in the history
This commit adds descriptions to the project settings page to improve
user understanding of each setting's purpose and impact.

- Added descriptions for Auth Webhook URL and methods
- Explained the Client Deactivate Threshold
- Included links to relevant documentation
  • Loading branch information
chacha912 authored Sep 11, 2024
1 parent af50b23 commit 4fb5588
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 58 deletions.
3 changes: 3 additions & 0 deletions public/assets/icons/icon_link.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/assets/styles/pages/admin_setting_account.scss
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@

.guide {
padding-top: variables.$spacing_8;
@include mixins-lib.rfonts(12, 16, 500);
@include mixins-lib.rfonts(13, 18, 400);
color: var(--gray-500);
}

Expand Down
31 changes: 23 additions & 8 deletions src/assets/styles/pages/admin_setting_project.scss
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@

.guide {
margin-top: variables.$spacing_8;
@include mixins-lib.rfonts(12, 16, 500);
@include mixins-lib.rfonts(13, 18, 400);
color: var(--gray-500);

@include mixins-lib.mobileStart() {
Expand Down Expand Up @@ -193,14 +193,12 @@
}

.webhook {
.sub_desc {
&:last-child {
margin-top: variables.$spacing_24;
padding: 0 variables.$spacing_8;
.webhook_methods {
margin-top: variables.$spacing_24;
padding: 0 variables.$spacing_8;

@include mixins-lib.tabletStart() {
padding: 0;
}
@include mixins-lib.tabletStart() {
padding: 0;
}
}
}
Expand Down Expand Up @@ -241,4 +239,21 @@
}
}
}

.page_link {
color: var(--orange-0);
border-bottom: 1px solid var(--orange-0);

&.icon_link {
&::after {
display: inline-block;
width: 13px;
height: 13px;
margin-left: 2px;
background: url('/assets/icons/icon_link.svg') no-repeat center;
content: '';
vertical-align: text-top;
}
}
}
}
2 changes: 1 addition & 1 deletion src/assets/styles/pages/admin_setting_team.scss
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@
}

.guide {
@include mixins-lib.rfonts(12, 16, 500);
@include mixins-lib.rfonts(13, 18, 400);
color: var(--gray-500);
}

Expand Down
139 changes: 91 additions & 48 deletions src/features/projects/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,10 @@ export function Settings() {
control,
name: 'authWebhookMethods',
});
const { field: clientDeactivateThreshold, fieldState: clientDeactivateThresholdState } = useController({
control,
const { field: clientDeactivateThreshold, fieldState: clientDeactivateThresholdState } = useController({
control,
name: 'clientDeactivateThreshold',
});
});
const checkFieldState = useCallback(
(fieldName: keyof UpdatableProjectFields | AuthWebhookMethod, state: 'success' | 'error'): boolean => {
return updateFieldInfo.target === fieldName && updateFieldInfo.state === state;
Expand Down Expand Up @@ -109,7 +109,12 @@ export function Settings() {
);

useEffect(() => {
if (updateFieldInfo.state !== 'success' && !nameFieldState.error && !webhookURLFieldState.error && !clientDeactivateThresholdState.error) {
if (
updateFieldInfo.state !== 'success' &&
!nameFieldState.error &&
!webhookURLFieldState.error &&
!clientDeactivateThresholdState.error
) {
setUpdateFieldInfo((info) => ({
...info,
state: null,
Expand All @@ -123,7 +128,14 @@ export function Settings() {
message: formErrors[updateFieldInfo.target as keyof UpdatableProjectFields]?.message || '',
}));
}
}, [formErrors, updateFieldInfo.state, updateFieldInfo.target, nameFieldState.error, webhookURLFieldState.error, clientDeactivateThresholdState.error]);
}, [
formErrors,
updateFieldInfo.state,
updateFieldInfo.target,
nameFieldState.error,
webhookURLFieldState.error,
clientDeactivateThresholdState.error,
]);

useEffect(() => {
if (isSuccess) {
Expand Down Expand Up @@ -198,8 +210,8 @@ export function Settings() {
checkFieldState('name', 'success')
? 'success'
: checkFieldState('name', 'error')
? 'error'
: undefined
? 'error'
: undefined
}
helperText={
updateFieldInfo.target === 'name' && updateFieldInfo.state !== null
Expand All @@ -219,6 +231,19 @@ export function Settings() {
<dl className="sub_info">
<dt className="sub_title">Auth webhook URL</dt>
<dd className="sub_desc">
<p className="guide">
Enter the URL of the endpoint you want to use for authorization. This allows the server to check if a
client is allowed to access a Document by calling this webhook URL. Changes to this setting may take
up to 10 minutes to take effect.{' '}
<a
href="https://yorkie.dev/docs/cli#auth-webhook"
className="page_link icon_link"
target="_blank"
rel="noreferrer"
>
Learn more about how to set up and use the Auth Webhook.
</a>
</p>
<div
className={classNames('input_field_box', {
is_error: checkFieldState('authWebhookURL', 'error'),
Expand All @@ -243,8 +268,8 @@ export function Settings() {
checkFieldState('authWebhookURL', 'success')
? 'success'
: checkFieldState('authWebhookURL', 'error')
? 'error'
: undefined
? 'error'
: undefined
}
helperText={
updateFieldInfo.target === 'authWebhookURL' && updateFieldInfo.state !== null
Expand All @@ -257,43 +282,49 @@ export function Settings() {
</dd>
<dt className="sub_title">Auth webhook methods</dt>
<dd className="sub_desc">
{AUTH_WEBHOOK_METHODS.map((method) => {
return (
<div
className={classNames('input_group', {
is_error: checkFieldState(method, 'error'),
is_success: checkFieldState(method, 'success'),
})}
key={method}
>
<InputToggle
id={method}
label={method}
checked={webhookMethodField.value.includes(method)}
onChange={(e) => {
let newWebhookMethods = [...project?.authWebhookMethods!];
if (e.target.checked) {
newWebhookMethods = newWebhookMethods.includes(method)
? newWebhookMethods
: [...newWebhookMethods, method];
} else {
newWebhookMethods = newWebhookMethods.filter((newMethod) => newMethod !== method);
}
webhookMethodField.onChange(newWebhookMethods);
setUpdateFieldInfo((info) => ({ ...info, target: method }));
onSubmit({ authWebhookMethods: newWebhookMethods });
}}
/>
{updateFieldInfo.target === method && updateFieldInfo.state !== null && (
<InputHelperText
state={updateFieldInfo.state}
message={updateFieldInfo.message}
onSuccessEnd={resetUpdateFieldInfo}
<p className="guide">
Select which methods require webhook authorization. Only the selected methods will be checked for
authorization.
</p>
<div className="webhook_methods">
{AUTH_WEBHOOK_METHODS.map((method) => {
return (
<div
className={classNames('input_group', {
is_error: checkFieldState(method, 'error'),
is_success: checkFieldState(method, 'success'),
})}
key={method}
>
<InputToggle
id={method}
label={method}
checked={webhookMethodField.value.includes(method)}
onChange={(e) => {
let newWebhookMethods = [...project?.authWebhookMethods!];
if (e.target.checked) {
newWebhookMethods = newWebhookMethods.includes(method)
? newWebhookMethods
: [...newWebhookMethods, method];
} else {
newWebhookMethods = newWebhookMethods.filter((newMethod) => newMethod !== method);
}
webhookMethodField.onChange(newWebhookMethods);
setUpdateFieldInfo((info) => ({ ...info, target: method }));
onSubmit({ authWebhookMethods: newWebhookMethods });
}}
/>
)}
</div>
);
})}
{updateFieldInfo.target === method && updateFieldInfo.state !== null && (
<InputHelperText
state={updateFieldInfo.state}
message={updateFieldInfo.message}
onSuccessEnd={resetUpdateFieldInfo}
/>
)}
</div>
);
})}
</div>
</dd>
</dl>
</div>
Expand All @@ -304,6 +335,18 @@ export function Settings() {
<dl className="sub_info">
<dt className="sub_title">Client Deactivate Threshold</dt>
<dd className="sub_desc">
<p className="guide">
Set the duration for automatic client deactivation on documents in this project. To improve garbage
collection efficiency, clients inactive for this period will be automatically deactivated.{' '}
<a
href="https://github.com/yorkie-team/yorkie/blob/main/design/housekeeping.md"
className="page_link icon_link"
target="_blank"
rel="noreferrer"
>
Learn more about deactivating outdated clients and improving GC efficiency.
</a>
</p>
<div
className={classNames('input_field_box', {
is_error: checkFieldState('clientDeactivateThreshold', 'error'),
Expand All @@ -320,7 +363,7 @@ export function Settings() {
pattern: {
value: /^(\d{1,2}h\s?)?(\d{1,2}m\s?)?(\d{1,2}s)?$/,
message:
'Client Deactivate Threshold should be a signed sequence of decimal numbers, each with a unit suffix, such as "23h30m10s" or "2h45m"',
'Client Deactivate Threshold should be a signed sequence of decimal numbers, each with a unit suffix, such as "23h30m10s" or "2h45m"',
},
onChange: async () => {
await trigger('clientDeactivateThreshold');
Expand All @@ -339,8 +382,8 @@ export function Settings() {
checkFieldState('clientDeactivateThreshold', 'success')
? 'success'
: checkFieldState('clientDeactivateThreshold', 'error')
? 'error'
: undefined
? 'error'
: undefined
}
helperText={
updateFieldInfo.target === 'clientDeactivateThreshold' && updateFieldInfo.state !== null
Expand Down

0 comments on commit 4fb5588

Please sign in to comment.