Fix key error with react.

This commit is contained in:
SergeantPanda 2025-06-15 11:28:57 -05:00
parent e80d30689c
commit 9757f6a48d
2 changed files with 302 additions and 304 deletions

View file

@ -203,7 +203,7 @@ def environment(request):
country_code = None
country_name = None
# 1) Get the public IP
# 1) Get the public IP from ipify.org API
try:
r = requests.get("https://api64.ipify.org?format=json", timeout=5)
r.raise_for_status()
@ -211,17 +211,17 @@ def environment(request):
except requests.RequestException as e:
public_ip = f"Error: {e}"
# 2) Get the local IP
# 2) Get the local IP by connecting to a public DNS server
try:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# connect to a “public” address so the OS can determine our local interface
# connect to a "public" address so the OS can determine our local interface
s.connect(("8.8.8.8", 80))
local_ip = s.getsockname()[0]
s.close()
except Exception as e:
local_ip = f"Error: {e}"
# 3) If we got a valid public_ip, fetch geo info from ipapi.co or ip-api.com
# 3) Get geolocation data from ipapi.co or ip-api.com
if public_ip and "Error" not in public_ip:
try:
# Attempt to get geo information from ipapi.co first
@ -250,6 +250,7 @@ def environment(request):
country_code = None
country_name = None
# 4) Get environment mode from system environment variable
return Response(
{
"authenticated": True,

View file

@ -143,15 +143,14 @@ const SettingsPage = () => {
}, {})
);
const proxySettings = JSON.parse(
settings['proxy-settings'].value || '{}'
);
proxySettingsForm.setValues(
Object.keys(PROXY_SETTINGS_OPTIONS).reduce((acc, key) => {
acc[key] = proxySettings[key] || '';
return acc;
}, {})
);
if (settings['proxy-settings']?.value) {
try {
const proxySettings = JSON.parse(settings['proxy-settings'].value);
proxySettingsForm.setValues(proxySettings);
} catch (error) {
console.error('Error parsing proxy settings:', error);
}
}
}
}, [settings]);
@ -246,143 +245,217 @@ const SettingsPage = () => {
defaultValue="ui-settings"
onChange={setAccordianValue}
>
{[
<Accordion.Item value="ui-settings">
<Accordion.Control>UI Settings</Accordion.Control>
<Accordion.Panel>
<Select
label="Table Size"
value={tableSize}
onChange={(val) => onUISettingsChange('table-size', val)}
data={[
{
value: 'default',
label: 'Default',
},
{
value: 'compact',
label: 'Compact',
},
{
value: 'large',
label: 'Large',
},
]}
/>
</Accordion.Panel>
</Accordion.Item>,
].concat(
authUser.user_level == USER_LEVELS.ADMIN
? [
<Accordion.Item value="stream-settings">
<Accordion.Control>Stream Settings</Accordion.Control>
<Accordion.Panel>
<form onSubmit={form.onSubmit(onSubmit)}>
<Select
searchable
{...form.getInputProps('default-user-agent')}
key={form.key('default-user-agent')}
id={
settings['default-user-agent']?.id ||
'default-user-agent'
}
name={
settings['default-user-agent']?.key ||
'default-user-agent'
}
label={
settings['default-user-agent']?.name ||
'Default User Agent'
}
data={userAgents.map((option) => ({
value: `${option.id}`,
label: option.name,
}))}
/>
<Accordion.Item value="ui-settings">
<Accordion.Control>UI Settings</Accordion.Control>
<Accordion.Panel>
<Select
label="Table Size"
value={tableSize}
onChange={(val) => onUISettingsChange('table-size', val)}
data={[
{
value: 'default',
label: 'Default',
},
{
value: 'compact',
label: 'Compact',
},
{
value: 'large',
label: 'Large',
},
]}
/>
</Accordion.Panel>
</Accordion.Item>
<Select
searchable
{...form.getInputProps('default-stream-profile')}
key={form.key('default-stream-profile')}
id={
settings['default-stream-profile']?.id ||
'default-stream-profile'
}
name={
settings['default-stream-profile']?.key ||
'default-stream-profile'
}
label={
settings['default-stream-profile']?.name ||
'Default Stream Profile'
}
data={streamProfiles.map((option) => ({
value: `${option.id}`,
label: option.name,
}))}
/>
<Select
searchable
{...form.getInputProps('preferred-region')}
key={form.key('preferred-region')}
id={
settings['preferred-region']?.id ||
'preferred-region'
}
name={
settings['preferred-region']?.key ||
'preferred-region'
}
label={
settings['preferred-region']?.name ||
'Preferred Region'
}
data={regionChoices.map((r) => ({
label: r.label,
value: `${r.value}`,
}))}
/>
{authUser.user_level == USER_LEVELS.ADMIN && (
<>
<Accordion.Item value="stream-settings">
<Accordion.Control>Stream Settings</Accordion.Control>
<Accordion.Panel>
<form onSubmit={form.onSubmit(onSubmit)}>
<Select
searchable
{...form.getInputProps('default-user-agent')}
key={form.key('default-user-agent')}
id={
settings['default-user-agent']?.id ||
'default-user-agent'
}
name={
settings['default-user-agent']?.key ||
'default-user-agent'
}
label={
settings['default-user-agent']?.name ||
'Default User Agent'
}
data={userAgents.map((option) => ({
value: `${option.id}`,
label: option.name,
}))}
/>
<Group
justify="space-between"
style={{ paddingTop: 5 }}
<Select
searchable
{...form.getInputProps('default-stream-profile')}
key={form.key('default-stream-profile')}
id={
settings['default-stream-profile']?.id ||
'default-stream-profile'
}
name={
settings['default-stream-profile']?.key ||
'default-stream-profile'
}
label={
settings['default-stream-profile']?.name ||
'Default Stream Profile'
}
data={streamProfiles.map((option) => ({
value: `${option.id}`,
label: option.name,
}))}
/>
<Select
searchable
{...form.getInputProps('preferred-region')}
key={form.key('preferred-region')}
id={
settings['preferred-region']?.id ||
'preferred-region'
}
name={
settings['preferred-region']?.key ||
'preferred-region'
}
label={
settings['preferred-region']?.name ||
'Preferred Region'
}
data={regionChoices.map((r) => ({
label: r.label,
value: `${r.value}`,
}))}
/>
<Group
justify="space-between"
style={{ paddingTop: 5 }}
>
<Text size="sm" fw={500}>
Auto-Import Mapped Files
</Text>
<Switch
{...form.getInputProps('auto-import-mapped-files', {
type: 'checkbox',
})}
key={form.key('auto-import-mapped-files')}
id={
settings['auto-import-mapped-files']?.id ||
'auto-import-mapped-files'
}
/>
</Group>
<MultiSelect
id="m3u-hash-key"
name="m3u-hash-key"
label="M3U Hash Key"
data={[
{
value: 'name',
label: 'Name',
},
{
value: 'url',
label: 'URL',
},
{
value: 'tvg_id',
label: 'TVG-ID',
},
]}
{...form.getInputProps('m3u-hash-key')}
key={form.key('m3u-hash-key')}
/>
<Flex
mih={50}
gap="xs"
justify="flex-end"
align="flex-end"
>
<Button
type="submit"
disabled={form.submitting}
variant="default"
>
<Text size="sm" fw={500}>
Auto-Import Mapped Files
</Text>
<Switch
{...form.getInputProps('auto-import-mapped-files', {
type: 'checkbox',
})}
key={form.key('auto-import-mapped-files')}
id={
settings['auto-import-mapped-files']?.id ||
'auto-import-mapped-files'
}
/>
</Group>
Save
</Button>
</Flex>
</form>
</Accordion.Panel>
</Accordion.Item>
<MultiSelect
id="m3u-hash-key"
name="m3u-hash-key"
label="M3U Hash Key"
data={[
{
value: 'name',
label: 'Name',
},
{
value: 'url',
label: 'URL',
},
{
value: 'tvg_id',
label: 'TVG-ID',
},
]}
{...form.getInputProps('m3u-hash-key')}
key={form.key('m3u-hash-key')}
/>
<Accordion.Item value="user-agents">
<Accordion.Control>User-Agents</Accordion.Control>
<Accordion.Panel>
<UserAgentsTable />
</Accordion.Panel>
</Accordion.Item>
<Accordion.Item value="stream-profiles">
<Accordion.Control>Stream Profiles</Accordion.Control>
<Accordion.Panel>
<StreamProfilesTable />
</Accordion.Panel>
</Accordion.Item>
<Accordion.Item value="network-access">
<Accordion.Control>
<Box>Network Access</Box>
{accordianValue == 'network-access' && (
<Box>
<Text size="sm">Comma-Delimited CIDR ranges</Text>
</Box>
)}
</Accordion.Control>
<Accordion.Panel>
<form
onSubmit={networkAccessForm.onSubmit(
onNetworkAccessSubmit
)}
>
<Stack gap="sm">
{networkAccessSaved && (
<Alert
variant="light"
color="green"
title="Saved Successfully"
></Alert>
)}
{networkAccessError && (
<Alert
variant="light"
color="red"
title={networkAccessError}
></Alert>
)}
{Object.entries(NETWORK_ACCESS_OPTIONS).map(
([key, config]) => {
return (
<TextInput
label={config.label}
{...networkAccessForm.getInputProps(key)}
key={networkAccessForm.key(key)}
description={config.description}
/>
);
}
)}
<Flex
mih={50}
@ -392,181 +465,105 @@ const SettingsPage = () => {
>
<Button
type="submit"
disabled={form.submitting}
disabled={networkAccessForm.submitting}
variant="default"
>
Save
</Button>
</Flex>
</form>
</Accordion.Panel>
</Accordion.Item>,
</Stack>
</form>
</Accordion.Panel>
</Accordion.Item>
<Accordion.Item value="user-agents">
<Accordion.Control>User-Agents</Accordion.Control>
<Accordion.Panel>
<UserAgentsTable />
</Accordion.Panel>
</Accordion.Item>,
<Accordion.Item value="stream-profiles">
<Accordion.Control>Stream Profiles</Accordion.Control>
<Accordion.Panel>
<StreamProfilesTable />
</Accordion.Panel>
</Accordion.Item>,
<Accordion.Item value="network-access">
<Accordion.Control>
<Box>Network Access</Box>
{accordianValue == 'network-access' && (
<Box>
<Text size="sm">Comma-Delimited CIDR ranges</Text>
</Box>
<Accordion.Item value="proxy-settings">
<Accordion.Control>
<Box>Proxy Settings</Box>
</Accordion.Control>
<Accordion.Panel>
<form
onSubmit={proxySettingsForm.onSubmit(
onProxySettingsSubmit
)}
</Accordion.Control>
<Accordion.Panel>
<form
onSubmit={networkAccessForm.onSubmit(
onNetworkAccessSubmit
>
<Stack gap="sm">
{proxySettingsSaved && (
<Alert
variant="light"
color="green"
title="Saved Successfully"
></Alert>
)}
>
<Stack gap="sm">
{networkAccessSaved && (
<Alert
variant="light"
color="green"
title="Saved Successfully"
></Alert>
)}
{networkAccessError && (
<Alert
variant="light"
color="red"
title={networkAccessError}
></Alert>
)}
{Object.entries(NETWORK_ACCESS_OPTIONS).map(
([key, config]) => {
{Object.entries(PROXY_SETTINGS_OPTIONS).map(
([key, config]) => {
// Determine if this field should be a NumberInput
const isNumericField = [
'buffering_timeout',
'redis_chunk_ttl',
'channel_shutdown_delay',
'channel_init_grace_period'
].includes(key);
const isFloatField = key === 'buffering_speed';
if (isNumericField) {
return (
<NumberInput
key={key}
label={config.label}
{...proxySettingsForm.getInputProps(key)}
description={config.description || null}
min={0}
max={key === 'buffering_timeout' ? 300 :
key === 'redis_chunk_ttl' ? 3600 :
key === 'channel_shutdown_delay' ? 300 : 60}
/>
);
} else if (isFloatField) {
return (
<NumberInput
key={key}
label={config.label}
{...proxySettingsForm.getInputProps(key)}
description={config.description || null}
min={0.0}
max={10.0}
step={0.01}
precision={1}
/>
);
} else {
return (
<TextInput
key={key}
label={config.label}
{...networkAccessForm.getInputProps(key)}
key={networkAccessForm.key(key)}
description={config.description}
{...proxySettingsForm.getInputProps(key)}
description={config.description || null}
/>
);
}
)}
<Flex
mih={50}
gap="xs"
justify="flex-end"
align="flex-end"
>
<Button
type="submit"
disabled={networkAccessForm.submitting}
variant="default"
>
Save
</Button>
</Flex>
</Stack>
</form>
</Accordion.Panel>
</Accordion.Item>,
<Accordion.Item value="proxy-settings">
<Accordion.Control>
<Box>Proxy Settings</Box>
</Accordion.Control>
<Accordion.Panel>
<form
onSubmit={proxySettingsForm.onSubmit(
onProxySettingsSubmit
}
)}
>
<Stack gap="sm">
{proxySettingsSaved && (
<Alert
variant="light"
color="green"
title="Saved Successfully"
></Alert>
)}
{Object.entries(PROXY_SETTINGS_OPTIONS).map(
([key, config]) => {
// Determine if this field should be a NumberInput
const isNumericField = [
'buffering_timeout',
'redis_chunk_ttl',
'channel_shutdown_delay',
'channel_init_grace_period'
].includes(key);
const isFloatField = key === 'buffering_speed';
if (isNumericField) {
return (
<NumberInput
key={key}
label={config.label}
{...proxySettingsForm.getInputProps(key)}
description={config.description || null}
min={0}
max={key === 'buffering_timeout' ? 300 :
key === 'redis_chunk_ttl' ? 3600 :
key === 'channel_shutdown_delay' ? 300 : 60}
/>
);
} else if (isFloatField) {
return (
<NumberInput
key={key}
label={config.label}
{...proxySettingsForm.getInputProps(key)}
description={config.description || null}
min={0.1}
max={10.0}
step={0.1}
precision={1}
/>
);
} else {
return (
<TextInput
key={key}
label={config.label}
{...proxySettingsForm.getInputProps(key)}
description={config.description || null}
/>
);
}
}
)}
<Flex
mih={50}
gap="xs"
justify="flex-end"
align="flex-end"
<Flex
mih={50}
gap="xs"
justify="flex-end"
align="flex-end"
>
<Button
type="submit"
disabled={networkAccessForm.submitting}
variant="default"
>
<Button
type="submit"
disabled={networkAccessForm.submitting}
variant="default"
>
Save
</Button>
</Flex>
</Stack>
</form>
</Accordion.Panel>
</Accordion.Item>,
]
: []
Save
</Button>
</Flex>
</Stack>
</form>
</Accordion.Panel>
</Accordion.Item>
</>
)}
</Accordion>
</Box>