Add react-select and use for dynamic fallback ID and continent selection

develop
Thomas Lynch 1 year ago
parent d3cbd5004e
commit 5d98ba68f6
  1. 820
      package-lock.json
  2. 3
      package.json
  3. 62
      pages/_app.js
  4. 104
      pages/dns/[domain]/[zone]/[type].js

820
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -37,7 +37,8 @@
"openapi-client-axios": "^7.1.1",
"react": "^18.2.0",
"react-content-loader": "^6.2.0",
"react-dom": "^18.2.0"
"react-dom": "^18.2.0",
"react-select": "^5.7.3"
},
"devDependencies": {
"eslint": "8.15.0",

@ -32,6 +32,16 @@ export default function App({ Component, pageProps }) {
.text-decoration-none { color: var(--bs-body-color); }
.sidebar { box-shadow: 0 0px 3px rgba(0,0,0,0.2); }
.card { background: var(--bs-body-bg) !important; color: var(--bs-body-color) !important; }
.select__control {
transition: none;
}
.select__control:hover:not(.select__control--is-focused) {
border-color: #ced4da;
}
.select__control--menu-is-open, .select__control--is-focused {
box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
border-color: #86b7fe!important;
}
@media (max-width: 650px) {
.table, .list-group { min-width: unset; }
}
@ -45,9 +55,59 @@ export default function App({ Component, pageProps }) {
:root { --bs-body-color: #fff; --bs-body-bg: #161616; }
.text-muted, a, a:visited, a:hover, .nav-link, .nav-link:hover { color:#fff!important; }
.list-group-item { color: #fff; background-color: unset; }
input:not(.btn), option, select.form-select, textarea { color: #fff!important; background-color: #393939!important; border: 1px solid black!important; }
input:not(.btn):not(.select__input), option, select.form-select, textarea { color: #fff!important; background-color: #393939!important; border: 1px solid black!important; }
.list-group-item-action:focus, .list-group-item-action:hover { color: #fff; background-color: #1F1F1F; }
.table { color: #fff; border-color: var(--bs-gray-900)!important; }
.select__control {
background-color: #393939;
border-color: var(--bs-gray-900);
transition: none;
}
.select__input {
color: white!important;
}
.select__control:hover:not(.select__control--is-focused) {
border-color: black;
}
.select__control--is-focused,
.select__control--menu-is-open {
box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
border-color: black!important;
}
.select__multi-value {
background-color: var(--bs-dark);
border-radius: 5px;
}
.select__multi-value__label {
padding: 2px 10px;
color: #fff;
}
.select__menu {
background-color: #393939;
border: 1px solid var(--bs-gray-900);
}
.select__option {
background-color: #393939;
}
.select__option:hover {
background-color: var(--bs-dark);
}
.select__indicator-separator {
background-color: #393939;
}
.select__clear-indicator:hover {
color: #fff;
}
.select__multi-value__remove:hover {
background-color: #5D2F24;
color: #DE350B;
border-radius: 0 5px 5px 0;
}
.select__placeholder,
.select__single-value {
color: #fff;
}
}
`}
</style>

@ -3,8 +3,32 @@ import React, { useState, useEffect } from 'react';
import Head from 'next/head';
import BackButton from '../../../../components/BackButton.js';
import ErrorAlert from '../../../../components/ErrorAlert.js';
import Select from 'react-select';
// import CreatableSelect from 'react-select/creatable';
import * as API from '../../../../api.js';
const continentMap = {
'NA': 'North America',
'SA': 'South America',
'EU': 'Europe',
'AS': 'Asia',
'OC': 'Oceania',
'AF': 'Africa',
'AN': 'Antarctica',
}
const fromEntries = (pairs) => {
return pairs
.reduce((obj, [k, v]) => {
return {
...obj,
[k]: k in obj
? [].concat(obj[k], v)
: v
}
}, {})
};
const DnsEditRecordPage = (props) => {
const router = useRouter();
@ -16,6 +40,21 @@ const DnsEditRecordPage = (props) => {
const [type, setType] = useState(routerType || "a");
const [recordSelection, setRecordSelection] = useState("roundrobin");
const [error, setError] = useState();
const handleIdChange = (value, index) => {
recordSet[index].id = value;
setRecordSet([...recordSet]);
}
const handleValueChange = (value, index) => {
recordSet[index].ip = value;
setRecordSet([...recordSet]);
}
const getFallbackValue = (id) => {
const rec = recordSet.find(r => r.id === id);
if (rec) {
return (rec.ip || rec.host || rec.value || rec.ns || rec.text || rec.target || 'No Value');
}
return 'No Value'
}
useEffect(() => {
if (!recordSet) {
@ -44,7 +83,8 @@ const DnsEditRecordPage = (props) => {
async function addUpdateRecord(e) {
e.preventDefault();
await API.addUpdateDnsRecord(domain, zone, type, Object.fromEntries(new FormData(e.target)), dispatch, setError, router);
console.log(fromEntries([...new FormData(e.target).entries()]));
await API.addUpdateDnsRecord(domain, zone, type, fromEntries([...new FormData(e.target).entries()]), dispatch, setError, router);
}
const { csrf } = state;
@ -283,12 +323,25 @@ const DnsEditRecordPage = (props) => {
<div className="row" key={`row1_${i}`}>
{supportsHealth && <div className="col-sm-4 col-md-2">
ID:
<input className="form-control" type="text" name={`id_${i}`} defaultValue={rec.id} required />
<input
className="form-control"
type="text"
name={`id_${i}`}
onChange={(e) => handleIdChange(e.target.value, i)}
defaultValue={rec.id} required
/>
</div>}
<div className="col">
<label className="w-100">
Value
<input className="form-control" type="text" name={`value_${i}`} defaultValue={rec.ip || rec.host || rec.value || rec.ns || rec.text || rec.target} required />
<input
className="form-control"
type="text"
name={`value_${i}`}
onChange={(e) => handleValueChange(e.target.value, i)}
defaultValue={rec.ip || rec.host || rec.value || rec.ns || rec.text || rec.target}
required
/>
</label>
</div>
<div className="col-auto ms-auto">
@ -329,13 +382,21 @@ const DnsEditRecordPage = (props) => {
<div className="col-sm-12 col-md">
<label className="w-100">
Fallback IDs
<input
className="form-control"
type="text"
name={`fallbacks_${i}`}
defaultValue={(rec.fb||[]).join(', ')}
disabled={!rec.h}
required
<Select
theme={(theme) => ({
...theme,
borderRadius: 5,
})}
required
isMulti
closeMenuOnSelect={false}
options={recordSet.map(x => ({ label: x.id, value: x.id}) )}
getOptionLabel={x => `${x.value} (${getFallbackValue(x.value)})`}
formatCreateLabel={(inputValue) => `Add fallback to record ID "${inputValue}"`}
defaultValue={(rec.fb||[]).map(x => ({ value: x, label: x }))}
classNamePrefix="select"
name={`fallbacks_${i}`}
className="basic-multi-select"
/>
</label>
</div>
@ -387,7 +448,28 @@ const DnsEditRecordPage = (props) => {
<div className="col">
<label className="w-100">
Geo Value(s)
<input className="form-control" type="text" name={`geov_${i}`} defaultValue={(rec.geov||[]).join(', ')} required />
<Select
theme={(theme) => ({
...theme,
borderRadius: 5,
})}
required
isMulti
closeMenuOnSelect={false}
options={[
{ value: 'NA', label: 'North America' },
{ value: 'SA', label: 'South America' },
{ value: 'EU', label: 'Europe' },
{ value: 'AS', label: 'Asia' },
{ value: 'OC', label: 'Oceania' },
{ value: 'AF', label: 'Africa' },
{ value: 'AN', label: 'Antarctica' },
]}
defaultValue={(rec.geov||[]).map(x => ({ value: x, label: continentMap[x] }))}
classNamePrefix="select"
name={`geov_${i}`}
className="basic-multi-select"
/>
</label>
</div>
</div>}

Loading…
Cancel
Save