mirror of
https://git.sr.ht/~ashkeel/strimertul
synced 2024-09-18 01:50:50 +00:00
parent
59cfee3f28
commit
18adbc2397
8 changed files with 91 additions and 16 deletions
|
@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- Added support for EventSub Websocket subscriptions on Twitch, making Twitch integration fully in-app without having to rely on third party servers. Check the "Events" tab in Twitch configuration for setting it up. The new keys for redeems are `twitch/ev/eventsub-event` and `twitch/eventsub-history`. History has been reduced to 50 to alleviate memory concerns.
|
||||
- Application logs are now visible from the UI, check the little floating boxes in the top right!
|
||||
- A new app icon drawn by [Sonic_chan](https://twitter.com/Sonic__Chan), say hello to Renko, strimertul's mascot!
|
||||
- Hidden fields (Client secret, Kilovolt password) now have a "Reveal" toggle to show the hidden value
|
||||
|
||||
### Changed
|
||||
|
||||
|
|
|
@ -261,7 +261,9 @@
|
|||
"add": "Add",
|
||||
"warning-delete": "This cannot be undone",
|
||||
"create": "Create",
|
||||
"submit": "Submit"
|
||||
"submit": "Submit",
|
||||
"password-reveal": "Reveal",
|
||||
"password-hide": "Hide"
|
||||
},
|
||||
"debug": {
|
||||
"dev-build": "Development build"
|
||||
|
|
23
frontend/src/ui/components/utils/PasswordField.tsx
Normal file
23
frontend/src/ui/components/utils/PasswordField.tsx
Normal file
|
@ -0,0 +1,23 @@
|
|||
import React from 'react';
|
||||
|
||||
export interface PasswordFieldProps {
|
||||
reveal: boolean;
|
||||
}
|
||||
|
||||
function PasswordField(
|
||||
props: PasswordFieldProps &
|
||||
React.PropsWithChildren<
|
||||
React.DetailedHTMLProps<
|
||||
React.InputHTMLAttributes<HTMLInputElement>,
|
||||
HTMLInputElement
|
||||
>
|
||||
>,
|
||||
) {
|
||||
return (
|
||||
<input type={props.reveal ? 'text' : 'password'} {...props}>
|
||||
{props.children}
|
||||
</input>
|
||||
);
|
||||
}
|
||||
|
||||
export default React.memo(PasswordField);
|
31
frontend/src/ui/components/utils/RevealLink.tsx
Normal file
31
frontend/src/ui/components/utils/RevealLink.tsx
Normal file
|
@ -0,0 +1,31 @@
|
|||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Button } from '../../theme';
|
||||
|
||||
export interface RevealLinkProps {
|
||||
value: boolean;
|
||||
setter: (newValue: boolean) => void;
|
||||
}
|
||||
|
||||
function RevealLink({ value, setter }: RevealLinkProps) {
|
||||
const { t } = useTranslation();
|
||||
const text = value
|
||||
? t('form-actions.password-hide')
|
||||
: t('form-actions.password-reveal');
|
||||
return (
|
||||
<Button
|
||||
type="button"
|
||||
css={{ display: 'inline-flex', marginLeft: '0.5rem' }}
|
||||
onClick={() => {
|
||||
if (setter) {
|
||||
setter(!value);
|
||||
}
|
||||
}}
|
||||
size={'smaller'}
|
||||
>
|
||||
{text}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
export default React.memo(RevealLink);
|
|
@ -1,8 +1,9 @@
|
|||
import React from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useModule, useStatus } from '../../lib/react-utils';
|
||||
import { useAppDispatch } from '../../store';
|
||||
import apiReducer, { modules } from '../../store/api/reducer';
|
||||
import RevealLink from '../components/utils/RevealLink';
|
||||
import SaveButton from '../components/utils/SaveButton';
|
||||
import {
|
||||
APPNAME,
|
||||
|
@ -13,6 +14,7 @@ import {
|
|||
PageContainer,
|
||||
PageHeader,
|
||||
PageTitle,
|
||||
PasswordInputBox,
|
||||
} from '../theme';
|
||||
|
||||
export default function ServerSettingsPage(): React.ReactElement {
|
||||
|
@ -24,6 +26,7 @@ export default function ServerSettingsPage(): React.ReactElement {
|
|||
const status = useStatus(loadStatus.save);
|
||||
const busy =
|
||||
loadStatus.load?.type !== 'success' || loadStatus.save?.type === 'pending';
|
||||
const [revealKVPassword, setRevealKVPassword] = useState(false);
|
||||
|
||||
return (
|
||||
<PageContainer>
|
||||
|
@ -59,22 +62,23 @@ export default function ServerSettingsPage(): React.ReactElement {
|
|||
<Field size="fullWidth">
|
||||
<Label htmlFor="kvpassword">
|
||||
{t('pages.http.kilovolt-password')}
|
||||
</Label>
|
||||
<InputBox
|
||||
type="password"
|
||||
<RevealLink value={revealKVPassword} setter={setRevealKVPassword} />
|
||||
</Label>{' '}
|
||||
<PasswordInputBox
|
||||
reveal={revealKVPassword}
|
||||
id="kvpassword"
|
||||
placeholder={t('pages.http.kilovolt-placeholder')}
|
||||
value={serverConfig?.kv_password ?? ''}
|
||||
disabled={busy}
|
||||
autoComplete="off"
|
||||
onChange={(e) =>
|
||||
onChange={(e) => {
|
||||
dispatch(
|
||||
apiReducer.actions.httpConfigChanged({
|
||||
...serverConfig,
|
||||
kv_password: e.target.value,
|
||||
}),
|
||||
)
|
||||
}
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<FieldNote>{t('pages.http.kilovolt-placeholder')}</FieldNote>
|
||||
</Field>
|
||||
|
|
|
@ -11,6 +11,7 @@ import { RootState, useAppDispatch } from '../../store';
|
|||
import apiReducer, { modules } from '../../store/api/reducer';
|
||||
import BrowserLink from '../components/BrowserLink';
|
||||
import DefinitionTable from '../components/DefinitionTable';
|
||||
import RevealLink from '../components/utils/RevealLink';
|
||||
import SaveButton from '../components/utils/SaveButton';
|
||||
import {
|
||||
APPNAME,
|
||||
|
@ -26,6 +27,7 @@ import {
|
|||
PageContainer,
|
||||
PageHeader,
|
||||
PageTitle,
|
||||
PasswordInputBox,
|
||||
SectionHeader,
|
||||
styled,
|
||||
TabButton,
|
||||
|
@ -59,6 +61,7 @@ function TwitchBotSettings() {
|
|||
const status = useStatus(loadStatus.save);
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
const [revealBotToken, setRevealBotToken] = useState(false);
|
||||
const active = twitchConfig?.enable_bot ?? false;
|
||||
|
||||
return (
|
||||
|
@ -138,9 +141,10 @@ function TwitchBotSettings() {
|
|||
<Field size="fullWidth">
|
||||
<Label htmlFor="bot-oauth">
|
||||
{t('pages.twitch-settings.bot-oauth')}
|
||||
<RevealLink value={revealBotToken} setter={setRevealBotToken} />
|
||||
</Label>
|
||||
<InputBox
|
||||
type="password"
|
||||
<PasswordInputBox
|
||||
reveal={revealBotToken}
|
||||
id="bot-oauth"
|
||||
required={active}
|
||||
disabled={!active || status?.type === 'pending'}
|
||||
|
@ -199,6 +203,7 @@ function TwitchAPISettings() {
|
|||
);
|
||||
const status = useStatus(loadStatus.save);
|
||||
const dispatch = useAppDispatch();
|
||||
const [revealClientSecret, setRevealClientSecret] = useState(false);
|
||||
|
||||
return (
|
||||
<form
|
||||
|
@ -265,9 +270,13 @@ function TwitchAPISettings() {
|
|||
<Field size="fullWidth">
|
||||
<Label htmlFor="clientsecret">
|
||||
{t('pages.twitch-settings.app-client-secret')}
|
||||
<RevealLink
|
||||
value={revealClientSecret}
|
||||
setter={setRevealClientSecret}
|
||||
/>
|
||||
</Label>
|
||||
<InputBox
|
||||
type="password"
|
||||
<PasswordInputBox
|
||||
reveal={revealClientSecret}
|
||||
id="clientsecret"
|
||||
placeholder={t('pages.twitch-settings.app-client-secret')}
|
||||
required={true}
|
||||
|
|
|
@ -2,9 +2,9 @@ import * as UnstyledLabel from '@radix-ui/react-label';
|
|||
import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
|
||||
import * as ToggleGroup from '@radix-ui/react-toggle-group';
|
||||
import { CSS } from '@stitches/react';
|
||||
import { styled } from './theme';
|
||||
import { theme } from '.';
|
||||
import { styled, theme } from './theme';
|
||||
import ControlledInput from '../components/utils/ControlledInput';
|
||||
import PasswordField from '../components/utils/PasswordField';
|
||||
|
||||
export const Field = styled('fieldset', {
|
||||
all: 'unset',
|
||||
|
@ -80,6 +80,7 @@ const inputStyles: CSS = {
|
|||
|
||||
export const InputBox = styled('input', inputStyles);
|
||||
export const ControlledInputBox = styled(ControlledInput, inputStyles);
|
||||
export const PasswordInputBox = styled(PasswordField, inputStyles);
|
||||
|
||||
export const Textarea = styled('textarea', {
|
||||
all: 'unset',
|
||||
|
@ -178,6 +179,11 @@ const button = {
|
|||
padding: '0.3rem 0.5rem',
|
||||
fontSize: '0.9rem',
|
||||
},
|
||||
smaller: {
|
||||
padding: '5px',
|
||||
paddingBottom: '3px',
|
||||
fontSize: '0.8rem',
|
||||
},
|
||||
},
|
||||
variation: {
|
||||
primary: {
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
/* eslint-disable import/prefer-default-export */
|
||||
|
||||
import { theme } from '.';
|
||||
import { styled } from './theme';
|
||||
import { styled, theme } from './theme';
|
||||
|
||||
export const FlexRow = styled('div', {
|
||||
display: 'flex',
|
||||
|
|
Loading…
Reference in a new issue