mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2025-12-10 14:16:59 -06:00
commit
0dc6d70dd9
24
CHANGELOG.md
24
CHANGELOG.md
@ -4,6 +4,30 @@ All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org).
|
||||
|
||||
## [4.5.0] - 2025-08-08
|
||||
### Added
|
||||
* [shlink-web-component#755](https://github.com/shlinkio/shlink-web-component/issues/755) Add support for `any-value-query-param` and `valueless-query-param` redirect conditions when using Shlink >=4.5.0.
|
||||
* [shlink-web-component#756](https://github.com/shlinkio/shlink-web-component/issues/756) Add support for desktop device types on device redirect conditions, when using Shlink >=4.5.0.
|
||||
* [shlink-web-component#713](https://github.com/shlinkio/shlink-web-component/issues/713) Expose a new `ShlinkSidebarToggleButton` component that can be used to customize the location of the sidebar toggle, rather than making it assume there's a header bar and position it there.
|
||||
* [shlink-web-component#657](https://github.com/shlinkio/shlink-web-component/issues/657) Allow visits table columns to be customized via settings, and add a new optional "Region" column.
|
||||
|
||||
As a side effect, the "Show user agent" toggle has been removed from the list, as this can now be globally configured in the settings.
|
||||
|
||||
### Changed
|
||||
* Update to FontAwesome 7
|
||||
* Update to Recharts 3
|
||||
* Update to `@shlinkio/shlink-web-component` 0.16.1
|
||||
|
||||
### Deprecated
|
||||
* *Nothing*
|
||||
|
||||
### Removed
|
||||
* *Nothing*
|
||||
|
||||
### Fixed
|
||||
* [shlink-web-component#698](https://github.com/shlinkio/shlink-web-component/issues/698) Fix line chart selection triggering after clicking a dot in the chart. It now works only when dragging while the mouse is clicked.
|
||||
|
||||
|
||||
## [4.4.1] - 2025-06-23
|
||||
### Added
|
||||
* *Nothing*
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
FROM node:24.2-alpine AS node
|
||||
FROM node:24.4-alpine AS node
|
||||
COPY . /shlink-web-client
|
||||
ARG VERSION="latest"
|
||||
ENV VERSION=${VERSION}
|
||||
RUN cd /shlink-web-client && npm ci && node --run build
|
||||
|
||||
FROM nginxinc/nginx-unprivileged:1.27-alpine
|
||||
FROM nginxinc/nginx-unprivileged:1.29-alpine
|
||||
ARG UID=101
|
||||
LABEL maintainer="Alejandro Celaya <alejandro@alejandrocelaya.com>"
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
FROM mcr.microsoft.com/playwright:v1.53.1-noble
|
||||
FROM mcr.microsoft.com/playwright:v1.54.2-noble
|
||||
|
||||
ENV NODE_VERSION 22.14
|
||||
ENV TINI_VERSION v0.19.0
|
||||
|
||||
1833
package-lock.json
generated
1833
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
46
package.json
46
package.json
@ -20,28 +20,28 @@
|
||||
"test:verbose": "node --run test -- --verbose"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-free": "^6.7.2",
|
||||
"@fortawesome/fontawesome-svg-core": "^6.7.2",
|
||||
"@fortawesome/free-brands-svg-icons": "^6.7.2",
|
||||
"@fortawesome/free-regular-svg-icons": "^6.7.2",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.7.2",
|
||||
"@fortawesome/react-fontawesome": "^0.2.2",
|
||||
"@fortawesome/fontawesome-free": "^7.0.0",
|
||||
"@fortawesome/fontawesome-svg-core": "^7.0.0",
|
||||
"@fortawesome/free-brands-svg-icons": "^7.0.0",
|
||||
"@fortawesome/free-regular-svg-icons": "^7.0.0",
|
||||
"@fortawesome/free-solid-svg-icons": "^7.0.0",
|
||||
"@fortawesome/react-fontawesome": "^0.2.3",
|
||||
"@json2csv/plainjs": "^7.0.6",
|
||||
"@reduxjs/toolkit": "^2.8.2",
|
||||
"@shlinkio/data-manipulation": "^1.0.3",
|
||||
"@shlinkio/shlink-frontend-kit": "^1.0.0",
|
||||
"@shlinkio/shlink-js-sdk": "^2.1.0",
|
||||
"@shlinkio/shlink-web-component": "^0.15.0",
|
||||
"@shlinkio/shlink-frontend-kit": "^1.1.0",
|
||||
"@shlinkio/shlink-js-sdk": "^2.2.1",
|
||||
"@shlinkio/shlink-web-component": "^0.16.1",
|
||||
"bottlejs": "^2.0.1",
|
||||
"clsx": "^2.1.1",
|
||||
"compare-versions": "^6.1.1",
|
||||
"csvtojson": "^2.0.10",
|
||||
"date-fns": "^4.1.0",
|
||||
"react": "^19.1.0",
|
||||
"react-dom": "^19.1.0",
|
||||
"react": "^19.1.1",
|
||||
"react-dom": "^19.1.1",
|
||||
"react-external-link": "^2.5.0",
|
||||
"react-redux": "^9.2.0",
|
||||
"react-router": "^7.6.2",
|
||||
"react-router": "^7.7.1",
|
||||
"redux-localstorage-simple": "^2.5.1",
|
||||
"workbox-core": "^7.3.0",
|
||||
"workbox-expiration": "^7.3.0",
|
||||
@ -51,21 +51,21 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@shlinkio/eslint-config-js-coding-standard": "~3.5.0",
|
||||
"@stylistic/eslint-plugin": "^4.4.1",
|
||||
"@tailwindcss/vite": "^4.1.10",
|
||||
"@testing-library/jest-dom": "^6.6.3",
|
||||
"@stylistic/eslint-plugin": "^5.2.2",
|
||||
"@tailwindcss/vite": "^4.1.11",
|
||||
"@testing-library/jest-dom": "^6.6.4",
|
||||
"@testing-library/react": "^16.3.0",
|
||||
"@testing-library/user-event": "^14.6.1",
|
||||
"@total-typescript/shoehorn": "^0.1.2",
|
||||
"@types/react": "^19.1.8",
|
||||
"@types/react-dom": "^19.1.6",
|
||||
"@vitejs/plugin-react": "^4.5.2",
|
||||
"@types/react": "^19.1.9",
|
||||
"@types/react-dom": "^19.1.7",
|
||||
"@vitejs/plugin-react": "^4.7.0",
|
||||
"@vitest/browser": "^3.2.4",
|
||||
"@vitest/coverage-v8": "^3.2.4",
|
||||
"adm-zip": "^0.5.16",
|
||||
"axe-core": "^4.10.3",
|
||||
"chalk": "^5.4.1",
|
||||
"eslint": "^9.29.0",
|
||||
"eslint": "^9.32.0",
|
||||
"eslint-plugin-import": "^2.32.0",
|
||||
"eslint-plugin-jsx-a11y": "^6.10.2",
|
||||
"eslint-plugin-react": "^7.37.5",
|
||||
@ -73,12 +73,12 @@
|
||||
"eslint-plugin-react-hooks": "^5.2.0",
|
||||
"eslint-plugin-simple-import-sort": "^12.1.1",
|
||||
"history": "^5.3.0",
|
||||
"playwright": "^1.53.1",
|
||||
"playwright": "^1.54.2",
|
||||
"tailwindcss": "^4.1.3",
|
||||
"typescript": "^5.8.3",
|
||||
"typescript-eslint": "^8.34.1",
|
||||
"vite": "^6.3.5",
|
||||
"vite-plugin-pwa": "^1.0.0",
|
||||
"typescript-eslint": "^8.38.0",
|
||||
"vite": "^7.0.6",
|
||||
"vite-plugin-pwa": "^1.0.2",
|
||||
"vitest": "^3.0.5"
|
||||
},
|
||||
"browserslist": [
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { changeThemeInMarkup, getSystemPreferredTheme } from '@shlinkio/shlink-frontend-kit';
|
||||
import { ShlinkSidebarToggleButton, ShlinkSidebarVisibilityProvider } from '@shlinkio/shlink-web-component';
|
||||
import type { Settings } from '@shlinkio/shlink-web-component/settings';
|
||||
import { clsx } from 'clsx';
|
||||
import type { FC } from 'react';
|
||||
@ -62,35 +63,38 @@ const App: FCWithDeps<AppProps, AppDeps> = (
|
||||
|
||||
return (
|
||||
<div className="h-full">
|
||||
<MainHeader />
|
||||
<ShlinkSidebarVisibilityProvider>
|
||||
<ShlinkSidebarToggleButton className="fixed top-3.5 left-3 z-901" />
|
||||
<MainHeader />
|
||||
|
||||
<div className="h-full pt-(--header-height)">
|
||||
<div
|
||||
data-testid="shlink-wrapper"
|
||||
className={clsx(
|
||||
'min-h-full pb-[calc(var(--footer-height)+var(--footer-margin))] -mb-[calc(var(--footer-height)+var(--footer-margin))]',
|
||||
{ 'flex items-center pt-4': isHome },
|
||||
)}
|
||||
>
|
||||
<Routes>
|
||||
<Route index element={<Home />} />
|
||||
<Route path="/settings">
|
||||
{['', '*'].map((path) => <Route key={path} path={path} element={<Settings />} />)}
|
||||
</Route>
|
||||
<Route path="/manage-servers" element={<ManageServers />} />
|
||||
<Route path="/server/create" element={<CreateServer />} />
|
||||
<Route path="/server/:serverId/edit" element={<EditServer />} />
|
||||
<Route path="/server/:serverId">
|
||||
{['', '*'].map((path) => <Route key={path} path={path} element={<ShlinkWebComponentContainer />} />)}
|
||||
</Route>
|
||||
<Route path="*" element={<NotFound />} />
|
||||
</Routes>
|
||||
</div>
|
||||
<div className="h-full pt-(--header-height)">
|
||||
<div
|
||||
data-testid="shlink-wrapper"
|
||||
className={clsx(
|
||||
'min-h-full pb-[calc(var(--footer-height)+var(--footer-margin))] -mb-[calc(var(--footer-height)+var(--footer-margin))]',
|
||||
{ 'flex items-center pt-4': isHome },
|
||||
)}
|
||||
>
|
||||
<Routes>
|
||||
<Route index element={<Home />} />
|
||||
<Route path="/settings">
|
||||
{['', '*'].map((path) => <Route key={path} path={path} element={<Settings />} />)}
|
||||
</Route>
|
||||
<Route path="/manage-servers" element={<ManageServers />} />
|
||||
<Route path="/server/create" element={<CreateServer />} />
|
||||
<Route path="/server/:serverId/edit" element={<EditServer />} />
|
||||
<Route path="/server/:serverId">
|
||||
{['', '*'].map((path) => <Route key={path} path={path} element={<ShlinkWebComponentContainer />} />)}
|
||||
</Route>
|
||||
<Route path="*" element={<NotFound />} />
|
||||
</Routes>
|
||||
</div>
|
||||
|
||||
<div className="h-(--footer-height) mt-(--footer-margin) md:px-4">
|
||||
<ShlinkVersionsContainer />
|
||||
<div className="h-(--footer-height) mt-(--footer-margin) md:px-4">
|
||||
<ShlinkVersionsContainer />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ShlinkSidebarVisibilityProvider>
|
||||
|
||||
<AppUpdateBanner isOpen={appUpdated} onClose={resetAppUpdate} forceUpdate={forceUpdate} />
|
||||
</div>
|
||||
|
||||
@ -50,7 +50,7 @@ export const Home = ({ servers }: HomeProps) => {
|
||||
<p>This application will help you manage your Shlink servers.</p>
|
||||
<p>
|
||||
<Button to="/server/create" size="lg" inline>
|
||||
<FontAwesomeIcon icon={faPlus} /> Add a server
|
||||
<FontAwesomeIcon icon={faPlus} widthAuto /> Add a server
|
||||
</Button>
|
||||
</p>
|
||||
<p>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import type { ShlinkWebComponentType, TagColorsStorage } from '@shlinkio/shlink-web-component';
|
||||
import type { ShlinkWebComponentProps, TagColorsStorage } from '@shlinkio/shlink-web-component';
|
||||
import type { Settings } from '@shlinkio/shlink-web-component/settings';
|
||||
import type { FC } from 'react';
|
||||
import { memo } from 'react';
|
||||
@ -17,7 +17,7 @@ type ShlinkWebComponentContainerProps = WithSelectedServerProps & {
|
||||
type ShlinkWebComponentContainerDeps = {
|
||||
buildShlinkApiClient: ShlinkApiClientBuilder,
|
||||
TagColorsStorage: TagColorsStorage,
|
||||
ShlinkWebComponent: ShlinkWebComponentType,
|
||||
ShlinkWebComponent: FC<ShlinkWebComponentProps>,
|
||||
ServerError: FC,
|
||||
};
|
||||
|
||||
@ -51,6 +51,7 @@ const ShlinkWebComponentContainer: FCWithDeps<
|
||||
createNotFound={(nonPrefixedHomePath) => (
|
||||
<NotFound to={`${routesPrefix}${nonPrefixedHomePath}`}>List short URLs</NotFound>
|
||||
)}
|
||||
autoSidebarToggle={false}
|
||||
/>
|
||||
);
|
||||
}));
|
||||
|
||||
@ -51,12 +51,12 @@ const ManageServers: FCWithDeps<ManageServersProps, ManageServersDeps> = ({ serv
|
||||
<ImportServersBtn className="flex-grow" onError={setErrorImporting}>Import servers</ImportServersBtn>
|
||||
{filteredServers.length > 0 && (
|
||||
<Button variant="secondary" className="flex-grow" onClick={async () => serversExporter.exportServers()}>
|
||||
<FontAwesomeIcon icon={exportIcon} /> Export servers
|
||||
<FontAwesomeIcon icon={exportIcon} widthAuto /> Export servers
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
<Button className="md:ml-auto" to="/server/create">
|
||||
<FontAwesomeIcon icon={plusIcon} /> Add a server
|
||||
<FontAwesomeIcon icon={plusIcon} widthAuto /> Add a server
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
|
||||
@ -38,17 +38,17 @@ const ManageServersRowDropdown: FCWithDeps<ManageServersRowDropdownConnectProps,
|
||||
<>
|
||||
<RowDropdown menuAlignment="right">
|
||||
<RowDropdown.Item to={serverUrl} className="gap-1.5">
|
||||
<FontAwesomeIcon icon={connectIcon} fixedWidth /> Connect
|
||||
<FontAwesomeIcon icon={connectIcon} /> Connect
|
||||
</RowDropdown.Item>
|
||||
<RowDropdown.Item to={`${serverUrl}/edit`} className="gap-1.5">
|
||||
<FontAwesomeIcon icon={editIcon} fixedWidth /> Edit server
|
||||
<FontAwesomeIcon icon={editIcon} /> Edit server
|
||||
</RowDropdown.Item>
|
||||
<RowDropdown.Item onClick={() => setAutoConnect(server, !isAutoConnect)} className="gap-1.5">
|
||||
<FontAwesomeIcon icon={autoConnectIcon} fixedWidth /> {isAutoConnect ? 'Do not a' : 'A'}uto-connect
|
||||
<FontAwesomeIcon icon={autoConnectIcon} /> {isAutoConnect ? 'Do not a' : 'A'}uto-connect
|
||||
</RowDropdown.Item>
|
||||
<RowDropdown.Separator />
|
||||
<RowDropdown.Item className="[&]:text-danger gap-1.5" onClick={showModal}>
|
||||
<FontAwesomeIcon icon={deleteIcon} fixedWidth /> Remove server
|
||||
<FontAwesomeIcon icon={deleteIcon} /> Remove server
|
||||
</RowDropdown.Item>
|
||||
</RowDropdown>
|
||||
|
||||
|
||||
@ -15,7 +15,7 @@ export const ServersDropdown = ({ servers, selectedServer }: ServersDropdownProp
|
||||
return (
|
||||
<NavBar.Dropdown buttonContent={(
|
||||
<span className="flex items-center gap-1.5">
|
||||
<FontAwesomeIcon icon={serverIcon} fixedWidth /> Servers
|
||||
<FontAwesomeIcon icon={serverIcon} /> Servers
|
||||
</span>
|
||||
)}>
|
||||
{serversList.length === 0 ? (
|
||||
|
||||
@ -84,7 +84,7 @@ const ImportServersBtn: FCWithDeps<ImportServersBtnConnectProps, ImportServersBt
|
||||
return (
|
||||
<>
|
||||
<Button variant="secondary" className={className} onClick={() => fileInputRef.current?.click()} {...anchor}>
|
||||
<FontAwesomeIcon icon={importIcon} fixedWidth /> {children ?? 'Import from file'}
|
||||
<FontAwesomeIcon icon={importIcon} widthAuto /> {children ?? 'Import from file'}
|
||||
</Button>
|
||||
<Tooltip {...tooltip}>
|
||||
You can create servers by importing a CSV file with <b>name</b>, <b>apiKey</b> and <b>url</b> columns.
|
||||
|
||||
@ -13,7 +13,7 @@ export const Settings: FC<SettingsProps> = ({ settings, setSettings }) => (
|
||||
<NoMenuLayout>
|
||||
<ShlinkWebSettings
|
||||
settings={settings}
|
||||
updateSettings={setSettings}
|
||||
onUpdateSettings={setSettings}
|
||||
defaultShortUrlsListOrdering={DEFAULT_SHORT_URLS_ORDERING}
|
||||
/>
|
||||
</NoMenuLayout>
|
||||
|
||||
@ -27,13 +27,11 @@ exports[`<ManageServersRow /> > renders auto-connect icon only if server is auto
|
||||
class="svg-inline--fa fa-check text-lm-brand dark:text-dm-brand"
|
||||
data-icon="check"
|
||||
data-prefix="fas"
|
||||
focusable="false"
|
||||
role="img"
|
||||
viewBox="0 0 448 512"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M438.6 105.4c12.5 12.5 12.5 32.8 0 45.3l-256 256c-12.5 12.5-32.8 12.5-45.3 0l-128-128c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0L160 338.7 393.4 105.4c12.5-12.5 32.8-12.5 45.3 0z"
|
||||
d="M434.8 70.1c14.3 10.4 17.5 30.4 7.1 44.7l-256 352c-5.5 7.6-14 12.3-23.4 13.1s-18.5-2.7-25.1-9.3l-128-128c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0l101.5 101.5 234-321.7c10.4-14.3 30.4-17.5 44.7-7.1z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
|
||||
@ -15,16 +15,14 @@ exports[`<ManageServersRowDropdown /> > renders expected size and icon 1`] = `
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="svg-inline--fa fa-ellipsis-vertical "
|
||||
class="svg-inline--fa fa-ellipsis-vertical fa-width-auto "
|
||||
data-icon="ellipsis-vertical"
|
||||
data-prefix="fas"
|
||||
focusable="false"
|
||||
role="img"
|
||||
viewBox="0 0 128 512"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M64 360a56 56 0 1 0 0 112 56 56 0 1 0 0-112zm0-160a56 56 0 1 0 0 112 56 56 0 1 0 0-112zM120 96A56 56 0 1 0 8 96a56 56 0 1 0 112 0z"
|
||||
d="M64 144a56 56 0 1 1 0-112 56 56 0 1 1 0 112zm0 224c30.9 0 56 25.1 56 56s-25.1 56-56 56-56-25.1-56-56 25.1-56 56-56zm56-112c0 30.9-25.1 56-56 56s-56-25.1-56-56 25.1-56 56-56 56 25.1 56 56z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
@ -52,16 +50,14 @@ exports[`<ManageServersRowDropdown /> > renders expected size and icon 2`] = `
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="svg-inline--fa fa-ellipsis-vertical "
|
||||
class="svg-inline--fa fa-ellipsis-vertical fa-width-auto "
|
||||
data-icon="ellipsis-vertical"
|
||||
data-prefix="fas"
|
||||
focusable="false"
|
||||
role="img"
|
||||
viewBox="0 0 128 512"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M64 360a56 56 0 1 0 0 112 56 56 0 1 0 0-112zm0-160a56 56 0 1 0 0 112 56 56 0 1 0 0-112zM120 96A56 56 0 1 0 8 96a56 56 0 1 0 112 0z"
|
||||
d="M64 144a56 56 0 1 1 0-112 56 56 0 1 1 0 112zm0 224c30.9 0 56 25.1 56 56s-25.1 56-56 56-56-25.1-56-56 25.1-56 56-56zm56-112c0 30.9-25.1 56-56 56s-56-25.1-56-56 25.1-56 56-56 56 25.1 56 56z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user