mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2025-12-11 18:41:12 -06:00
Add advanced options to servers
This commit is contained in:
parent
4947e0490a
commit
e997d11c2c
14
package-lock.json
generated
14
package-lock.json
generated
@ -16,7 +16,7 @@
|
|||||||
"@json2csv/plainjs": "^7.0.6",
|
"@json2csv/plainjs": "^7.0.6",
|
||||||
"@reduxjs/toolkit": "^2.7.0",
|
"@reduxjs/toolkit": "^2.7.0",
|
||||||
"@shlinkio/data-manipulation": "^1.0.3",
|
"@shlinkio/data-manipulation": "^1.0.3",
|
||||||
"@shlinkio/shlink-frontend-kit": "^0.8.10",
|
"@shlinkio/shlink-frontend-kit": "^0.8.12",
|
||||||
"@shlinkio/shlink-js-sdk": "^2.1.0",
|
"@shlinkio/shlink-js-sdk": "^2.1.0",
|
||||||
"@shlinkio/shlink-web-component": "^0.13.3",
|
"@shlinkio/shlink-web-component": "^0.13.3",
|
||||||
"bootstrap": "5.2.3",
|
"bootstrap": "5.2.3",
|
||||||
@ -3438,9 +3438,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@shlinkio/shlink-frontend-kit": {
|
"node_modules/@shlinkio/shlink-frontend-kit": {
|
||||||
"version": "0.8.10",
|
"version": "0.8.12",
|
||||||
"resolved": "https://registry.npmjs.org/@shlinkio/shlink-frontend-kit/-/shlink-frontend-kit-0.8.10.tgz",
|
"resolved": "https://registry.npmjs.org/@shlinkio/shlink-frontend-kit/-/shlink-frontend-kit-0.8.12.tgz",
|
||||||
"integrity": "sha512-cB5qyZBCWEwLzEf3XK6ih/32x8i4ER4Tn6WNqIROhcr6Myjot0gvAfNStoXbEeYjJSw2+5wRFSccbAh3w5RxJA==",
|
"integrity": "sha512-J3t0HnvOaZDLSZ1zjbAn9l025GNTy7XvcKEV5+t8iYirf6THyGCK7JDoY1CfgRWfjiWBCFA+WmzrK92a2PqcAA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"clsx": "^2.1.1"
|
"clsx": "^2.1.1"
|
||||||
@ -13699,9 +13699,9 @@
|
|||||||
"requires": {}
|
"requires": {}
|
||||||
},
|
},
|
||||||
"@shlinkio/shlink-frontend-kit": {
|
"@shlinkio/shlink-frontend-kit": {
|
||||||
"version": "0.8.10",
|
"version": "0.8.12",
|
||||||
"resolved": "https://registry.npmjs.org/@shlinkio/shlink-frontend-kit/-/shlink-frontend-kit-0.8.10.tgz",
|
"resolved": "https://registry.npmjs.org/@shlinkio/shlink-frontend-kit/-/shlink-frontend-kit-0.8.12.tgz",
|
||||||
"integrity": "sha512-cB5qyZBCWEwLzEf3XK6ih/32x8i4ER4Tn6WNqIROhcr6Myjot0gvAfNStoXbEeYjJSw2+5wRFSccbAh3w5RxJA==",
|
"integrity": "sha512-J3t0HnvOaZDLSZ1zjbAn9l025GNTy7XvcKEV5+t8iYirf6THyGCK7JDoY1CfgRWfjiWBCFA+WmzrK92a2PqcAA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"clsx": "^2.1.1"
|
"clsx": "^2.1.1"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,7 +29,7 @@
|
|||||||
"@json2csv/plainjs": "^7.0.6",
|
"@json2csv/plainjs": "^7.0.6",
|
||||||
"@reduxjs/toolkit": "^2.7.0",
|
"@reduxjs/toolkit": "^2.7.0",
|
||||||
"@shlinkio/data-manipulation": "^1.0.3",
|
"@shlinkio/data-manipulation": "^1.0.3",
|
||||||
"@shlinkio/shlink-frontend-kit": "^0.8.10",
|
"@shlinkio/shlink-frontend-kit": "^0.8.12",
|
||||||
"@shlinkio/shlink-js-sdk": "^2.1.0",
|
"@shlinkio/shlink-js-sdk": "^2.1.0",
|
||||||
"@shlinkio/shlink-web-component": "^0.13.3",
|
"@shlinkio/shlink-web-component": "^0.13.3",
|
||||||
"bootstrap": "5.2.3",
|
"bootstrap": "5.2.3",
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import type { GetState } from '../../container/types';
|
|||||||
import type { ServerWithId } from '../../servers/data';
|
import type { ServerWithId } from '../../servers/data';
|
||||||
import { hasServerData } from '../../servers/data';
|
import { hasServerData } from '../../servers/data';
|
||||||
|
|
||||||
const apiClients: Record<string, ShlinkApiClient> = {};
|
const apiClients: Map<string, ShlinkApiClient> = new Map();
|
||||||
|
|
||||||
const isGetState = (getStateOrSelectedServer: GetState | ServerWithId): getStateOrSelectedServer is GetState =>
|
const isGetState = (getStateOrSelectedServer: GetState | ServerWithId): getStateOrSelectedServer is GetState =>
|
||||||
typeof getStateOrSelectedServer === 'function';
|
typeof getStateOrSelectedServer === 'function';
|
||||||
@ -18,19 +18,22 @@ const getSelectedServerFromState = (getState: GetState): ServerWithId => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const buildShlinkApiClient = (httpClient: HttpClient) => (getStateOrSelectedServer: GetState | ServerWithId) => {
|
export const buildShlinkApiClient = (httpClient: HttpClient) => (getStateOrSelectedServer: GetState | ServerWithId) => {
|
||||||
const { url: baseUrl, apiKey } = isGetState(getStateOrSelectedServer)
|
const { url: baseUrl, apiKey, forwardCredentials } = isGetState(getStateOrSelectedServer)
|
||||||
? getSelectedServerFromState(getStateOrSelectedServer)
|
? getSelectedServerFromState(getStateOrSelectedServer)
|
||||||
: getStateOrSelectedServer;
|
: getStateOrSelectedServer;
|
||||||
const serverKey = `${apiKey}_${baseUrl}`;
|
const serverKey = `${apiKey}_${baseUrl}_${forwardCredentials ? 'forward' : 'no-forward'}`;
|
||||||
|
const existingApiClient = apiClients.get(serverKey);
|
||||||
|
|
||||||
const apiClient = apiClients[serverKey] ?? new ShlinkApiClient(
|
if (existingApiClient) {
|
||||||
|
return existingApiClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
const apiClient = new ShlinkApiClient(
|
||||||
httpClient,
|
httpClient,
|
||||||
{ apiKey, baseUrl },
|
{ apiKey, baseUrl },
|
||||||
// FIXME Disabling this as it's breaking existing Shlink servers as configured out of the box
|
{ requestCredentials: forwardCredentials ? 'include' : undefined },
|
||||||
// { requestCredentials: 'include' },
|
|
||||||
);
|
);
|
||||||
apiClients[serverKey] = apiClient;
|
apiClients.set(serverKey, apiClient);
|
||||||
|
|
||||||
return apiClient;
|
return apiClient;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,7 @@ export interface ServerData {
|
|||||||
name: string;
|
name: string;
|
||||||
url: string;
|
url: string;
|
||||||
apiKey: string;
|
apiKey: string;
|
||||||
|
forwardCredentials?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ServerWithId extends ServerData {
|
export interface ServerWithId extends ServerData {
|
||||||
|
|||||||
@ -1,11 +1,15 @@
|
|||||||
|
import { useToggle } from '@shlinkio/shlink-frontend-kit';
|
||||||
import {
|
import {
|
||||||
|
Checkbox,
|
||||||
|
Details,
|
||||||
|
Label,
|
||||||
LabelledInput,
|
LabelledInput,
|
||||||
LabelledRevealablePasswordInput,
|
LabelledRevealablePasswordInput,
|
||||||
SimpleCard,
|
SimpleCard,
|
||||||
} from '@shlinkio/shlink-frontend-kit/tailwind';
|
} from '@shlinkio/shlink-frontend-kit/tailwind';
|
||||||
import type { FC, PropsWithChildren, ReactNode } from 'react';
|
import type { FC, PropsWithChildren, ReactNode } from 'react';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { handleEventPreventingDefault } from '../../utils/utils';
|
import { usePreventDefault } from '../../utils/utils';
|
||||||
import type { ServerData } from '../data';
|
import type { ServerData } from '../data';
|
||||||
|
|
||||||
type ServerFormProps = PropsWithChildren<{
|
type ServerFormProps = PropsWithChildren<{
|
||||||
@ -18,7 +22,11 @@ export const ServerForm: FC<ServerFormProps> = ({ onSubmit, initialValues, child
|
|||||||
const [name, setName] = useState(initialValues?.name ?? '');
|
const [name, setName] = useState(initialValues?.name ?? '');
|
||||||
const [url, setUrl] = useState(initialValues?.url ?? '');
|
const [url, setUrl] = useState(initialValues?.url ?? '');
|
||||||
const [apiKey, setApiKey] = useState(initialValues?.apiKey ?? '');
|
const [apiKey, setApiKey] = useState(initialValues?.apiKey ?? '');
|
||||||
const handleSubmit = handleEventPreventingDefault(() => onSubmit({ name, url, apiKey }));
|
const { flag: forwardCredentials, toggle: toggleForwardCredentials } = useToggle(
|
||||||
|
initialValues?.forwardCredentials ?? false,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
const handleSubmit = usePreventDefault(() => onSubmit({ name, url, apiKey, forwardCredentials }));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form name="serverForm" onSubmit={handleSubmit}>
|
<form name="serverForm" onSubmit={handleSubmit}>
|
||||||
@ -31,6 +39,19 @@ export const ServerForm: FC<ServerFormProps> = ({ onSubmit, initialValues, child
|
|||||||
onChange={(e) => setApiKey(e.target.value)}
|
onChange={(e) => setApiKey(e.target.value)}
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
|
<Details summary="Advanced options">
|
||||||
|
<div className="tw:flex tw:flex-col tw:gap-1">
|
||||||
|
<Label className="tw:flex tw:items-center tw:gap-x-1.5 tw:cursor-pointer">
|
||||||
|
<Checkbox onChange={toggleForwardCredentials} checked={forwardCredentials} />
|
||||||
|
Forward credentials (like cookies) to this server on every request.
|
||||||
|
</Label>
|
||||||
|
<small className="tw:pl-5.5 tw:text-gray-600 tw:dark:text-gray-400">
|
||||||
|
<b>Important!</b> If you are not sure what this means, leave it unchecked. Enabling this option will
|
||||||
|
make all requests fail for Shlink older than v4.5.0, as it requires the server to set a more strict
|
||||||
|
value for <code className="tw:whitespace-nowrap">Access-Control-Allow-Origin</code> than <code>*</code>.
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
</Details>
|
||||||
</SimpleCard>
|
</SimpleCard>
|
||||||
|
|
||||||
<div className="tw:flex tw:items-center tw:justify-end tw:gap-x-2">{children}</div>
|
<div className="tw:flex tw:items-center tw:justify-end tw:gap-x-2">{children}</div>
|
||||||
|
|||||||
@ -1,6 +1,11 @@
|
|||||||
import type { SyntheticEvent } from 'react';
|
import type { SyntheticEvent } from 'react';
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
export const handleEventPreventingDefault = <T>(handler: () => T) => (e: SyntheticEvent) => {
|
/**
|
||||||
|
* Wraps an event handler so that it calls e.preventDefault() before invoking the event handler
|
||||||
|
*/
|
||||||
|
export const usePreventDefault = <Event extends SyntheticEvent = SyntheticEvent>(handler: (e: Event) => void) =>
|
||||||
|
useCallback((e: Event) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
handler();
|
handler(e);
|
||||||
};
|
}, [handler]);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user