update readme; more style tweaks
This commit is contained in:
parent
b7ba430b32
commit
834ddafc9b
@ -1,10 +1,44 @@
|
||||
# About the Config editing section
|
||||
# Tips for creating a new Admin form
|
||||
|
||||
An adventure with React, React Hooks and Ant Design forms.
|
||||
### Layout
|
||||
- Give your page or form a title. Feel free to use Ant Design's `<Title>` component.
|
||||
- Give your form a description inside of a `<p className="description" />` tag.
|
||||
|
||||
## General data flow in this React app
|
||||
- Use some Ant Design `Row` and `Col`'s to layout your forms if you want to spread them out into responsive columns.
|
||||
|
||||
- Use the `form-module` CSS class if you want to add a visual separation to a grouping of items.
|
||||
|
||||
|
||||
|
||||
### Form fields
|
||||
- Feel free to use the pre-styled `<TextField>` text form field or the `<ToggleSwitch>` compnent, in a group of form fields together. These have been styled and laid out to match each other.
|
||||
|
||||
- `Slider`'s - If your form uses an Ant Slider component, follow this recommended markup of CSS classes to maintain a consistent look and feel to other Sliders in the app.
|
||||
```
|
||||
<div className="segment-slider-container">
|
||||
<Slider ...props />
|
||||
<p className="selected-value-note">{selected value}</p>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Submit Statuses
|
||||
- It would be nice to display indicators of success/warnings to let users know if something has been successfully updated on the server. It has a lot of steps (sorry, but it could probably be optimized), but it'll provide a consistent way to display messaging.
|
||||
|
||||
- See `reset-yp.tsx` for an example of using `submitStatus` with `useState()` and the `<FormStatusIndicator>` component to achieve this.
|
||||
|
||||
### Styling
|
||||
- This admin site chooses to have a generally Dark color palette, but with colors that are different from Ant design's _dark_ stylesheet, so that style sheet is not included. This results in a very large `ant-overrides.scss` file to reset colors on frequently used Ant components in the system. If you find yourself a new Ant Component that has not yet been used in this app, feel free to add a reset style for that component to the overrides stylesheet.
|
||||
|
||||
- Take a look at `variables.scss` CSS file if you want to give some elements custom css colors.
|
||||
|
||||
|
||||
---
|
||||
---
|
||||
# Creating Admin forms the Config section
|
||||
First things first..
|
||||
|
||||
## General Config data flow in this React app
|
||||
|
||||
### First things to note
|
||||
- When the Admin app loads, the `ServerStatusContext` (in addition to checking server `/status` on a timer) makes a call to the `/serverconfig` API to get your config details. This data will be stored as **`serverConfig`** in app state, and _provided_ to the app via `useContext` hook.
|
||||
|
||||
- The `serverConfig` in state is be the central source of data that pre-populates the forms.
|
||||
@ -13,10 +47,14 @@ An adventure with React, React Hooks and Ant Design forms.
|
||||
|
||||
- After you have updated a config value in a form field, and successfully submitted it through its endpoint, you should call `setFieldInConfigState` to update the global state with the new value.
|
||||
|
||||
- Each top field of the serverConfig has its own API update endpoint.
|
||||
|
||||
### Form Flow
|
||||
Each form input (or group of inputs) you make, you should
|
||||
## Suggested Config Form Flow
|
||||
- *NOTE: Each top field of the serverConfig has its own API update endpoint.*
|
||||
|
||||
|
||||
There many steps here, but they are highly suggested to ensure that Config values are updated and displayed properly throughout the entire admin form.
|
||||
|
||||
For each form input (or group of inputs) you make, you should:
|
||||
1. Get the field values that you want out of `serverConfig` from ServerStatusContext with `useContext`.
|
||||
2. Next we'll have to put these field values of interest into a `useState` in each grouping. This will help you edit the form.
|
||||
3. Because ths config data is populated asynchronously, Use a `useEffect` to check when that data has arrived before putting it into state.
|
||||
@ -27,7 +65,18 @@ Each form input (or group of inputs) you make, you should
|
||||
|
||||
There are also a variety of other local states to manage the display of error/success messaging.
|
||||
|
||||
## Notes about `form-textfield` and `form-togglefield`
|
||||
- It is recommended that you use `form-textfield-with-submit` and `form-toggleswitch`(with `useSubmit=true`) Components to edit Config fields.
|
||||
|
||||
Examples of Config form groups where individual form fields submitting to the update API include:
|
||||
- `edit-instance-details.tsx`
|
||||
- `edit-server-details.tsx`
|
||||
|
||||
Examples of Config form groups where there is 1 submit button for the entire group include:
|
||||
- `edit-storage.tsx`
|
||||
|
||||
|
||||
---
|
||||
#### Notes about `form-textfield-with-submit` and `form-togglefield` (with useSubmit=true)
|
||||
- The text field is intentionally designed to make it difficult for the user to submit bad data.
|
||||
- If you make a change on a field, a Submit buttton will show up that you have to click to update. That will be the only way you can update it.
|
||||
- If you clear out a field that is marked as Required, then exit/blur the field, it will repopulate with its original value.
|
||||
@ -40,7 +89,3 @@ There are also a variety of other local states to manage the display of error/su
|
||||
|
||||
- NOTE: you don't have to use these components. Some form groups may require a customized UX flow where you're better off using the Ant components straight up.
|
||||
|
||||
|
||||
|
||||
segment-slider-container
|
||||
selected-value-note
|
@ -51,7 +51,6 @@ export default function CPUUsageSelector({ defaultValue, onChange }: Props) {
|
||||
</p>
|
||||
<div className="segment-slider-container">
|
||||
<Slider
|
||||
tooltipVisible={false}
|
||||
tipFormatter={value => TOOLTIPS[value]}
|
||||
onChange={handleChange}
|
||||
min={1}
|
||||
|
@ -86,7 +86,7 @@ export default function EditInstanceDetails() {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="edit-public-details-container">
|
||||
<div className="edit-server-details-container">
|
||||
<div className="field-container field-streamkey-container">
|
||||
<div className="left-side">
|
||||
<TextFieldWithSubmit
|
||||
|
@ -1,27 +1,46 @@
|
||||
import { Popconfirm, Button, Typography } from 'antd';
|
||||
import { useContext } from 'react';
|
||||
import { useContext, useState } from 'react';
|
||||
import { AlertMessageContext } from '../../utils/alert-message-context';
|
||||
|
||||
import { API_YP_RESET, fetchData } from '../../utils/apis';
|
||||
import { RESET_TIMEOUT } from '../../utils/config-constants';
|
||||
import {
|
||||
createInputStatus,
|
||||
STATUS_ERROR,
|
||||
STATUS_PROCESSING,
|
||||
STATUS_SUCCESS,
|
||||
} from '../../utils/input-statuses';
|
||||
import FormStatusIndicator from './form-status-indicator';
|
||||
|
||||
export default function ResetYP() {
|
||||
const { setMessage } = useContext(AlertMessageContext);
|
||||
|
||||
const { Title } = Typography;
|
||||
const [submitStatus, setSubmitStatus] = useState(null);
|
||||
let resetTimer = null;
|
||||
const resetStates = () => {
|
||||
setSubmitStatus(null);
|
||||
resetTimer = null;
|
||||
clearTimeout(resetTimer);
|
||||
};
|
||||
|
||||
const resetDirectoryRegistration = async () => {
|
||||
setSubmitStatus(createInputStatus(STATUS_PROCESSING));
|
||||
try {
|
||||
await fetchData(API_YP_RESET);
|
||||
setMessage('');
|
||||
setSubmitStatus(createInputStatus(STATUS_SUCCESS));
|
||||
resetTimer = setTimeout(resetStates, RESET_TIMEOUT);
|
||||
} catch (error) {
|
||||
alert(error);
|
||||
setSubmitStatus(createInputStatus(STATUS_ERROR, `There was an error: ${error}`));
|
||||
resetTimer = setTimeout(resetStates, RESET_TIMEOUT);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Title level={3} className="section-title">
|
||||
<Typography.Title level={3} className="section-title">
|
||||
Reset Directory
|
||||
</Title>
|
||||
</Typography.Title>
|
||||
<p className="description">
|
||||
If you are experiencing issues with your listing on the Owncast Directory and were asked to
|
||||
"reset" your connection to the service, you can do that here. The next time you go
|
||||
@ -37,6 +56,9 @@ export default function ResetYP() {
|
||||
>
|
||||
<Button type="primary">Reset Directory Connection</Button>
|
||||
</Popconfirm>
|
||||
<p>
|
||||
<FormStatusIndicator status={submitStatus} />
|
||||
</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -36,14 +36,6 @@ const SLIDER_COMMENTS = {
|
||||
6: 'Highest latency, highest error tolerance',
|
||||
};
|
||||
|
||||
interface SegmentToolTipProps {
|
||||
value: string;
|
||||
}
|
||||
|
||||
function SegmentToolTip({ value }: SegmentToolTipProps) {
|
||||
return <span className="segment-tip">{value}</span>;
|
||||
}
|
||||
|
||||
export default function VideoLatency() {
|
||||
const [submitStatus, setSubmitStatus] = useState<StatusState>(null);
|
||||
const [selectedOption, setSelectedOption] = useState(null);
|
||||
@ -120,7 +112,7 @@ export default function VideoLatency() {
|
||||
|
||||
<div className="segment-slider-container">
|
||||
<Slider
|
||||
tooltipVisible={false}
|
||||
tipFormatter={value => SLIDER_COMMENTS[value]}
|
||||
onChange={handleChange}
|
||||
min={1}
|
||||
max={6}
|
||||
|
@ -230,7 +230,6 @@ export default function VideoVariantForm({
|
||||
<p className="description">{VIDEO_VARIANT_DEFAULTS.framerate.tip}</p>
|
||||
<div className="segment-slider-container">
|
||||
<Slider
|
||||
// tooltipVisible
|
||||
tipFormatter={value => `${value} ${framerateUnit}`}
|
||||
defaultValue={dataState.framerate}
|
||||
value={dataState.framerate}
|
||||
|
@ -472,7 +472,7 @@ textarea.ant-input {
|
||||
|
||||
// ANT POPOVER
|
||||
.ant-popover-inner {
|
||||
background-color: var(--black);
|
||||
background-color: var(--gray);
|
||||
}
|
||||
.ant-popover-message,
|
||||
.ant-popover-inner-content {
|
||||
@ -480,7 +480,7 @@ textarea.ant-input {
|
||||
|
||||
}
|
||||
.ant-popover-placement-topLeft > .ant-popover-content > .ant-popover-arrow {
|
||||
border-color: var(--black);
|
||||
border-color: var(--gray);
|
||||
}
|
||||
|
||||
|
||||
|
@ -22,8 +22,10 @@
|
||||
}
|
||||
|
||||
|
||||
// Do something special for the stream key field
|
||||
.field-streamkey-container {
|
||||
.edit-server-details-container {
|
||||
|
||||
// Do something special for the stream key field
|
||||
.field-streamkey-container {
|
||||
margin-bottom: 1.5em;
|
||||
.field-tip {
|
||||
color: var(--ant-warning);
|
||||
@ -47,4 +49,10 @@
|
||||
margin-top: 2em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.advanced-settings {
|
||||
max-width: 800px;
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user