shlink-web-client/feature/fix-multi-dots/static/js/main.07ae98bb.chunk.js.map

1 line
No EOL
499 KiB
Text

{"version":3,"sources":["servers/helpers/withoutSelectedServer.tsx","utils/helpers/files.ts","common/img/ShlinkLogo.tsx","servers/helpers/withSelectedServer.tsx","common/NotFound.tsx","servers/ServersListGroup.tsx","utils/helpers/hooks.ts","utils/utils.ts","servers/data/index.ts","common/services/provideServices.ts","common/ScrollToTop.tsx","common/ErrorHandler.tsx","common/services/ImageDownloader.ts","utils/services/provideServices.ts","utils/services/LocalStorage.ts","utils/services/ColorGenerator.ts","common/ShlinkVersions.tsx","common/ShlinkVersionsContainer.tsx","common/MainHeader.tsx","common/Home.tsx","common/MenuLayout.tsx","common/AsideMenu.tsx","utils/SimpleCard.tsx","utils/helpers/features.ts","utils/theme/index.ts","utils/helpers/query.ts","utils/Message.tsx","utils/SearchField.tsx","api/services/ShlinkApiClient.ts","api/services/ShlinkApiClientBuilder.ts","api/services/provideServices.ts","short-urls/ShortUrls.tsx","tags/helpers/Tag.tsx","utils/DropdownBtn.tsx","utils/helpers/date.ts","utils/dates/types/index.ts","utils/DateInput.tsx","utils/dates/DateRangeRow.tsx","utils/dates/DateIntervalDropdownItems.tsx","utils/dates/DateRangeSelector.tsx","short-urls/SearchBar.tsx","utils/SortingDropdown.tsx","mercure/helpers/boundToMercureHub.tsx","mercure/helpers/index.ts","mercure/helpers/Topics.ts","utils/helpers/redux.ts","visits/VisitsStats.tsx","short-urls/helpers/index.ts","visits/reducers/visitCreation.ts","api/utils/index.ts","short-urls/reducers/shortUrlDeletion.ts","short-urls/reducers/shortUrlCreation.ts","short-urls/reducers/shortUrlEdition.ts","short-urls/reducers/shortUrlsList.ts","short-urls/reducers/shortUrlsListParams.ts","utils/helpers/numbers.ts","utils/helpers/pagination.ts","short-urls/Paginator.tsx","short-urls/ShortUrlsList.tsx","utils/CopyToClipboardIcon.tsx","utils/Time.tsx","short-urls/helpers/ShortUrlDetailLink.tsx","short-urls/helpers/ShortUrlVisitsCount.tsx","short-urls/helpers/ShortUrlsRow.tsx","utils/DropdownBtnMenu.tsx","short-urls/helpers/ShortUrlsRowMenu.tsx","short-urls/CreateShortUrl.tsx","utils/Result.tsx","api/ShlinkApiError.tsx","short-urls/helpers/DeleteShortUrlModal.tsx","short-urls/helpers/CreateShortUrlResult.tsx","short-urls/ShortUrlsTable.tsx","short-urls/helpers/qr-codes/QrFormatDropdown.tsx","short-urls/helpers/qr-codes/QrErrorCorrectionDropdown.tsx","short-urls/helpers/QrCodeModal.tsx","utils/helpers/qrCodes.ts","utils/BooleanControl.tsx","utils/Checkbox.tsx","short-urls/UseExistingIfFoundInfoIcon.tsx","utils/InfoTooltip.tsx","short-urls/helpers/ShortUrlFormCheckboxGroup.tsx","short-urls/ShortUrlForm.tsx","short-urls/EditShortUrl.tsx","short-urls/reducers/shortUrlDetail.ts","short-urls/services/provideServices.ts","utils/FormGroupContainer.tsx","servers/helpers/ServerForm.tsx","servers/CreateServer.tsx","servers/ServersDropdown.tsx","servers/DeleteServerModal.tsx","servers/DeleteServerButton.tsx","servers/EditServer.tsx","servers/helpers/ImportServersBtn.tsx","servers/reducers/selectedServer.ts","servers/reducers/servers.ts","servers/reducers/remoteServers.ts","servers/helpers/ForServerVersion.tsx","servers/helpers/ServerError.tsx","servers/Overview.tsx","servers/services/ServersImporter.ts","servers/services/ServersExporter.ts","servers/services/provideServices.ts","visits/VisitsHeader.tsx","visits/ShortUrlVisitsHeader.tsx","utils/helpers/visits.ts","utils/ToggleSwitch.tsx","utils/helpers/charts.ts","visits/charts/LineChartCard.tsx","common/SimplePaginator.tsx","visits/VisitsTable.tsx","visits/helpers/MapModal.tsx","visits/helpers/OpenMapModalBtn.tsx","visits/types/helpers.ts","visits/services/VisitsParser.ts","visits/helpers/VisitsFilterDropdown.tsx","visits/charts/DoughnutChartLegend.tsx","visits/charts/DoughnutChart.tsx","visits/charts/ChartCard.tsx","visits/charts/DoughnutChartCard.tsx","utils/PaginationDropdown.tsx","visits/charts/HorizontalBarChart.tsx","visits/charts/SortableBarChartCard.tsx","visits/ShortUrlVisits.tsx","visits/reducers/common.ts","visits/reducers/shortUrlVisits.ts","visits/TagVisitsHeader.tsx","visits/TagVisits.tsx","visits/reducers/tagVisits.ts","visits/OrphanVisitsHeader.tsx","visits/OrphanVisits.tsx","visits/reducers/orphanVisits.ts","visits/reducers/visitsOverview.ts","visits/services/VisitsExporter.ts","visits/services/provideServices.ts","tags/helpers/TagBullet.tsx","tags/helpers/TagsSelector.tsx","tags/TagCard.tsx","tags/helpers/DeleteTagConfirmModal.tsx","tags/helpers/EditTagModal.tsx","tags/TagsModeDropdown.tsx","tags/TagsList.tsx","tags/reducers/tagDelete.ts","tags/reducers/tagEdit.ts","tags/reducers/tagsList.ts","tags/TagsCards.tsx","tags/TagsTable.tsx","tags/TagsTableRow.tsx","tags/services/provideServices.ts","mercure/reducers/mercureInfo.ts","mercure/services/provideServices.ts","settings/RealTimeUpdates.tsx","settings/Settings.tsx","settings/reducers/settings.ts","settings/ShortUrlCreation.tsx","settings/UserInterface.tsx","utils/dates/DateIntervalSelector.tsx","settings/Visits.tsx","settings/services/provideServices.ts","domains/reducers/domainRedirects.ts","domains/reducers/domainsList.ts","domains/DomainSelector.tsx","domains/helpers/EditDomainRedirectsModal.tsx","domains/DomainRow.tsx","domains/ManageDomains.tsx","domains/services/provideServices.ts","app/reducers/appUpdates.ts","common/AppUpdateBanner.tsx","utils/helpers/sw.ts","app/App.tsx","app/services/provideServices.ts","container/index.ts","reducers/index.ts","container/store.ts","serviceWorkerRegistration.ts","utils/helpers/leaflet.ts","index.tsx","common/NoMenuLayout.tsx","utils/helpers/version.ts"],"names":["withoutSelectedServer","WrappedComponent","props","useEffect","resetSelectedServer","saveUrl","url","filename","document","link","createElement","setAttribute","style","visibility","body","appendChild","click","removeChild","saveCsv","window","csv","blob","Blob","type","URL","createObjectURL","ShlinkLogo","color","MAIN_COLOR","className","viewBox","version","xmlns","fill","d","withSelectedServer","ServerError","selectServer","selectedServer","match","params","serverId","isNotFoundServer","loading","NotFound","to","children","ServerListItem","id","name","ListGroupItem","tag","Link","icon","chevronIcon","ServersListGroup","servers","embedded","length","ListGroup","classNames","map","useStateFlagTimeout","setTimeout","clearTimeout","initialValue","delay","useState","flag","setFlag","timeout","useRef","undefined","callback","current","useToggle","useSwipeable","showSidebar","hideSidebar","swipeMenuIfNoModalExists","e","event","composedPath","some","classList","contains","querySelector","useReactSwipeable","delta","onSwipedLeft","onSwipedRight","useQueryState","paramName","initialState","value","setValue","location","history","query","parseQuery","search","pushState","pathname","stringifyQuery","determineOrderDir","currentField","newField","currentOrderDir","ASC","DESC","rangeOf","size","mappingFn","startAt","range","hasValue","isNil","isEmpty","handleEventPreventingDefault","handler","pipe","preventDefault","nonEmptyValueOrNull","capitalize","charAt","toUpperCase","slice","hasServerData","server","apiKey","isServerWithId","hasOwnProperty","isReachableServer","getServerId","provideServices","bottle","connect","withRouter","constant","global","console","axios","service","ImageDownloader","serviceFactory","ScrollToTop","decorator","MainHeader","Home","MenuLayout","AsideMenu","ShlinkVersionsContainer","ErrorHandler","scrollTo","error","state","hasError","this","outline","onClick","reload","Component","imgUrl","get","responseType","data","localStorage","LocalStorage","ColorGenerator","buildPath","path","key","item","getItem","JSON","parse","set","setItem","stringify","floor","Math","random","letters","normalizeKey","toLowerCase","trim","storage","colors","getColorForKey","normalizedKey","setColorForKey","join","normalizeVersion","versionToSemVer","versionToPrintable","VersionLink","project","href","ShlinkVersions","clientVersion","normalizedClientVersion","printableVersion","classes","ServersDropdown","isOpen","toggleOpen","close","settingsPath","toggleClass","Navbar","dark","fixed","expand","NavbarBrand","NavbarToggler","arrowIcon","Collapse","navbar","Nav","NavItem","NavLink","active","cogsIcon","serversList","values","hasServers","Card","Row","noGutters","faPlus","faExternalLinkAlt","TagsList","ShortUrls","CreateShortUrl","ShortUrlVisits","TagVisits","OrphanVisits","Overview","EditShortUrl","ManageDomains","sidebarVisible","toggleSidebar","addOrphanVisitsRoute","supportsOrphanVisits","addManageDomainsRoute","supportsDomainRedirects","burgerClasses","swipeableProps","burgerIcon","showOnMobile","exact","from","component","render","AsideMenuItem","rest","activeClassName","DeleteServerButton","addManageDomainsLink","asideClass","suffix","fixedWidth","overviewIcon","isActive","_","listIcon","createIcon","flip","tagsIcon","domainsIcon","editIcon","textClassName","SimpleCard","title","bodyClassName","serverMatchesVersions","versions","versionMatch","supportsQrCodeSizeInQuery","minVersion","supportsShortUrlTitle","supportsQrCodeMargin","supportsTagsInPatch","supportsBotVisits","supportsCrawlableVisits","supportsQrErrorCorrection","MAIN_COLOR_ALPHA","HIGHLIGHTED_COLOR","HIGHLIGHTED_COLOR_ALPHA","PRIMARY_LIGHT_COLOR","PRIMARY_DARK_COLOR","changeThemeInMarkup","theme","html","getElementsByTagName","isDarkThemeEnabled","getAttribute","qs","ignoreQueryPrefix","arrayFormat","getClassForType","default","getTextClassForType","Message","fullWidth","preloader","spin","timer","buildShlinkBaseUrl","apiVersion","rejectNilProps","reject","ShlinkApiClient","baseUrl","listShortUrls","a","performRequest","then","shortUrls","createShortUrl","options","filteredOptions","resp","getShortUrlVisits","shortCode","visits","getTagVisits","getOrphanVisits","getVisitsOverview","getShortUrl","domain","deleteShortUrl","updateShortUrlTags","tags","updateShortUrl","listTags","withStats","stats","deleteTags","editTag","oldName","newName","health","mercureInfo","listDomains","domains","editDomainRedirects","domainRedirects","method","headers","paramsSerializer","response","apiClients","buildShlinkApiClient","getStateOrSelectedServer","getState","isGetState","prop","Error","clientKey","SearchBar","ShortUrlsList","page","urlsListKey","setUrlsListKey","SearchField","onChange","large","noBorder","searchTerm","setSearchTerm","resetTimer","searchTermChanged","newSearchTerm","placeholder","target","searchIcon","hidden","Tag","text","clearable","colorGenerator","onClose","backgroundColor","cursor","DropdownBtn","disabled","dropdownClassName","right","minWidth","toggle","toggleClasses","Dropdown","DropdownToggle","caret","DropdownMenu","isDateObject","date","formatDateFromFormat","theFormat","format","formatISO","formatIsoDate","formatInternational","formatDate","dateRangeIsEmpty","dateRange","filter","Boolean","rangeIsInterval","INTERVAL_TO_STRING_MAP","today","yesterday","last7Days","last30Days","last90Days","last180days","last365Days","DATE_INTERVALS","Object","keys","rangeOrIntervalToString","startDate","endDate","dateRangeToString","startOfDaysAgo","daysAgo","startOfDay","subDays","Date","endingToday","endOfDay","intervalToDateRange","dateInterval","DateInput","isClearable","selected","showCalendarIcon","ref","dateFormat","calendarIcon","input","focus","DateRangeRow","onStartDateChange","onEndDateChange","placeholderText","maxDate","minDate","DateIntervalDropdownItems","interval","DropdownItem","DateRangeSelector","onDatesChange","initialDateRange","defaultText","activeInterval","setActiveInterval","activeDateRange","setActiveDateRange","updateDateRange","updateInterval","divider","header","dateOrNull","parseISO","shortUrlsListParams","selectedTags","setDates","dates","selectedTag","SortingDropdown","items","orderField","orderDir","isButton","handleItemClick","fieldKey","newOrderDir","UncontrolledDropdown","toPairs","fieldValue","sortAscIcon","sortDescIcon","boundToMercureHub","getTopicsForProps","pendingUpdates","Set","createNewVisits","loadMercureInfo","closeEventSource","topics","onMessage","onTokenExpired","mercureHubUrl","token","onEventSourceMessage","onEventSourceError","status","subscriptions","topic","hubUrl","searchParams","append","es","EventSource","Authorization","onmessage","onerror","forEach","bindToMercureTopic","visit","add","setInterval","clear","clearInterval","Topics","orphanVisits","shortUrlVisits","selectedBar","buildReducer","action","actionHandler","currentState","buildActionCreator","shortUrlMatches","shortUrl","CREATE_VISITS","createdVisits","parseApiError","isInvalidDeletionError","DELETE_SHORT_URL_START","DELETE_SHORT_URL_ERROR","SHORT_URL_DELETED","RESET_DELETE_SHORT_URL","errorData","dispatch","resetDeleteShortUrl","CREATE_SHORT_URL_START","CREATE_SHORT_URL_ERROR","CREATE_SHORT_URL","RESET_CREATE_SHORT_URL","result","saving","resetCreateShortUrl","EDIT_SHORT_URL_START","EDIT_SHORT_URL_ERROR","SHORT_URL_EDITED","editShortUrl","sendTagsSeparately","Promise","all","LIST_SHORT_URLS_START","LIST_SHORT_URLS_ERROR","LIST_SHORT_URLS","assocPath","pagination","totalItems","currentShortUrl","lastVisit","last","assoc","visitsCount","init","editedShortUrl","RESET_SHORT_URL_PARAMS","SORTABLE_FIELDS","dateCreated","longUrl","orderBy","resetShortUrlParams","ceil","formatter","Intl","NumberFormat","prettify","number","Number","ELLIPSIS","progressivePagination","currentPage","pageCount","pages","max","min","unshift","push","pageIsEllipsis","pageNumber","prettifyPageNumber","keyForPage","index","Paginator","paginator","pagesCount","Pagination","listClassName","PaginationItem","PaginationLink","previous","next","ShortUrlsTable","shortUrlsList","head","order","setOrder","refreshList","extraParams","handleOrderBy","decodeURIComponent","itemsPerPage","orderByColumn","field","renderOrderIcon","caretUpIcon","caretDownIcon","onTagClick","CopyToClipboardIcon","onCopy","copyIcon","Time","relative","dateObject","dateTime","getUnixTime","formatDistance","buildUrl","ShortUrlDetailLink","ShortUrlVisitsCount","maxVisits","meta","visitsLink","prettifiedMaxVisits","tooltipRef","el","infoIcon","UncontrolledTooltip","placement","ShortUrlsRow","ShortUrlsRowMenu","copiedToClipboard","setCopiedToClipboard","setActive","isFirstRun","data-th","DropdownBtnMenu","ButtonDropdown","menuIcon","DeleteShortUrlModal","QrCodeModal","isQrModalOpen","toggleQrCode","isDeleteModalOpen","toggleDelete","pieChartIcon","qrIcon","deleteIcon","ShortUrlForm","CreateShortUrlResult","shortUrlCreationResult","basicMode","shortUrlCreationSettings","settings","shortUrlCreation","useMemo","customSlug","shortCodeLength","validSince","validUntil","findIfExists","validateUrl","validateUrls","getInitialState","mode","onSave","canBeClosed","Result","small","ShlinkApiError","fallbackMessage","detail","invalidElements","shortUrlDeletion","inputValue","setInputValue","handleDeleteUrl","catch","identity","Modal","centered","onSubmit","ModalHeader","ModalBody","ModalFooter","showCopyTooltip","setShowCopyTooltip","closeIcon","Tooltip","actionableFieldClasses","orderableColumnsClasses","tableClasses","supportsTitle","colSpan","QrFormatDropdown","setFormat","QrErrorCorrectionDropdown","errorCorrection","setErrorCorrection","imageDownloader","ForServerVersion","setSize","margin","setMargin","capabilities","useSizeInPath","marginIsSupported","errorCorrectionIsSupported","willRenderThreeControls","qrCodeUrl","buildQrCodeUrl","totalSize","modalSize","step","src","alt","Button","block","saveImage","downloadIcon","BooleanControl","checked","inline","uuid","typeClasses","display","htmlFor","Checkbox","InfoModal","UseExistingIfFoundInfoIcon","isModalOpen","toggleModal","InfoTooltip","ShortUrlFormCheckboxGroup","infoTooltip","normalizeTag","replace","toDate","TagsSelector","DomainSelector","shortUrlData","setShortUrlData","isEdit","submit","renderOptionalInput","Input","renderDateInput","basicComponents","bsSize","required","showCustomizeCard","limitAccessCardClasses","showCrawlableControl","crawlable","goBack","shortUrlDetail","getShortUrlDetail","shortUrlEdition","savingError","savingErrorData","savingSucceeded","isSuccessful","isNotSuccessful","faArrowLeft","GET_SHORT_URL_DETAIL_START","GET_SHORT_URL_DETAIL_ERROR","GET_SHORT_URL_DETAIL","find","FormGroupContainer","labelClassName","forId","FormGroup","ServerForm","initialValues","setName","setUrl","setApiKey","handleSubmit","ImportResult","CreateServer","ImportServersBtn","createServer","serversImported","setServersImported","errorImporting","setErrorImporting","NoMenuLayout","serverData","onImport","onImportError","serversExporter","createServerItem","plusIcon","nav","inNavbar","serverIcon","exportServers","exportIcon","DeleteServerModal","deleteServer","showModal","hideModal","EditServer","editServer","importServersFromFile","createServers","fileRef","files","accept","SELECT_SERVER","RESET_SELECTED_SERVER","toSemVer","getServerVersion","memoizeWith","_serverId","serverNotFound","serverNotReachable","EDIT_SERVER","DELETE_SERVER","CREATE_SERVERS","newServers","dissoc","serversListToMap","reduce","acc","responseToServersList","Array","isArray","fetchServers","homepage","remoteList","maxVersion","tagsList","loadVisitsOverview","visitsOverview","loadingTags","loadingVisits","orphanVisitsCount","useHistory","CardTitle","CardText","CardHeader","CardBody","validateServer","validateServers","every","ServersImporter","csvJson","fileReaderFactory","file","reader","resolve","addEventListener","content","toString","toObject","readAsText","ServersExporter","csvjson","toCSV","FileReader","VisitsHeader","ShortUrlVisitsHeader","shortLink","longLink","visitsStatsTitle","DEFAULT","BROWSERS_WHITELIST","extractDomain","split","includes","fillTheGaps","labels","zipObj","ToggleSwitch","pointerOnHover","native","firstElement","renderChartLabel","dataset","formattedValue","label","renderPieChartLabel","STEPS_MAP","monthly","weekly","daily","hourly","STEP_TO_DURATION_MAP","hours","days","weeks","months","STEP_TO_DIFF_FUNC_MAP","differenceInHours","differenceInDays","differenceInWeeks","differenceInMonths","STEP_TO_DATE_FORMAT","firstWeekDay","startOfISOWeek","lastWeekDay","endOfISOWeek","groupVisitsByStep","countBy","generateLabelsAndGroupedVisits","groupedVisitsWithGaps","skipNoElements","diffFunc","newerDate","oldestDate","duration","num","generateLabels","generateDataset","tension","borderColor","selectedLabel","chartElementAtEvent","datasetsByPoint","setSelectedVisits","chart","LineChartCard","highlightedVisits","highlightedLabel","oldestVisitDate","now","cond","always","matcher","determineInitialStep","setStep","skipNoVisits","toggleSkipNoVisits","visitsToDatasetGroups","reverse","groupedVisits","groupedHighlighted","generateChartDatasets","mainDataset","maintainAspectRatio","plugins","legend","tooltip","intersect","axis","callbacks","scales","y","beginAtZero","ticks","precision","x","onHover","renderLineChart","datasets","getElementAtEvent","entries","menuText","SimplePaginator","setCurrentPage","searchVisits","browser","os","referer","country","city","visitedUrl","visitMatchesSearch","VisitsTable","selectedVisits","matchMedia","isOrphanVisits","headerCellsClass","matchMobile","matches","isMobileDevice","setIsMobileDevice","dir","resultSet","allVisits","sortedVisits","sort","b","greaterThan","smallerThan","sortVisits","total","visitsGroups","splitEvery","calculateVisits","isFirstLoad","setPage","end","start","supportsBots","fullSizeColSpan","listener","removeEventListener","flat","checkIcon","botIcon","isSelected","v","potentialBot","OpenStreetMapTile","TileLayer","attribution","calculateMapProps","locations","bounds","zoom","center","latLong","MapModal","contentClassName","MapContainer","cityName","count","Marker","position","Popup","OpenMapModalBtn","modalTitle","activeCities","mapIsOpened","openMap","closeMap","dropdownIsOpened","toggleDropdown","openDropdown","locationsToShow","setLocationsToShow","buttonRef","openMapWithLocations","filtered","mapIcon","isOrphanVisit","groupNewVisitsByType","groupBy","newVisit","regularVisits","highlightedVisitsToStats","property","toApiParams","excludeBots","visitHasProperty","propertyName","optionalNumericToNumber","numeric","parseFloat","updateLocationsStatsForVisit","updateCountriesStatsForVisit","updateCitiesStatsForVisit","processStatsFromVisits","osStats","updateOsStatsForVisit","browsersStats","updateBrowsersStatsForVisit","browsers","referrersStats","updateReferrersStatsForVisit","referrers","countries","cities","citiesForMapStats","latitude","longitude","currentCity","updateCitiesForMapForVisit","citiesForMap","visitedUrlsStats","isNormalizedOrphanVisit","updateVisitedUrlsForVisit","visitedUrls","normalizeVisits","userAgent","visitLocation","common","bowser","parseUserAgent","countryName","VisitsFilterDropdown","botsSupported","orphanVisitsType","propsForOrphanVisitsTypeItem","DoughnutChartLegend","config","defaultColor","borderWidth","DoughnutChart","memo","chartRef","setChartRef","chartData","generateChartData","height","element","ChartCard","footer","CardFooter","DoughnutChartCard","PaginationDropdown","toggleClassName","ranges","Infinity","dropLabelIfHidden","startsWith","highlightedData","HorizontalBarChart","highlightedStats","statsAreDefined","highlightedKey","stacked","indexAxis","determineHeight","renderChartComponent","customKey","toLowerIfString","toLower","pickKeyFromPair","pickValueFromPair","SortableBarChartCard","sortingItems","extraHeaderContent","withPagination","setItemsPerPage","determineCurrentPagePairs","firstPageLength","i","sortedPairs","pairs","sortBy","getSortedPairsForStats","sortedKeys","sortedHighlightedPairs","currentPageStats","fromPairs","currentPageHighlightedStats","highlightedPages","determineStats","sections","byTime","subPath","faCalendarAlt","byContext","faChartPie","byLocation","faMapMarkedAlt","list","faList","VisitsNavLink","RouterNavLink","endsWith","VisitsStats","visitsInfo","getVisits","cancelGetVisits","exportCsv","initialInterval","defaultInterval","setDateRange","setHighlightedVisits","setHighlightedLabel","visitsFilter","setVisitsFilter","buildSectionUrl","loadingLarge","progress","normalizedVisits","mapLocations","highlightVisitsForProp","newSelectedBar","propEq","faFileDownload","Progress","striped","pills","section","amount","exportVisits","cancelGetShortUrlVisits","ITEMS_PER_PAGE","isLastPage","calcProgress","getVisitsWithLoader","visitsLoader","extraFinishActionData","actionMap","shouldCancel","loadVisitsInParallel","flatten","loadPagesBlocks","pagesBlocks","concat","loadVisits","pagesRange","finish","GET_SHORT_URL_VISITS_START","GET_SHORT_URL_VISITS_ERROR","GET_SHORT_URL_VISITS","GET_SHORT_URL_VISITS_LARGE","GET_SHORT_URL_VISITS_CANCEL","GET_SHORT_URL_VISITS_PROGRESS_CHANGED","cancelLoad","newVisits","TagVisitsHeader","tagVisits","cancelGetTagVisits","GET_TAG_VISITS_START","GET_TAG_VISITS_ERROR","GET_TAG_VISITS","GET_TAG_VISITS_LARGE","GET_TAG_VISITS_CANCEL","GET_TAG_VISITS_PROGRESS_CHANGED","OrphanVisitsHeader","cancelGetOrphanVisits","GET_ORPHAN_VISITS_START","GET_ORPHAN_VISITS_ERROR","GET_ORPHAN_VISITS","GET_ORPHAN_VISITS_LARGE","GET_ORPHAN_VISITS_CANCEL","GET_ORPHAN_VISITS_PROGRESS_CHANGED","matchesType","GET_OVERVIEW_START","GET_OVERVIEW_ERROR","GET_OVERVIEW","VisitsExporter","visitsParser","TagBullet","toComponentTag","searchMode","tagFilteringMode","tagComponent","onDelete","suggestions","suggestionComponent","allowNew","addOnBlur","minQueryLength","delimiters","suggestionsTransform","removedTagIndex","tagsCopy","splice","onAddition","newTag","TagCard","DeleteTagConfirmModal","EditTagModal","tagStats","displayed","isEditModalOpen","toggleEdit","hasTitle","displayTitle","titleRef","scrollWidth","clientWidth","encodeURIComponent","faLink","shortUrlsCount","faEye","deleteTag","tagDelete","tagDeleted","deleting","doDelete","tagEdited","tagEdit","newTagName","setNewTagName","setColor","showColorPicker","toggleColorPicker","hideColorPicker","editing","saveTag","onClosed","colorIcon","Popover","disableAlpha","hex","TagsModeDropdown","renderTitle","cardsIcon","TagsCards","TagsTable","filterTags","forceListTags","ui","tagsMode","setMode","filteredTags","DELETE_TAG_START","DELETE_TAG_ERROR","DELETE_TAG","TAG_DELETED","EDIT_TAG_START","EDIT_TAG_ERROR","EDIT_TAG","TAG_EDITED","pick","LIST_TAGS_START","LIST_TAGS_ERROR","LIST_TAGS","FILTER_TAGS","renameTag","rejectTag","tagToReject","calculateVisitsPerTag","increase","displayedTag","setDisplayedTag","tagsCount","tagsGroups","group","TagsTableRow","pageFromQuery","sortedTags","showPaginator","isDropdownOpen","listTagsActionFactory","force","processedStats","factory","GET_MERCURE_INFO_START","GET_MERCURE_INFO_ERROR","GET_MERCURE_INFO","realTimeUpdates","enabled","info","RealTimeUpdates","toggleRealTimeUpdates","setRealTimeUpdatesInterval","SettingsSections","child","subChild","subIndex","Settings","ShortUrlCreation","UserInterface","Visits","SET_SETTINGS","mergeDeepRight","setShortUrlCreationSettings","setUiSettings","setVisitsSettings","tagFilteringModeText","changeTagsFilteringMode","faMoon","faSun","useDarkTheme","DateIntervalSelector","EDIT_DOMAIN_REDIRECTS","redirects","LIST_DOMAINS_START","LIST_DOMAINS_ERROR","LIST_DOMAINS","FILTER_DOMAINS","filteredDomains","replaceRedirectsOnDomain","filterDomains","domainsList","inputDisplayed","showInput","hideInput","valueIsEmpty","unselectDomain","InputGroup","InputGroupAddon","addonType","faUndo","trigger","isDefault","isLast","EditDomainRedirectsModal","baseUrlRedirect","setBaseUrlRedirect","regular404Redirect","setRegular404Redirect","invalidShortUrlRedirect","setInvalidShortUrlRedirect","Nr","fallback","DefaultDomain","defaultDomainIcon","DomainRow","defaultRedirects","authority","domainId","forbiddenIcon","column","APP_UPDATE_AVAILABLE","RESET_APP_UPDATE","appUpdateAvailable","resetAppUpdate","AppUpdateBanner","forceUpdate","isUpdating","setUpdating","Alert","reloadIcon","navigator","serviceWorker","getRegistrations","registrations","registration","waiting","postMessage","App","appUpdated","Bottle","container","mapActionService","actionName","serviceName","lazyService","propsFromState","actionServiceNames","reduxConnect","provideAppServices","provideCommonServices","provideApiServices","provideShortUrlsServices","provideServersServices","provideTagsServices","provideVisitsServices","provideUtilsServices","provideMercureServices","provideSettingsServices","provideDomainsServices","combineReducers","serversReducer","selectedServerReducer","shortUrlsListReducer","shortUrlsListParamsReducer","shortUrlCreationReducer","shortUrlDeletionReducer","shortUrlEditionReducer","shortUrlVisitsReducer","tagVisitsReducer","orphanVisitsReducer","shortUrlDetailReducer","tagsListReducer","tagDeleteReducer","tagEditReducer","mercureInfoReducer","settingsReducer","domainsListReducer","visitsOverviewReducer","appUpdatesReducer","composeEnhancers","__REDUX_DEVTOOLS_EXTENSION_COMPOSE__","compose","localStorageConfig","states","namespace","namespaceSeparator","debounce","store","createStore","reducers","load","applyMiddleware","save","ReduxThunk","isLocalhost","hostname","registerValidSW","swUrl","register","onupdatefound","installingWorker","installing","onstatechange","controller","log","onUpdate","onSuccess","L","Icon","Default","prototype","_getIconUrl","mergeOptions","iconRetinaUrl","marker2x","iconUrl","marker","shadowUrl","markerShadow","basename","getElementById","process","origin","fetch","contentType","indexOf","ready","unregister","checkValidServiceWorker","registerServiceWorker","versionToMatch","matchesMinVersion","compare","versionIsValidSemVer","defaultValue"],"mappings":"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","file":"static/js/main.07ae98bb.chunk.js","sourcesContent":["import { FC, useEffect } from 'react';\n\ninterface WithoutSelectedServerProps {\n resetSelectedServer: Function;\n}\n\nexport function withoutSelectedServer<T = {}>(WrappedComponent: FC<WithoutSelectedServerProps & T>) {\n return (props: WithoutSelectedServerProps & T) => {\n useEffect(() => {\n props.resetSelectedServer();\n }, []);\n\n return <WrappedComponent {...props} />;\n };\n}\n","export const saveUrl = ({ document }: Window, url: string, filename: string) => {\n const link = document.createElement('a');\n\n link.setAttribute('href', url);\n link.setAttribute('download', filename);\n link.style.visibility = 'hidden';\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n};\n\nexport const saveCsv = (window: Window, csv: string, filename: string) => {\n const blob = new Blob([ csv ], { type: 'text/csv;charset=utf-8;' });\n const url = URL.createObjectURL(blob);\n\n saveUrl(window, url, filename);\n};\n","import { MAIN_COLOR } from '../../utils/theme';\n\nexport interface ShlinkLogoProps {\n color?: string;\n className?: string;\n}\n\nexport const ShlinkLogo = ({ color = MAIN_COLOR, className }: ShlinkLogoProps) => (\n <svg className={className} viewBox=\"0 0 512 512\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">\n <g fill={color}>\n <path\n d=\" M 23.71 85.08 C 17.22 49.81 49.44 14.86 85.08 18.12 C 118.83 19.21 145.72 53.33 139.45 86.37 C 155.64 102.30 171.32 118.83 187.87 134.36 C 198.32 111.73 208.84 89.12 219.57 66.62 C 226.05 53.84 243.47 48.74 255.73 56.27 C 263.76 62.10 270.34 69.69 277.25 76.75 C 286.28 86.61 285.72 102.89 276.31 112.31 C 223.38 165.37 170.38 218.37 117.35 271.34 C 107.72 280.99 91.01 281.25 81.11 271.86 C 74.39 264.94 66.82 258.69 61.24 250.77 C 53.72 238.52 58.85 221.07 71.64 214.62 C 94.11 203.87 116.72 193.38 139.33 182.91 C 123.81 166.36 107.30 150.68 91.37 134.49 C 60.20 140.28 27.37 116.78 23.71 85.08 Z\"\n />\n <path\n d=\" M 205.21 201.23 C 225.32 181.36 260.88 181.11 281.14 200.86 C 299.25 218.75 317.37 236.65 335.10 254.93 C 356.73 278.01 352.01 318.70 326.03 336.56 C 320.07 330.47 313.73 324.65 308.12 318.28 C 323.86 309.39 328.76 286.18 316.63 272.39 C 301.73 256.95 286.30 242.03 271.24 226.75 C 264.49 219.65 256.80 212.00 246.37 211.52 C 224.65 208.64 205.52 233.36 214.49 253.58 C 221.09 266.81 234.22 275.12 243.62 286.24 C 240.43 295.96 238.09 306.13 238.29 316.46 C 225.55 304.29 213.16 291.73 200.89 279.09 C 180.97 257.57 183.10 220.45 205.21 201.23 Z\"\n />\n <path\n d=\" M 273.90 352.07 C 252.28 328.99 256.98 288.31 282.96 270.46 C 288.93 276.54 295.26 282.36 300.88 288.72 C 285.14 297.62 280.23 320.82 292.38 334.61 C 307.27 350.05 322.70 364.96 337.75 380.25 C 344.51 387.35 352.20 395.00 362.64 395.48 C 384.35 398.37 403.49 373.64 394.51 353.42 C 387.92 340.18 374.78 331.88 365.38 320.76 C 368.56 311.04 370.91 300.86 370.71 290.54 C 383.45 302.70 395.84 315.27 408.11 327.91 C 428.03 349.43 425.90 386.55 403.78 405.77 C 383.68 425.64 348.13 425.89 327.86 406.14 C 309.75 388.25 291.60 370.37 273.90 352.07 Z\"\n />\n <path\n d=\" M 422.11 403.83 C 431.96 394.07 441.60 384.06 451.66 374.51 C 460.90 383.74 471.89 392.70 474.89 406.11 C 480.16 429.97 484.08 454.13 488.76 478.12 C 490.00 483.41 484.47 488.29 479.35 486.63 C 454.66 481.52 429.55 478.12 405.14 471.84 C 393.17 467.97 385.20 457.75 376.55 449.27 C 386.39 439.49 396.13 429.60 406.06 419.91 C 416.37 433.45 435.74 414.00 422.11 403.83 Z\"\n />\n </g>\n </svg>\n);\n","import { FC, useEffect } from 'react';\nimport { RouteComponentProps } from 'react-router';\nimport Message from '../../utils/Message';\nimport { isNotFoundServer, SelectedServer } from '../data';\nimport NoMenuLayout from '../../common/NoMenuLayout';\n\ninterface WithSelectedServerProps extends RouteComponentProps<{ serverId: string }> {\n selectServer: (serverId: string) => void;\n selectedServer: SelectedServer;\n}\n\nexport function withSelectedServer<T = {}>(WrappedComponent: FC<WithSelectedServerProps & T>, ServerError: FC) {\n return (props: WithSelectedServerProps & T) => {\n const { selectServer, selectedServer, match } = props;\n\n useEffect(() => {\n selectServer(match.params.serverId);\n }, [ match.params.serverId ]);\n\n if (!selectedServer) {\n return (\n <NoMenuLayout>\n <Message loading />\n </NoMenuLayout>\n );\n }\n\n if (isNotFoundServer(selectedServer)) {\n return <ServerError />;\n }\n\n return <WrappedComponent {...props} />;\n };\n}\n","import { FC } from 'react';\nimport { Link } from 'react-router-dom';\nimport { SimpleCard } from '../utils/SimpleCard';\n\ninterface NotFoundProps {\n to?: string;\n}\n\nconst NotFound: FC<NotFoundProps> = ({ to = '/', children = 'Home' }) => (\n <div className=\"home\">\n <SimpleCard className=\"p-4\">\n <h2>Oops! We could not find requested route.</h2>\n <p>\n Use your browser&apos;s back button to navigate to the page you have previously come from, or just press this\n button.\n </p>\n <br />\n <Link to={to} className=\"btn btn-outline-primary btn-lg\">{children}</Link>\n </SimpleCard>\n </div>\n);\n\nexport default NotFound;\n","import { FC } from 'react';\nimport { ListGroup, ListGroupItem } from 'reactstrap';\nimport { Link } from 'react-router-dom';\nimport classNames from 'classnames';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faChevronRight as chevronIcon } from '@fortawesome/free-solid-svg-icons';\nimport { ServerWithId } from './data';\nimport './ServersListGroup.scss';\n\ninterface ServersListGroupProps {\n servers: ServerWithId[];\n embedded?: boolean;\n}\n\nconst ServerListItem = ({ id, name }: { id: string; name: string }) => (\n <ListGroupItem tag={Link} to={`/server/${id}`} className=\"servers-list__server-item\">\n {name}\n <FontAwesomeIcon icon={chevronIcon} className=\"servers-list__server-item-icon\" />\n </ListGroupItem>\n);\n\nconst ServersListGroup: FC<ServersListGroupProps> = ({ servers, children, embedded = false }) => (\n <>\n {children && <h5 className=\"mb-md-3\">{children}</h5>}\n {servers.length > 0 && (\n <ListGroup\n className={classNames('servers-list__list-group', { 'servers-list__list-group--embedded': embedded })}\n >\n {servers.map(({ id, name }) => <ServerListItem key={id} id={id} name={name} />)}\n </ListGroup>\n )}\n </>\n);\n\nexport default ServersListGroup;\n","import { useState, useRef } from 'react';\nimport { useSwipeable as useReactSwipeable } from 'react-swipeable';\nimport { parseQuery, stringifyQuery } from './query';\n\nconst DEFAULT_DELAY = 2000;\n\nexport type StateFlagTimeout = (initialValue?: boolean, delay?: number) => [ boolean, () => void ];\n\nexport const useStateFlagTimeout = (\n setTimeout: (callback: Function, timeout: number) => number,\n clearTimeout: (timer: number) => void,\n): StateFlagTimeout => (initialValue = false, delay = DEFAULT_DELAY) => {\n const [ flag, setFlag ] = useState<boolean>(initialValue);\n const timeout = useRef<number | undefined>(undefined);\n const callback = () => {\n setFlag(!initialValue);\n\n if (timeout.current) {\n clearTimeout(timeout.current);\n }\n\n timeout.current = setTimeout(() => setFlag(initialValue), delay);\n };\n\n return [ flag, callback ];\n};\n\ntype ToggleResult = [ boolean, () => void, () => void, () => void ];\n\nexport const useToggle = (initialValue = false): ToggleResult => {\n const [ flag, setFlag ] = useState<boolean>(initialValue);\n\n return [ flag, () => setFlag(!flag), () => setFlag(true), () => setFlag(false) ];\n};\n\nexport const useSwipeable = (showSidebar: () => void, hideSidebar: () => void) => {\n const swipeMenuIfNoModalExists = (callback: () => void) => (e: any) => {\n const swippedOnVisitsTable = (e.event.composedPath() as HTMLElement[]).some( // eslint-disable-line @typescript-eslint/no-unsafe-call\n ({ classList }) => classList?.contains('visits-table'),\n );\n\n if (swippedOnVisitsTable || document.querySelector('.modal')) {\n return;\n }\n\n callback();\n };\n\n return useReactSwipeable({\n delta: 40,\n onSwipedLeft: swipeMenuIfNoModalExists(hideSidebar),\n onSwipedRight: swipeMenuIfNoModalExists(showSidebar),\n });\n};\n\nexport const useQueryState = <T>(paramName: string, initialState: T): [ T, (newValue: T) => void ] => {\n const [ value, setValue ] = useState(initialState);\n const setValueWithLocation = (value: T) => {\n const { location, history } = window;\n const query = parseQuery<any>(location.search);\n\n query[paramName] = value;\n history.pushState(null, '', `${location.pathname}?${stringifyQuery(query)}`);\n setValue(value);\n };\n\n return [ value, setValueWithLocation ];\n};\n","import { isEmpty, isNil, pipe, range } from 'ramda';\nimport { SyntheticEvent } from 'react';\n\nexport type OrderDir = 'ASC' | 'DESC' | undefined;\n\nexport const determineOrderDir = <T extends string = string>(\n currentField: T,\n newField?: T,\n currentOrderDir?: OrderDir,\n): OrderDir => {\n if (currentField !== newField) {\n return 'ASC';\n }\n\n const newOrderMap: Record<'ASC' | 'DESC', OrderDir> = {\n ASC: 'DESC',\n DESC: undefined,\n };\n\n return currentOrderDir ? newOrderMap[currentOrderDir] : 'ASC';\n};\n\nexport const rangeOf = <T>(size: number, mappingFn: (value: number) => T, startAt = 1): T[] =>\n range(startAt, size + 1).map(mappingFn);\n\nexport type Empty = null | undefined | '' | never[];\n\nexport const hasValue = <T>(value: T | Empty): value is T => !isNil(value) && !isEmpty(value);\n\nexport const handleEventPreventingDefault = <T>(handler: () => T) => pipe(\n (e: SyntheticEvent) => e.preventDefault(),\n handler,\n);\n\nexport type Nullable<T> = {\n [P in keyof T]: T[P] | null\n};\n\ntype Optional<T> = T | null | undefined;\n\nexport type OptionalString = Optional<string>;\n\nexport type RecursivePartial<T> = {\n [P in keyof T]?: RecursivePartial<T[P]>;\n};\n\nexport const nonEmptyValueOrNull = <T>(value: T): T | null => isEmpty(value) ? null : value;\n\nexport const capitalize = <T extends string>(value: T): string => `${value.charAt(0).toUpperCase()}${value.slice(1)}`;\n","import { SemVer } from '../../utils/helpers/version';\n\nexport interface ServerData {\n name: string;\n url: string;\n apiKey: string;\n}\n\nexport interface ServerWithId extends ServerData {\n id: string;\n}\n\nexport interface ReachableServer extends ServerWithId {\n version: SemVer;\n printableVersion: string;\n}\n\nexport interface NonReachableServer extends ServerWithId {\n serverNotReachable: true;\n}\n\nexport interface NotFoundServer {\n serverNotFound: true;\n}\n\nexport type RegularServer = ReachableServer | NonReachableServer;\n\nexport type SelectedServer = RegularServer | NotFoundServer | null;\n\nexport type ServersMap = Record<string, ServerWithId>;\n\nexport const hasServerData = (server: SelectedServer | ServerData): server is ServerData =>\n !!(server as ServerData)?.url && !!(server as ServerData)?.apiKey;\n\nexport const isServerWithId = (server: SelectedServer | ServerWithId): server is ServerWithId =>\n !!server?.hasOwnProperty('id');\n\nexport const isReachableServer = (server: SelectedServer): server is ReachableServer =>\n !!server?.hasOwnProperty('version');\n\nexport const isNotFoundServer = (server: SelectedServer): server is NotFoundServer =>\n !!server?.hasOwnProperty('serverNotFound');\n\nexport const getServerId = (server: SelectedServer) => isServerWithId(server) ? server.id : '';\n","import axios from 'axios';\nimport Bottle, { Decorator } from 'bottlejs';\nimport ScrollToTop from '../ScrollToTop';\nimport MainHeader from '../MainHeader';\nimport Home from '../Home';\nimport MenuLayout from '../MenuLayout';\nimport AsideMenu from '../AsideMenu';\nimport ErrorHandler from '../ErrorHandler';\nimport ShlinkVersionsContainer from '../ShlinkVersionsContainer';\nimport { ConnectDecorator } from '../../container/types';\nimport { withoutSelectedServer } from '../../servers/helpers/withoutSelectedServer';\nimport { ImageDownloader } from './ImageDownloader';\n\nconst provideServices = (bottle: Bottle, connect: ConnectDecorator, withRouter: Decorator) => {\n // Services\n bottle.constant('window', (global as any).window);\n bottle.constant('console', global.console);\n bottle.constant('axios', axios);\n\n bottle.service('ImageDownloader', ImageDownloader, 'axios', 'window');\n\n // Components\n bottle.serviceFactory('ScrollToTop', ScrollToTop);\n bottle.decorator('ScrollToTop', withRouter);\n\n bottle.serviceFactory('MainHeader', MainHeader, 'ServersDropdown');\n bottle.decorator('MainHeader', withRouter);\n\n bottle.serviceFactory('Home', () => Home);\n bottle.decorator('Home', withoutSelectedServer);\n bottle.decorator('Home', connect([ 'servers' ], [ 'resetSelectedServer' ]));\n\n bottle.serviceFactory(\n 'MenuLayout',\n MenuLayout,\n 'TagsList',\n 'ShortUrls',\n 'AsideMenu',\n 'CreateShortUrl',\n 'ShortUrlVisits',\n 'TagVisits',\n 'OrphanVisits',\n 'ServerError',\n 'Overview',\n 'EditShortUrl',\n 'ManageDomains',\n );\n bottle.decorator('MenuLayout', connect([ 'selectedServer', 'shortUrlsListParams' ], [ 'selectServer' ]));\n bottle.decorator('MenuLayout', withRouter);\n\n bottle.serviceFactory('AsideMenu', AsideMenu, 'DeleteServerButton');\n\n bottle.serviceFactory('ShlinkVersionsContainer', () => ShlinkVersionsContainer);\n bottle.decorator('ShlinkVersionsContainer', connect([ 'selectedServer' ]));\n\n bottle.serviceFactory('ErrorHandler', ErrorHandler, 'window', 'console');\n};\n\nexport default provideServices;\n","import { PropsWithChildren, useEffect } from 'react';\nimport { RouteComponentProps } from 'react-router';\n\nconst ScrollToTop = () => ({ location, children }: PropsWithChildren<RouteComponentProps>) => {\n useEffect(() => {\n scrollTo(0, 0);\n }, [ location ]);\n\n return <>{children}</>;\n};\n\nexport default ScrollToTop;\n","import { Component, ReactNode } from 'react';\nimport { Button } from 'reactstrap';\nimport { SimpleCard } from '../utils/SimpleCard';\n\ninterface ErrorHandlerState {\n hasError: boolean;\n}\n\nconst ErrorHandler = (\n { location }: Window,\n { error }: Console,\n) => class ErrorHandler extends Component<any, ErrorHandlerState> {\n public constructor(props: object) {\n super(props);\n this.state = { hasError: false };\n }\n\n public static getDerivedStateFromError(): ErrorHandlerState {\n return { hasError: true };\n }\n\n public componentDidCatch(e: Error): void {\n if (process.env.NODE_ENV !== 'development') {\n error(e);\n }\n }\n\n public render(): ReactNode {\n if (this.state.hasError) {\n return (\n <div className=\"home\">\n <SimpleCard className=\"p-4\">\n <h1>Oops! This is awkward :S</h1>\n <p>It seems that something went wrong. Try refreshing the page or just click this button.</p>\n <br />\n <Button outline color=\"primary\" onClick={() => location.reload()}>Take me back</Button>\n </SimpleCard>\n </div>\n );\n }\n\n return this.props.children;\n }\n};\n\nexport default ErrorHandler;\n","import { AxiosInstance } from 'axios';\nimport { saveUrl } from '../../utils/helpers/files';\n\nexport class ImageDownloader {\n public constructor(private readonly axios: AxiosInstance, private readonly window: Window) {}\n\n public async saveImage(imgUrl: string, filename: string): Promise<void> {\n const { data } = await this.axios.get(imgUrl, { responseType: 'blob' });\n const url = URL.createObjectURL(data);\n\n saveUrl(this.window, url, filename);\n }\n}\n","import Bottle from 'bottlejs';\nimport { useStateFlagTimeout } from '../helpers/hooks';\nimport LocalStorage from './LocalStorage';\nimport ColorGenerator from './ColorGenerator';\n\nconst provideServices = (bottle: Bottle) => {\n bottle.constant('localStorage', (global as any).localStorage);\n bottle.service('Storage', LocalStorage, 'localStorage');\n bottle.service('ColorGenerator', ColorGenerator, 'Storage');\n\n bottle.constant('setTimeout', global.setTimeout);\n bottle.constant('clearTimeout', global.clearTimeout);\n bottle.serviceFactory('useStateFlagTimeout', useStateFlagTimeout, 'setTimeout', 'clearTimeout');\n};\n\nexport default provideServices;\n","const PREFIX = 'shlink';\nconst buildPath = (path: string) => `${PREFIX}.${path}`;\n\nexport default class LocalStorage {\n public constructor(private readonly localStorage: Storage) {}\n\n public readonly get = <T>(key: string): T | undefined => {\n const item = this.localStorage.getItem(buildPath(key));\n\n return item ? JSON.parse(item) as T : undefined;\n };\n\n public readonly set = (key: string, value: any) => this.localStorage.setItem(buildPath(key), JSON.stringify(value));\n}\n","import { rangeOf } from '../utils';\nimport LocalStorage from './LocalStorage';\n\nconst HEX_COLOR_LENGTH = 6;\nconst { floor, random } = Math;\nconst letters = '0123456789ABCDEF';\nconst buildRandomColor = () => `#${rangeOf(HEX_COLOR_LENGTH, () => letters[floor(random() * letters.length)]).join('')}`;\nconst normalizeKey = (key: string) => key.toLowerCase().trim();\n\nexport default class ColorGenerator {\n private readonly colors: Record<string, string>;\n\n public constructor(private readonly storage: LocalStorage) {\n this.colors = this.storage.get<Record<string, string>>('colors') ?? {};\n }\n\n public readonly getColorForKey = (key: string) => {\n const normalizedKey = normalizeKey(key);\n const color = this.colors[normalizedKey];\n\n // If a color has not been set yet, generate a random one and save it\n if (!color) {\n return this.setColorForKey(normalizedKey, buildRandomColor());\n }\n\n return color;\n };\n\n public readonly setColorForKey = (key: string, color: string) => {\n const normalizedKey = normalizeKey(key);\n\n this.colors[normalizedKey] = color;\n this.storage.set('colors', this.colors);\n\n return color;\n };\n}\n","import { pipe } from 'ramda';\nimport { ExternalLink } from 'react-external-link';\nimport { versionToPrintable, versionToSemVer } from '../utils/helpers/version';\nimport { isReachableServer } from '../servers/data';\nimport { ShlinkVersionsContainerProps } from './ShlinkVersionsContainer';\n\nconst SHLINK_WEB_CLIENT_VERSION = '%_VERSION_%';\nconst normalizeVersion = pipe(versionToSemVer(), versionToPrintable);\n\nexport interface ShlinkVersionsProps extends ShlinkVersionsContainerProps {\n clientVersion?: string;\n}\n\nconst VersionLink = ({ project, version }: { project: 'shlink' | 'shlink-web-client'; version: string }) => (\n <ExternalLink href={`https://github.com/shlinkio/${project}/releases/${version}`} className=\"text-muted\">\n <b>{version}</b>\n </ExternalLink>\n);\n\nconst ShlinkVersions = ({ selectedServer, clientVersion = SHLINK_WEB_CLIENT_VERSION }: ShlinkVersionsProps) => {\n const normalizedClientVersion = normalizeVersion(clientVersion);\n\n return (\n <small className=\"text-muted\">\n {isReachableServer(selectedServer) &&\n <>Server: <VersionLink project=\"shlink\" version={selectedServer.printableVersion} /> - </>\n }\n Client: <VersionLink project=\"shlink-web-client\" version={normalizedClientVersion} />\n </small>\n );\n};\n\nexport default ShlinkVersions;\n","import classNames from 'classnames';\nimport { isReachableServer, SelectedServer } from '../servers/data';\nimport ShlinkVersions from './ShlinkVersions';\nimport './ShlinkVersionsContainer.scss';\n\nexport interface ShlinkVersionsContainerProps {\n selectedServer: SelectedServer;\n}\n\nconst ShlinkVersionsContainer = ({ selectedServer }: ShlinkVersionsContainerProps) => {\n const classes = classNames('text-center', {\n 'shlink-versions-container--with-server': isReachableServer(selectedServer),\n });\n\n return (\n <div className={classes}>\n <ShlinkVersions selectedServer={selectedServer} />\n </div>\n );\n};\n\nexport default ShlinkVersionsContainer;\n","import { faChevronDown as arrowIcon, faCogs as cogsIcon } from '@fortawesome/free-solid-svg-icons';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { FC, useEffect } from 'react';\nimport { Link } from 'react-router-dom';\nimport { Collapse, Nav, Navbar, NavbarBrand, NavbarToggler, NavItem, NavLink } from 'reactstrap';\nimport classNames from 'classnames';\nimport { RouteComponentProps } from 'react-router';\nimport { useToggle } from '../utils/helpers/hooks';\nimport { ShlinkLogo } from './img/ShlinkLogo';\nimport './MainHeader.scss';\n\nconst MainHeader = (ServersDropdown: FC) => ({ location }: RouteComponentProps) => {\n const [ isOpen, toggleOpen, , close ] = useToggle();\n const { pathname } = location;\n\n useEffect(close, [ location ]);\n\n const settingsPath = '/settings';\n const toggleClass = classNames('main-header__toggle-icon', { 'main-header__toggle-icon--opened': isOpen });\n\n return (\n <Navbar color=\"primary\" dark fixed=\"top\" className=\"main-header\" expand=\"md\">\n <NavbarBrand tag={Link} to=\"/\">\n <ShlinkLogo className=\"main-header__brand-logo\" color=\"white\" /> Shlink\n </NavbarBrand>\n\n <NavbarToggler onClick={toggleOpen}>\n <FontAwesomeIcon icon={arrowIcon} className={toggleClass} />\n </NavbarToggler>\n\n <Collapse navbar isOpen={isOpen}>\n <Nav navbar className=\"ml-auto\">\n <NavItem>\n <NavLink tag={Link} to={settingsPath} active={pathname === settingsPath}>\n <FontAwesomeIcon icon={cogsIcon} />&nbsp; Settings\n </NavLink>\n </NavItem>\n <ServersDropdown />\n </Nav>\n </Collapse>\n </Navbar>\n );\n};\n\nexport default MainHeader;\n","import { isEmpty, values } from 'ramda';\nimport { Link } from 'react-router-dom';\nimport { Card, Row } from 'reactstrap';\nimport { ExternalLink } from 'react-external-link';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faExternalLinkAlt, faPlus } from '@fortawesome/free-solid-svg-icons';\nimport ServersListGroup from '../servers/ServersListGroup';\nimport { ServersMap } from '../servers/data';\nimport { ShlinkLogo } from './img/ShlinkLogo';\nimport './Home.scss';\n\nexport interface HomeProps {\n servers: ServersMap;\n}\n\nconst Home = ({ servers }: HomeProps) => {\n const serversList = values(servers);\n const hasServers = !isEmpty(serversList);\n\n return (\n <div className=\"home\">\n <Card className=\"home__main-card\">\n <Row noGutters>\n <div className=\"col-md-5 d-none d-md-block\">\n <div className=\"p-4\">\n <ShlinkLogo />\n </div>\n </div>\n <div className=\"col-md-7 home__servers-container\">\n <div className=\"p-4\">\n <h1 className=\"home__title\">Welcome!</h1>\n </div>\n <ServersListGroup embedded servers={serversList}>\n {!hasServers && (\n <div className=\"p-4 text-center\">\n <p className=\"mb-5\">This application will help you manage your Shlink servers.</p>\n <p>\n <Link to=\"/server/create\" className=\"btn btn-outline-primary btn-lg mr-2\">\n <FontAwesomeIcon icon={faPlus} /> <span className=\"ml-1\">Add a server</span>\n </Link>\n </p>\n <p className=\"mb-0 mt-5\">\n <ExternalLink href=\"https://shlink.io/documentation\">\n <small>\n <span className=\"mr-1\">Learn more about Shlink</span> <FontAwesomeIcon icon={faExternalLinkAlt} />\n </small>\n </ExternalLink>\n </p>\n </div>\n )}\n </ServersListGroup>\n </div>\n </Row>\n </Card>\n </div>\n );\n};\n\nexport default Home;\n","import { FC, useEffect } from 'react';\nimport { Redirect, Route, Switch } from 'react-router-dom';\nimport { faBars as burgerIcon } from '@fortawesome/free-solid-svg-icons';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport classNames from 'classnames';\nimport { withSelectedServer } from '../servers/helpers/withSelectedServer';\nimport { useSwipeable, useToggle } from '../utils/helpers/hooks';\nimport { supportsDomainRedirects, supportsOrphanVisits } from '../utils/helpers/features';\nimport { isReachableServer } from '../servers/data';\nimport NotFound from './NotFound';\nimport { AsideMenuProps } from './AsideMenu';\nimport './MenuLayout.scss';\n\nconst MenuLayout = (\n TagsList: FC,\n ShortUrls: FC,\n AsideMenu: FC<AsideMenuProps>,\n CreateShortUrl: FC,\n ShortUrlVisits: FC,\n TagVisits: FC,\n OrphanVisits: FC,\n ServerError: FC,\n Overview: FC,\n EditShortUrl: FC,\n ManageDomains: FC,\n) => withSelectedServer(({ location, selectedServer }) => {\n const [ sidebarVisible, toggleSidebar, showSidebar, hideSidebar ] = useToggle();\n\n useEffect(() => hideSidebar(), [ location ]);\n\n if (!isReachableServer(selectedServer)) {\n return <ServerError />;\n }\n\n const addOrphanVisitsRoute = supportsOrphanVisits(selectedServer);\n const addManageDomainsRoute = supportsDomainRedirects(selectedServer);\n const burgerClasses = classNames('menu-layout__burger-icon', { 'menu-layout__burger-icon--active': sidebarVisible });\n const swipeableProps = useSwipeable(showSidebar, hideSidebar);\n\n return (\n <>\n <FontAwesomeIcon icon={burgerIcon} className={burgerClasses} onClick={toggleSidebar} />\n\n <div {...swipeableProps} className=\"menu-layout__swipeable\">\n <div className=\"menu-layout__swipeable-inner\">\n <AsideMenu selectedServer={selectedServer} showOnMobile={sidebarVisible} />\n <div className=\"menu-layout__container\" onClick={() => hideSidebar()}>\n <div className=\"container-xl\">\n <Switch>\n <Redirect exact from=\"/server/:serverId\" to=\"/server/:serverId/overview\" />\n <Route exact path=\"/server/:serverId/overview\" component={Overview} />\n <Route exact path=\"/server/:serverId/list-short-urls/:page\" component={ShortUrls} />\n <Route exact path=\"/server/:serverId/create-short-url\" component={CreateShortUrl} />\n <Route path=\"/server/:serverId/short-code/:shortCode/visits\" component={ShortUrlVisits} />\n <Route path=\"/server/:serverId/short-code/:shortCode/edit\" component={EditShortUrl} />\n <Route path=\"/server/:serverId/tag/:tag/visits\" component={TagVisits} />\n {addOrphanVisitsRoute && <Route path=\"/server/:serverId/orphan-visits\" component={OrphanVisits} />}\n <Route exact path=\"/server/:serverId/manage-tags\" component={TagsList} />\n {addManageDomainsRoute && <Route exact path=\"/server/:serverId/manage-domains\" component={ManageDomains} />}\n <Route\n render={() => <NotFound to={`/server/${selectedServer.id}/list-short-urls/1`}>List short URLs</NotFound>}\n />\n </Switch>\n </div>\n </div>\n </div>\n </div>\n </>\n );\n}, ServerError);\n\nexport default MenuLayout;\n","import {\n faList as listIcon,\n faLink as createIcon,\n faTags as tagsIcon,\n faPen as editIcon,\n faHome as overviewIcon,\n faGlobe as domainsIcon,\n} from '@fortawesome/free-solid-svg-icons';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { FC } from 'react';\nimport { NavLink, NavLinkProps } from 'react-router-dom';\nimport classNames from 'classnames';\nimport { Location } from 'history';\nimport { DeleteServerButtonProps } from '../servers/DeleteServerButton';\nimport { isServerWithId, SelectedServer } from '../servers/data';\nimport { supportsDomainRedirects } from '../utils/helpers/features';\nimport './AsideMenu.scss';\n\nexport interface AsideMenuProps {\n selectedServer: SelectedServer;\n className?: string;\n showOnMobile?: boolean;\n}\n\ninterface AsideMenuItemProps extends NavLinkProps {\n to: string;\n}\n\nconst AsideMenuItem: FC<AsideMenuItemProps> = ({ children, to, className, ...rest }) => (\n <NavLink\n className={classNames('aside-menu__item', className)}\n activeClassName=\"aside-menu__item--selected\"\n to={to}\n {...rest}\n >\n {children}\n </NavLink>\n);\n\nconst AsideMenu = (DeleteServerButton: FC<DeleteServerButtonProps>) => (\n { selectedServer, showOnMobile = false }: AsideMenuProps,\n) => {\n const serverId = isServerWithId(selectedServer) ? selectedServer.id : '';\n const addManageDomainsLink = supportsDomainRedirects(selectedServer);\n const asideClass = classNames('aside-menu', {\n 'aside-menu--hidden': !showOnMobile,\n });\n const shortUrlsIsActive = (_: null, location: Location) => location.pathname.match('/list-short-urls') !== null;\n const buildPath = (suffix: string) => `/server/${serverId}${suffix}`;\n\n return (\n <aside className={asideClass}>\n <nav className=\"nav flex-column aside-menu__nav\">\n <AsideMenuItem to={buildPath('/overview')}>\n <FontAwesomeIcon fixedWidth icon={overviewIcon} />\n <span className=\"aside-menu__item-text\">Overview</span>\n </AsideMenuItem>\n <AsideMenuItem to={buildPath('/list-short-urls/1')} isActive={shortUrlsIsActive}>\n <FontAwesomeIcon fixedWidth icon={listIcon} />\n <span className=\"aside-menu__item-text\">List short URLs</span>\n </AsideMenuItem>\n <AsideMenuItem to={buildPath('/create-short-url')}>\n <FontAwesomeIcon fixedWidth icon={createIcon} flip=\"horizontal\" />\n <span className=\"aside-menu__item-text\">Create short URL</span>\n </AsideMenuItem>\n <AsideMenuItem to={buildPath('/manage-tags')}>\n <FontAwesomeIcon fixedWidth icon={tagsIcon} />\n <span className=\"aside-menu__item-text\">Manage tags</span>\n </AsideMenuItem>\n {addManageDomainsLink && (\n <AsideMenuItem to={buildPath('/manage-domains')}>\n <FontAwesomeIcon fixedWidth icon={domainsIcon} />\n <span className=\"aside-menu__item-text\">Manage domains</span>\n </AsideMenuItem>\n )}\n <AsideMenuItem to={buildPath('/edit')} className=\"aside-menu__item--push\">\n <FontAwesomeIcon fixedWidth icon={editIcon} />\n <span className=\"aside-menu__item-text\">Edit this server</span>\n </AsideMenuItem>\n {isServerWithId(selectedServer) && (\n <DeleteServerButton\n className=\"aside-menu__item aside-menu__item--danger\"\n textClassName=\"aside-menu__item-text\"\n server={selectedServer}\n />\n )}\n </nav>\n </aside>\n );\n};\n\nexport default AsideMenu;\n","import { CardProps } from 'reactstrap/lib/Card';\nimport { Card, CardBody, CardHeader } from 'reactstrap';\nimport { ReactNode } from 'react';\n\ninterface SimpleCardProps extends Omit<CardProps, 'title'> {\n title?: ReactNode;\n bodyClassName?: string;\n}\n\nexport const SimpleCard = ({ title, children, bodyClassName, ...rest }: SimpleCardProps) => (\n <Card {...rest}>\n {title && <CardHeader>{title}</CardHeader>}\n <CardBody className={bodyClassName}>{children}</CardBody>\n </Card>\n);\n","import { isReachableServer, SelectedServer } from '../../servers/data';\nimport { versionMatch, Versions } from './version';\n\nconst serverMatchesVersions = (versions: Versions) => (selectedServer: SelectedServer): boolean =>\n isReachableServer(selectedServer) && versionMatch(selectedServer.version, versions);\n\nexport const supportsQrCodeSizeInQuery = serverMatchesVersions({ minVersion: '2.5.0' });\n\nexport const supportsShortUrlTitle = serverMatchesVersions({ minVersion: '2.6.0' });\n\nexport const supportsOrphanVisits = supportsShortUrlTitle;\n\nexport const supportsQrCodeMargin = supportsShortUrlTitle;\n\nexport const supportsTagsInPatch = supportsShortUrlTitle;\n\nexport const supportsBotVisits = serverMatchesVersions({ minVersion: '2.7.0' });\n\nexport const supportsCrawlableVisits = supportsBotVisits;\n\nexport const supportsQrErrorCorrection = serverMatchesVersions({ minVersion: '2.8.0' });\n\nexport const supportsDomainRedirects = supportsQrErrorCorrection;\n","export const MAIN_COLOR = '#4696e5';\n\nexport const MAIN_COLOR_ALPHA = 'rgba(70, 150, 229, 0.4)';\n\nexport const HIGHLIGHTED_COLOR = '#f77f28';\n\nexport const HIGHLIGHTED_COLOR_ALPHA = 'rgba(247, 127, 40, 0.4)';\n\nexport const PRIMARY_LIGHT_COLOR = 'white';\n\nexport const PRIMARY_DARK_COLOR = '#161b22';\n\nexport type Theme = 'dark' | 'light';\n\nexport const changeThemeInMarkup = (theme: Theme) => {\n const html = document.getElementsByTagName('html');\n\n html?.[0]?.setAttribute('data-theme', theme);\n};\n\nexport const isDarkThemeEnabled = (): boolean => {\n const html = document.getElementsByTagName('html');\n\n return html?.[0]?.getAttribute('data-theme') === 'dark';\n};\n","import qs from 'qs';\n\nexport const parseQuery = <T>(search: string) => qs.parse(search, { ignoreQueryPrefix: true }) as unknown as T;\n\nexport const stringifyQuery = (query: any): string => qs.stringify(query, { arrayFormat: 'brackets' });\n","import { FC } from 'react';\nimport { Card, Row } from 'reactstrap';\nimport classNames from 'classnames';\nimport { faCircleNotch as preloader } from '@fortawesome/free-solid-svg-icons';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\n\ntype MessageType = 'default' | 'error';\n\nconst getClassForType = (type: MessageType) => {\n const map: Record<MessageType, string> = {\n error: 'border-danger',\n default: '',\n };\n\n return map[type];\n};\nconst getTextClassForType = (type: MessageType) => {\n const map: Record<MessageType, string> = {\n error: 'text-danger',\n default: 'text-muted',\n };\n\n return map[type];\n};\n\nexport interface MessageProps {\n className?: string;\n loading?: boolean;\n fullWidth?: boolean;\n type?: MessageType;\n}\n\nconst Message: FC<MessageProps> = ({ className, children, loading = false, type = 'default', fullWidth = false }) => {\n const classes = classNames({\n 'col-md-12': fullWidth,\n 'col-md-10 offset-md-1': !fullWidth,\n });\n\n return (\n <Row noGutters className={className}>\n <div className={classes}>\n <Card className={getClassForType(type)} body>\n <h3 className={classNames('text-center mb-0', getTextClassForType(type))}>\n {loading && <FontAwesomeIcon icon={preloader} spin />}\n {loading && <span className=\"ml-2\">{children ?? 'Loading...'}</span>}\n {!loading && children}\n </h3>\n </Card>\n </div>\n </Row>\n );\n};\n\nexport default Message;\n","import { useState } from 'react';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faSearch as searchIcon } from '@fortawesome/free-solid-svg-icons';\nimport classNames from 'classnames';\nimport './SearchField.scss';\n\nconst DEFAULT_SEARCH_INTERVAL = 500;\nlet timer: NodeJS.Timeout | null;\n\ninterface SearchFieldProps {\n onChange: (value: string) => void;\n className?: string;\n large?: boolean;\n noBorder?: boolean;\n}\n\nconst SearchField = ({ onChange, className, large = true, noBorder = false }: SearchFieldProps) => {\n const [ searchTerm, setSearchTerm ] = useState('');\n\n const resetTimer = () => {\n timer && clearTimeout(timer);\n timer = null;\n };\n const searchTermChanged = (newSearchTerm: string, timeout = DEFAULT_SEARCH_INTERVAL) => {\n setSearchTerm(newSearchTerm);\n\n resetTimer();\n\n timer = setTimeout(() => {\n onChange(newSearchTerm);\n resetTimer();\n }, timeout);\n };\n\n return (\n <div className={classNames('search-field', className)}>\n <input\n type=\"text\"\n className={classNames('form-control search-field__input', {\n 'form-control-lg': large,\n 'search-field__input--no-border': noBorder,\n })}\n placeholder=\"Search...\"\n value={searchTerm}\n onChange={(e) => searchTermChanged(e.target.value)}\n />\n <FontAwesomeIcon icon={searchIcon} className=\"search-field__icon\" />\n <div\n className=\"close search-field__close\"\n hidden={searchTerm === ''}\n id=\"search-field__close\"\n onClick={() => searchTermChanged('', 0)}\n >\n &times;\n </div>\n </div>\n );\n};\n\nexport default SearchField;\n","import { isEmpty, isNil, reject } from 'ramda';\nimport { AxiosInstance, AxiosResponse, Method } from 'axios';\nimport { ShortUrlsListParams } from '../../short-urls/reducers/shortUrlsListParams';\nimport { ShortUrl, ShortUrlData } from '../../short-urls/data';\nimport { OptionalString } from '../../utils/utils';\nimport {\n ShlinkHealth,\n ShlinkMercureInfo,\n ShlinkShortUrlsResponse,\n ShlinkTags,\n ShlinkTagsResponse,\n ShlinkVisits,\n ShlinkVisitsParams,\n ShlinkShortUrlData,\n ShlinkDomain,\n ShlinkDomainsResponse,\n ShlinkVisitsOverview,\n ShlinkEditDomainRedirects,\n ShlinkDomainRedirects,\n} from '../types';\nimport { stringifyQuery } from '../../utils/helpers/query';\n\nconst buildShlinkBaseUrl = (url: string, apiVersion: number) => url ? `${url}/rest/v${apiVersion}` : '';\nconst rejectNilProps = reject(isNil);\n\nexport default class ShlinkApiClient {\n private apiVersion: number;\n\n public constructor(\n private readonly axios: AxiosInstance,\n private readonly baseUrl: string,\n private readonly apiKey: string,\n ) {\n this.apiVersion = 2;\n }\n\n public readonly listShortUrls = async (params: ShortUrlsListParams = {}): Promise<ShlinkShortUrlsResponse> =>\n this.performRequest<{ shortUrls: ShlinkShortUrlsResponse }>('/short-urls', 'GET', params)\n .then(({ data }) => data.shortUrls);\n\n public readonly createShortUrl = async (options: ShortUrlData): Promise<ShortUrl> => {\n const filteredOptions = reject((value) => isEmpty(value) || isNil(value), options as any);\n\n return this.performRequest<ShortUrl>('/short-urls', 'POST', {}, filteredOptions)\n .then((resp) => resp.data);\n };\n\n public readonly getShortUrlVisits = async (shortCode: string, query?: ShlinkVisitsParams): Promise<ShlinkVisits> =>\n this.performRequest<{ visits: ShlinkVisits }>(`/short-urls/${shortCode}/visits`, 'GET', query)\n .then(({ data }) => data.visits);\n\n public readonly getTagVisits = async (tag: string, query?: Omit<ShlinkVisitsParams, 'domain'>): Promise<ShlinkVisits> =>\n this.performRequest<{ visits: ShlinkVisits }>(`/tags/${tag}/visits`, 'GET', query)\n .then(({ data }) => data.visits);\n\n public readonly getOrphanVisits = async (query?: Omit<ShlinkVisitsParams, 'domain'>): Promise<ShlinkVisits> =>\n this.performRequest<{ visits: ShlinkVisits }>('/visits/orphan', 'GET', query)\n .then(({ data }) => data.visits);\n\n public readonly getVisitsOverview = async (): Promise<ShlinkVisitsOverview> =>\n this.performRequest<{ visits: ShlinkVisitsOverview }>('/visits', 'GET')\n .then(({ data }) => data.visits);\n\n public readonly getShortUrl = async (shortCode: string, domain?: OptionalString): Promise<ShortUrl> =>\n this.performRequest<ShortUrl>(`/short-urls/${shortCode}`, 'GET', { domain })\n .then(({ data }) => data);\n\n public readonly deleteShortUrl = async (shortCode: string, domain?: OptionalString): Promise<void> =>\n this.performRequest(`/short-urls/${shortCode}`, 'DELETE', { domain })\n .then(() => {});\n\n /* @deprecated. If using Shlink 2.6.0 or greater, use updateShortUrl instead */\n public readonly updateShortUrlTags = async (\n shortCode: string,\n domain: OptionalString,\n tags: string[],\n ): Promise<string[]> =>\n this.performRequest<{ tags: string[] }>(`/short-urls/${shortCode}/tags`, 'PUT', { domain }, { tags })\n .then(({ data }) => data.tags);\n\n public readonly updateShortUrl = async (\n shortCode: string,\n domain: OptionalString,\n data: ShlinkShortUrlData,\n ): Promise<ShortUrl> =>\n this.performRequest<ShortUrl>(`/short-urls/${shortCode}`, 'PATCH', { domain }, data)\n .then(({ data }) => data);\n\n public readonly listTags = async (): Promise<ShlinkTags> =>\n this.performRequest<{ tags: ShlinkTagsResponse }>('/tags', 'GET', { withStats: 'true' })\n .then((resp) => resp.data.tags)\n .then(({ data, stats }) => ({ tags: data, stats }));\n\n public readonly deleteTags = async (tags: string[]): Promise<{ tags: string[] }> =>\n this.performRequest('/tags', 'DELETE', { tags })\n .then(() => ({ tags }));\n\n public readonly editTag = async (oldName: string, newName: string): Promise<{ oldName: string; newName: string }> =>\n this.performRequest('/tags', 'PUT', {}, { oldName, newName })\n .then(() => ({ oldName, newName }));\n\n public readonly health = async (): Promise<ShlinkHealth> =>\n this.performRequest<ShlinkHealth>('/health', 'GET')\n .then((resp) => resp.data);\n\n public readonly mercureInfo = async (): Promise<ShlinkMercureInfo> =>\n this.performRequest<ShlinkMercureInfo>('/mercure-info', 'GET')\n .then((resp) => resp.data);\n\n public readonly listDomains = async (): Promise<ShlinkDomain[]> =>\n this.performRequest<{ domains: ShlinkDomainsResponse }>('/domains', 'GET').then(({ data }) => data.domains.data);\n\n public readonly editDomainRedirects = async (\n domainRedirects: ShlinkEditDomainRedirects,\n ): Promise<ShlinkDomainRedirects> =>\n this.performRequest<ShlinkDomainRedirects>('/domains/redirects', 'PATCH', {}, domainRedirects).then(({ data }) => data);\n\n private readonly performRequest = async <T>(url: string, method: Method = 'GET', query = {}, body = {}): Promise<AxiosResponse<T>> => {\n try {\n return await this.axios({\n method,\n url: `${buildShlinkBaseUrl(this.baseUrl, this.apiVersion)}${url}`,\n headers: { 'X-Api-Key': this.apiKey },\n params: rejectNilProps(query),\n data: body,\n paramsSerializer: stringifyQuery,\n });\n } catch (e) {\n const { response } = e;\n\n // Due to a bug on all previous Shlink versions, requests to non-matching URLs will always result on a CORS error\n // when performed from the browser (due to the preflight request not returning a 2xx status.\n // See https://github.com/shlinkio/shlink/issues/614), which will make the \"response\" prop not to be set here.\n // The bug will be fixed on upcoming Shlink patches, but for other versions, we can consider this situation as\n // if a request has been performed to a not supported API version.\n const apiVersionIsNotSupported = !response;\n\n // When the request is not invalid or we have already tried both API versions, throw the error and let the\n // caller handle it\n if (!apiVersionIsNotSupported || this.apiVersion === 2) {\n throw e;\n }\n\n this.apiVersion = this.apiVersion - 1;\n\n return await this.performRequest(url, method, query, body);\n }\n };\n}\n","import { AxiosInstance } from 'axios';\nimport { prop } from 'ramda';\nimport { hasServerData, SelectedServer, ServerWithId } from '../../servers/data';\nimport { GetState } from '../../container/types';\nimport ShlinkApiClient from './ShlinkApiClient';\n\nconst apiClients: Record<string, ShlinkApiClient> = {};\n\nconst isGetState = (getStateOrSelectedServer: GetState | ServerWithId): getStateOrSelectedServer is GetState =>\n typeof getStateOrSelectedServer === 'function';\nconst getSelectedServerFromState = (getState: GetState): SelectedServer => prop('selectedServer', getState());\n\nexport type ShlinkApiClientBuilder = (getStateOrSelectedServer: GetState | ServerWithId) => ShlinkApiClient;\n\nconst buildShlinkApiClient = (axios: AxiosInstance): ShlinkApiClientBuilder => (\n getStateOrSelectedServer: GetState | ServerWithId,\n) => {\n const server = isGetState(getStateOrSelectedServer)\n ? getSelectedServerFromState(getStateOrSelectedServer)\n : getStateOrSelectedServer;\n\n if (!hasServerData(server)) {\n throw new Error('There\\'s no selected server or it is not found');\n }\n\n const { url, apiKey } = server;\n const clientKey = `${url}_${apiKey}`;\n\n if (!apiClients[clientKey]) {\n apiClients[clientKey] = new ShlinkApiClient(axios, url, apiKey);\n }\n\n return apiClients[clientKey];\n};\n\nexport default buildShlinkApiClient;\n","import Bottle from 'bottlejs';\nimport buildShlinkApiClient from './ShlinkApiClientBuilder';\n\nconst provideServices = (bottle: Bottle) => {\n bottle.serviceFactory('buildShlinkApiClient', buildShlinkApiClient, 'axios');\n};\n\nexport default provideServices;\n","import { FC, useEffect, useState } from 'react';\nimport { ShortUrlsListProps } from './ShortUrlsList';\n\nconst ShortUrls = (SearchBar: FC, ShortUrlsList: FC<ShortUrlsListProps>) => (props: ShortUrlsListProps) => {\n const { match } = props;\n const { page = '1', serverId = '' } = match?.params ?? {};\n const [ urlsListKey, setUrlsListKey ] = useState(`${serverId}_${page}`);\n\n // Using a key on a component makes react to create a new instance every time the key changes\n // Without it, pagination on the URL will not make the component to be refreshed\n useEffect(() => {\n setUrlsListKey(`${serverId}_${page}`);\n }, [ serverId, page ]);\n\n return (\n <>\n <div className=\"form-group\"><SearchBar /></div>\n <ShortUrlsList {...props} key={urlsListKey} />\n </>\n );\n};\n\nexport default ShortUrls;\n","import { FC, MouseEventHandler } from 'react';\nimport ColorGenerator from '../../utils/services/ColorGenerator';\nimport './Tag.scss';\n\ninterface TagProps {\n colorGenerator: ColorGenerator;\n text: string;\n className?: string;\n clearable?: boolean;\n onClick?: MouseEventHandler;\n onClose?: MouseEventHandler;\n}\n\nconst Tag: FC<TagProps> = ({ text, children, clearable, className = '', colorGenerator, onClick, onClose }) => (\n <span\n className={`badge tag ${className}`}\n style={{ backgroundColor: colorGenerator.getColorForKey(text), cursor: clearable || !onClick ? 'auto' : 'pointer' }}\n onClick={onClick}\n >\n {children ?? text}\n {clearable && <span className=\"close tag__close-selected-tag\" onClick={onClose}>&times;</span>}\n </span>\n);\n\nexport default Tag;\n","import { FC } from 'react';\nimport { Dropdown, DropdownMenu, DropdownToggle } from 'reactstrap';\nimport { useToggle } from './helpers/hooks';\nimport './DropdownBtn.scss';\n\nexport interface DropdownBtnProps {\n text: string;\n disabled?: boolean;\n className?: string;\n dropdownClassName?: string;\n right?: boolean;\n minWidth?: number;\n}\n\nexport const DropdownBtn: FC<DropdownBtnProps> = (\n { text, disabled = false, className = '', children, dropdownClassName, right = false, minWidth },\n) => {\n const [ isOpen, toggle ] = useToggle();\n const toggleClasses = `dropdown-btn__toggle btn-block ${className}`;\n const style = { minWidth: minWidth && `${minWidth}px` };\n\n return (\n <Dropdown isOpen={isOpen} toggle={toggle} disabled={disabled} className={dropdownClassName}>\n <DropdownToggle caret className={toggleClasses} color=\"primary\">{text}</DropdownToggle>\n <DropdownMenu className=\"w-100\" right={right} style={style}>{children}</DropdownMenu>\n </Dropdown>\n );\n};\n","import { format, formatISO, parse } from 'date-fns';\nimport { OptionalString } from '../utils';\n\ntype DateOrString = Date | string;\ntype NullableDate = DateOrString | null;\n\nexport const isDateObject = (date: DateOrString): date is Date => typeof date !== 'string';\n\nconst formatDateFromFormat = (date?: NullableDate, theFormat?: string): OptionalString => {\n if (!date || !isDateObject(date)) {\n return date;\n }\n\n return theFormat ? format(date, theFormat) : formatISO(date);\n};\n\nexport const formatDate = (format = 'yyyy-MM-dd') => (date?: NullableDate) => formatDateFromFormat(date, format);\n\nexport const formatIsoDate = (date?: NullableDate) => formatDateFromFormat(date, undefined);\n\nexport const formatInternational = formatDate();\n\nexport const parseDate = (date: string, format: string) => parse(date, format, new Date());\n","import { subDays, startOfDay, endOfDay } from 'date-fns';\nimport { filter, isEmpty } from 'ramda';\nimport { formatInternational } from '../../helpers/date';\n\nexport interface DateRange {\n startDate?: Date | null;\n endDate?: Date | null;\n}\n\nexport type DateInterval = 'today' | 'yesterday' | 'last7Days' | 'last30Days' | 'last90Days' | 'last180days' | 'last365Days';\n\nexport const dateRangeIsEmpty = (dateRange?: DateRange): boolean => dateRange === undefined\n || isEmpty(filter(Boolean, dateRange as any));\n\nexport const rangeIsInterval = (range?: DateRange | DateInterval): range is DateInterval => typeof range === 'string';\n\nconst INTERVAL_TO_STRING_MAP: Record<DateInterval, string> = {\n today: 'Today',\n yesterday: 'Yesterday',\n last7Days: 'Last 7 days',\n last30Days: 'Last 30 days',\n last90Days: 'Last 90 days',\n last180days: 'Last 180 days',\n last365Days: 'Last 365 days',\n};\n\nexport const DATE_INTERVALS: DateInterval[] = Object.keys(INTERVAL_TO_STRING_MAP) as DateInterval[];\n\nconst dateRangeToString = (range?: DateRange): string | undefined => {\n if (!range || dateRangeIsEmpty(range)) {\n return undefined;\n }\n\n if (range.startDate && !range.endDate) {\n return `Since ${formatInternational(range.startDate)}`;\n }\n\n if (!range.startDate && range.endDate) {\n return `Until ${formatInternational(range.endDate)}`;\n }\n\n return `${formatInternational(range.startDate)} - ${formatInternational(range.endDate)}`;\n};\n\nexport const rangeOrIntervalToString = (range?: DateRange | DateInterval): string | undefined => {\n if (!range) {\n return undefined;\n }\n\n if (!rangeIsInterval(range)) {\n return dateRangeToString(range);\n }\n\n return INTERVAL_TO_STRING_MAP[range];\n};\n\nconst startOfDaysAgo = (daysAgo: number) => startOfDay(subDays(new Date(), daysAgo));\nconst endingToday = (startDate: Date): DateRange => ({ startDate, endDate: endOfDay(new Date()) });\n\nexport const intervalToDateRange = (dateInterval?: DateInterval): DateRange => {\n if (!dateInterval) {\n return {};\n }\n\n switch (dateInterval) {\n case 'today':\n return endingToday(startOfDay(new Date()));\n case 'yesterday':\n return { startDate: startOfDaysAgo(1), endDate: endOfDay(subDays(new Date(), 1)) };\n case 'last7Days':\n return endingToday(startOfDaysAgo(7));\n case 'last30Days':\n return endingToday(startOfDaysAgo(30));\n case 'last90Days':\n return endingToday(startOfDaysAgo(90));\n case 'last180days':\n return endingToday(startOfDaysAgo(180));\n case 'last365Days':\n return endingToday(startOfDaysAgo(365));\n }\n\n return {};\n};\n","import { useRef } from 'react';\nimport { isNil } from 'ramda';\nimport DatePicker, { ReactDatePickerProps } from 'react-datepicker';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faCalendarAlt as calendarIcon } from '@fortawesome/free-regular-svg-icons';\nimport classNames from 'classnames';\nimport './DateInput.scss';\n\nexport type DateInputProps = ReactDatePickerProps;\n\nconst DateInput = (props: DateInputProps) => {\n const { className, isClearable, selected } = props;\n const showCalendarIcon = !isClearable || isNil(selected);\n const ref = useRef<{ input: HTMLInputElement }>();\n\n return (\n <div className=\"date-input-container\">\n <DatePicker\n {...props}\n dateFormat=\"yyyy-MM-dd\"\n className={classNames('date-input-container__input form-control', className)}\n // @ts-expect-error The DatePicker type definition is wrong. It has a ref prop\n ref={ref}\n />\n {showCalendarIcon && (\n <FontAwesomeIcon\n icon={calendarIcon}\n className=\"date-input-container__icon\"\n onClick={() => ref.current?.input.focus()}\n />\n )}\n </div>\n );\n};\n\nexport default DateInput;\n","import DateInput from '../DateInput';\nimport { DateRange } from './types';\n\ninterface DateRangeRowProps extends DateRange {\n onStartDateChange: (date: Date | null) => void;\n onEndDateChange: (date: Date | null) => void;\n disabled?: boolean;\n}\n\nconst DateRangeRow = (\n { startDate = null, endDate = null, disabled = false, onStartDateChange, onEndDateChange }: DateRangeRowProps,\n) => (\n <div className=\"row\">\n <div className=\"col-md-6\">\n <DateInput\n selected={startDate}\n placeholderText=\"Since...\"\n isClearable\n maxDate={endDate ?? undefined}\n disabled={disabled}\n onChange={onStartDateChange}\n />\n </div>\n <div className=\"col-md-6\">\n <DateInput\n className=\"mt-2 mt-md-0\"\n selected={endDate}\n placeholderText=\"Until...\"\n isClearable\n minDate={startDate ?? undefined}\n disabled={disabled}\n onChange={onEndDateChange}\n />\n </div>\n </div>\n);\n\nexport default DateRangeRow;\n","import { DropdownItem } from 'reactstrap';\nimport { FC } from 'react';\nimport { DATE_INTERVALS, DateInterval, rangeOrIntervalToString } from './types';\n\nexport interface DateIntervalDropdownProps {\n active?: DateInterval;\n onChange: (interval: DateInterval) => void;\n}\n\nexport const DateIntervalDropdownItems: FC<DateIntervalDropdownProps> = ({ active, onChange }) => (\n <>\n {DATE_INTERVALS.map(\n (interval) => (\n <DropdownItem key={interval} active={active === interval} onClick={() => onChange(interval)}>\n {rangeOrIntervalToString(interval)}\n </DropdownItem>\n ),\n )}\n </>\n);\n","import { useState } from 'react';\nimport { DropdownItem } from 'reactstrap';\nimport { DropdownBtn } from '../DropdownBtn';\nimport {\n DateInterval,\n DateRange,\n dateRangeIsEmpty,\n rangeOrIntervalToString,\n intervalToDateRange,\n rangeIsInterval,\n} from './types';\nimport DateRangeRow from './DateRangeRow';\nimport { DateIntervalDropdownItems } from './DateIntervalDropdownItems';\n\nexport interface DateRangeSelectorProps {\n initialDateRange?: DateInterval | DateRange;\n disabled?: boolean;\n onDatesChange: (dateRange: DateRange) => void;\n defaultText: string;\n}\n\nexport const DateRangeSelector = (\n { onDatesChange, initialDateRange, defaultText, disabled }: DateRangeSelectorProps,\n) => {\n const [ activeInterval, setActiveInterval ] = useState(\n rangeIsInterval(initialDateRange) ? initialDateRange : undefined,\n );\n const [ activeDateRange, setActiveDateRange ] = useState(\n !rangeIsInterval(initialDateRange) ? initialDateRange : undefined,\n );\n const updateDateRange = (dateRange: DateRange) => {\n setActiveInterval(undefined);\n setActiveDateRange(dateRange);\n onDatesChange(dateRange);\n };\n const updateInterval = (dateInterval?: DateInterval) => () => {\n setActiveInterval(dateInterval);\n setActiveDateRange(undefined);\n onDatesChange(intervalToDateRange(dateInterval));\n };\n\n return (\n <DropdownBtn disabled={disabled} text={rangeOrIntervalToString(activeInterval ?? activeDateRange) ?? defaultText}>\n <DropdownItem\n active={activeInterval === undefined && dateRangeIsEmpty(activeDateRange)}\n onClick={updateInterval(undefined)}\n >\n {defaultText}\n </DropdownItem>\n <DropdownItem divider />\n <DateIntervalDropdownItems active={activeInterval} onChange={(interval) => updateInterval(interval)()} />\n <DropdownItem divider />\n <DropdownItem header>Custom:</DropdownItem>\n <DropdownItem text>\n <DateRangeRow\n {...activeDateRange}\n onStartDateChange={(startDate) => updateDateRange({ ...activeDateRange, startDate })}\n onEndDateChange={(endDate) => updateDateRange({ ...activeDateRange, endDate })}\n />\n </DropdownItem>\n </DropdownBtn>\n );\n};\n","import { faTags as tagsIcon } from '@fortawesome/free-solid-svg-icons';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { isEmpty, pipe } from 'ramda';\nimport { parseISO } from 'date-fns';\nimport SearchField from '../utils/SearchField';\nimport Tag from '../tags/helpers/Tag';\nimport { DateRangeSelector } from '../utils/dates/DateRangeSelector';\nimport { formatIsoDate } from '../utils/helpers/date';\nimport ColorGenerator from '../utils/services/ColorGenerator';\nimport { DateRange } from '../utils/dates/types';\nimport { ShortUrlsListParams } from './reducers/shortUrlsListParams';\nimport './SearchBar.scss';\n\ninterface SearchBarProps {\n listShortUrls: (params: ShortUrlsListParams) => void;\n shortUrlsListParams: ShortUrlsListParams;\n}\n\nconst dateOrNull = (date?: string) => date ? parseISO(date) : null;\n\nconst SearchBar = (colorGenerator: ColorGenerator) => ({ listShortUrls, shortUrlsListParams }: SearchBarProps) => {\n const selectedTags = shortUrlsListParams.tags ?? [];\n const setDates = pipe(\n ({ startDate, endDate }: DateRange) => ({\n startDate: formatIsoDate(startDate) ?? undefined,\n endDate: formatIsoDate(endDate) ?? undefined,\n }),\n (dates) => listShortUrls({ ...shortUrlsListParams, ...dates }),\n );\n\n return (\n <div className=\"search-bar-container\">\n <SearchField onChange={(searchTerm) => listShortUrls({ ...shortUrlsListParams, searchTerm })} />\n\n <div className=\"mt-3\">\n <div className=\"row\">\n <div className=\"col-lg-8 offset-lg-4 col-xl-6 offset-xl-6\">\n <DateRangeSelector\n defaultText=\"All short URLs\"\n initialDateRange={{\n startDate: dateOrNull(shortUrlsListParams.startDate),\n endDate: dateOrNull(shortUrlsListParams.endDate),\n }}\n onDatesChange={setDates}\n />\n </div>\n </div>\n </div>\n\n {!isEmpty(selectedTags) && (\n <h4 className=\"search-bar__selected-tag mt-3\">\n <FontAwesomeIcon icon={tagsIcon} className=\"search-bar__tags-icon\" />\n &nbsp;\n {selectedTags.map((tag) => (\n <Tag\n colorGenerator={colorGenerator}\n key={tag}\n text={tag}\n clearable\n onClose={() => listShortUrls(\n {\n ...shortUrlsListParams,\n tags: selectedTags.filter((selectedTag) => selectedTag !== tag),\n },\n )}\n />\n ))}\n </h4>\n )}\n </div>\n );\n};\n\nexport default SearchBar;\n","import { UncontrolledDropdown, DropdownToggle, DropdownMenu, DropdownItem } from 'reactstrap';\nimport { toPairs } from 'ramda';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faSortAmountUp as sortAscIcon, faSortAmountDown as sortDescIcon } from '@fortawesome/free-solid-svg-icons';\nimport classNames from 'classnames';\nimport { determineOrderDir, OrderDir } from './utils';\nimport './SortingDropdown.scss';\n\nexport interface SortingDropdownProps<T extends string = string> {\n items: Record<T, string>;\n orderField?: T;\n orderDir?: OrderDir;\n onChange: (orderField?: T, orderDir?: OrderDir) => void;\n isButton?: boolean;\n right?: boolean;\n}\n\nexport default function SortingDropdown<T extends string = string>(\n { items, orderField, orderDir, onChange, isButton = true, right = false }: SortingDropdownProps<T>,\n) {\n const handleItemClick = (fieldKey: T) => () => {\n const newOrderDir = determineOrderDir(fieldKey, orderField, orderDir);\n\n onChange(newOrderDir ? fieldKey : undefined, newOrderDir);\n };\n\n return (\n <UncontrolledDropdown>\n <DropdownToggle\n caret\n color={isButton ? 'primary' : 'link'}\n className={classNames({ 'dropdown-btn__toggle btn-block': isButton, 'btn-sm p-0': !isButton })}\n >\n {!isButton && <>Order by</>}\n {isButton && !orderField && <>Order by...</>}\n {isButton && orderField && `Order by: \"${items[orderField]}\" - \"${orderDir ?? 'DESC'}\"`}\n </DropdownToggle>\n <DropdownMenu\n right={right}\n className={classNames('w-100', { 'sorting-dropdown__menu--link': !isButton })}\n >\n {toPairs(items).map(([ fieldKey, fieldValue ]) => (\n <DropdownItem key={fieldKey} active={orderField === fieldKey} onClick={handleItemClick(fieldKey as T)}>\n {fieldValue}\n {orderField === fieldKey && (\n <FontAwesomeIcon\n icon={orderDir === 'ASC' ? sortAscIcon : sortDescIcon}\n className=\"sorting-dropdown__sort-icon\"\n />\n )}\n </DropdownItem>\n ))}\n <DropdownItem divider />\n <DropdownItem disabled={!orderField} onClick={() => onChange()}>\n <i>Clear selection</i>\n </DropdownItem>\n </DropdownMenu>\n </UncontrolledDropdown>\n );\n}\n","import { FC, useEffect } from 'react';\nimport { pipe } from 'ramda';\nimport { CreateVisit } from '../../visits/types';\nimport { MercureInfo } from '../reducers/mercureInfo';\nimport { bindToMercureTopic } from './index';\n\nexport interface MercureBoundProps {\n createNewVisits: (createdVisits: CreateVisit[]) => void;\n loadMercureInfo: () => void;\n mercureInfo: MercureInfo;\n}\n\nexport function boundToMercureHub<T = {}>(\n WrappedComponent: FC<MercureBoundProps & T>,\n getTopicsForProps: (props: T) => string[],\n) {\n const pendingUpdates = new Set<CreateVisit>();\n\n return (props: MercureBoundProps & T) => {\n const { createNewVisits, loadMercureInfo, mercureInfo } = props;\n const { interval } = mercureInfo;\n\n useEffect(() => {\n const onMessage = (visit: CreateVisit) => interval ? pendingUpdates.add(visit) : createNewVisits([ visit ]);\n const closeEventSource = bindToMercureTopic(mercureInfo, getTopicsForProps(props), onMessage, loadMercureInfo);\n\n if (!interval) {\n return closeEventSource;\n }\n\n const timer = setInterval(() => {\n createNewVisits([ ...pendingUpdates ]);\n pendingUpdates.clear();\n }, interval * 1000 * 60);\n\n return pipe(() => clearInterval(timer), () => closeEventSource?.());\n }, [ mercureInfo ]);\n\n return <WrappedComponent {...props} />;\n };\n}\n","import { EventSourcePolyfill as EventSource } from 'event-source-polyfill';\nimport { MercureInfo } from '../reducers/mercureInfo';\n\nexport const bindToMercureTopic = <T>(mercureInfo: MercureInfo, topics: string[], onMessage: (message: T) => void, onTokenExpired: () => void) => { // eslint-disable-line max-len\n const { mercureHubUrl, token, loading, error } = mercureInfo;\n\n if (loading || error || !mercureHubUrl) {\n return undefined;\n }\n\n const onEventSourceMessage = ({ data }: { data: string }) => onMessage(JSON.parse(data) as T);\n const onEventSourceError = ({ status }: { status: number }) => status === 401 && onTokenExpired();\n\n const subscriptions = topics.map((topic) => {\n const hubUrl = new URL(mercureHubUrl);\n\n hubUrl.searchParams.append('topic', topic);\n const es = new EventSource(hubUrl, {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n es.onmessage = onEventSourceMessage;\n es.onerror = onEventSourceError;\n\n return es;\n });\n\n return () => subscriptions.forEach((es) => es.close());\n};\n","export class Topics {\n public static readonly visits = 'https://shlink.io/new-visit';\n\n public static readonly orphanVisits = 'https://shlink.io/new-orphan-visit';\n\n public static readonly shortUrlVisits = (shortCode: string) => `https://shlink.io/new-visit/${shortCode}`;\n}\n","import { Action } from 'redux';\n\ntype ActionHandler<State, AT> = (currentState: State, action: AT) => State;\ntype ActionHandlerMap<State, AT> = Record<string, ActionHandler<State, AT>>;\n\nexport const buildReducer = <State, AT extends Action>(map: ActionHandlerMap<State, AT>, initialState: State) => (\n state: State | undefined,\n action: AT,\n): State => {\n const { type } = action;\n const actionHandler = map[type];\n const currentState = state ?? initialState;\n\n return actionHandler ? actionHandler(currentState, action) : currentState;\n};\n\nexport const buildActionCreator = <T extends string>(type: T) => (): Action<T> => ({ type });\n","import { isEmpty, propEq, values } from 'ramda';\nimport { useState, useEffect, useMemo, FC } from 'react';\nimport { Button, Card, Nav, NavLink, Progress, Row } from 'reactstrap';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faCalendarAlt, faMapMarkedAlt, faList, faChartPie, faFileDownload } from '@fortawesome/free-solid-svg-icons';\nimport { IconDefinition } from '@fortawesome/fontawesome-common-types';\nimport { Route, Switch, NavLink as RouterNavLink, Redirect } from 'react-router-dom';\nimport { Location } from 'history';\nimport classNames from 'classnames';\nimport { DateRangeSelector } from '../utils/dates/DateRangeSelector';\nimport Message from '../utils/Message';\nimport { DateInterval, DateRange, intervalToDateRange } from '../utils/dates/types';\nimport { Result } from '../utils/Result';\nimport { ShlinkApiError } from '../api/ShlinkApiError';\nimport { Settings } from '../settings/reducers/settings';\nimport { SelectedServer } from '../servers/data';\nimport { supportsBotVisits } from '../utils/helpers/features';\nimport LineChartCard from './charts/LineChartCard';\nimport VisitsTable from './VisitsTable';\nimport { NormalizedOrphanVisit, NormalizedVisit, VisitsFilter, VisitsInfo, VisitsParams } from './types';\nimport OpenMapModalBtn from './helpers/OpenMapModalBtn';\nimport { normalizeVisits, processStatsFromVisits } from './services/VisitsParser';\nimport { VisitsFilterDropdown } from './helpers/VisitsFilterDropdown';\nimport { HighlightableProps, highlightedVisitsToStats } from './types/helpers';\nimport { DoughnutChartCard } from './charts/DoughnutChartCard';\nimport { SortableBarChartCard } from './charts/SortableBarChartCard';\nimport './VisitsStats.scss';\n\nexport interface VisitsStatsProps {\n getVisits: (params: VisitsParams) => void;\n visitsInfo: VisitsInfo;\n settings: Settings;\n selectedServer: SelectedServer;\n cancelGetVisits: () => void;\n baseUrl: string;\n domain?: string;\n exportCsv: (visits: NormalizedVisit[]) => void;\n isOrphanVisits?: boolean;\n}\n\ninterface VisitsNavLinkProps {\n title: string;\n subPath: string;\n icon: IconDefinition;\n}\n\ntype Section = 'byTime' | 'byContext' | 'byLocation' | 'list';\n\nconst sections: Record<Section, VisitsNavLinkProps> = {\n byTime: { title: 'By time', subPath: '', icon: faCalendarAlt },\n byContext: { title: 'By context', subPath: '/by-context', icon: faChartPie },\n byLocation: { title: 'By location', subPath: '/by-location', icon: faMapMarkedAlt },\n list: { title: 'List', subPath: '/list', icon: faList },\n};\n\nlet selectedBar: string | undefined;\n\nconst VisitsNavLink: FC<VisitsNavLinkProps & { to: string }> = ({ subPath, title, icon, to }) => (\n <NavLink\n tag={RouterNavLink}\n className=\"visits-stats__nav-link\"\n to={to}\n isActive={(_: null, { pathname }: Location) => pathname.endsWith(`visits${subPath}`)}\n replace\n >\n <FontAwesomeIcon icon={icon} />\n <span className=\"ml-2 d-none d-sm-inline\">{title}</span>\n </NavLink>\n);\n\nconst VisitsStats: FC<VisitsStatsProps> = ({\n children,\n visitsInfo,\n getVisits,\n cancelGetVisits,\n baseUrl,\n domain,\n settings,\n exportCsv,\n selectedServer,\n isOrphanVisits = false,\n}) => {\n const initialInterval: DateInterval = settings.visits?.defaultInterval ?? 'last30Days';\n const [ dateRange, setDateRange ] = useState<DateRange>(intervalToDateRange(initialInterval));\n const [ highlightedVisits, setHighlightedVisits ] = useState<NormalizedVisit[]>([]);\n const [ highlightedLabel, setHighlightedLabel ] = useState<string | undefined>();\n const [ visitsFilter, setVisitsFilter ] = useState<VisitsFilter>({});\n const botsSupported = supportsBotVisits(selectedServer);\n\n const buildSectionUrl = (subPath?: string) => {\n const query = domain ? `?domain=${domain}` : '';\n\n return !subPath ? `${baseUrl}${query}` : `${baseUrl}${subPath}${query}`;\n };\n const { visits, loading, loadingLarge, error, errorData, progress } = visitsInfo;\n const normalizedVisits = useMemo(() => normalizeVisits(visits), [ visits ]);\n const { os, browsers, referrers, countries, cities, citiesForMap, visitedUrls } = useMemo(\n () => processStatsFromVisits(normalizedVisits),\n [ normalizedVisits ],\n );\n const mapLocations = values(citiesForMap);\n\n const setSelectedVisits = (selectedVisits: NormalizedVisit[]) => {\n selectedBar = undefined;\n setHighlightedVisits(selectedVisits);\n };\n const highlightVisitsForProp = (prop: HighlightableProps<NormalizedOrphanVisit>) => (value: string) => {\n const newSelectedBar = `${prop}_${value}`;\n\n if (selectedBar === newSelectedBar) {\n setHighlightedVisits([]);\n setHighlightedLabel(undefined);\n selectedBar = undefined;\n } else {\n setHighlightedVisits((normalizedVisits as NormalizedOrphanVisit[]).filter(propEq(prop, value)));\n setHighlightedLabel(value);\n selectedBar = newSelectedBar;\n }\n };\n\n useEffect(() => cancelGetVisits, []);\n useEffect(() => {\n getVisits({ dateRange, filter: visitsFilter });\n }, [ dateRange, visitsFilter ]);\n\n const renderVisitsContent = () => {\n if (loadingLarge) {\n return (\n <Message loading>\n This is going to take a while... :S\n <Progress value={progress} striped={progress === 100} className=\"mt-3\" />\n </Message>\n );\n }\n\n if (loading) {\n return <Message loading />;\n }\n\n if (error) {\n return (\n <Result type=\"error\">\n <ShlinkApiError errorData={errorData} fallbackMessage=\"An error occurred while loading visits :(\" />\n </Result>\n );\n }\n\n if (isEmpty(visits)) {\n return <Message>There are no visits matching current filter :(</Message>;\n }\n\n return (\n <>\n <Card className=\"visits-stats__nav p-0 overflow-hidden\" body>\n <Nav pills fill>\n {Object.entries(sections).map(([ section, props ]) =>\n <VisitsNavLink key={section} {...props} to={buildSectionUrl(props.subPath)} />)}\n </Nav>\n </Card>\n <Row>\n <Switch>\n <Route exact path={baseUrl}>\n <div className=\"col-12 mt-3\">\n <LineChartCard\n title=\"Visits during time\"\n visits={normalizedVisits}\n highlightedVisits={highlightedVisits}\n highlightedLabel={highlightedLabel}\n setSelectedVisits={setSelectedVisits}\n />\n </div>\n </Route>\n\n <Route exact path={`${baseUrl}${sections.byContext.subPath}`}>\n <div className={classNames('mt-3 col-lg-6', { 'col-xl-4': !isOrphanVisits })}>\n <DoughnutChartCard title=\"Operating systems\" stats={os} />\n </div>\n <div className={classNames('mt-3 col-lg-6', { 'col-xl-4': !isOrphanVisits })}>\n <DoughnutChartCard title=\"Browsers\" stats={browsers} />\n </div>\n <div className={classNames('mt-3', { 'col-xl-4': !isOrphanVisits, 'col-lg-6': isOrphanVisits })}>\n <SortableBarChartCard\n title=\"Referrers\"\n stats={referrers}\n withPagination={false}\n highlightedStats={highlightedVisitsToStats(highlightedVisits, 'referer')}\n highlightedLabel={highlightedLabel}\n sortingItems={{\n name: 'Referrer name',\n amount: 'Visits amount',\n }}\n onClick={highlightVisitsForProp('referer')}\n />\n </div>\n {isOrphanVisits && (\n <div className=\"mt-3 col-lg-6\">\n <SortableBarChartCard\n title=\"Visited URLs\"\n stats={visitedUrls}\n highlightedLabel={highlightedLabel}\n highlightedStats={highlightedVisitsToStats(highlightedVisits, 'visitedUrl')}\n sortingItems={{\n visitedUrl: 'Visited URL',\n amount: 'Visits amount',\n }}\n onClick={highlightVisitsForProp('visitedUrl')}\n />\n </div>\n )}\n </Route>\n\n <Route exact path={`${baseUrl}${sections.byLocation.subPath}`}>\n <div className=\"col-lg-6 mt-3\">\n <SortableBarChartCard\n title=\"Countries\"\n stats={countries}\n highlightedStats={highlightedVisitsToStats(highlightedVisits, 'country')}\n highlightedLabel={highlightedLabel}\n sortingItems={{\n name: 'Country name',\n amount: 'Visits amount',\n }}\n onClick={highlightVisitsForProp('country')}\n />\n </div>\n <div className=\"col-lg-6 mt-3\">\n <SortableBarChartCard\n title=\"Cities\"\n stats={cities}\n highlightedStats={highlightedVisitsToStats(highlightedVisits, 'city')}\n highlightedLabel={highlightedLabel}\n extraHeaderContent={(activeCities: string[]) =>\n mapLocations.length > 0 &&\n <OpenMapModalBtn modalTitle=\"Cities\" locations={mapLocations} activeCities={activeCities} />\n }\n sortingItems={{\n name: 'City name',\n amount: 'Visits amount',\n }}\n onClick={highlightVisitsForProp('city')}\n />\n </div>\n </Route>\n\n <Route exact path={`${baseUrl}${sections.list.subPath}`}>\n <div className=\"col-12\">\n <VisitsTable\n visits={normalizedVisits}\n selectedVisits={highlightedVisits}\n setSelectedVisits={setSelectedVisits}\n isOrphanVisits={isOrphanVisits}\n selectedServer={selectedServer}\n />\n </div>\n </Route>\n\n <Redirect to={baseUrl} />\n </Switch>\n </Row>\n </>\n );\n };\n\n return (\n <>\n {children}\n\n <section className=\"mt-3\">\n <div className=\"row flex-md-row-reverse\">\n <div className=\"col-lg-7 col-xl-6\">\n <div className=\"d-md-flex\">\n <div className=\"flex-fill\">\n <DateRangeSelector\n disabled={loading}\n initialDateRange={initialInterval}\n defaultText=\"All visits\"\n onDatesChange={setDateRange}\n />\n </div>\n <VisitsFilterDropdown\n className=\"ml-0 ml-md-2 mt-3 mt-md-0\"\n isOrphanVisits={isOrphanVisits}\n botsSupported={botsSupported}\n selected={visitsFilter}\n onChange={setVisitsFilter}\n />\n </div>\n </div>\n {visits.length > 0 && (\n <div className=\"col-lg-5 col-xl-6 mt-3 mt-lg-0\">\n <div className=\"d-flex\">\n <Button\n outline\n disabled={highlightedVisits.length === 0}\n className=\"btn-md-block mr-2\"\n onClick={() => setSelectedVisits([])}\n >\n Clear selection {highlightedVisits.length > 0 && <>({highlightedVisits.length})</>}\n </Button>\n <Button\n outline\n color=\"primary\"\n className=\"btn-md-block\"\n onClick={() => exportCsv(normalizedVisits)}\n >\n <FontAwesomeIcon icon={faFileDownload} /> Export ({normalizedVisits.length})\n </Button>\n </div>\n </div>\n )}\n </div>\n </section>\n\n <section className=\"mt-3\">\n {renderVisitsContent()}\n </section>\n </>\n );\n};\n\nexport default VisitsStats;\n","import { isNil } from 'ramda';\nimport { ShortUrl } from '../data';\nimport { OptionalString } from '../../utils/utils';\n\nexport const shortUrlMatches = (shortUrl: ShortUrl, shortCode: string, domain: OptionalString): boolean => {\n if (isNil(domain)) {\n return shortUrl.shortCode === shortCode && !shortUrl.domain;\n }\n\n return shortUrl.shortCode === shortCode && shortUrl.domain === domain;\n};\n","import { Action } from 'redux';\nimport { CreateVisit } from '../types';\n\nexport const CREATE_VISITS = 'shlink/visitCreation/CREATE_VISITS';\n\nexport interface CreateVisitsAction extends Action<typeof CREATE_VISITS> {\n createdVisits: CreateVisit[];\n}\n\nexport const createNewVisits = (createdVisits: CreateVisit[]): CreateVisitsAction => ({\n type: CREATE_VISITS,\n createdVisits,\n});\n","import { AxiosError } from 'axios';\nimport { InvalidArgumentError, InvalidShortUrlDeletion, ProblemDetailsError } from '../types';\n\nexport const parseApiError = (e: AxiosError<ProblemDetailsError>) => e.response?.data;\n\nexport const isInvalidArgumentError = (error?: ProblemDetailsError): error is InvalidArgumentError =>\n error?.type === 'INVALID_ARGUMENT';\n\nexport const isInvalidDeletionError = (error?: ProblemDetailsError): error is InvalidShortUrlDeletion =>\n error?.type === 'INVALID_SHORTCODE_DELETION';\n","import { Action, Dispatch } from 'redux';\nimport { buildActionCreator, buildReducer } from '../../utils/helpers/redux';\nimport { ProblemDetailsError } from '../../api/types';\nimport { GetState } from '../../container/types';\nimport { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';\nimport { parseApiError } from '../../api/utils';\nimport { ApiErrorAction } from '../../api/types/actions';\n\n/* eslint-disable padding-line-between-statements */\nexport const DELETE_SHORT_URL_START = 'shlink/deleteShortUrl/DELETE_SHORT_URL_START';\nexport const DELETE_SHORT_URL_ERROR = 'shlink/deleteShortUrl/DELETE_SHORT_URL_ERROR';\nexport const SHORT_URL_DELETED = 'shlink/deleteShortUrl/SHORT_URL_DELETED';\nexport const RESET_DELETE_SHORT_URL = 'shlink/deleteShortUrl/RESET_DELETE_SHORT_URL';\n/* eslint-enable padding-line-between-statements */\n\nexport interface ShortUrlDeletion {\n shortCode: string;\n loading: boolean;\n error: boolean;\n errorData?: ProblemDetailsError;\n}\n\nexport interface DeleteShortUrlAction extends Action<string> {\n shortCode: string;\n domain?: string | null;\n}\n\nconst initialState: ShortUrlDeletion = {\n shortCode: '',\n loading: false,\n error: false,\n};\n\nexport default buildReducer<ShortUrlDeletion, DeleteShortUrlAction & ApiErrorAction>({\n [DELETE_SHORT_URL_START]: (state) => ({ ...state, loading: true, error: false }),\n [DELETE_SHORT_URL_ERROR]: (state, { errorData }) => ({ ...state, errorData, loading: false, error: true }),\n [SHORT_URL_DELETED]: (state, { shortCode }) => ({ ...state, shortCode, loading: false, error: false }),\n [RESET_DELETE_SHORT_URL]: () => initialState,\n}, initialState);\n\nexport const deleteShortUrl = (buildShlinkApiClient: ShlinkApiClientBuilder) => (\n shortCode: string,\n domain?: string | null,\n) => async (dispatch: Dispatch, getState: GetState) => {\n dispatch({ type: DELETE_SHORT_URL_START });\n const { deleteShortUrl } = buildShlinkApiClient(getState);\n\n try {\n await deleteShortUrl(shortCode, domain);\n dispatch<DeleteShortUrlAction>({ type: SHORT_URL_DELETED, shortCode, domain });\n } catch (e) {\n dispatch<ApiErrorAction>({ type: DELETE_SHORT_URL_ERROR, errorData: parseApiError(e) });\n\n throw e;\n }\n};\n\nexport const resetDeleteShortUrl = buildActionCreator(RESET_DELETE_SHORT_URL);\n","import { Action, Dispatch } from 'redux';\nimport { GetState } from '../../container/types';\nimport { ShortUrl, ShortUrlData } from '../data';\nimport { buildReducer, buildActionCreator } from '../../utils/helpers/redux';\nimport { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';\nimport { ProblemDetailsError } from '../../api/types';\nimport { parseApiError } from '../../api/utils';\nimport { ApiErrorAction } from '../../api/types/actions';\n\n/* eslint-disable padding-line-between-statements */\nexport const CREATE_SHORT_URL_START = 'shlink/createShortUrl/CREATE_SHORT_URL_START';\nexport const CREATE_SHORT_URL_ERROR = 'shlink/createShortUrl/CREATE_SHORT_URL_ERROR';\nexport const CREATE_SHORT_URL = 'shlink/createShortUrl/CREATE_SHORT_URL';\nexport const RESET_CREATE_SHORT_URL = 'shlink/createShortUrl/RESET_CREATE_SHORT_URL';\n/* eslint-enable padding-line-between-statements */\n\nexport interface ShortUrlCreation {\n result: ShortUrl | null;\n saving: boolean;\n error: boolean;\n errorData?: ProblemDetailsError;\n}\n\nexport interface CreateShortUrlAction extends Action<string> {\n result: ShortUrl;\n}\n\nconst initialState: ShortUrlCreation = {\n result: null,\n saving: false,\n error: false,\n};\n\nexport default buildReducer<ShortUrlCreation, CreateShortUrlAction & ApiErrorAction>({\n [CREATE_SHORT_URL_START]: (state) => ({ ...state, saving: true, error: false }),\n [CREATE_SHORT_URL_ERROR]: (state, { errorData }) => ({ ...state, saving: false, error: true, errorData }),\n [CREATE_SHORT_URL]: (_, { result }) => ({ result, saving: false, error: false }),\n [RESET_CREATE_SHORT_URL]: () => initialState,\n}, initialState);\n\nexport const createShortUrl = (buildShlinkApiClient: ShlinkApiClientBuilder) => (data: ShortUrlData) => async (\n dispatch: Dispatch,\n getState: GetState,\n) => {\n dispatch({ type: CREATE_SHORT_URL_START });\n const { createShortUrl } = buildShlinkApiClient(getState);\n\n try {\n const result = await createShortUrl(data);\n\n dispatch<CreateShortUrlAction>({ type: CREATE_SHORT_URL, result });\n } catch (e) {\n dispatch<ApiErrorAction>({ type: CREATE_SHORT_URL_ERROR, errorData: parseApiError(e) });\n\n throw e;\n }\n};\n\nexport const resetCreateShortUrl = buildActionCreator(RESET_CREATE_SHORT_URL);\n","import { Action, Dispatch } from 'redux';\nimport { buildReducer } from '../../utils/helpers/redux';\nimport { GetState } from '../../container/types';\nimport { OptionalString } from '../../utils/utils';\nimport { EditShortUrlData, ShortUrl } from '../data';\nimport { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';\nimport { ProblemDetailsError } from '../../api/types';\nimport { parseApiError } from '../../api/utils';\nimport { supportsTagsInPatch } from '../../utils/helpers/features';\nimport { ApiErrorAction } from '../../api/types/actions';\n\n/* eslint-disable padding-line-between-statements */\nexport const EDIT_SHORT_URL_START = 'shlink/shortUrlEdition/EDIT_SHORT_URL_START';\nexport const EDIT_SHORT_URL_ERROR = 'shlink/shortUrlEdition/EDIT_SHORT_URL_ERROR';\nexport const SHORT_URL_EDITED = 'shlink/shortUrlEdition/SHORT_URL_EDITED';\n/* eslint-enable padding-line-between-statements */\n\nexport interface ShortUrlEdition {\n shortUrl?: ShortUrl;\n saving: boolean;\n error: boolean;\n errorData?: ProblemDetailsError;\n}\n\nexport interface ShortUrlEditedAction extends Action<string> {\n shortUrl: ShortUrl;\n}\n\nconst initialState: ShortUrlEdition = {\n saving: false,\n error: false,\n};\n\nexport default buildReducer<ShortUrlEdition, ShortUrlEditedAction & ApiErrorAction>({\n [EDIT_SHORT_URL_START]: (state) => ({ ...state, saving: true, error: false }),\n [EDIT_SHORT_URL_ERROR]: (state, { errorData }) => ({ ...state, saving: false, error: true, errorData }),\n [SHORT_URL_EDITED]: (_, { shortUrl }) => ({ shortUrl, saving: false, error: false }),\n}, initialState);\n\nexport const editShortUrl = (buildShlinkApiClient: ShlinkApiClientBuilder) => (\n shortCode: string,\n domain: OptionalString,\n data: EditShortUrlData,\n) => async (dispatch: Dispatch, getState: GetState) => {\n dispatch({ type: EDIT_SHORT_URL_START });\n\n const { selectedServer } = getState();\n const sendTagsSeparately = !supportsTagsInPatch(selectedServer);\n const { updateShortUrl, updateShortUrlTags } = buildShlinkApiClient(getState);\n\n try {\n const [ shortUrl ] = await Promise.all([\n updateShortUrl(shortCode, domain, data as any), // FIXME Parse dates\n sendTagsSeparately && data.tags ? updateShortUrlTags(shortCode, domain, data.tags) : undefined,\n ]);\n\n dispatch<ShortUrlEditedAction>({ shortUrl, type: SHORT_URL_EDITED });\n } catch (e) {\n dispatch<ApiErrorAction>({ type: EDIT_SHORT_URL_ERROR, errorData: parseApiError(e) });\n\n throw e;\n }\n};\n","import { assoc, assocPath, init, last, pipe, reject } from 'ramda';\nimport { Action, Dispatch } from 'redux';\nimport { shortUrlMatches } from '../helpers';\nimport { CREATE_VISITS, CreateVisitsAction } from '../../visits/reducers/visitCreation';\nimport { buildReducer } from '../../utils/helpers/redux';\nimport { GetState } from '../../container/types';\nimport { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';\nimport { ShlinkShortUrlsResponse } from '../../api/types';\nimport { DeleteShortUrlAction, SHORT_URL_DELETED } from './shortUrlDeletion';\nimport { ShortUrlsListParams } from './shortUrlsListParams';\nimport { CREATE_SHORT_URL, CreateShortUrlAction } from './shortUrlCreation';\nimport { SHORT_URL_EDITED, ShortUrlEditedAction } from './shortUrlEdition';\n\n/* eslint-disable padding-line-between-statements */\nexport const LIST_SHORT_URLS_START = 'shlink/shortUrlsList/LIST_SHORT_URLS_START';\nexport const LIST_SHORT_URLS_ERROR = 'shlink/shortUrlsList/LIST_SHORT_URLS_ERROR';\nexport const LIST_SHORT_URLS = 'shlink/shortUrlsList/LIST_SHORT_URLS';\n/* eslint-enable padding-line-between-statements */\n\nexport interface ShortUrlsList {\n shortUrls?: ShlinkShortUrlsResponse;\n loading: boolean;\n error: boolean;\n}\n\nexport interface ListShortUrlsAction extends Action<string> {\n shortUrls: ShlinkShortUrlsResponse;\n params: ShortUrlsListParams;\n}\n\nexport type ListShortUrlsCombinedAction = (\n ListShortUrlsAction\n & CreateVisitsAction\n & CreateShortUrlAction\n & DeleteShortUrlAction\n & ShortUrlEditedAction\n);\n\nconst initialState: ShortUrlsList = {\n loading: true,\n error: false,\n};\n\nexport default buildReducer<ShortUrlsList, ListShortUrlsCombinedAction>({\n [LIST_SHORT_URLS_START]: (state) => ({ ...state, loading: true, error: false }),\n [LIST_SHORT_URLS_ERROR]: () => ({ loading: false, error: true }),\n [LIST_SHORT_URLS]: (_, { shortUrls }) => ({ loading: false, error: false, shortUrls }),\n [SHORT_URL_DELETED]: pipe(\n (state: ShortUrlsList, { shortCode, domain }: DeleteShortUrlAction) => !state.shortUrls ? state : assocPath(\n [ 'shortUrls', 'data' ],\n reject((shortUrl) => shortUrlMatches(shortUrl, shortCode, domain), state.shortUrls.data),\n state,\n ),\n (state) => !state.shortUrls ? state : assocPath(\n [ 'shortUrls', 'pagination', 'totalItems' ],\n state.shortUrls.pagination.totalItems - 1,\n state,\n ),\n ),\n [CREATE_VISITS]: (state, { createdVisits }) => assocPath(\n [ 'shortUrls', 'data' ],\n state.shortUrls?.data?.map(\n (currentShortUrl) => {\n // Find the last of the new visit for this short URL, and pick the amount of visits from it\n const lastVisit = last(\n createdVisits.filter(\n ({ shortUrl }) => shortUrl && shortUrlMatches(currentShortUrl, shortUrl.shortCode, shortUrl.domain),\n ),\n );\n\n return lastVisit?.shortUrl\n ? assoc('visitsCount', lastVisit.shortUrl.visitsCount, currentShortUrl)\n : currentShortUrl;\n },\n ),\n state,\n ),\n [CREATE_SHORT_URL]: pipe(\n // The only place where the list and the creation form coexist is the overview page.\n // There we can assume we are displaying page 1, and therefore, we can safely prepend the new short URL and remove the last one.\n (state: ShortUrlsList, { result }: CreateShortUrlAction) => !state.shortUrls ? state : assocPath(\n [ 'shortUrls', 'data' ],\n [ result, ...init(state.shortUrls.data) ],\n state,\n ),\n (state: ShortUrlsList) => !state.shortUrls ? state : assocPath(\n [ 'shortUrls', 'pagination', 'totalItems' ],\n state.shortUrls.pagination.totalItems + 1,\n state,\n ),\n ),\n [SHORT_URL_EDITED]: (state, { shortUrl: editedShortUrl }) => !state.shortUrls ? state : assocPath(\n [ 'shortUrls', 'data' ],\n state.shortUrls.data.map((shortUrl) => {\n const { shortCode, domain } = editedShortUrl;\n\n return shortUrlMatches(shortUrl, shortCode, domain) ? editedShortUrl : shortUrl;\n }),\n state,\n ),\n}, initialState);\n\nexport const listShortUrls = (buildShlinkApiClient: ShlinkApiClientBuilder) => (\n params: ShortUrlsListParams = {},\n) => async (dispatch: Dispatch, getState: GetState) => {\n dispatch({ type: LIST_SHORT_URLS_START });\n const { listShortUrls } = buildShlinkApiClient(getState);\n\n try {\n const shortUrls = await listShortUrls(params);\n\n dispatch<ListShortUrlsAction>({ type: LIST_SHORT_URLS, shortUrls, params });\n } catch (e) {\n dispatch({ type: LIST_SHORT_URLS_ERROR, params });\n }\n};\n","import { buildActionCreator, buildReducer } from '../../utils/helpers/redux';\nimport { OrderDir } from '../../utils/utils';\nimport { LIST_SHORT_URLS, ListShortUrlsAction } from './shortUrlsList';\n\nexport const RESET_SHORT_URL_PARAMS = 'shlink/shortUrlsListParams/RESET_SHORT_URL_PARAMS';\n\nexport const SORTABLE_FIELDS = {\n dateCreated: 'Created at',\n shortCode: 'Short URL',\n longUrl: 'Long URL',\n title: 'Title',\n visits: 'Visits',\n};\n\nexport type OrderableFields = keyof typeof SORTABLE_FIELDS;\n\nexport interface ShortUrlsListParams {\n page?: string;\n itemsPerPage?: number;\n tags?: string[];\n searchTerm?: string;\n startDate?: string;\n endDate?: string;\n orderBy?: Partial<Record<OrderableFields, OrderDir>>;\n}\n\nconst initialState: ShortUrlsListParams = {\n page: '1',\n orderBy: { dateCreated: 'DESC' },\n};\n\nexport default buildReducer<ShortUrlsListParams, ListShortUrlsAction>({\n [LIST_SHORT_URLS]: (state, { params }) => ({ ...state, ...params }),\n [RESET_SHORT_URL_PARAMS]: () => initialState,\n}, initialState);\n\nexport const resetShortUrlParams = buildActionCreator(RESET_SHORT_URL_PARAMS);\n","const TEN_ROUNDING_NUMBER = 10;\nconst { ceil } = Math;\nconst formatter = new Intl.NumberFormat('en-US');\n\nexport const prettify = (number: number | string) => formatter.format(Number(number));\n\nexport const roundTen = (number: number) => ceil(number / TEN_ROUNDING_NUMBER) * TEN_ROUNDING_NUMBER;\n","import { max, min, range } from 'ramda';\nimport { prettify } from './numbers';\n\nconst DELTA = 2;\n\nexport const ELLIPSIS = '...';\n\ntype Ellipsis = typeof ELLIPSIS;\n\nexport type NumberOrEllipsis = number | Ellipsis;\n\nexport const progressivePagination = (currentPage: number, pageCount: number): NumberOrEllipsis[] => {\n const pages: NumberOrEllipsis[] = range(\n max(DELTA, currentPage - DELTA),\n min(pageCount - 1, currentPage + DELTA) + 1,\n );\n\n if (currentPage - DELTA > DELTA) {\n pages.unshift(ELLIPSIS);\n }\n if (currentPage + DELTA < pageCount - 1) {\n pages.push(ELLIPSIS);\n }\n\n pages.unshift(1);\n pages.push(pageCount);\n\n return pages;\n};\n\nexport const pageIsEllipsis = (pageNumber: NumberOrEllipsis): pageNumber is Ellipsis => pageNumber === ELLIPSIS;\n\nexport const prettifyPageNumber = (pageNumber: NumberOrEllipsis): string =>\n pageIsEllipsis(pageNumber) ? pageNumber : prettify(pageNumber);\n\nexport const keyForPage = (pageNumber: NumberOrEllipsis, index: number) => !pageIsEllipsis(pageNumber) ? `${pageNumber}` : `${pageNumber}_${index}`;\n","import { Link } from 'react-router-dom';\nimport { Pagination, PaginationItem, PaginationLink } from 'reactstrap';\nimport { pageIsEllipsis, keyForPage, progressivePagination, prettifyPageNumber } from '../utils/helpers/pagination';\nimport { ShlinkPaginator } from '../api/types';\n\ninterface PaginatorProps {\n paginator?: ShlinkPaginator;\n serverId: string;\n}\n\nconst Paginator = ({ paginator, serverId }: PaginatorProps) => {\n const { currentPage = 0, pagesCount = 0 } = paginator ?? {};\n\n if (pagesCount <= 1) {\n return null;\n }\n\n const renderPages = () =>\n progressivePagination(currentPage, pagesCount).map((pageNumber, index) => (\n <PaginationItem\n key={keyForPage(pageNumber, index)}\n disabled={pageIsEllipsis(pageNumber)}\n active={currentPage === pageNumber}\n >\n <PaginationLink\n tag={Link}\n to={`/server/${serverId}/list-short-urls/${pageNumber}`}\n >\n {prettifyPageNumber(pageNumber)}\n </PaginationLink>\n </PaginationItem>\n ));\n\n return (\n <Pagination className=\"sticky-card-paginator\" listClassName=\"flex-wrap justify-content-center mb-0\">\n <PaginationItem disabled={currentPage === 1}>\n <PaginationLink\n previous\n tag={Link}\n to={`/server/${serverId}/list-short-urls/${currentPage - 1}`}\n />\n </PaginationItem>\n {renderPages()}\n <PaginationItem disabled={currentPage >= pagesCount}>\n <PaginationLink\n next\n tag={Link}\n to={`/server/${serverId}/list-short-urls/${currentPage + 1}`}\n />\n </PaginationItem>\n </Pagination>\n );\n};\n\nexport default Paginator;\n","import { faCaretDown as caretDownIcon, faCaretUp as caretUpIcon } from '@fortawesome/free-solid-svg-icons';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { head, keys, values } from 'ramda';\nimport { FC, useEffect, useState } from 'react';\nimport { RouteComponentProps } from 'react-router';\nimport { Card } from 'reactstrap';\nimport SortingDropdown from '../utils/SortingDropdown';\nimport { determineOrderDir, OrderDir } from '../utils/utils';\nimport { isReachableServer, SelectedServer } from '../servers/data';\nimport { boundToMercureHub } from '../mercure/helpers/boundToMercureHub';\nimport { parseQuery } from '../utils/helpers/query';\nimport { Topics } from '../mercure/helpers/Topics';\nimport { ShortUrlsList as ShortUrlsListState } from './reducers/shortUrlsList';\nimport { OrderableFields, ShortUrlsListParams, SORTABLE_FIELDS } from './reducers/shortUrlsListParams';\nimport { ShortUrlsTableProps } from './ShortUrlsTable';\nimport Paginator from './Paginator';\nimport './ShortUrlsList.scss';\n\ninterface RouteParams {\n page: string;\n serverId: string;\n}\n\nexport interface ShortUrlsListProps extends RouteComponentProps<RouteParams> {\n selectedServer: SelectedServer;\n shortUrlsList: ShortUrlsListState;\n listShortUrls: (params: ShortUrlsListParams) => void;\n shortUrlsListParams: ShortUrlsListParams;\n resetShortUrlParams: () => void;\n}\n\nconst ShortUrlsList = (ShortUrlsTable: FC<ShortUrlsTableProps>) => boundToMercureHub(({\n listShortUrls,\n resetShortUrlParams,\n shortUrlsListParams,\n match,\n location,\n shortUrlsList,\n selectedServer,\n}: ShortUrlsListProps) => {\n const { orderBy } = shortUrlsListParams;\n const [ order, setOrder ] = useState<{ orderField?: OrderableFields; orderDir?: OrderDir }>({\n orderField: orderBy && (head(keys(orderBy)) as OrderableFields),\n orderDir: orderBy && head(values(orderBy)),\n });\n const { pagination } = shortUrlsList?.shortUrls ?? {};\n const refreshList = (extraParams: ShortUrlsListParams) => listShortUrls({ ...shortUrlsListParams, ...extraParams });\n const handleOrderBy = (orderField?: OrderableFields, orderDir?: OrderDir) => {\n setOrder({ orderField, orderDir });\n refreshList({ orderBy: orderField ? { [orderField]: orderDir } : undefined });\n };\n const orderByColumn = (field: OrderableFields) => () =>\n handleOrderBy(field, determineOrderDir(field, order.orderField, order.orderDir));\n const renderOrderIcon = (field: OrderableFields) => {\n if (order.orderField !== field) {\n return null;\n }\n\n if (!order.orderDir) {\n return null;\n }\n\n return (\n <FontAwesomeIcon\n icon={order.orderDir === 'ASC' ? caretUpIcon : caretDownIcon}\n className=\"short-urls-list__header-icon\"\n />\n );\n };\n\n useEffect(() => {\n const { tag } = parseQuery<{ tag?: string }>(location.search);\n const tags = tag ? [ decodeURIComponent(tag) ] : shortUrlsListParams.tags;\n\n refreshList({ page: match.params.page, tags, itemsPerPage: undefined });\n\n return resetShortUrlParams;\n }, []);\n\n return (\n <>\n <div className=\"d-block d-lg-none mb-3\">\n <SortingDropdown\n items={SORTABLE_FIELDS}\n orderField={order.orderField}\n orderDir={order.orderDir}\n onChange={handleOrderBy}\n />\n </div>\n <Card body className=\"pb-1\">\n <ShortUrlsTable\n orderByColumn={orderByColumn}\n renderOrderIcon={renderOrderIcon}\n selectedServer={selectedServer}\n shortUrlsList={shortUrlsList}\n onTagClick={(tag) => refreshList({ tags: [ ...shortUrlsListParams.tags ?? [], tag ] })}\n />\n <Paginator paginator={pagination} serverId={isReachableServer(selectedServer) ? selectedServer.id : ''} />\n </Card>\n </>\n );\n}, () => [ Topics.visits ]);\n\nexport default ShortUrlsList;\n","import { FC } from 'react';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faCopy as copyIcon } from '@fortawesome/free-regular-svg-icons';\nimport CopyToClipboard from 'react-copy-to-clipboard';\nimport './CopyToClipboardIcon.scss';\n\ninterface CopyToClipboardIconProps {\n text: string;\n onCopy?: (text: string, result: boolean) => void;\n}\n\nexport const CopyToClipboardIcon: FC<CopyToClipboardIconProps> = ({ text, onCopy }) => (\n <CopyToClipboard text={text} onCopy={onCopy}>\n <FontAwesomeIcon icon={copyIcon} className=\"ml-2 copy-to-clipboard-icon\" />\n </CopyToClipboard>\n);\n","import { parseISO, format as formatDate, getUnixTime, formatDistance } from 'date-fns';\nimport { isDateObject } from './helpers/date';\n\nexport interface DateProps {\n date: Date | string;\n format?: string;\n relative?: boolean;\n}\n\nexport const Time = ({ date, format = 'yyyy-MM-dd HH:mm', relative = false }: DateProps) => {\n const dateObject = isDateObject(date) ? date : parseISO(date);\n\n return (\n <time dateTime={`${getUnixTime(dateObject)}000`}>\n {relative ? `${formatDistance(new Date(), dateObject)} ago` : formatDate(dateObject, format)}\n </time>\n );\n};\n","import { FC } from 'react';\nimport { Link } from 'react-router-dom';\nimport { isServerWithId, SelectedServer, ServerWithId } from '../../servers/data';\nimport { ShortUrl } from '../data';\n\nexport type LinkSuffix = 'visits' | 'edit';\n\nexport interface ShortUrlDetailLinkProps {\n shortUrl?: ShortUrl | null;\n selectedServer?: SelectedServer;\n suffix: LinkSuffix;\n}\n\nconst buildUrl = ({ id }: ServerWithId, { shortCode, domain }: ShortUrl, suffix: LinkSuffix) => {\n const query = domain ? `?domain=${domain}` : '';\n\n return `/server/${id}/short-code/${shortCode}/${suffix}${query}`;\n};\n\nconst ShortUrlDetailLink: FC<ShortUrlDetailLinkProps & Record<string | number, any>> = (\n { selectedServer, shortUrl, suffix, children, ...rest },\n) => {\n if (!selectedServer || !isServerWithId(selectedServer) || !shortUrl) {\n return <span {...rest}>{children}</span>;\n }\n\n return <Link to={buildUrl(selectedServer, shortUrl, suffix)} {...rest}>{children}</Link>;\n};\n\nexport default ShortUrlDetailLink;\n","import { useRef } from 'react';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faInfoCircle as infoIcon } from '@fortawesome/free-solid-svg-icons';\nimport { UncontrolledTooltip } from 'reactstrap';\nimport classNames from 'classnames';\nimport { prettify } from '../../utils/helpers/numbers';\nimport { ShortUrl } from '../data';\nimport { SelectedServer } from '../../servers/data';\nimport ShortUrlDetailLink from './ShortUrlDetailLink';\nimport './ShortUrlVisitsCount.scss';\n\ninterface ShortUrlVisitsCountProps {\n shortUrl?: ShortUrl | null;\n selectedServer?: SelectedServer;\n visitsCount: number;\n active?: boolean;\n}\n\nconst ShortUrlVisitsCount = ({ visitsCount, shortUrl, selectedServer, active = false }: ShortUrlVisitsCountProps) => {\n const maxVisits = shortUrl?.meta?.maxVisits;\n const visitsLink = (\n <ShortUrlDetailLink selectedServer={selectedServer} shortUrl={shortUrl} suffix=\"visits\">\n <strong\n className={classNames('short-url-visits-count__amount', { 'short-url-visits-count__amount--big': active })}\n >\n {prettify(visitsCount)}\n </strong>\n </ShortUrlDetailLink>\n );\n\n if (!maxVisits) {\n return visitsLink;\n }\n\n const prettifiedMaxVisits = prettify(maxVisits);\n const tooltipRef = useRef<HTMLElement | null>();\n\n return (\n <>\n <span className=\"indivisible\">\n {visitsLink}\n <small\n className=\"short-urls-visits-count__max-visits-control\"\n ref={(el) => {\n tooltipRef.current = el;\n }}\n >\n {' '}/ {prettifiedMaxVisits}{' '}\n <sup>\n <FontAwesomeIcon icon={infoIcon} />\n </sup>\n </small>\n </span>\n <UncontrolledTooltip target={(() => tooltipRef.current) as any} placement=\"bottom\">\n This short URL will not accept more than <b>{prettifiedMaxVisits}</b> visits.\n </UncontrolledTooltip>\n </>\n );\n};\n\nexport default ShortUrlVisitsCount;\n","import { FC, useEffect, useRef } from 'react';\nimport { isEmpty } from 'ramda';\nimport { ExternalLink } from 'react-external-link';\nimport ColorGenerator from '../../utils/services/ColorGenerator';\nimport { StateFlagTimeout } from '../../utils/helpers/hooks';\nimport Tag from '../../tags/helpers/Tag';\nimport { SelectedServer } from '../../servers/data';\nimport { CopyToClipboardIcon } from '../../utils/CopyToClipboardIcon';\nimport { ShortUrl } from '../data';\nimport { Time } from '../../utils/Time';\nimport ShortUrlVisitsCount from './ShortUrlVisitsCount';\nimport { ShortUrlsRowMenuProps } from './ShortUrlsRowMenu';\nimport './ShortUrlsRow.scss';\n\nexport interface ShortUrlsRowProps {\n onTagClick?: (tag: string) => void;\n selectedServer: SelectedServer;\n shortUrl: ShortUrl;\n}\n\nconst ShortUrlsRow = (\n ShortUrlsRowMenu: FC<ShortUrlsRowMenuProps>,\n colorGenerator: ColorGenerator,\n useStateFlagTimeout: StateFlagTimeout,\n) => ({ shortUrl, selectedServer, onTagClick }: ShortUrlsRowProps) => {\n const [ copiedToClipboard, setCopiedToClipboard ] = useStateFlagTimeout();\n const [ active, setActive ] = useStateFlagTimeout(false, 500);\n const isFirstRun = useRef(true);\n\n const renderTags = (tags: string[]) => {\n if (isEmpty(tags)) {\n return <i className=\"indivisible\"><small>No tags</small></i>;\n }\n\n return tags.map((tag) => (\n <Tag\n colorGenerator={colorGenerator}\n key={tag}\n text={tag}\n onClick={() => onTagClick?.(tag)}\n />\n ));\n };\n\n useEffect(() => {\n if (isFirstRun.current) {\n isFirstRun.current = false;\n } else {\n setActive();\n }\n }, [ shortUrl.visitsCount ]);\n\n return (\n <tr className=\"responsive-table__row\">\n <td className=\"indivisible short-urls-row__cell responsive-table__cell\" data-th=\"Created at\">\n <Time date={shortUrl.dateCreated} />\n </td>\n <td className=\"responsive-table__cell short-urls-row__cell\" data-th=\"Short URL\">\n <span className=\"indivisible short-urls-row__cell--relative\">\n <ExternalLink href={shortUrl.shortUrl} />\n <CopyToClipboardIcon text={shortUrl.shortUrl} onCopy={setCopiedToClipboard} />\n <span className=\"badge badge-warning short-urls-row__copy-hint\" hidden={!copiedToClipboard}>\n Copied short URL!\n </span>\n </span>\n </td>\n <td className=\"responsive-table__cell short-urls-row__cell short-urls-row__cell--break\" data-th={`${shortUrl.title ? 'Title' : 'Long URL'}`}>\n <ExternalLink href={shortUrl.longUrl}>{shortUrl.title ?? shortUrl.longUrl}</ExternalLink>\n </td>\n {shortUrl.title && (\n <td className=\"short-urls-row__cell responsive-table__cell short-urls-row__cell--break d-lg-none\" data-th=\"Long URL\">\n <ExternalLink href={shortUrl.longUrl} />\n </td>\n )}\n <td className=\"responsive-table__cell short-urls-row__cell\" data-th=\"Tags\">{renderTags(shortUrl.tags)}</td>\n <td className=\"responsive-table__cell short-urls-row__cell text-lg-right\" data-th=\"Visits\">\n <ShortUrlVisitsCount\n visitsCount={shortUrl.visitsCount}\n shortUrl={shortUrl}\n selectedServer={selectedServer}\n active={active}\n />\n </td>\n <td className=\"responsive-table__cell short-urls-row__cell\">\n <ShortUrlsRowMenu selectedServer={selectedServer} shortUrl={shortUrl} />\n </td>\n </tr>\n );\n};\n\nexport default ShortUrlsRow;\n","import { FC } from 'react';\nimport { ButtonDropdown, DropdownMenu, DropdownToggle } from 'reactstrap';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faEllipsisV as menuIcon } from '@fortawesome/free-solid-svg-icons';\nimport './DropdownBtnMenu.scss';\n\nexport interface DropdownBtnMenuProps {\n isOpen: boolean;\n toggle: () => void;\n right?: boolean;\n}\n\nexport const DropdownBtnMenu: FC<DropdownBtnMenuProps> = ({ isOpen, toggle, children, right = true }) => (\n <ButtonDropdown toggle={toggle} isOpen={isOpen}>\n <DropdownToggle size=\"sm\" caret outline className=\"dropdown-btn-menu__dropdown-toggle\">\n &nbsp;<FontAwesomeIcon icon={menuIcon} />&nbsp;\n </DropdownToggle>\n <DropdownMenu right={right}>{children}</DropdownMenu>\n </ButtonDropdown>\n);\n","import {\n faChartPie as pieChartIcon,\n faQrcode as qrIcon,\n faMinusCircle as deleteIcon,\n faEdit as editIcon,\n} from '@fortawesome/free-solid-svg-icons';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { FC } from 'react';\nimport { DropdownItem } from 'reactstrap';\nimport { useToggle } from '../../utils/helpers/hooks';\nimport { ShortUrl, ShortUrlModalProps } from '../data';\nimport { SelectedServer } from '../../servers/data';\nimport { DropdownBtnMenu } from '../../utils/DropdownBtnMenu';\nimport ShortUrlDetailLink from './ShortUrlDetailLink';\nimport './ShortUrlsRowMenu.scss';\n\nexport interface ShortUrlsRowMenuProps {\n selectedServer: SelectedServer;\n shortUrl: ShortUrl;\n}\ntype ShortUrlModal = FC<ShortUrlModalProps>;\n\nconst ShortUrlsRowMenu = (\n DeleteShortUrlModal: ShortUrlModal,\n QrCodeModal: ShortUrlModal,\n) => ({ shortUrl, selectedServer }: ShortUrlsRowMenuProps) => {\n const [ isOpen, toggle ] = useToggle();\n const [ isQrModalOpen, toggleQrCode ] = useToggle();\n const [ isDeleteModalOpen, toggleDelete ] = useToggle();\n\n return (\n <DropdownBtnMenu toggle={toggle} isOpen={isOpen}>\n <DropdownItem tag={ShortUrlDetailLink} selectedServer={selectedServer} shortUrl={shortUrl} suffix=\"visits\">\n <FontAwesomeIcon icon={pieChartIcon} fixedWidth /> Visit stats\n </DropdownItem>\n\n <DropdownItem tag={ShortUrlDetailLink} selectedServer={selectedServer} shortUrl={shortUrl} suffix=\"edit\">\n <FontAwesomeIcon icon={editIcon} fixedWidth /> Edit short URL\n </DropdownItem>\n\n <DropdownItem onClick={toggleQrCode}>\n <FontAwesomeIcon icon={qrIcon} fixedWidth /> QR code\n </DropdownItem>\n <QrCodeModal shortUrl={shortUrl} isOpen={isQrModalOpen} toggle={toggleQrCode} />\n\n <DropdownItem divider />\n\n <DropdownItem className=\"short-urls-row-menu__dropdown-item--danger\" onClick={toggleDelete}>\n <FontAwesomeIcon icon={deleteIcon} fixedWidth /> Delete short URL\n </DropdownItem>\n <DeleteShortUrlModal shortUrl={shortUrl} isOpen={isDeleteModalOpen} toggle={toggleDelete} />\n </DropdownBtnMenu>\n );\n};\n\nexport default ShortUrlsRowMenu;\n","import { FC, useMemo } from 'react';\nimport { SelectedServer } from '../servers/data';\nimport { Settings, ShortUrlCreationSettings } from '../settings/reducers/settings';\nimport { ShortUrlData } from './data';\nimport { ShortUrlCreation } from './reducers/shortUrlCreation';\nimport { CreateShortUrlResultProps } from './helpers/CreateShortUrlResult';\nimport { ShortUrlFormProps } from './ShortUrlForm';\n\nexport interface CreateShortUrlProps {\n basicMode?: boolean;\n}\n\ninterface CreateShortUrlConnectProps extends CreateShortUrlProps {\n settings: Settings;\n shortUrlCreationResult: ShortUrlCreation;\n selectedServer: SelectedServer;\n createShortUrl: (data: ShortUrlData) => Promise<void>;\n resetCreateShortUrl: () => void;\n}\n\nconst getInitialState = (settings?: ShortUrlCreationSettings): ShortUrlData => ({\n longUrl: '',\n tags: [],\n customSlug: '',\n title: undefined,\n shortCodeLength: undefined,\n domain: '',\n validSince: undefined,\n validUntil: undefined,\n maxVisits: undefined,\n findIfExists: false,\n validateUrl: settings?.validateUrls ?? false,\n});\n\nconst CreateShortUrl = (ShortUrlForm: FC<ShortUrlFormProps>, CreateShortUrlResult: FC<CreateShortUrlResultProps>) => ({\n createShortUrl,\n shortUrlCreationResult,\n resetCreateShortUrl,\n selectedServer,\n basicMode = false,\n settings: { shortUrlCreation: shortUrlCreationSettings },\n}: CreateShortUrlConnectProps) => {\n const initialState = useMemo(() => getInitialState(shortUrlCreationSettings), [ shortUrlCreationSettings ]);\n\n return (\n <>\n <ShortUrlForm\n initialState={initialState}\n saving={shortUrlCreationResult.saving}\n selectedServer={selectedServer}\n mode={basicMode ? 'create-basic' : 'create'}\n onSave={async (data: ShortUrlData) => {\n resetCreateShortUrl();\n\n return createShortUrl(data);\n }}\n />\n <CreateShortUrlResult\n {...shortUrlCreationResult}\n resetCreateShortUrl={resetCreateShortUrl}\n canBeClosed={basicMode}\n />\n </>\n );\n};\n\nexport default CreateShortUrl;\n","import { FC } from 'react';\nimport { Row } from 'reactstrap';\nimport classNames from 'classnames';\nimport { SimpleCard } from './SimpleCard';\n\nexport type ResultType = 'success' | 'error' | 'warning';\n\nexport interface ResultProps {\n type: ResultType;\n className?: string;\n small?: boolean;\n}\n\nexport const Result: FC<ResultProps> = ({ children, type, className, small = false }) => (\n <Row className={className}>\n <div className={classNames({ 'col-md-10 offset-md-1': !small, 'col-12': small })}>\n <SimpleCard\n className={classNames('text-center', {\n 'bg-main': type === 'success',\n 'bg-danger': type === 'error',\n 'bg-warning': type === 'warning',\n 'text-white': type !== 'warning',\n })}\n bodyClassName={classNames({ 'p-2': small })}\n >\n {children}\n </SimpleCard>\n </div>\n </Row>\n);\n","import { ProblemDetailsError } from './types';\nimport { isInvalidArgumentError } from './utils';\n\nexport interface ShlinkApiErrorProps {\n errorData?: ProblemDetailsError;\n fallbackMessage?: string;\n}\n\nexport const ShlinkApiError = ({ errorData, fallbackMessage }: ShlinkApiErrorProps) => (\n <>\n {errorData?.detail ?? fallbackMessage}\n {isInvalidArgumentError(errorData) &&\n <p className=\"mb-0\">Invalid elements: [{errorData.invalidElements.join(', ')}]</p>\n }\n </>\n);\n","import { useEffect, useState } from 'react';\nimport { Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap';\nimport { identity, pipe } from 'ramda';\nimport { ShortUrlDeletion } from '../reducers/shortUrlDeletion';\nimport { ShortUrlModalProps } from '../data';\nimport { handleEventPreventingDefault, OptionalString } from '../../utils/utils';\nimport { Result } from '../../utils/Result';\nimport { isInvalidDeletionError } from '../../api/utils';\nimport { ShlinkApiError } from '../../api/ShlinkApiError';\n\ninterface DeleteShortUrlModalConnectProps extends ShortUrlModalProps {\n shortUrlDeletion: ShortUrlDeletion;\n deleteShortUrl: (shortCode: string, domain: OptionalString) => Promise<void>;\n resetDeleteShortUrl: () => void;\n}\n\nconst DeleteShortUrlModal = (\n { shortUrl, toggle, isOpen, shortUrlDeletion, resetDeleteShortUrl, deleteShortUrl }: DeleteShortUrlModalConnectProps,\n) => {\n const [ inputValue, setInputValue ] = useState('');\n\n useEffect(() => resetDeleteShortUrl, []);\n\n const { error, errorData } = shortUrlDeletion;\n const close = pipe(resetDeleteShortUrl, toggle);\n const handleDeleteUrl = handleEventPreventingDefault(() => {\n const { shortCode, domain } = shortUrl;\n\n deleteShortUrl(shortCode, domain)\n .then(toggle)\n .catch(identity);\n });\n\n return (\n <Modal isOpen={isOpen} toggle={close} centered>\n <form onSubmit={handleDeleteUrl}>\n <ModalHeader toggle={close}>\n <span className=\"text-danger\">Delete short URL</span>\n </ModalHeader>\n <ModalBody>\n <p><b className=\"text-danger\">Caution!</b> You are about to delete a short URL.</p>\n <p>This action cannot be undone. Once you have deleted it, all the visits stats will be lost.</p>\n <p>Write <b>{shortUrl.shortCode}</b> to confirm deletion.</p>\n\n <input\n type=\"text\"\n className=\"form-control\"\n placeholder={`Insert the short code (${shortUrl.shortCode})`}\n value={inputValue}\n onChange={(e) => setInputValue(e.target.value)}\n />\n\n {error && (\n <Result type={isInvalidDeletionError(errorData) ? 'warning' : 'error'} small className=\"mt-2\">\n <ShlinkApiError errorData={errorData} fallbackMessage=\"Something went wrong while deleting the URL :(\" />\n </Result>\n )}\n </ModalBody>\n <ModalFooter>\n <button type=\"button\" className=\"btn btn-link\" onClick={close}>Cancel</button>\n <button\n type=\"submit\"\n className=\"btn btn-danger\"\n disabled={inputValue !== shortUrl.shortCode || shortUrlDeletion.loading}\n >\n {shortUrlDeletion.loading ? 'Deleting...' : 'Delete'}\n </button>\n </ModalFooter>\n </form>\n </Modal>\n );\n};\n\nexport default DeleteShortUrlModal;\n","import { faCopy as copyIcon } from '@fortawesome/free-regular-svg-icons';\nimport { faTimes as closeIcon } from '@fortawesome/free-solid-svg-icons';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { isNil } from 'ramda';\nimport { useEffect } from 'react';\nimport CopyToClipboard from 'react-copy-to-clipboard';\nimport { Tooltip } from 'reactstrap';\nimport { ShortUrlCreation } from '../reducers/shortUrlCreation';\nimport { StateFlagTimeout } from '../../utils/helpers/hooks';\nimport { Result } from '../../utils/Result';\nimport './CreateShortUrlResult.scss';\nimport { ShlinkApiError } from '../../api/ShlinkApiError';\n\nexport interface CreateShortUrlResultProps extends ShortUrlCreation {\n resetCreateShortUrl: () => void;\n canBeClosed?: boolean;\n}\n\nconst CreateShortUrlResult = (useStateFlagTimeout: StateFlagTimeout) => (\n { error, errorData, result, resetCreateShortUrl, canBeClosed = false }: CreateShortUrlResultProps,\n) => {\n const [ showCopyTooltip, setShowCopyTooltip ] = useStateFlagTimeout();\n\n useEffect(() => {\n resetCreateShortUrl();\n }, []);\n\n if (error) {\n return (\n <Result type=\"error\" className=\"mt-3\">\n {canBeClosed && <FontAwesomeIcon icon={closeIcon} className=\"float-right pointer\" onClick={resetCreateShortUrl} />}\n <ShlinkApiError errorData={errorData} fallbackMessage=\"An error occurred while creating the URL :(\" />\n </Result>\n );\n }\n\n if (isNil(result)) {\n return null;\n }\n\n const { shortUrl } = result;\n\n return (\n <Result type=\"success\" className=\"mt-3\">\n {canBeClosed && <FontAwesomeIcon icon={closeIcon} className=\"float-right pointer\" onClick={resetCreateShortUrl} />}\n <b>Great!</b> The short URL is <b>{shortUrl}</b>\n\n <CopyToClipboard text={shortUrl} onCopy={setShowCopyTooltip}>\n <button\n className=\"btn btn-light btn-sm create-short-url-result__copy-btn\"\n id=\"copyBtn\"\n type=\"button\"\n >\n <FontAwesomeIcon icon={copyIcon} /> Copy\n </button>\n </CopyToClipboard>\n\n <Tooltip placement=\"left\" isOpen={showCopyTooltip} target=\"copyBtn\">\n Copied!\n </Tooltip>\n </Result>\n );\n};\n\nexport default CreateShortUrlResult;\n","import { FC, ReactNode } from 'react';\nimport { isEmpty } from 'ramda';\nimport classNames from 'classnames';\nimport { SelectedServer } from '../servers/data';\nimport { supportsShortUrlTitle } from '../utils/helpers/features';\nimport { ShortUrlsList as ShortUrlsListState } from './reducers/shortUrlsList';\nimport { ShortUrlsRowProps } from './helpers/ShortUrlsRow';\nimport { OrderableFields } from './reducers/shortUrlsListParams';\nimport './ShortUrlsTable.scss';\n\nexport interface ShortUrlsTableProps {\n orderByColumn?: (column: OrderableFields) => () => void;\n renderOrderIcon?: (column: OrderableFields) => ReactNode;\n shortUrlsList: ShortUrlsListState;\n selectedServer: SelectedServer;\n onTagClick?: (tag: string) => void;\n className?: string;\n}\n\nexport const ShortUrlsTable = (ShortUrlsRow: FC<ShortUrlsRowProps>) => ({\n orderByColumn,\n renderOrderIcon,\n shortUrlsList,\n onTagClick,\n selectedServer,\n className,\n}: ShortUrlsTableProps) => {\n const { error, loading, shortUrls } = shortUrlsList;\n const actionableFieldClasses = classNames({ 'short-urls-table__header-cell--with-action': !!orderByColumn });\n const orderableColumnsClasses = classNames('short-urls-table__header-cell', actionableFieldClasses);\n const tableClasses = classNames('table table-hover', className);\n const supportsTitle = supportsShortUrlTitle(selectedServer);\n\n const renderShortUrls = () => {\n if (error) {\n return (\n <tr>\n <td colSpan={6} className=\"text-center table-danger\">Something went wrong while loading short URLs :(</td>\n </tr>\n );\n }\n\n if (loading) {\n return <tr><td colSpan={6} className=\"text-center\">Loading...</td></tr>;\n }\n\n if (!loading && isEmpty(shortUrls?.data)) {\n return <tr><td colSpan={6} className=\"text-center\">No results found</td></tr>;\n }\n\n return shortUrls?.data.map((shortUrl) => (\n <ShortUrlsRow\n key={shortUrl.shortUrl}\n shortUrl={shortUrl}\n selectedServer={selectedServer}\n onTagClick={onTagClick}\n />\n ));\n };\n\n return (\n <table className={tableClasses}>\n <thead className=\"responsive-table__header short-urls-table__header\">\n <tr>\n <th className={orderableColumnsClasses} onClick={orderByColumn?.('dateCreated')}>\n Created at\n {renderOrderIcon?.('dateCreated')}\n </th>\n <th className={orderableColumnsClasses} onClick={orderByColumn?.('shortCode')}>\n Short URL\n {renderOrderIcon?.('shortCode')}\n </th>\n {!supportsTitle && (\n <th className={orderableColumnsClasses} onClick={orderByColumn?.('longUrl')}>\n Long URL\n {renderOrderIcon?.('longUrl')}\n </th>\n ) || (\n <th className=\"short-urls-table__header-cell\">\n <span className={actionableFieldClasses} onClick={orderByColumn?.('title')}>\n Title\n {renderOrderIcon?.('title')}\n </span>\n &nbsp;&nbsp;/&nbsp;&nbsp;\n <span className={actionableFieldClasses} onClick={orderByColumn?.('longUrl')}>\n <span className=\"indivisible\">Long URL</span>\n {renderOrderIcon?.('longUrl')}\n </span>\n </th>\n )}\n <th className=\"short-urls-table__header-cell\">Tags</th>\n <th className={orderableColumnsClasses} onClick={orderByColumn?.('visits')}>\n <span className=\"indivisible\">Visits{renderOrderIcon?.('visits')}</span>\n </th>\n <th className=\"short-urls-table__header-cell\">&nbsp;</th>\n </tr>\n </thead>\n <tbody>\n {renderShortUrls()}\n </tbody>\n </table>\n );\n};\n","import { FC } from 'react';\nimport { DropdownItem } from 'reactstrap';\nimport { DropdownBtn } from '../../../utils/DropdownBtn';\nimport { QrCodeFormat } from '../../../utils/helpers/qrCodes';\n\ninterface QrFormatDropdownProps {\n format: QrCodeFormat;\n setFormat: (format: QrCodeFormat) => void;\n}\n\nexport const QrFormatDropdown: FC<QrFormatDropdownProps> = ({ format, setFormat }) => (\n <DropdownBtn text={`Format (${format})`}>\n <DropdownItem active={format === 'png'} onClick={() => setFormat('png')}>PNG</DropdownItem>\n <DropdownItem active={format === 'svg'} onClick={() => setFormat('svg')}>SVG</DropdownItem>\n </DropdownBtn>\n);\n","import { FC } from 'react';\nimport { DropdownItem } from 'reactstrap';\nimport { DropdownBtn } from '../../../utils/DropdownBtn';\nimport { QrErrorCorrection } from '../../../utils/helpers/qrCodes';\n\ninterface QrErrorCorrectionDropdownProps {\n errorCorrection: QrErrorCorrection;\n setErrorCorrection: (errorCorrection: QrErrorCorrection) => void;\n}\n\nexport const QrErrorCorrectionDropdown: FC<QrErrorCorrectionDropdownProps> = (\n { errorCorrection, setErrorCorrection },\n) => (\n <DropdownBtn text={`Error correction (${errorCorrection})`}>\n <DropdownItem active={errorCorrection === 'L'} onClick={() => setErrorCorrection('L')}>\n <b>L</b>ow\n </DropdownItem>\n <DropdownItem active={errorCorrection === 'M'} onClick={() => setErrorCorrection('M')}>\n <b>M</b>edium\n </DropdownItem>\n <DropdownItem active={errorCorrection === 'Q'} onClick={() => setErrorCorrection('Q')}>\n <b>Q</b>uartile\n </DropdownItem>\n <DropdownItem active={errorCorrection === 'H'} onClick={() => setErrorCorrection('H')}>\n <b>H</b>igh\n </DropdownItem>\n </DropdownBtn>\n);\n","import { FC, useMemo, useState } from 'react';\nimport { Modal, FormGroup, ModalBody, ModalHeader, Row, Button } from 'reactstrap';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faFileDownload as downloadIcon } from '@fortawesome/free-solid-svg-icons';\nimport { ExternalLink } from 'react-external-link';\nimport classNames from 'classnames';\nimport { ShortUrlModalProps } from '../data';\nimport { SelectedServer } from '../../servers/data';\nimport { CopyToClipboardIcon } from '../../utils/CopyToClipboardIcon';\nimport { buildQrCodeUrl, QrCodeCapabilities, QrCodeFormat, QrErrorCorrection } from '../../utils/helpers/qrCodes';\nimport {\n supportsQrCodeSizeInQuery,\n supportsQrCodeMargin,\n supportsQrErrorCorrection,\n} from '../../utils/helpers/features';\nimport { ImageDownloader } from '../../common/services/ImageDownloader';\nimport { Versions } from '../../utils/helpers/version';\nimport { QrFormatDropdown } from './qr-codes/QrFormatDropdown';\nimport './QrCodeModal.scss';\nimport { QrErrorCorrectionDropdown } from './qr-codes/QrErrorCorrectionDropdown';\n\ninterface QrCodeModalConnectProps extends ShortUrlModalProps {\n selectedServer: SelectedServer;\n}\n\nconst QrCodeModal = (imageDownloader: ImageDownloader, ForServerVersion: FC<Versions>) => ( // eslint-disable-line\n { shortUrl: { shortUrl, shortCode }, toggle, isOpen, selectedServer }: QrCodeModalConnectProps,\n) => {\n const [ size, setSize ] = useState(300);\n const [ margin, setMargin ] = useState(0);\n const [ format, setFormat ] = useState<QrCodeFormat>('png');\n const [ errorCorrection, setErrorCorrection ] = useState<QrErrorCorrection>('L');\n const capabilities: QrCodeCapabilities = useMemo(() => ({\n useSizeInPath: !supportsQrCodeSizeInQuery(selectedServer),\n marginIsSupported: supportsQrCodeMargin(selectedServer),\n errorCorrectionIsSupported: supportsQrErrorCorrection(selectedServer),\n }), [ selectedServer ]);\n const willRenderThreeControls = capabilities.marginIsSupported !== capabilities.errorCorrectionIsSupported;\n const qrCodeUrl = useMemo(\n () => buildQrCodeUrl(shortUrl, { size, format, margin, errorCorrection }, capabilities),\n [ shortUrl, size, format, margin, errorCorrection, capabilities ],\n );\n const totalSize = useMemo(() => size + margin, [ size, margin ]);\n const modalSize = useMemo(() => {\n if (totalSize < 500) {\n return undefined;\n }\n\n return totalSize < 800 ? 'lg' : 'xl';\n }, [ totalSize ]);\n\n return (\n <Modal isOpen={isOpen} toggle={toggle} centered size={modalSize}>\n <ModalHeader toggle={toggle}>\n QR code for <ExternalLink href={shortUrl}>{shortUrl}</ExternalLink>\n </ModalHeader>\n <ModalBody>\n <Row>\n <FormGroup\n className={classNames({ 'col-md-4': willRenderThreeControls, 'col-md-6': !willRenderThreeControls })}\n >\n <label className=\"mb-0\">Size: {size}px</label>\n <input\n type=\"range\"\n className=\"form-control-range\"\n value={size}\n step={10}\n min={50}\n max={1000}\n onChange={(e) => setSize(Number(e.target.value))}\n />\n </FormGroup>\n {capabilities.marginIsSupported && (\n <FormGroup className={willRenderThreeControls ? 'col-md-4' : 'col-md-6'}>\n <label className=\"mb-0\">Margin: {margin}px</label>\n <input\n type=\"range\"\n className=\"form-control-range\"\n value={margin}\n step={1}\n min={0}\n max={100}\n onChange={(e) => setMargin(Number(e.target.value))}\n />\n </FormGroup>\n )}\n <FormGroup className={willRenderThreeControls ? 'col-md-4' : 'col-md-6'}>\n <QrFormatDropdown format={format} setFormat={setFormat} />\n </FormGroup>\n {capabilities.errorCorrectionIsSupported && (\n <FormGroup className=\"col-md-6\">\n <QrErrorCorrectionDropdown errorCorrection={errorCorrection} setErrorCorrection={setErrorCorrection} />\n </FormGroup>\n )}\n </Row>\n <div className=\"text-center\">\n <div className=\"mb-3\">\n <ExternalLink href={qrCodeUrl} />\n <CopyToClipboardIcon text={qrCodeUrl} />\n </div>\n <img src={qrCodeUrl} className=\"qr-code-modal__img\" alt=\"QR code\" />\n <ForServerVersion minVersion=\"2.9.0\">\n <div className=\"mt-3\">\n <Button\n block\n color=\"primary\"\n onClick={async () => imageDownloader.saveImage(qrCodeUrl, `${shortCode}-qr-code.${format}`)}\n >\n Download <FontAwesomeIcon icon={downloadIcon} className=\"ml-1\" />\n </Button>\n </div>\n </ForServerVersion>\n </div>\n </ModalBody>\n </Modal>\n );\n};\n\nexport default QrCodeModal;\n","import { isEmpty } from 'ramda';\nimport { stringifyQuery } from './query';\n\nexport interface QrCodeCapabilities {\n useSizeInPath: boolean;\n marginIsSupported: boolean;\n errorCorrectionIsSupported: boolean;\n}\n\nexport type QrCodeFormat = 'svg' | 'png';\n\nexport type QrErrorCorrection = 'L' | 'M' | 'Q' | 'H';\n\nexport interface QrCodeOptions {\n size: number;\n format: QrCodeFormat;\n margin: number;\n errorCorrection: QrErrorCorrection;\n}\n\nexport const buildQrCodeUrl = (\n shortUrl: string,\n { size, format, margin, errorCorrection }: QrCodeOptions,\n { useSizeInPath, marginIsSupported, errorCorrectionIsSupported }: QrCodeCapabilities,\n): string => {\n const baseUrl = `${shortUrl}/qr-code${useSizeInPath ? `/${size}` : ''}`;\n const query = stringifyQuery({\n size: useSizeInPath ? undefined : size,\n format,\n margin: marginIsSupported && margin > 0 ? margin : undefined,\n errorCorrection: errorCorrectionIsSupported ? errorCorrection : undefined,\n });\n\n return `${baseUrl}${isEmpty(query) ? '' : `?${query}`}`;\n};\n","import { ChangeEvent, FC, useRef } from 'react';\nimport classNames from 'classnames';\nimport { v4 as uuid } from 'uuid';\nimport { identity } from 'ramda';\n\nexport interface BooleanControlProps {\n checked?: boolean;\n onChange?: (checked: boolean, e: ChangeEvent<HTMLInputElement>) => void;\n className?: string;\n inline?: boolean;\n}\n\ninterface BooleanControlWithTypeProps extends BooleanControlProps {\n type: 'switch' | 'checkbox';\n}\n\nconst BooleanControl: FC<BooleanControlWithTypeProps> = (\n { checked = false, onChange = identity, className, children, type, inline = false },\n) => {\n const { current: id } = useRef(uuid());\n const onChecked = (e: ChangeEvent<HTMLInputElement>) => onChange(e.target.checked, e);\n const typeClasses = {\n 'custom-switch': type === 'switch',\n 'custom-checkbox': type === 'checkbox',\n };\n const style = inline ? { display: 'inline-block' } : {};\n\n return (\n <span className={classNames('custom-control', typeClasses, className)} style={style}>\n <input type=\"checkbox\" className=\"custom-control-input\" id={id} checked={checked} onChange={onChecked} />\n <label className=\"custom-control-label\" htmlFor={id}>{children}</label>\n </span>\n );\n};\n\nexport default BooleanControl;\n","import { FC } from 'react';\nimport BooleanControl, { BooleanControlProps } from './BooleanControl';\n\nconst Checkbox: FC<BooleanControlProps> = (props) => <BooleanControl type=\"checkbox\" {...props} />;\n\nexport default Checkbox;\n","import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faInfoCircle as infoIcon } from '@fortawesome/free-solid-svg-icons';\nimport { Modal, ModalBody, ModalHeader } from 'reactstrap';\nimport { useToggle } from '../utils/helpers/hooks';\nimport './UseExistingIfFoundInfoIcon.scss';\n\nconst InfoModal = ({ isOpen, toggle }: { isOpen: boolean; toggle: () => void }) => (\n <Modal isOpen={isOpen} toggle={toggle} centered size=\"lg\">\n <ModalHeader toggle={toggle}>Info</ModalHeader>\n <ModalBody>\n <p>\n When the&nbsp;\n <b><i>&quot;Use existing URL if found&quot;</i></b>\n &nbsp;checkbox is checked, the server will return an existing short URL if it matches provided params.\n </p>\n <p>\n These are the checks performed by Shlink in order to determine if an existing short URL should be returned:\n </p>\n <ul>\n <li>\n When only the long URL is provided: The most recent match will be returned, or a new short URL will be created\n if none is found.\n </li>\n <li>\n When long URL and custom slug and/or domain are provided: Same as in previous case, but it will try to match\n the short URL using both the long URL and the slug, the long URL and the domain, or the three of them.\n <br />\n If the slug is being used by another long URL, an error will be returned.\n </li>\n <li>\n When other params are provided: Same as in previous cases, but it will try to match existing short URLs with\n all provided data. If any of them does not match, a new short URL will be created\n </li>\n </ul>\n </ModalBody>\n </Modal>\n);\n\nconst UseExistingIfFoundInfoIcon = () => {\n const [ isModalOpen, toggleModal ] = useToggle();\n\n return (\n <>\n <span title=\"What does this mean?\">\n <FontAwesomeIcon icon={infoIcon} style={{ cursor: 'pointer' }} onClick={toggleModal} />\n </span>\n <InfoModal isOpen={isModalOpen} toggle={toggleModal} />\n </>\n );\n};\n\nexport default UseExistingIfFoundInfoIcon;\n","import { FC, useRef } from 'react';\nimport * as Popper from 'popper.js';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faInfoCircle as infoIcon } from '@fortawesome/free-solid-svg-icons';\nimport { UncontrolledTooltip } from 'reactstrap';\n\ninterface InfoTooltipProps {\n className?: string;\n placement: Popper.Placement;\n}\n\nexport const InfoTooltip: FC<InfoTooltipProps> = ({ className = '', placement, children }) => {\n const ref = useRef<HTMLSpanElement | null>();\n const refCallback = (el: HTMLSpanElement) => {\n ref.current = el;\n };\n\n return (\n <>\n <span className={className} ref={refCallback}>\n <FontAwesomeIcon icon={infoIcon} />\n </span>\n <UncontrolledTooltip target={(() => ref.current) as any} placement={placement}>{children}</UncontrolledTooltip>\n </>\n );\n};\n","import { ChangeEvent, FC } from 'react';\nimport Checkbox from '../../utils/Checkbox';\nimport { InfoTooltip } from '../../utils/InfoTooltip';\n\ninterface ShortUrlFormCheckboxGroupProps {\n checked?: boolean;\n onChange?: (checked: boolean, e: ChangeEvent<HTMLInputElement>) => void;\n infoTooltip?: string;\n}\n\nexport const ShortUrlFormCheckboxGroup: FC<ShortUrlFormCheckboxGroupProps> = (\n { children, infoTooltip, checked, onChange },\n) => (\n <p>\n <Checkbox inline checked={checked} className={infoTooltip ? 'mr-2' : ''} onChange={onChange}>\n {children}\n </Checkbox>\n {infoTooltip && <InfoTooltip placement=\"right\">{infoTooltip}</InfoTooltip>}\n </p>\n);\n","import { FC, useEffect, useState } from 'react';\nimport { InputType } from 'reactstrap/lib/Input';\nimport { Button, FormGroup, Input, Row } from 'reactstrap';\nimport { isEmpty, pipe, replace, trim } from 'ramda';\nimport classNames from 'classnames';\nimport { parseISO } from 'date-fns';\nimport DateInput, { DateInputProps } from '../utils/DateInput';\nimport { supportsCrawlableVisits, supportsShortUrlTitle } from '../utils/helpers/features';\nimport { SimpleCard } from '../utils/SimpleCard';\nimport { handleEventPreventingDefault, hasValue } from '../utils/utils';\nimport Checkbox from '../utils/Checkbox';\nimport { SelectedServer } from '../servers/data';\nimport { TagsSelectorProps } from '../tags/helpers/TagsSelector';\nimport { DomainSelectorProps } from '../domains/DomainSelector';\nimport { formatIsoDate } from '../utils/helpers/date';\nimport UseExistingIfFoundInfoIcon from './UseExistingIfFoundInfoIcon';\nimport { ShortUrlData } from './data';\nimport { ShortUrlFormCheckboxGroup } from './helpers/ShortUrlFormCheckboxGroup';\nimport './ShortUrlForm.scss';\n\nexport type Mode = 'create' | 'create-basic' | 'edit';\n\ntype DateFields = 'validSince' | 'validUntil';\ntype NonDateFields = 'longUrl' | 'customSlug' | 'shortCodeLength' | 'domain' | 'maxVisits' | 'title';\n\nexport interface ShortUrlFormProps {\n mode: Mode;\n saving: boolean;\n initialState: ShortUrlData;\n onSave: (shortUrlData: ShortUrlData) => Promise<unknown>;\n selectedServer: SelectedServer;\n}\n\nconst normalizeTag = pipe(trim, replace(/ /g, '-'));\nconst toDate = (date?: string | Date): Date | undefined => typeof date === 'string' ? parseISO(date) : date;\n\nexport const ShortUrlForm = (\n TagsSelector: FC<TagsSelectorProps>,\n DomainSelector: FC<DomainSelectorProps>,\n): FC<ShortUrlFormProps> => ({ mode, saving, onSave, initialState, selectedServer }) => {\n const [ shortUrlData, setShortUrlData ] = useState(initialState);\n const isEdit = mode === 'edit';\n const changeTags = (tags: string[]) => setShortUrlData({ ...shortUrlData, tags: tags.map(normalizeTag) });\n const reset = () => setShortUrlData(initialState);\n const submit = handleEventPreventingDefault(async () => onSave({\n ...shortUrlData,\n validSince: formatIsoDate(shortUrlData.validSince) ?? null,\n validUntil: formatIsoDate(shortUrlData.validUntil) ?? null,\n maxVisits: !hasValue(shortUrlData.maxVisits) ? null : Number(shortUrlData.maxVisits),\n title: !hasValue(shortUrlData.title) ? undefined : shortUrlData.title,\n }).then(() => !isEdit && reset()).catch(() => {}));\n\n useEffect(() => {\n setShortUrlData(initialState);\n }, [ initialState ]);\n\n const renderOptionalInput = (id: NonDateFields, placeholder: string, type: InputType = 'text', props = {}) => (\n <FormGroup>\n <Input\n id={id}\n type={type}\n placeholder={placeholder}\n value={shortUrlData[id] ?? ''}\n onChange={(e) => setShortUrlData({ ...shortUrlData, [id]: e.target.value })}\n {...props}\n />\n </FormGroup>\n );\n const renderDateInput = (id: DateFields, placeholder: string, props: Partial<DateInputProps> = {}) => (\n <div className=\"form-group\">\n <DateInput\n selected={shortUrlData[id] ? toDate(shortUrlData[id] as string | Date) : null}\n placeholderText={placeholder}\n isClearable\n onChange={(date) => setShortUrlData({ ...shortUrlData, [id]: date })}\n {...props}\n />\n </div>\n );\n const basicComponents = (\n <>\n <FormGroup>\n <Input\n bsSize=\"lg\"\n type=\"url\"\n placeholder=\"URL to be shortened\"\n required\n value={shortUrlData.longUrl}\n onChange={(e) => setShortUrlData({ ...shortUrlData, longUrl: e.target.value })}\n />\n </FormGroup>\n\n <FormGroup>\n <TagsSelector selectedTags={shortUrlData.tags ?? []} onChange={changeTags} />\n </FormGroup>\n </>\n );\n\n const supportsTitle = supportsShortUrlTitle(selectedServer);\n const showCustomizeCard = supportsTitle || !isEdit;\n const limitAccessCardClasses = classNames('mb-3', {\n 'col-sm-6': showCustomizeCard,\n 'col-sm-12': !showCustomizeCard,\n });\n const showCrawlableControl = supportsCrawlableVisits(selectedServer);\n\n return (\n <form className=\"short-url-form\" onSubmit={submit}>\n {mode === 'create-basic' && basicComponents}\n {mode !== 'create-basic' && (\n <>\n <SimpleCard title=\"Basic options\" className=\"mb-3\">\n {basicComponents}\n </SimpleCard>\n\n <Row>\n {showCustomizeCard && (\n <div className=\"col-sm-6 mb-3\">\n <SimpleCard title=\"Customize the short URL\">\n {supportsTitle && renderOptionalInput('title', 'Title')}\n {!isEdit && (\n <>\n <Row>\n <div className=\"col-lg-6\">\n {renderOptionalInput('customSlug', 'Custom slug', 'text', {\n disabled: hasValue(shortUrlData.shortCodeLength),\n })}\n </div>\n <div className=\"col-lg-6\">\n {renderOptionalInput('shortCodeLength', 'Short code length', 'number', {\n min: 4,\n disabled: hasValue(shortUrlData.customSlug),\n })}\n </div>\n </Row>\n <FormGroup>\n <DomainSelector\n value={shortUrlData.domain}\n onChange={(domain?: string) => setShortUrlData({ ...shortUrlData, domain })}\n />\n </FormGroup>\n </>\n )}\n </SimpleCard>\n </div>\n )}\n\n <div className={limitAccessCardClasses}>\n <SimpleCard title=\"Limit access to the short URL\">\n {renderOptionalInput('maxVisits', 'Maximum number of visits allowed', 'number', { min: 1 })}\n {renderDateInput('validSince', 'Enabled since...', { maxDate: shortUrlData.validUntil ? toDate(shortUrlData.validUntil) : undefined })}\n {renderDateInput('validUntil', 'Enabled until...', { minDate: shortUrlData.validSince ? toDate(shortUrlData.validSince) : undefined })}\n </SimpleCard>\n </div>\n </Row>\n\n <SimpleCard title=\"Extra checks\" className=\"mb-3\">\n <ShortUrlFormCheckboxGroup\n infoTooltip=\"If checked, Shlink will try to reach the long URL, failing in case it's not publicly accessible.\"\n checked={shortUrlData.validateUrl}\n onChange={(validateUrl) => setShortUrlData({ ...shortUrlData, validateUrl })}\n >\n Validate URL\n </ShortUrlFormCheckboxGroup>\n {showCrawlableControl && (\n <ShortUrlFormCheckboxGroup\n infoTooltip=\"This short URL will be included in the robots.txt for your Shlink instance, allowing web crawlers (like Google) to index it.\"\n checked={shortUrlData.crawlable}\n onChange={(crawlable) => setShortUrlData({ ...shortUrlData, crawlable })}\n >\n Make it crawlable\n </ShortUrlFormCheckboxGroup>\n )}\n {!isEdit && (\n <p>\n <Checkbox\n inline\n className=\"mr-2\"\n checked={shortUrlData.findIfExists}\n onChange={(findIfExists) => setShortUrlData({ ...shortUrlData, findIfExists })}\n >\n Use existing URL if found\n </Checkbox>\n <UseExistingIfFoundInfoIcon />\n </p>\n )}\n </SimpleCard>\n </>\n )}\n\n <div className=\"text-center\">\n <Button\n outline\n color=\"primary\"\n disabled={saving || isEmpty(shortUrlData.longUrl)}\n className=\"btn-xs-block\"\n >\n {saving ? 'Saving...' : 'Save'}\n </Button>\n </div>\n </form>\n );\n};\n","import { FC, useEffect, useMemo } from 'react';\nimport { RouteComponentProps } from 'react-router';\nimport { Button, Card } from 'reactstrap';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faArrowLeft } from '@fortawesome/free-solid-svg-icons';\nimport { ExternalLink } from 'react-external-link';\nimport { SelectedServer } from '../servers/data';\nimport { Settings, ShortUrlCreationSettings } from '../settings/reducers/settings';\nimport { OptionalString } from '../utils/utils';\nimport { parseQuery } from '../utils/helpers/query';\nimport Message from '../utils/Message';\nimport { Result } from '../utils/Result';\nimport { ShlinkApiError } from '../api/ShlinkApiError';\nimport { useToggle } from '../utils/helpers/hooks';\nimport { ShortUrlFormProps } from './ShortUrlForm';\nimport { ShortUrlDetail } from './reducers/shortUrlDetail';\nimport { EditShortUrlData, ShortUrl, ShortUrlData } from './data';\nimport { ShortUrlEdition } from './reducers/shortUrlEdition';\n\ninterface EditShortUrlConnectProps extends RouteComponentProps<{ shortCode: string }> {\n settings: Settings;\n selectedServer: SelectedServer;\n shortUrlDetail: ShortUrlDetail;\n shortUrlEdition: ShortUrlEdition;\n getShortUrlDetail: (shortCode: string, domain: OptionalString) => void;\n editShortUrl: (shortUrl: string, domain: OptionalString, data: EditShortUrlData) => Promise<void>;\n}\n\nconst getInitialState = (shortUrl?: ShortUrl, settings?: ShortUrlCreationSettings): ShortUrlData => {\n const validateUrl = settings?.validateUrls ?? false;\n\n if (!shortUrl) {\n return { longUrl: '', validateUrl };\n }\n\n return {\n longUrl: shortUrl.longUrl,\n tags: shortUrl.tags,\n title: shortUrl.title ?? undefined,\n domain: shortUrl.domain ?? undefined,\n validSince: shortUrl.meta.validSince ?? undefined,\n validUntil: shortUrl.meta.validUntil ?? undefined,\n maxVisits: shortUrl.meta.maxVisits ?? undefined,\n crawlable: shortUrl.crawlable,\n validateUrl,\n };\n};\n\nexport const EditShortUrl = (ShortUrlForm: FC<ShortUrlFormProps>) => ({\n history: { goBack },\n match: { params },\n location: { search },\n settings: { shortUrlCreation: shortUrlCreationSettings },\n selectedServer,\n shortUrlDetail,\n getShortUrlDetail,\n shortUrlEdition,\n editShortUrl,\n}: EditShortUrlConnectProps) => {\n const { loading, error, errorData, shortUrl } = shortUrlDetail;\n const { saving, error: savingError, errorData: savingErrorData } = shortUrlEdition;\n const { domain } = parseQuery<{ domain?: string }>(search);\n const initialState = useMemo(\n () => getInitialState(shortUrl, shortUrlCreationSettings),\n [ shortUrl, shortUrlCreationSettings ],\n );\n const [ savingSucceeded,, isSuccessful, isNotSuccessful ] = useToggle();\n\n useEffect(() => {\n getShortUrlDetail(params.shortCode, domain);\n }, []);\n\n if (loading) {\n return <Message loading />;\n }\n\n if (error) {\n return (\n <Result type=\"error\">\n <ShlinkApiError errorData={errorData} fallbackMessage=\"An error occurred while loading short URL detail :(\" />\n </Result>\n );\n }\n\n return (\n <>\n <header className=\"mb-3\">\n <Card body>\n <h2 className=\"d-sm-flex justify-content-between align-items-center mb-0\">\n <Button color=\"link\" size=\"lg\" className=\"p-0 mr-3\" onClick={goBack}>\n <FontAwesomeIcon icon={faArrowLeft} />\n </Button>\n <span className=\"text-center\">\n <small>Edit <ExternalLink href={shortUrl?.shortUrl ?? ''} /></small>\n </span>\n <span />\n </h2>\n </Card>\n </header>\n <ShortUrlForm\n initialState={initialState}\n saving={saving}\n selectedServer={selectedServer}\n mode=\"edit\"\n onSave={async (shortUrlData) => {\n if (!shortUrl) {\n return;\n }\n\n isNotSuccessful();\n editShortUrl(shortUrl.shortCode, shortUrl.domain, shortUrlData)\n .then(isSuccessful)\n .catch(isNotSuccessful);\n }}\n />\n {savingError && (\n <Result type=\"error\" className=\"mt-3\">\n <ShlinkApiError errorData={savingErrorData} fallbackMessage=\"An error occurred while updating short URL :(\" />\n </Result>\n )}\n {savingSucceeded && <Result type=\"success\" className=\"mt-3\">Short URL properly edited.</Result>}\n </>\n );\n};\n","import { Action, Dispatch } from 'redux';\nimport { ShortUrl } from '../data';\nimport { buildReducer } from '../../utils/helpers/redux';\nimport { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';\nimport { OptionalString } from '../../utils/utils';\nimport { GetState } from '../../container/types';\nimport { shortUrlMatches } from '../helpers';\nimport { ProblemDetailsError } from '../../api/types';\nimport { parseApiError } from '../../api/utils';\nimport { ApiErrorAction } from '../../api/types/actions';\n\n/* eslint-disable padding-line-between-statements */\nexport const GET_SHORT_URL_DETAIL_START = 'shlink/shortUrlDetail/GET_SHORT_URL_DETAIL_START';\nexport const GET_SHORT_URL_DETAIL_ERROR = 'shlink/shortUrlDetail/GET_SHORT_URL_DETAIL_ERROR';\nexport const GET_SHORT_URL_DETAIL = 'shlink/shortUrlDetail/GET_SHORT_URL_DETAIL';\n/* eslint-enable padding-line-between-statements */\n\nexport interface ShortUrlDetail {\n shortUrl?: ShortUrl;\n loading: boolean;\n error: boolean;\n errorData?: ProblemDetailsError;\n}\n\nexport interface ShortUrlDetailAction extends Action<string> {\n shortUrl: ShortUrl;\n}\n\nconst initialState: ShortUrlDetail = {\n loading: false,\n error: false,\n};\n\nexport default buildReducer<ShortUrlDetail, ShortUrlDetailAction & ApiErrorAction>({\n [GET_SHORT_URL_DETAIL_START]: () => ({ loading: true, error: false }),\n [GET_SHORT_URL_DETAIL_ERROR]: (_, { errorData }) => ({ loading: false, error: true, errorData }),\n [GET_SHORT_URL_DETAIL]: (_, { shortUrl }) => ({ shortUrl, ...initialState }),\n}, initialState);\n\nexport const getShortUrlDetail = (buildShlinkApiClient: ShlinkApiClientBuilder) => (\n shortCode: string,\n domain: OptionalString,\n) => async (dispatch: Dispatch, getState: GetState) => {\n dispatch({ type: GET_SHORT_URL_DETAIL_START });\n\n try {\n const { shortUrlsList } = getState();\n const shortUrl = shortUrlsList?.shortUrls?.data.find(\n (shortUrl) => shortUrlMatches(shortUrl, shortCode, domain),\n ) ?? await buildShlinkApiClient(getState).getShortUrl(shortCode, domain);\n\n dispatch<ShortUrlDetailAction>({ shortUrl, type: GET_SHORT_URL_DETAIL });\n } catch (e) {\n dispatch<ApiErrorAction>({ type: GET_SHORT_URL_DETAIL_ERROR, errorData: parseApiError(e) });\n }\n};\n","import Bottle from 'bottlejs';\nimport ShortUrls from '../ShortUrls';\nimport SearchBar from '../SearchBar';\nimport ShortUrlsList from '../ShortUrlsList';\nimport ShortUrlsRow from '../helpers/ShortUrlsRow';\nimport ShortUrlsRowMenu from '../helpers/ShortUrlsRowMenu';\nimport CreateShortUrl from '../CreateShortUrl';\nimport DeleteShortUrlModal from '../helpers/DeleteShortUrlModal';\nimport CreateShortUrlResult from '../helpers/CreateShortUrlResult';\nimport { listShortUrls } from '../reducers/shortUrlsList';\nimport { createShortUrl, resetCreateShortUrl } from '../reducers/shortUrlCreation';\nimport { deleteShortUrl, resetDeleteShortUrl } from '../reducers/shortUrlDeletion';\nimport { resetShortUrlParams } from '../reducers/shortUrlsListParams';\nimport { editShortUrl } from '../reducers/shortUrlEdition';\nimport { ConnectDecorator } from '../../container/types';\nimport { ShortUrlsTable } from '../ShortUrlsTable';\nimport QrCodeModal from '../helpers/QrCodeModal';\nimport { ShortUrlForm } from '../ShortUrlForm';\nimport { EditShortUrl } from '../EditShortUrl';\nimport { getShortUrlDetail } from '../reducers/shortUrlDetail';\n\nconst provideServices = (bottle: Bottle, connect: ConnectDecorator) => {\n // Components\n bottle.serviceFactory('ShortUrls', ShortUrls, 'SearchBar', 'ShortUrlsList');\n bottle.decorator('ShortUrls', connect([ 'shortUrlsList' ]));\n\n bottle.serviceFactory('ShortUrlsList', ShortUrlsList, 'ShortUrlsTable');\n bottle.decorator('ShortUrlsList', connect(\n [ 'selectedServer', 'shortUrlsListParams', 'mercureInfo' ],\n [ 'listShortUrls', 'resetShortUrlParams', 'createNewVisits', 'loadMercureInfo' ],\n ));\n\n bottle.serviceFactory('ShortUrlsTable', ShortUrlsTable, 'ShortUrlsRow');\n bottle.serviceFactory('ShortUrlsRow', ShortUrlsRow, 'ShortUrlsRowMenu', 'ColorGenerator', 'useStateFlagTimeout');\n bottle.serviceFactory('ShortUrlsRowMenu', ShortUrlsRowMenu, 'DeleteShortUrlModal', 'QrCodeModal');\n bottle.serviceFactory('CreateShortUrlResult', CreateShortUrlResult, 'useStateFlagTimeout');\n bottle.serviceFactory('ShortUrlForm', ShortUrlForm, 'TagsSelector', 'DomainSelector');\n\n bottle.serviceFactory('CreateShortUrl', CreateShortUrl, 'ShortUrlForm', 'CreateShortUrlResult');\n bottle.decorator(\n 'CreateShortUrl',\n connect([ 'shortUrlCreationResult', 'selectedServer', 'settings' ], [ 'createShortUrl', 'resetCreateShortUrl' ]),\n );\n\n bottle.serviceFactory('EditShortUrl', EditShortUrl, 'ShortUrlForm');\n bottle.decorator('EditShortUrl', connect(\n [ 'shortUrlDetail', 'shortUrlEdition', 'selectedServer', 'settings' ],\n [ 'getShortUrlDetail', 'editShortUrl' ],\n ));\n\n bottle.serviceFactory('DeleteShortUrlModal', () => DeleteShortUrlModal);\n bottle.decorator('DeleteShortUrlModal', connect([ 'shortUrlDeletion' ], [ 'deleteShortUrl', 'resetDeleteShortUrl' ]));\n\n bottle.serviceFactory('QrCodeModal', QrCodeModal, 'ImageDownloader', 'ForServerVersion');\n bottle.decorator('QrCodeModal', connect([ 'selectedServer' ]));\n\n // Services\n bottle.serviceFactory('SearchBar', SearchBar, 'ColorGenerator');\n bottle.decorator('SearchBar', connect([ 'shortUrlsListParams' ], [ 'listShortUrls' ]));\n\n // Actions\n bottle.serviceFactory('listShortUrls', listShortUrls, 'buildShlinkApiClient');\n bottle.serviceFactory('resetShortUrlParams', () => resetShortUrlParams);\n\n bottle.serviceFactory('createShortUrl', createShortUrl, 'buildShlinkApiClient');\n bottle.serviceFactory('resetCreateShortUrl', () => resetCreateShortUrl);\n\n bottle.serviceFactory('deleteShortUrl', deleteShortUrl, 'buildShlinkApiClient');\n bottle.serviceFactory('resetDeleteShortUrl', () => resetDeleteShortUrl);\n\n bottle.serviceFactory('getShortUrlDetail', getShortUrlDetail, 'buildShlinkApiClient');\n\n bottle.serviceFactory('editShortUrl', editShortUrl, 'buildShlinkApiClient');\n};\n\nexport default provideServices;\n","import { FC, useRef } from 'react';\nimport { v4 as uuid } from 'uuid';\nimport { InputType } from 'reactstrap/lib/Input';\n\nexport interface FormGroupContainerProps {\n value: string;\n onChange: (newValue: string) => void;\n id?: string;\n type?: InputType;\n required?: boolean;\n placeholder?: string;\n className?: string;\n labelClassName?: string;\n}\n\nexport const FormGroupContainer: FC<FormGroupContainerProps> = (\n { children, value, onChange, id, type, required, placeholder, className, labelClassName },\n) => {\n const forId = useRef<string>(id ?? uuid());\n\n return (\n <div className={`form-group ${className ?? ''}`}>\n <label htmlFor={forId.current} className={labelClassName ?? ''}>\n {children}:\n </label>\n <input\n className=\"form-control\"\n type={type ?? 'text'}\n id={forId.current}\n value={value}\n required={required ?? true}\n placeholder={placeholder}\n onChange={(e) => onChange(e.target.value)}\n />\n </div>\n );\n};\n","import { FC, ReactNode, useEffect, useState } from 'react';\nimport { FormGroupContainer, FormGroupContainerProps } from '../../utils/FormGroupContainer';\nimport { handleEventPreventingDefault } from '../../utils/utils';\nimport { ServerData } from '../data';\nimport { SimpleCard } from '../../utils/SimpleCard';\nimport './ServerForm.scss';\n\ninterface ServerFormProps {\n onSubmit: (server: ServerData) => void;\n initialValues?: ServerData;\n title?: ReactNode;\n}\n\nconst FormGroup: FC<FormGroupContainerProps> = (props) =>\n <FormGroupContainer {...props} labelClassName=\"create-server__label\" />;\n\nexport const ServerForm: FC<ServerFormProps> = ({ onSubmit, initialValues, children, title }) => {\n const [ name, setName ] = useState('');\n const [ url, setUrl ] = useState('');\n const [ apiKey, setApiKey ] = useState('');\n const handleSubmit = handleEventPreventingDefault(() => onSubmit({ name, url, apiKey }));\n\n useEffect(() => {\n initialValues && setName(initialValues.name);\n initialValues && setUrl(initialValues.url);\n initialValues && setApiKey(initialValues.apiKey);\n }, [ initialValues ]);\n\n return (\n <form className=\"server-form\" onSubmit={handleSubmit}>\n <SimpleCard className=\"mb-3\" title={title}>\n <FormGroup value={name} onChange={setName}>Name</FormGroup>\n <FormGroup type=\"url\" value={url} onChange={setUrl}>URL</FormGroup>\n <FormGroup value={apiKey} onChange={setApiKey}>APIkey</FormGroup>\n </SimpleCard>\n\n <div className=\"text-right\">{children}</div>\n </form>\n );\n};\n","import { FC } from 'react';\nimport { v4 as uuid } from 'uuid';\nimport { RouterProps } from 'react-router';\nimport { Result } from '../utils/Result';\nimport NoMenuLayout from '../common/NoMenuLayout';\nimport { StateFlagTimeout } from '../utils/helpers/hooks';\nimport { ServerForm } from './helpers/ServerForm';\nimport { ImportServersBtnProps } from './helpers/ImportServersBtn';\nimport { ServerData, ServerWithId } from './data';\nimport './CreateServer.scss';\n\nconst SHOW_IMPORT_MSG_TIME = 4000;\n\ninterface CreateServerProps extends RouterProps {\n createServer: (server: ServerWithId) => void;\n}\n\nconst ImportResult = ({ type }: { type: 'error' | 'success' }) => (\n <Result type={type}>\n {type === 'success' && 'Servers properly imported. You can now select one from the list :)'}\n {type === 'error' && 'The servers could not be imported. Make sure the format is correct.'}\n </Result>\n);\n\nconst CreateServer = (ImportServersBtn: FC<ImportServersBtnProps>, useStateFlagTimeout: StateFlagTimeout) => (\n { createServer, history: { push } }: CreateServerProps,\n) => {\n const [ serversImported, setServersImported ] = useStateFlagTimeout(false, SHOW_IMPORT_MSG_TIME);\n const [ errorImporting, setErrorImporting ] = useStateFlagTimeout(false, SHOW_IMPORT_MSG_TIME);\n const handleSubmit = (serverData: ServerData) => {\n const id = uuid();\n\n createServer({ ...serverData, id });\n push(`/server/${id}`);\n };\n\n return (\n <NoMenuLayout>\n <ServerForm title={<h5 className=\"mb-0\">Add new server</h5>} onSubmit={handleSubmit}>\n <ImportServersBtn onImport={setServersImported} onImportError={setErrorImporting} />\n <button className=\"btn btn-outline-primary\">Create server</button>\n </ServerForm>\n\n {(serversImported || errorImporting) && (\n <div className=\"mt-3\">\n {serversImported && <ImportResult type=\"success\" />}\n {errorImporting && <ImportResult type=\"error\" />}\n </div>\n )}\n </NoMenuLayout>\n );\n};\n\nexport default CreateServer;\n","import { isEmpty, values } from 'ramda';\nimport { DropdownItem, DropdownMenu, DropdownToggle, UncontrolledDropdown } from 'reactstrap';\nimport { Link } from 'react-router-dom';\nimport { faPlus as plusIcon, faFileDownload as exportIcon, faServer as serverIcon } from '@fortawesome/free-solid-svg-icons';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport ServersExporter from './services/ServersExporter';\nimport { isServerWithId, SelectedServer, ServersMap } from './data';\n\nexport interface ServersDropdownProps {\n servers: ServersMap;\n selectedServer: SelectedServer;\n}\n\nconst ServersDropdown = (serversExporter: ServersExporter) => ({ servers, selectedServer }: ServersDropdownProps) => {\n const serversList = values(servers);\n const createServerItem = (\n <DropdownItem tag={Link} to=\"/server/create\">\n <FontAwesomeIcon icon={plusIcon} /> <span className=\"ml-1\">Add a server</span>\n </DropdownItem>\n );\n\n const renderServers = () => {\n if (isEmpty(serversList)) {\n return createServerItem;\n }\n\n return (\n <>\n {serversList.map(({ name, id }) => (\n <DropdownItem\n key={id}\n tag={Link}\n to={`/server/${id}`}\n active={isServerWithId(selectedServer) && selectedServer.id === id}\n >\n {name}\n </DropdownItem>\n ))}\n <DropdownItem divider />\n {createServerItem}\n <DropdownItem className=\"servers-dropdown__export-item\" onClick={async () => serversExporter.exportServers()}>\n <FontAwesomeIcon icon={exportIcon} /> <span className=\"ml-1\">Export servers</span>\n </DropdownItem>\n </>\n );\n };\n\n return (\n <UncontrolledDropdown nav inNavbar>\n <DropdownToggle nav caret>\n <FontAwesomeIcon icon={serverIcon} /> <span className=\"ml-1\">Servers</span>\n </DropdownToggle>\n <DropdownMenu right>{renderServers()}</DropdownMenu>\n </UncontrolledDropdown>\n );\n};\n\nexport default ServersDropdown;\n","import { Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap';\nimport { RouterProps } from 'react-router';\nimport { ServerWithId } from './data';\n\nexport interface DeleteServerModalProps {\n server: ServerWithId;\n toggle: () => void;\n isOpen: boolean;\n}\n\ninterface DeleteServerModalConnectProps extends DeleteServerModalProps, RouterProps {\n deleteServer: (server: ServerWithId) => void;\n}\n\nconst DeleteServerModal = ({ server, toggle, isOpen, deleteServer, history }: DeleteServerModalConnectProps) => {\n const closeModal = () => {\n deleteServer(server);\n toggle();\n history.push('/');\n };\n\n return (\n <Modal isOpen={isOpen} toggle={toggle} centered>\n <ModalHeader toggle={toggle}><span className=\"text-danger\">Remove server</span></ModalHeader>\n <ModalBody>\n <p>Are you sure you want to remove <b>{server ? server.name : ''}</b>?</p>\n <p>\n <i>\n No data will be deleted, only the access to this server will be removed from this device.\n You can create it again at any moment.\n </i>\n </p>\n </ModalBody>\n <ModalFooter>\n <button className=\"btn btn-link\" onClick={toggle}>Cancel</button>\n <button className=\"btn btn-danger\" onClick={() => closeModal()}>Delete</button>\n </ModalFooter>\n </Modal>\n );\n};\n\nexport default DeleteServerModal;\n","import { FC } from 'react';\nimport { faMinusCircle as deleteIcon } from '@fortawesome/free-solid-svg-icons';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { useToggle } from '../utils/helpers/hooks';\nimport { DeleteServerModalProps } from './DeleteServerModal';\nimport { ServerWithId } from './data';\n\nexport interface DeleteServerButtonProps {\n server: ServerWithId;\n className?: string;\n textClassName?: string;\n}\n\nconst DeleteServerButton = (DeleteServerModal: FC<DeleteServerModalProps>): FC<DeleteServerButtonProps> => (\n { server, className, children, textClassName },\n) => {\n const [ isModalOpen, , showModal, hideModal ] = useToggle();\n\n return (\n <>\n <span className={className} onClick={showModal}>\n {!children && <FontAwesomeIcon fixedWidth icon={deleteIcon} />}\n <span className={textClassName}>{children ?? 'Remove this server'}</span>\n </span>\n\n <DeleteServerModal server={server} isOpen={isModalOpen} toggle={hideModal} />\n </>\n );\n};\n\nexport default DeleteServerButton;\n","import { FC } from 'react';\nimport { Button } from 'reactstrap';\nimport NoMenuLayout from '../common/NoMenuLayout';\nimport { ServerForm } from './helpers/ServerForm';\nimport { withSelectedServer } from './helpers/withSelectedServer';\nimport { isServerWithId, ServerData } from './data';\n\ninterface EditServerProps {\n editServer: (serverId: string, serverData: ServerData) => void;\n}\n\nexport const EditServer = (ServerError: FC) => withSelectedServer<EditServerProps>((\n { editServer, selectedServer, history: { push, goBack } },\n) => {\n if (!isServerWithId(selectedServer)) {\n return null;\n }\n\n const handleSubmit = (serverData: ServerData) => {\n editServer(selectedServer.id, serverData);\n push(`/server/${selectedServer.id}`);\n };\n\n return (\n <NoMenuLayout>\n <ServerForm\n title={<h5 className=\"mb-0\">Edit &quot;{selectedServer.name}&quot;</h5>}\n initialValues={selectedServer}\n onSubmit={handleSubmit}\n >\n <Button outline className=\"mr-2\" onClick={goBack}>Cancel</Button>\n <Button outline color=\"primary\">Save</Button>\n </ServerForm>\n </NoMenuLayout>\n );\n}, ServerError);\n","import { useRef, RefObject, ChangeEvent, MutableRefObject } from 'react';\nimport { UncontrolledTooltip } from 'reactstrap';\nimport ServersImporter from '../services/ServersImporter';\nimport { ServerData } from '../data';\n\ntype Ref<T> = RefObject<T> | MutableRefObject<T>;\n\nexport interface ImportServersBtnProps {\n onImport?: () => void;\n onImportError?: (error: Error) => void;\n}\n\ninterface ImportServersBtnConnectProps extends ImportServersBtnProps {\n createServers: (servers: ServerData[]) => void;\n fileRef: Ref<HTMLInputElement>;\n}\n\nconst ImportServersBtn = ({ importServersFromFile }: ServersImporter) => ({\n createServers,\n fileRef,\n onImport = () => {},\n onImportError = () => {},\n}: ImportServersBtnConnectProps) => {\n const ref = fileRef ?? useRef<HTMLInputElement>();\n const onChange = async ({ target }: ChangeEvent<HTMLInputElement>) =>\n importServersFromFile(target.files?.[0])\n .then(createServers)\n .then(onImport)\n .then(() => {\n // Reset input after processing file\n (target as { value: string | null }).value = null;\n })\n .catch(onImportError);\n\n return (\n <>\n <button\n type=\"button\"\n className=\"btn btn-outline-secondary mr-2\"\n id=\"importBtn\"\n onClick={() => ref.current?.click()}\n >\n Import from file\n </button>\n <UncontrolledTooltip placement=\"top\" target=\"importBtn\">\n You can create servers by importing a CSV file with columns <b>name</b>, <b>apiKey</b> and <b>url</b>.\n </UncontrolledTooltip>\n\n <input type=\"file\" accept=\"text/csv\" className=\"create-server__csv-select\" ref={ref} onChange={onChange} />\n </>\n );\n};\n\nexport default ImportServersBtn;\n","import { identity, memoizeWith, pipe } from 'ramda';\nimport { Action, Dispatch } from 'redux';\nimport { resetShortUrlParams } from '../../short-urls/reducers/shortUrlsListParams';\nimport { versionToPrintable, versionToSemVer as toSemVer } from '../../utils/helpers/version';\nimport { SelectedServer } from '../data';\nimport { GetState } from '../../container/types';\nimport { ShlinkHealth } from '../../api/types';\nimport { buildActionCreator, buildReducer } from '../../utils/helpers/redux';\nimport { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';\n\n/* eslint-disable padding-line-between-statements */\nexport const SELECT_SERVER = 'shlink/selectedServer/SELECT_SERVER';\nexport const RESET_SELECTED_SERVER = 'shlink/selectedServer/RESET_SELECTED_SERVER';\n\nexport const MIN_FALLBACK_VERSION = '1.0.0';\nexport const MAX_FALLBACK_VERSION = '999.999.999';\nexport const LATEST_VERSION_CONSTRAINT = 'latest';\n/* eslint-enable padding-line-between-statements */\n\nexport interface SelectServerAction extends Action<string> {\n selectedServer: SelectedServer;\n}\n\nconst versionToSemVer = pipe(\n (version: string) => version === LATEST_VERSION_CONSTRAINT ? MAX_FALLBACK_VERSION : version,\n toSemVer(MIN_FALLBACK_VERSION),\n);\n\nconst getServerVersion = memoizeWith(\n identity,\n async (_serverId: string, health: () => Promise<ShlinkHealth>) => health().then(({ version }) => ({\n version: versionToSemVer(version),\n printableVersion: versionToPrintable(version),\n })),\n);\n\nconst initialState: SelectedServer = null;\n\nexport default buildReducer<SelectedServer, SelectServerAction>({\n [RESET_SELECTED_SERVER]: () => initialState,\n [SELECT_SERVER]: (_, { selectedServer }) => selectedServer,\n}, initialState);\n\nexport const resetSelectedServer = buildActionCreator(RESET_SELECTED_SERVER);\n\nexport const selectServer = (\n buildShlinkApiClient: ShlinkApiClientBuilder,\n loadMercureInfo: () => Action,\n) => (\n serverId: string,\n) => async (\n dispatch: Dispatch,\n getState: GetState,\n) => {\n dispatch(resetSelectedServer());\n dispatch(resetShortUrlParams());\n\n const { servers } = getState();\n const selectedServer = servers[serverId];\n\n if (!selectedServer) {\n dispatch<SelectServerAction>({\n type: SELECT_SERVER,\n selectedServer: { serverNotFound: true },\n });\n\n return;\n }\n\n try {\n const { health } = buildShlinkApiClient(selectedServer);\n const { version, printableVersion } = await getServerVersion(serverId, health);\n\n dispatch<SelectServerAction>({\n type: SELECT_SERVER,\n selectedServer: {\n ...selectedServer,\n version,\n printableVersion,\n },\n });\n dispatch(loadMercureInfo());\n } catch (e) {\n dispatch<SelectServerAction>({\n type: SELECT_SERVER,\n selectedServer: { ...selectedServer, serverNotReachable: true },\n });\n }\n};\n","import { assoc, dissoc, map, pipe, reduce } from 'ramda';\nimport { v4 as uuid } from 'uuid';\nimport { Action } from 'redux';\nimport { ServerData, ServersMap, ServerWithId } from '../data';\nimport { buildReducer } from '../../utils/helpers/redux';\n\n/* eslint-disable padding-line-between-statements */\nexport const EDIT_SERVER = 'shlink/servers/EDIT_SERVER';\nexport const DELETE_SERVER = 'shlink/servers/DELETE_SERVER';\nexport const CREATE_SERVERS = 'shlink/servers/CREATE_SERVERS';\n/* eslint-enable padding-line-between-statements */\n\nexport interface CreateServersAction extends Action<string> {\n newServers: ServersMap;\n}\n\nconst initialState: ServersMap = {};\n\nconst serverWithId = (server: ServerWithId | ServerData): ServerWithId => {\n if ((server as ServerWithId).id) {\n return server as ServerWithId;\n }\n\n return assoc('id', uuid(), server);\n};\n\nexport default buildReducer<ServersMap, CreateServersAction>({\n [CREATE_SERVERS]: (state, { newServers }) => ({ ...state, ...newServers }),\n [DELETE_SERVER]: (state, { serverId }: any) => dissoc(serverId, state),\n [EDIT_SERVER]: (state, { serverId, serverData }: any) => !state[serverId]\n ? state\n : assoc(serverId, { ...state[serverId], ...serverData }, state),\n}, initialState);\n\nconst serversListToMap = reduce<ServerWithId, ServersMap>((acc, server) => assoc(server.id, server, acc), {});\n\nexport const createServers = pipe(\n map(serverWithId),\n serversListToMap,\n (newServers: ServersMap) => ({ type: CREATE_SERVERS, newServers }),\n);\n\nexport const createServer = (server: ServerWithId) => createServers([ server ]);\n\nexport const editServer = (serverId: string, serverData: Partial<ServerData>) => ({\n type: EDIT_SERVER,\n serverId,\n serverData,\n});\n\nexport const deleteServer = ({ id }: ServerWithId) => ({ type: DELETE_SERVER, serverId: id });\n","import { pipe, prop } from 'ramda';\nimport { AxiosInstance } from 'axios';\nimport { Dispatch } from 'redux';\nimport { homepage } from '../../../package.json';\nimport { ServerData } from '../data';\nimport { createServers } from './servers';\n\nconst responseToServersList = pipe(\n prop<any, any>('data'),\n (data: any): ServerData[] => {\n if (!Array.isArray(data)) {\n throw new Error('Value is not an array');\n }\n\n return data as ServerData[];\n },\n);\n\nexport const fetchServers = ({ get }: AxiosInstance) => () => async (dispatch: Dispatch) => {\n const remoteList = await get(`${homepage}/servers.json`)\n .then(responseToServersList)\n .catch(() => []);\n\n dispatch(createServers(remoteList));\n};\n","import { FC } from 'react';\nimport { versionMatch, Versions } from '../../utils/helpers/version';\nimport { isReachableServer, SelectedServer } from '../data';\n\ninterface ForServerVersionProps extends Versions {\n selectedServer: SelectedServer;\n}\n\nconst ForServerVersion: FC<ForServerVersionProps> = ({ minVersion, maxVersion, selectedServer, children }) => {\n if (!isReachableServer(selectedServer)) {\n return null;\n }\n\n const { version } = selectedServer;\n const matchesVersion = versionMatch(version, { maxVersion, minVersion });\n\n if (!matchesVersion) {\n return null;\n }\n\n return <>{children}</>;\n};\n\nexport default ForServerVersion;\n","import { FC } from 'react';\nimport { Link } from 'react-router-dom';\nimport Message from '../../utils/Message';\nimport ServersListGroup from '../ServersListGroup';\nimport { DeleteServerButtonProps } from '../DeleteServerButton';\nimport { isServerWithId, SelectedServer, ServersMap } from '../data';\nimport NoMenuLayout from '../../common/NoMenuLayout';\nimport './ServerError.scss';\n\ninterface ServerErrorProps {\n servers: ServersMap;\n selectedServer: SelectedServer;\n}\n\nexport const ServerError = (DeleteServerButton: FC<DeleteServerButtonProps>): FC<ServerErrorProps> => (\n { servers, selectedServer },\n) => (\n <NoMenuLayout>\n <div className=\"server-error__container flex-column\">\n <Message className=\"w-100 mb-3 mb-md-5\" type=\"error\" fullWidth>\n {!isServerWithId(selectedServer) && 'Could not find this Shlink server.'}\n {isServerWithId(selectedServer) && (\n <>\n <p>Oops! Could not connect to this Shlink server.</p>\n Make sure you have internet connection, and the server is properly configured and on-line.\n </>\n )}\n </Message>\n\n <ServersListGroup servers={Object.values(servers)}>\n These are the Shlink servers currently configured. Choose one of\n them or <Link to=\"/server/create\">add a new one</Link>.\n </ServersListGroup>\n\n {isServerWithId(selectedServer) && (\n <div className=\"container mt-3 mt-md-5\">\n <h5>\n Alternatively, if you think you may have miss-configured this server, you\n can <DeleteServerButton server={selectedServer} className=\"server-error__delete-btn\">remove it</DeleteServerButton> or&nbsp;\n <Link to={`/server/${selectedServer.id}/edit`}>edit it</Link>.\n </h5>\n </div>\n )}\n </div>\n </NoMenuLayout>\n);\n","import { FC, useEffect } from 'react';\nimport { Card, CardBody, CardHeader, CardText, CardTitle, Row } from 'reactstrap';\nimport { Link, useHistory } from 'react-router-dom';\nimport { ShortUrlsListParams } from '../short-urls/reducers/shortUrlsListParams';\nimport { ShortUrlsList as ShortUrlsListState } from '../short-urls/reducers/shortUrlsList';\nimport { prettify } from '../utils/helpers/numbers';\nimport { TagsList } from '../tags/reducers/tagsList';\nimport { ShortUrlsTableProps } from '../short-urls/ShortUrlsTable';\nimport { boundToMercureHub } from '../mercure/helpers/boundToMercureHub';\nimport { CreateShortUrlProps } from '../short-urls/CreateShortUrl';\nimport { VisitsOverview } from '../visits/reducers/visitsOverview';\nimport { Versions } from '../utils/helpers/version';\nimport { Topics } from '../mercure/helpers/Topics';\nimport { isServerWithId, SelectedServer } from './data';\nimport './Overview.scss';\n\ninterface OverviewConnectProps {\n shortUrlsList: ShortUrlsListState;\n listShortUrls: (params: ShortUrlsListParams) => void;\n listTags: Function;\n tagsList: TagsList;\n selectedServer: SelectedServer;\n visitsOverview: VisitsOverview;\n loadVisitsOverview: Function;\n}\n\nexport const Overview = (\n ShortUrlsTable: FC<ShortUrlsTableProps>,\n CreateShortUrl: FC<CreateShortUrlProps>,\n ForServerVersion: FC<Versions>,\n) => boundToMercureHub(({\n shortUrlsList,\n listShortUrls,\n listTags,\n tagsList,\n selectedServer,\n loadVisitsOverview,\n visitsOverview,\n}: OverviewConnectProps) => {\n const { loading, shortUrls } = shortUrlsList;\n const { loading: loadingTags } = tagsList;\n const { loading: loadingVisits, visitsCount, orphanVisitsCount } = visitsOverview;\n const serverId = isServerWithId(selectedServer) ? selectedServer.id : '';\n const history = useHistory();\n\n useEffect(() => {\n listShortUrls({ itemsPerPage: 5, orderBy: { dateCreated: 'DESC' } });\n listTags();\n loadVisitsOverview();\n }, []);\n\n return (\n <>\n <Row>\n <div className=\"col-md-6 col-xl-3\">\n <Card className=\"overview__card mb-3\" body>\n <CardTitle tag=\"h5\" className=\"overview__card-title\">Visits</CardTitle>\n <CardText tag=\"h2\">{loadingVisits ? 'Loading...' : prettify(visitsCount)}</CardText>\n </Card>\n </div>\n <div className=\"col-md-6 col-xl-3\">\n <Card className=\"overview__card mb-3\" body tag={Link} to={`/server/${serverId}/orphan-visits`}>\n <CardTitle tag=\"h5\" className=\"overview__card-title\">Orphan visits</CardTitle>\n <CardText tag=\"h2\">\n <ForServerVersion minVersion=\"2.6.0\">\n {loadingVisits ? 'Loading...' : prettify(orphanVisitsCount ?? 0)}\n </ForServerVersion>\n <ForServerVersion maxVersion=\"2.5.*\">\n <small className=\"text-muted\"><i>Shlink 2.6 is needed</i></small>\n </ForServerVersion>\n </CardText>\n </Card>\n </div>\n <div className=\"col-md-6 col-xl-3\">\n <Card className=\"overview__card mb-3\" body tag={Link} to={`/server/${serverId}/list-short-urls/1`}>\n <CardTitle tag=\"h5\" className=\"overview__card-title\">Short URLs</CardTitle>\n <CardText tag=\"h2\">\n {loading ? 'Loading...' : prettify(shortUrls?.pagination.totalItems ?? 0)}\n </CardText>\n </Card>\n </div>\n <div className=\"col-md-6 col-xl-3\">\n <Card className=\"overview__card mb-3\" body tag={Link} to={`/server/${serverId}/manage-tags`}>\n <CardTitle tag=\"h5\" className=\"overview__card-title\">Tags</CardTitle>\n <CardText tag=\"h2\">{loadingTags ? 'Loading...' : prettify(tagsList.tags.length)}</CardText>\n </Card>\n </div>\n </Row>\n <Card className=\"mb-3\">\n <CardHeader>\n <span className=\"d-sm-none\">Create a short URL</span>\n <h5 className=\"d-none d-sm-inline\">Create a short URL</h5>\n <Link className=\"float-right\" to={`/server/${serverId}/create-short-url`}>Advanced options &raquo;</Link>\n </CardHeader>\n <CardBody>\n <CreateShortUrl basicMode />\n </CardBody>\n </Card>\n <Card>\n <CardHeader>\n <span className=\"d-sm-none\">Recently created URLs</span>\n <h5 className=\"d-none d-sm-inline\">Recently created URLs</h5>\n <Link className=\"float-right\" to={`/server/${serverId}/list-short-urls/1`}>See all &raquo;</Link>\n </CardHeader>\n <CardBody>\n <ShortUrlsTable\n shortUrlsList={shortUrlsList}\n selectedServer={selectedServer}\n className=\"mb-0\"\n onTagClick={(tag) => history.push(`/server/${serverId}/list-short-urls/1?tag=${tag}`)}\n />\n </CardBody>\n </Card>\n </>\n );\n}, () => [ Topics.visits, Topics.orphanVisits ]);\n","import { CsvJson } from 'csvjson';\nimport { ServerData } from '../data';\n\nconst validateServer = (server: any): server is ServerData =>\n typeof server.url === 'string' && typeof server.apiKey === 'string' && typeof server.name === 'string';\n\nconst validateServers = (servers: any): servers is ServerData[] =>\n Array.isArray(servers) && servers.every(validateServer);\n\nexport default class ServersImporter {\n public constructor(private readonly csvJson: CsvJson, private readonly fileReaderFactory: () => FileReader) {}\n\n public readonly importServersFromFile = async (file?: File | null): Promise<ServerData[]> => {\n if (!file) {\n throw new Error('No file provided');\n }\n\n const reader = this.fileReaderFactory();\n\n return new Promise((resolve, reject) => {\n reader.addEventListener('loadend', (e: ProgressEvent<FileReader>) => {\n try {\n // TODO Read as stream, otherwise, if the file is too big, this will block the browser tab\n const content = e.target?.result?.toString() ?? '';\n const servers = this.csvJson.toObject(content);\n\n if (!validateServers(servers)) {\n throw new Error('Provided file does not have the right format.');\n }\n\n resolve(servers);\n } catch (e) {\n reject(e);\n }\n });\n reader.readAsText(file);\n });\n };\n}\n","import { dissoc, values } from 'ramda';\nimport { CsvJson } from 'csvjson';\nimport LocalStorage from '../../utils/services/LocalStorage';\nimport { ServersMap } from '../data';\nimport { saveCsv } from '../../utils/helpers/files';\n\nconst SERVERS_FILENAME = 'shlink-servers.csv';\n\nexport default class ServersExporter {\n public constructor(\n private readonly storage: LocalStorage,\n private readonly window: Window,\n private readonly csvjson: CsvJson,\n ) {}\n\n public readonly exportServers = async () => {\n const servers = values(this.storage.get<ServersMap>('servers') ?? {}).map(dissoc('id'));\n\n try {\n const csv = this.csvjson.toCSV(servers, { headers: 'key' });\n\n saveCsv(this.window, csv, SERVERS_FILENAME);\n } catch (e) {\n // FIXME Handle error\n console.error(e); // eslint-disable-line no-console\n }\n };\n}\n","import csvjson from 'csvjson';\nimport Bottle, { Decorator } from 'bottlejs';\nimport CreateServer from '../CreateServer';\nimport ServersDropdown from '../ServersDropdown';\nimport DeleteServerModal from '../DeleteServerModal';\nimport DeleteServerButton from '../DeleteServerButton';\nimport { EditServer } from '../EditServer';\nimport ImportServersBtn from '../helpers/ImportServersBtn';\nimport { resetSelectedServer, selectServer } from '../reducers/selectedServer';\nimport { createServer, createServers, deleteServer, editServer } from '../reducers/servers';\nimport { fetchServers } from '../reducers/remoteServers';\nimport ForServerVersion from '../helpers/ForServerVersion';\nimport { ServerError } from '../helpers/ServerError';\nimport { ConnectDecorator } from '../../container/types';\nimport { withoutSelectedServer } from '../helpers/withoutSelectedServer';\nimport { Overview } from '../Overview';\nimport ServersImporter from './ServersImporter';\nimport ServersExporter from './ServersExporter';\n\nconst provideServices = (bottle: Bottle, connect: ConnectDecorator, withRouter: Decorator) => {\n // Components\n bottle.serviceFactory('CreateServer', CreateServer, 'ImportServersBtn', 'useStateFlagTimeout');\n bottle.decorator('CreateServer', withoutSelectedServer);\n bottle.decorator('CreateServer', connect([ 'selectedServer' ], [ 'createServer', 'resetSelectedServer' ]));\n\n bottle.serviceFactory('EditServer', EditServer, 'ServerError');\n bottle.decorator('EditServer', connect([ 'selectedServer' ], [ 'editServer', 'selectServer' ]));\n\n bottle.serviceFactory('ServersDropdown', ServersDropdown, 'ServersExporter');\n bottle.decorator('ServersDropdown', connect([ 'servers', 'selectedServer' ]));\n\n bottle.serviceFactory('DeleteServerModal', () => DeleteServerModal);\n bottle.decorator('DeleteServerModal', withRouter);\n bottle.decorator('DeleteServerModal', connect(null, [ 'deleteServer' ]));\n\n bottle.serviceFactory('DeleteServerButton', DeleteServerButton, 'DeleteServerModal');\n\n bottle.serviceFactory('ImportServersBtn', ImportServersBtn, 'ServersImporter');\n bottle.decorator('ImportServersBtn', connect(null, [ 'createServers' ]));\n\n bottle.serviceFactory('ForServerVersion', () => ForServerVersion);\n bottle.decorator('ForServerVersion', connect([ 'selectedServer' ]));\n\n bottle.serviceFactory('ServerError', ServerError, 'DeleteServerButton');\n bottle.decorator('ServerError', connect([ 'servers', 'selectedServer' ]));\n\n bottle.serviceFactory('Overview', Overview, 'ShortUrlsTable', 'CreateShortUrl', 'ForServerVersion');\n bottle.decorator('Overview', connect(\n [ 'shortUrlsList', 'tagsList', 'selectedServer', 'mercureInfo', 'visitsOverview' ],\n [ 'listShortUrls', 'listTags', 'createNewVisits', 'loadMercureInfo', 'loadVisitsOverview' ],\n ));\n\n // Services\n bottle.constant('csvjson', csvjson);\n bottle.constant('fileReaderFactory', () => new FileReader());\n bottle.service('ServersImporter', ServersImporter, 'csvjson', 'fileReaderFactory');\n bottle.service('ServersExporter', ServersExporter, 'Storage', 'window', 'csvjson');\n\n // Actions\n bottle.serviceFactory('selectServer', selectServer, 'buildShlinkApiClient', 'loadMercureInfo');\n bottle.serviceFactory('createServer', () => createServer);\n bottle.serviceFactory('createServers', () => createServers);\n bottle.serviceFactory('deleteServer', () => deleteServer);\n bottle.serviceFactory('editServer', () => editServer);\n bottle.serviceFactory('fetchServers', fetchServers, 'axios');\n\n bottle.serviceFactory('resetSelectedServer', () => resetSelectedServer);\n};\n\nexport default provideServices;\n","import { Button, Card } from 'reactstrap';\nimport { FC, ReactNode } from 'react';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faArrowLeft } from '@fortawesome/free-solid-svg-icons';\nimport ShortUrlVisitsCount from '../short-urls/helpers/ShortUrlVisitsCount';\nimport { ShortUrl } from '../short-urls/data';\nimport { Visit } from './types';\n\ninterface VisitsHeaderProps {\n visits: Visit[];\n goBack: () => void;\n title: ReactNode;\n shortUrl?: ShortUrl;\n}\n\nconst VisitsHeader: FC<VisitsHeaderProps> = ({ visits, goBack, shortUrl, children, title }) => (\n <header>\n <Card body>\n <h2 className=\"d-flex justify-content-between align-items-center mb-0\">\n <Button color=\"link\" size=\"lg\" className=\"p-0 mr-3\" onClick={goBack}>\n <FontAwesomeIcon icon={faArrowLeft} />\n </Button>\n <span className=\"text-center d-none d-sm-block\">\n <small>{title}</small>\n </span>\n <span className=\"badge badge-main ml-3\">\n Visits:{' '}\n <ShortUrlVisitsCount visitsCount={visits.length} shortUrl={shortUrl} />\n </span>\n </h2>\n <h3 className=\"text-center d-block d-sm-none mb-0 mt-3\">\n <small>{title}</small>\n </h3>\n\n {children && <div className=\"mt-md-2\">{children}</div>}\n </Card>\n </header>\n);\n\nexport default VisitsHeader;\n","import { UncontrolledTooltip } from 'reactstrap';\nimport { ExternalLink } from 'react-external-link';\nimport { ShortUrlDetail } from '../short-urls/reducers/shortUrlDetail';\nimport { Time } from '../utils/Time';\nimport { ShortUrlVisits } from './reducers/shortUrlVisits';\nimport VisitsHeader from './VisitsHeader';\nimport './ShortUrlVisitsHeader.scss';\n\ninterface ShortUrlVisitsHeaderProps {\n shortUrlDetail: ShortUrlDetail;\n shortUrlVisits: ShortUrlVisits;\n goBack: () => void;\n}\n\nconst ShortUrlVisitsHeader = ({ shortUrlDetail, shortUrlVisits, goBack }: ShortUrlVisitsHeaderProps) => {\n const { shortUrl, loading } = shortUrlDetail;\n const { visits } = shortUrlVisits;\n const shortLink = shortUrl?.shortUrl ?? '';\n const longLink = shortUrl?.longUrl ?? '';\n const title = shortUrl?.title;\n\n const renderDate = () => !shortUrl ? <small>Loading...</small> : (\n <span>\n <b id=\"created\" className=\"short-url-visits-header__created-at\">\n <Time date={shortUrl.dateCreated} relative />\n </b>\n <UncontrolledTooltip placement=\"bottom\" target=\"created\">\n <Time date={shortUrl.dateCreated} />\n </UncontrolledTooltip>\n </span>\n );\n const visitsStatsTitle = <>Visits for <ExternalLink href={shortLink} /></>;\n\n return (\n <VisitsHeader title={visitsStatsTitle} goBack={goBack} visits={visits} shortUrl={shortUrl}>\n <hr />\n <div>Created: {renderDate()}</div>\n <div>\n {`${title ? 'Title' : 'Long URL'}: `}\n {loading && <small>Loading...</small>}\n {!loading && <ExternalLink href={longLink}>{title ?? longLink}</ExternalLink>}\n </div>\n </VisitsHeader>\n );\n};\n\nexport default ShortUrlVisitsHeader;\n","import bowser from 'bowser';\nimport { zipObj } from 'ramda';\nimport { Empty, hasValue } from '../utils';\nimport { Stats, UserAgent } from '../../visits/types';\n\nconst DEFAULT = 'Others';\nconst BROWSERS_WHITELIST = [\n 'Android Browser',\n 'Chrome',\n 'Chromium',\n 'Firefox',\n 'Internet Explorer',\n 'Microsoft Edge',\n 'Opera',\n 'Safari',\n 'Samsung Internet for Android',\n 'Vivaldi',\n 'WeChat',\n];\n\nexport const parseUserAgent = (userAgent: string | Empty): UserAgent => {\n if (!hasValue(userAgent)) {\n return { browser: DEFAULT, os: DEFAULT };\n }\n\n const { browser: { name: browser }, os: { name: os } } = bowser.parse(userAgent);\n\n return { os: os ?? DEFAULT, browser: browser && BROWSERS_WHITELIST.includes(browser) ? browser : DEFAULT };\n};\n\nexport const extractDomain = (url: string | Empty): string => {\n if (!hasValue(url)) {\n return 'Direct';\n }\n\n return url.split('/')[url.includes('://') ? 2 : 0]?.split(':')[0] ?? '';\n};\n\nexport const fillTheGaps = (stats: Stats, labels: string[]): number[] =>\n Object.values({ ...zipObj(labels, labels.map(() => 0)), ...stats });\n","import { FC } from 'react';\nimport BooleanControl, { BooleanControlProps } from './BooleanControl';\n\nconst ToggleSwitch: FC<BooleanControlProps> = (props) => <BooleanControl type=\"switch\" {...props} />;\n\nexport default ToggleSwitch;\n","import { ActiveElement, ChartEvent, ChartType, TooltipItem } from 'chart.js';\nimport { prettify } from './numbers';\n\nexport const pointerOnHover = ({ native }: ChartEvent, [ firstElement ]: ActiveElement[]) => {\n if (!native?.target) {\n return;\n }\n\n const canvas = native.target as HTMLCanvasElement;\n\n canvas.style.cursor = firstElement ? 'pointer' : 'default';\n};\n\nexport const renderChartLabel = ({ dataset, formattedValue }: TooltipItem<ChartType>) =>\n `${dataset.label}: ${prettify(formattedValue)}`;\n\nexport const renderPieChartLabel = ({ label, formattedValue }: TooltipItem<ChartType>) =>\n `${label}: ${prettify(formattedValue)}`;\n","import { useState, useMemo } from 'react';\nimport {\n Card,\n CardHeader,\n CardBody,\n UncontrolledDropdown,\n DropdownToggle,\n DropdownMenu,\n DropdownItem,\n} from 'reactstrap';\nimport { Line } from 'react-chartjs-2';\nimport { always, cond, countBy, reverse } from 'ramda';\nimport {\n add,\n differenceInDays,\n differenceInHours,\n differenceInMonths,\n differenceInWeeks,\n parseISO,\n format,\n startOfISOWeek,\n endOfISOWeek,\n} from 'date-fns';\nimport { ChartData, ChartDataset, ChartOptions } from 'chart.js';\nimport { NormalizedVisit, Stats } from '../types';\nimport { fillTheGaps } from '../../utils/helpers/visits';\nimport { useToggle } from '../../utils/helpers/hooks';\nimport { rangeOf } from '../../utils/utils';\nimport ToggleSwitch from '../../utils/ToggleSwitch';\nimport { prettify } from '../../utils/helpers/numbers';\nimport { pointerOnHover, renderChartLabel } from '../../utils/helpers/charts';\nimport { HIGHLIGHTED_COLOR, MAIN_COLOR } from '../../utils/theme';\nimport './LineChartCard.scss';\n\ninterface LineChartCardProps {\n title: string;\n highlightedLabel?: string;\n visits: NormalizedVisit[];\n highlightedVisits: NormalizedVisit[];\n setSelectedVisits?: (visits: NormalizedVisit[]) => void;\n}\n\ntype Step = 'monthly' | 'weekly' | 'daily' | 'hourly';\n\nconst STEPS_MAP: Record<Step, string> = {\n monthly: 'Month',\n weekly: 'Week',\n daily: 'Day',\n hourly: 'Hour',\n};\n\nconst STEP_TO_DURATION_MAP: Record<Step, (amount: number) => Duration> = {\n hourly: (hours: number) => ({ hours }),\n daily: (days: number) => ({ days }),\n weekly: (weeks: number) => ({ weeks }),\n monthly: (months: number) => ({ months }),\n};\n\nconst STEP_TO_DIFF_FUNC_MAP: Record<Step, (dateLeft: Date, dateRight: Date) => number> = {\n hourly: differenceInHours,\n daily: differenceInDays,\n weekly: differenceInWeeks,\n monthly: differenceInMonths,\n};\n\nconst STEP_TO_DATE_FORMAT: Record<Step, (date: Date) => string> = {\n hourly: (date) => format(date, 'yyyy-MM-dd HH:00'),\n daily: (date) => format(date, 'yyyy-MM-dd'),\n weekly(date) {\n const firstWeekDay = format(startOfISOWeek(date), 'yyyy-MM-dd');\n const lastWeekDay = format(endOfISOWeek(date), 'yyyy-MM-dd');\n\n return `${firstWeekDay} - ${lastWeekDay}`;\n },\n monthly: (date) => format(date, 'yyyy-MM'),\n};\n\nconst determineInitialStep = (oldestVisitDate: string): Step => {\n const now = new Date();\n const oldestDate = parseISO(oldestVisitDate);\n const matcher = cond<never, Step | undefined>([\n [ () => differenceInDays(now, oldestDate) <= 2, always<Step>('hourly') ], // Less than 2 days\n [ () => differenceInMonths(now, oldestDate) <= 1, always<Step>('daily') ], // Between 2 days and 1 month\n [ () => differenceInMonths(now, oldestDate) <= 6, always<Step>('weekly') ], // Between 1 and 6 months\n ]);\n\n return matcher() ?? 'monthly';\n};\n\nconst groupVisitsByStep = (step: Step, visits: NormalizedVisit[]): Stats => countBy(\n (visit) => STEP_TO_DATE_FORMAT[step](parseISO(visit.date)),\n visits,\n);\n\nconst visitsToDatasetGroups = (step: Step, visits: NormalizedVisit[]) =>\n visits.reduce<Record<string, NormalizedVisit[]>>(\n (acc, visit) => {\n const key = STEP_TO_DATE_FORMAT[step](parseISO(visit.date));\n\n acc[key] = acc[key] ?? [];\n acc[key].push(visit);\n\n return acc;\n },\n {},\n );\n\nconst generateLabels = (step: Step, visits: NormalizedVisit[]): string[] => {\n const diffFunc = STEP_TO_DIFF_FUNC_MAP[step];\n const formatter = STEP_TO_DATE_FORMAT[step];\n const newerDate = parseISO(visits[0].date);\n const oldestDate = parseISO(visits[visits.length - 1].date);\n const size = diffFunc(newerDate, oldestDate);\n const duration = STEP_TO_DURATION_MAP[step];\n\n return [\n formatter(oldestDate),\n ...rangeOf(size, (num) => formatter(add(oldestDate, duration(num)))),\n ];\n};\n\nconst generateLabelsAndGroupedVisits = (\n visits: NormalizedVisit[],\n groupedVisitsWithGaps: Stats,\n step: Step,\n skipNoElements: boolean,\n): [string[], number[]] => {\n if (skipNoElements) {\n return [ Object.keys(groupedVisitsWithGaps), Object.values(groupedVisitsWithGaps) ];\n }\n\n const labels = generateLabels(step, visits);\n\n return [ labels, fillTheGaps(groupedVisitsWithGaps, labels) ];\n};\n\nconst generateDataset = (data: number[], label: string, color: string): ChartDataset => ({\n label,\n data,\n fill: false,\n tension: 0.2,\n borderColor: color,\n backgroundColor: color,\n});\n\nlet selectedLabel: string | null = null;\n\nconst chartElementAtEvent = (\n labels: string[],\n datasetsByPoint: Record<string, NormalizedVisit[]>,\n setSelectedVisits?: (visits: NormalizedVisit[]) => void,\n) => ([ chart ]: [{ index: number }]) => {\n if (!setSelectedVisits || !chart) {\n return;\n }\n\n const { index } = chart;\n\n if (selectedLabel === labels[index]) {\n setSelectedVisits([]);\n selectedLabel = null;\n } else {\n setSelectedVisits(labels[index] && datasetsByPoint[labels[index]] || []);\n selectedLabel = labels[index] ?? null;\n }\n};\n\nconst LineChartCard = (\n { title, visits, highlightedVisits, highlightedLabel = 'Selected', setSelectedVisits }: LineChartCardProps,\n) => {\n const [ step, setStep ] = useState<Step>(\n visits.length > 0 ? determineInitialStep(visits[visits.length - 1].date) : 'monthly',\n );\n const [ skipNoVisits, toggleSkipNoVisits ] = useToggle(true);\n\n const datasetsByPoint = useMemo(() => visitsToDatasetGroups(step, visits), [ step, visits ]);\n const groupedVisitsWithGaps = useMemo(() => groupVisitsByStep(step, reverse(visits)), [ step, visits ]);\n const [ labels, groupedVisits ] = useMemo(\n () => generateLabelsAndGroupedVisits(visits, groupedVisitsWithGaps, step, skipNoVisits),\n [ visits, step, skipNoVisits ],\n );\n const groupedHighlighted = useMemo(\n () => fillTheGaps(groupVisitsByStep(step, reverse(highlightedVisits)), labels),\n [ highlightedVisits, step, labels ],\n );\n const generateChartDatasets = (): ChartDataset[] => {\n const mainDataset = generateDataset(groupedVisits, 'Visits', MAIN_COLOR);\n\n if (highlightedVisits.length === 0) {\n return [ mainDataset ];\n }\n\n const highlightedDataset = generateDataset(groupedHighlighted, highlightedLabel, HIGHLIGHTED_COLOR);\n\n return [ mainDataset, highlightedDataset ];\n };\n const generateChartData = (): ChartData => ({ labels, datasets: generateChartDatasets() });\n\n const options: ChartOptions = {\n maintainAspectRatio: false,\n plugins: {\n legend: { display: false },\n tooltip: {\n intersect: false,\n axis: 'x',\n callbacks: { label: renderChartLabel },\n },\n },\n scales: {\n y: {\n beginAtZero: true,\n ticks: {\n precision: 0,\n callback: prettify,\n },\n },\n x: {\n title: { display: true, text: STEPS_MAP[step] },\n },\n },\n onHover: pointerOnHover,\n };\n const renderLineChart = () => (\n <Line\n data={generateChartData()}\n options={options}\n getElementAtEvent={chartElementAtEvent(labels, datasetsByPoint, setSelectedVisits) as any}\n />\n );\n\n return (\n <Card>\n <CardHeader>\n {title}\n <div className=\"float-right\">\n <UncontrolledDropdown>\n <DropdownToggle caret color=\"link\" className=\"btn-sm p-0\">\n Group by\n </DropdownToggle>\n <DropdownMenu right>\n {Object.entries(STEPS_MAP).map(([ value, menuText ]) => (\n <DropdownItem key={value} active={step === value} onClick={() => setStep(value as Step)}>\n {menuText}\n </DropdownItem>\n ))}\n </DropdownMenu>\n </UncontrolledDropdown>\n </div>\n <div className=\"float-right mr-2\">\n <ToggleSwitch checked={skipNoVisits} onChange={toggleSkipNoVisits}>\n <small>Skip dates with no visits</small>\n </ToggleSwitch>\n </div>\n </CardHeader>\n <CardBody className=\"line-chart-card__body\">\n {/* It's VERY IMPORTANT to render two different components here, as one has 1 dataset and the other has 2 */}\n {/* Using the same component causes a crash when switching from 1 to 2 datasets, and then back to 1 dataset */}\n {highlightedVisits.length > 0 && renderLineChart()}\n {highlightedVisits.length === 0 && renderLineChart()}\n </CardBody>\n </Card>\n );\n};\n\nexport default LineChartCard;\n","import { FC } from 'react';\nimport classNames from 'classnames';\nimport { Pagination, PaginationItem, PaginationLink } from 'reactstrap';\nimport {\n pageIsEllipsis,\n keyForPage,\n NumberOrEllipsis,\n progressivePagination,\n prettifyPageNumber,\n} from '../utils/helpers/pagination';\nimport './SimplePaginator.scss';\n\ninterface SimplePaginatorProps {\n pagesCount: number;\n currentPage: number;\n setCurrentPage: (currentPage: number) => void;\n centered?: boolean;\n}\n\nconst SimplePaginator: FC<SimplePaginatorProps> = ({ pagesCount, currentPage, setCurrentPage, centered = true }) => {\n if (pagesCount < 2) {\n return null;\n }\n\n const onClick = (page: NumberOrEllipsis) => () => !pageIsEllipsis(page) && setCurrentPage(page);\n\n return (\n <Pagination listClassName={classNames('flex-wrap mb-0 simple-paginator', { 'justify-content-center': centered })}>\n <PaginationItem disabled={currentPage <= 1}>\n <PaginationLink previous tag=\"span\" onClick={onClick(currentPage - 1)} />\n </PaginationItem>\n {progressivePagination(currentPage, pagesCount).map((pageNumber, index) => (\n <PaginationItem\n key={keyForPage(pageNumber, index)}\n disabled={pageIsEllipsis(pageNumber)}\n active={currentPage === pageNumber}\n >\n <PaginationLink tag=\"span\" onClick={onClick(pageNumber)}>{prettifyPageNumber(pageNumber)}</PaginationLink>\n </PaginationItem>\n ))}\n <PaginationItem disabled={currentPage >= pagesCount}>\n <PaginationLink next tag=\"span\" onClick={onClick(currentPage + 1)} />\n </PaginationItem>\n </Pagination>\n );\n};\n\nexport default SimplePaginator;\n","import { useEffect, useMemo, useState, useRef } from 'react';\nimport classNames from 'classnames';\nimport { min, splitEvery } from 'ramda';\nimport {\n faCaretDown as caretDownIcon,\n faCaretUp as caretUpIcon,\n faCheck as checkIcon,\n faRobot as botIcon,\n} from '@fortawesome/free-solid-svg-icons';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { UncontrolledTooltip } from 'reactstrap';\nimport SimplePaginator from '../common/SimplePaginator';\nimport SearchField from '../utils/SearchField';\nimport { determineOrderDir, OrderDir } from '../utils/utils';\nimport { prettify } from '../utils/helpers/numbers';\nimport { supportsBotVisits } from '../utils/helpers/features';\nimport { SelectedServer } from '../servers/data';\nimport { Time } from '../utils/Time';\nimport { NormalizedOrphanVisit, NormalizedVisit } from './types';\nimport './VisitsTable.scss';\n\nexport interface VisitsTableProps {\n visits: NormalizedVisit[];\n selectedVisits?: NormalizedVisit[];\n setSelectedVisits: (visits: NormalizedVisit[]) => void;\n matchMedia?: (query: string) => MediaQueryList;\n isOrphanVisits?: boolean;\n selectedServer: SelectedServer;\n}\n\ntype OrderableFields = 'date' | 'country' | 'city' | 'browser' | 'os' | 'referer' | 'visitedUrl' | 'potentialBot';\n\ninterface Order {\n field?: OrderableFields;\n dir?: OrderDir;\n}\n\nconst PAGE_SIZE = 20;\nconst visitMatchesSearch = ({ browser, os, referer, country, city, ...rest }: NormalizedVisit, searchTerm: string) =>\n `${browser} ${os} ${referer} ${country} ${city} ${(rest as NormalizedOrphanVisit).visitedUrl}`.toLowerCase().includes(\n searchTerm.toLowerCase(),\n );\nconst searchVisits = (searchTerm: string, visits: NormalizedVisit[]) =>\n visits.filter((visit) => visitMatchesSearch(visit, searchTerm));\nconst sortVisits = ({ field, dir }: Order, visits: NormalizedVisit[]) => !field || !dir ? visits : visits.sort(\n (a, b) => {\n const greaterThan = dir === 'ASC' ? 1 : -1;\n const smallerThan = dir === 'ASC' ? -1 : 1;\n\n return (a as NormalizedOrphanVisit)[field] > (b as NormalizedOrphanVisit)[field] ? greaterThan : smallerThan;\n },\n);\nconst calculateVisits = (allVisits: NormalizedVisit[], searchTerm: string | undefined, order: Order) => {\n const filteredVisits = searchTerm ? searchVisits(searchTerm, allVisits) : [ ...allVisits ];\n const sortedVisits = sortVisits(order, filteredVisits);\n const total = sortedVisits.length;\n const visitsGroups = splitEvery(PAGE_SIZE, sortedVisits);\n\n return { visitsGroups, total };\n};\n\nconst VisitsTable = ({\n visits,\n selectedVisits = [],\n setSelectedVisits,\n selectedServer,\n matchMedia = window.matchMedia,\n isOrphanVisits = false,\n}: VisitsTableProps) => {\n const headerCellsClass = 'visits-table__header-cell visits-table__sticky';\n const matchMobile = () => matchMedia('(max-width: 767px)').matches;\n\n const [ isMobileDevice, setIsMobileDevice ] = useState(matchMobile());\n const [ searchTerm, setSearchTerm ] = useState<string | undefined>(undefined);\n const [ order, setOrder ] = useState<Order>({ field: undefined, dir: undefined });\n const resultSet = useMemo(() => calculateVisits(visits, searchTerm, order), [ searchTerm, order ]);\n const isFirstLoad = useRef(true);\n const [ page, setPage ] = useState(1);\n const end = page * PAGE_SIZE;\n const start = end - PAGE_SIZE;\n const supportsBots = supportsBotVisits(selectedServer);\n const fullSizeColSpan = 7 + Number(supportsBots) + Number(isOrphanVisits);\n\n const orderByColumn = (field: OrderableFields) =>\n () => setOrder({ field, dir: determineOrderDir(field, order.field, order.dir) });\n const renderOrderIcon = (field: OrderableFields) => order.dir && order.field === field && (\n <FontAwesomeIcon\n icon={order.dir === 'ASC' ? caretUpIcon : caretDownIcon}\n className=\"visits-table__header-icon\"\n />\n );\n\n useEffect(() => {\n const listener = () => setIsMobileDevice(matchMobile());\n\n window.addEventListener('resize', listener);\n\n return () => window.removeEventListener('resize', listener);\n }, []);\n useEffect(() => {\n setPage(1);\n\n !isFirstLoad.current && setSelectedVisits([]);\n isFirstLoad.current = false;\n }, [ searchTerm ]);\n\n return (\n <table className=\"table table-bordered table-hover table-sm table-responsive-sm visits-table\">\n <thead className=\"visits-table__header\">\n <tr>\n <th\n className={`${headerCellsClass} text-center`}\n onClick={() => setSelectedVisits(\n selectedVisits.length < resultSet.total ? resultSet.visitsGroups.flat() : [],\n )}\n >\n <FontAwesomeIcon icon={checkIcon} className={classNames({ 'text-primary': selectedVisits.length > 0 })} />\n </th>\n {supportsBots && (\n <th className={`${headerCellsClass} text-center`} onClick={orderByColumn('potentialBot')}>\n <FontAwesomeIcon icon={botIcon} />\n {renderOrderIcon('potentialBot')}\n </th>\n )}\n <th className={headerCellsClass} onClick={orderByColumn('date')}>\n Date\n {renderOrderIcon('date')}\n </th>\n <th className={headerCellsClass} onClick={orderByColumn('country')}>\n Country\n {renderOrderIcon('country')}\n </th>\n <th className={headerCellsClass} onClick={orderByColumn('city')}>\n City\n {renderOrderIcon('city')}\n </th>\n <th className={headerCellsClass} onClick={orderByColumn('browser')}>\n Browser\n {renderOrderIcon('browser')}\n </th>\n <th className={headerCellsClass} onClick={orderByColumn('os')}>\n OS\n {renderOrderIcon('os')}\n </th>\n <th className={headerCellsClass} onClick={orderByColumn('referer')}>\n Referrer\n {renderOrderIcon('referer')}\n </th>\n {isOrphanVisits && (\n <th className={headerCellsClass} onClick={orderByColumn('visitedUrl')}>\n Visited URL\n {renderOrderIcon('visitedUrl')}\n </th>\n )}\n </tr>\n <tr>\n <td colSpan={fullSizeColSpan} className=\"p-0\">\n <SearchField noBorder large={false} onChange={setSearchTerm} />\n </td>\n </tr>\n </thead>\n <tbody>\n {!resultSet.visitsGroups[page - 1]?.length && (\n <tr>\n <td colSpan={fullSizeColSpan} className=\"text-center\">\n No visits found with current filtering\n </td>\n </tr>\n )}\n {resultSet.visitsGroups[page - 1]?.map((visit, index) => {\n const isSelected = selectedVisits.includes(visit);\n\n return (\n <tr\n key={index}\n style={{ cursor: 'pointer' }}\n className={classNames({ 'table-active': isSelected })}\n onClick={() => setSelectedVisits(\n isSelected ? selectedVisits.filter((v) => v !== visit) : [ ...selectedVisits, visit ],\n )}\n >\n <td className=\"text-center\">\n {isSelected && <FontAwesomeIcon icon={checkIcon} className=\"text-primary\" />}\n </td>\n {supportsBots && (\n <td className=\"text-center\">\n {visit.potentialBot && (\n <>\n <FontAwesomeIcon icon={botIcon} id={`botIcon${index}`} />\n <UncontrolledTooltip placement=\"right\" target={`botIcon${index}`}>\n Potentially a visit from a bot or crawler\n </UncontrolledTooltip>\n </>\n )}\n </td>\n )}\n <td><Time date={visit.date} /></td>\n <td>{visit.country}</td>\n <td>{visit.city}</td>\n <td>{visit.browser}</td>\n <td>{visit.os}</td>\n <td>{visit.referer}</td>\n {isOrphanVisits && <td>{(visit as NormalizedOrphanVisit).visitedUrl}</td>}\n </tr>\n );\n })}\n </tbody>\n {resultSet.total > PAGE_SIZE && (\n <tfoot>\n <tr>\n <td colSpan={fullSizeColSpan} className=\"visits-table__footer-cell visits-table__sticky\">\n <div className=\"row\">\n <div className=\"col-md-6\">\n <SimplePaginator\n pagesCount={Math.ceil(resultSet.total / PAGE_SIZE)}\n currentPage={page}\n setCurrentPage={setPage}\n centered={isMobileDevice}\n />\n </div>\n <div\n className={classNames('col-md-6', {\n 'd-flex align-items-center flex-row-reverse': !isMobileDevice,\n 'text-center mt-3': isMobileDevice,\n })}\n >\n <div>\n Visits <b>{prettify(start + 1)}</b> to{' '}\n <b>{prettify(min(end, resultSet.total))}</b> of{' '}\n <b>{prettify(resultSet.total)}</b>\n </div>\n </div>\n </div>\n </td>\n </tr>\n </tfoot>\n )}\n </table>\n );\n};\n\nexport default VisitsTable;\n","import { FC } from 'react';\nimport { Modal, ModalBody } from 'reactstrap';\nimport { MapContainer, TileLayer, Marker, Popup, MapContainerProps } from 'react-leaflet';\nimport { prop } from 'ramda';\nimport { CityStats } from '../types';\nimport './MapModal.scss';\n\ninterface MapModalProps {\n toggle: () => void;\n isOpen: boolean;\n title: string;\n locations?: CityStats[];\n}\n\nconst OpenStreetMapTile: FC = () => (\n <TileLayer\n attribution='&amp;copy <a href=\"http://osm.org/copyright\">OpenStreetMap</a> contributors'\n url=\"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png\"\n />\n);\n\nconst calculateMapProps = (locations: CityStats[]): MapContainerProps => {\n if (locations.length === 0) {\n return {};\n }\n\n if (locations.length > 1) {\n return { bounds: locations.map(prop('latLong')) };\n }\n\n // When there's only one location, an error is thrown if trying to calculate the bounds.\n // When that happens, we use zoom and center as a workaround\n const [{ latLong: center }] = locations;\n\n return { zoom: 10, center };\n};\n\nconst MapModal = ({ toggle, isOpen, title, locations = [] }: MapModalProps) => (\n <Modal toggle={toggle} isOpen={isOpen} className=\"map-modal__modal\" contentClassName=\"map-modal__modal-content\">\n <ModalBody className=\"map-modal__modal-body\">\n <h3 className=\"map-modal__modal-title\">\n {title}\n <button type=\"button\" className=\"close\" onClick={toggle}>&times;</button>\n </h3>\n <MapContainer {...calculateMapProps(locations)}>\n <OpenStreetMapTile />\n {locations.map(({ cityName, latLong, count }, index) => (\n <Marker key={index} position={latLong}>\n <Popup><b>{count}</b> visit{count > 1 ? 's' : ''} from <b>{cityName}</b></Popup>\n </Marker>\n ))}\n </MapContainer>\n </ModalBody>\n </Modal>\n);\n\nexport default MapModal;\n","import { useRef, useState } from 'react';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faMapMarkedAlt as mapIcon } from '@fortawesome/free-solid-svg-icons';\nimport { Dropdown, DropdownItem, DropdownMenu, UncontrolledTooltip } from 'reactstrap';\nimport { useToggle } from '../../utils/helpers/hooks';\nimport { CityStats } from '../types';\nimport MapModal from './MapModal';\nimport './OpenMapModalBtn.scss';\n\ninterface OpenMapModalBtnProps {\n modalTitle: string;\n activeCities: string[];\n locations?: CityStats[];\n}\n\nconst OpenMapModalBtn = ({ modalTitle, activeCities, locations = [] }: OpenMapModalBtnProps) => {\n const [ mapIsOpened, , openMap, closeMap ] = useToggle();\n const [ dropdownIsOpened, toggleDropdown, openDropdown ] = useToggle();\n const [ locationsToShow, setLocationsToShow ] = useState<CityStats[]>([]);\n const buttonRef = useRef<HTMLElement>();\n\n const filterLocations = (cities: CityStats[]) => cities.filter(({ cityName }) => activeCities.includes(cityName));\n const onClick = () => {\n if (!activeCities) {\n setLocationsToShow(locations);\n openMap();\n\n return;\n }\n\n openDropdown();\n };\n const openMapWithLocations = (filtered: boolean) => () => {\n setLocationsToShow(filtered ? filterLocations(locations) : locations);\n openMap();\n };\n\n return (\n <>\n <button className=\"btn btn-link open-map-modal-btn__btn\" ref={buttonRef as any} onClick={onClick}>\n <FontAwesomeIcon icon={mapIcon} />\n </button>\n <UncontrolledTooltip placement=\"left\" target={(() => buttonRef.current) as any}>Show in map</UncontrolledTooltip>\n <Dropdown isOpen={dropdownIsOpened} toggle={toggleDropdown} inNavbar>\n <DropdownMenu right>\n <DropdownItem onClick={openMapWithLocations(false)}>Show all locations</DropdownItem>\n <DropdownItem onClick={openMapWithLocations(true)}>Show locations in current page</DropdownItem>\n </DropdownMenu>\n </Dropdown>\n <MapModal toggle={closeMap} isOpen={mapIsOpened} title={modalTitle} locations={locationsToShow} />\n </>\n );\n};\n\nexport default OpenMapModalBtn;\n","import { countBy, groupBy, pipe, prop } from 'ramda';\nimport { formatIsoDate } from '../../utils/helpers/date';\nimport { ShlinkVisitsParams } from '../../api/types';\nimport { CreateVisit, NormalizedOrphanVisit, NormalizedVisit, OrphanVisit, Stats, Visit, VisitsParams } from './index';\n\nexport const isOrphanVisit = (visit: Visit): visit is OrphanVisit => visit.hasOwnProperty('visitedUrl');\n\nexport const isNormalizedOrphanVisit = (visit: NormalizedVisit): visit is NormalizedOrphanVisit =>\n visit.hasOwnProperty('visitedUrl');\n\nexport interface GroupedNewVisits {\n orphanVisits: CreateVisit[];\n regularVisits: CreateVisit[];\n}\n\nexport const groupNewVisitsByType = pipe(\n groupBy((newVisit: CreateVisit) => isOrphanVisit(newVisit.visit) ? 'orphanVisits' : 'regularVisits'),\n // @ts-expect-error Type declaration on groupBy is not correct. It can return undefined props\n (result): GroupedNewVisits => ({ orphanVisits: [], regularVisits: [], ...result }),\n);\n\nexport type HighlightableProps<T extends NormalizedVisit> = T extends NormalizedOrphanVisit\n ? ('referer' | 'country' | 'city' | 'visitedUrl')\n : ('referer' | 'country' | 'city');\n\nexport const highlightedVisitsToStats = <T extends NormalizedVisit>(\n highlightedVisits: T[],\n property: HighlightableProps<T>,\n): Stats => countBy(prop(property) as any, highlightedVisits);\n\nexport const toApiParams = ({ page, itemsPerPage, filter, dateRange }: VisitsParams): ShlinkVisitsParams => {\n const startDate = (dateRange?.startDate && formatIsoDate(dateRange?.startDate)) ?? undefined;\n const endDate = (dateRange?.endDate && formatIsoDate(dateRange?.endDate)) ?? undefined;\n const excludeBots = filter?.excludeBots || undefined; // eslint-disable-line @typescript-eslint/prefer-nullish-coalescing\n\n return { page, itemsPerPage, startDate, endDate, excludeBots };\n};\n","import { isNil, map } from 'ramda';\nimport { extractDomain, parseUserAgent } from '../../utils/helpers/visits';\nimport { hasValue } from '../../utils/utils';\nimport { CityStats, NormalizedVisit, Stats, Visit, VisitsStats } from '../types';\nimport { isNormalizedOrphanVisit, isOrphanVisit } from '../types/helpers';\n\nconst visitHasProperty = (visit: NormalizedVisit, propertyName: keyof NormalizedVisit) =>\n !isNil(visit) && hasValue(visit[propertyName]);\n\nconst optionalNumericToNumber = (numeric: string | number | null | undefined): number => {\n if (typeof numeric === 'number') {\n return numeric;\n }\n\n return numeric ? parseFloat(numeric) : 0;\n};\n\nconst updateOsStatsForVisit = (osStats: Stats, { os }: NormalizedVisit) => {\n osStats[os] = (osStats[os] || 0) + 1;\n};\n\nconst updateBrowsersStatsForVisit = (browsersStats: Stats, { browser }: NormalizedVisit) => {\n browsersStats[browser] = (browsersStats[browser] || 0) + 1;\n};\n\nconst updateReferrersStatsForVisit = (referrersStats: Stats, { referer: domain }: NormalizedVisit) => {\n referrersStats[domain] = (referrersStats[domain] || 0) + 1;\n};\n\nconst updateLocationsStatsForVisit = (propertyName: 'country' | 'city') => (stats: Stats, visit: NormalizedVisit) => {\n const hasLocationProperty = visitHasProperty(visit, propertyName);\n const value = hasLocationProperty ? visit[propertyName] : 'Unknown';\n\n stats[value] = (stats[value] || 0) + 1;\n};\n\nconst updateCountriesStatsForVisit = updateLocationsStatsForVisit('country');\nconst updateCitiesStatsForVisit = updateLocationsStatsForVisit('city');\n\nconst updateCitiesForMapForVisit = (citiesForMapStats: Record<string, CityStats>, visit: NormalizedVisit) => {\n if (!visitHasProperty(visit, 'city') || visit.city === 'Unknown') {\n return;\n }\n\n const { city, latitude, longitude } = visit;\n const currentCity = citiesForMapStats[city] || {\n cityName: city,\n count: 0,\n latLong: [ optionalNumericToNumber(latitude), optionalNumericToNumber(longitude) ],\n };\n\n currentCity.count++;\n\n citiesForMapStats[city] = currentCity;\n};\n\nconst updateVisitedUrlsForVisit = (visitedUrlsStats: Stats, visit: NormalizedVisit) => {\n if (!isNormalizedOrphanVisit(visit)) {\n return;\n }\n\n const { visitedUrl } = visit;\n\n visitedUrlsStats[visitedUrl] = (visitedUrlsStats[visitedUrl] || 0) + 1;\n};\n\nexport const processStatsFromVisits = (visits: NormalizedVisit[]) => visits.reduce(\n (stats: VisitsStats, visit: NormalizedVisit) => {\n // We mutate the original object because it has a big performance impact when large data sets are processed\n updateOsStatsForVisit(stats.os, visit);\n updateBrowsersStatsForVisit(stats.browsers, visit);\n updateReferrersStatsForVisit(stats.referrers, visit);\n updateCountriesStatsForVisit(stats.countries, visit);\n updateCitiesStatsForVisit(stats.cities, visit);\n updateCitiesForMapForVisit(stats.citiesForMap, visit);\n updateVisitedUrlsForVisit(stats.visitedUrls, visit);\n\n return stats;\n },\n { os: {}, browsers: {}, referrers: {}, countries: {}, cities: {}, citiesForMap: {}, visitedUrls: {} },\n);\n\nexport const normalizeVisits = map((visit: Visit): NormalizedVisit => {\n const { userAgent, date, referer, visitLocation, potentialBot = false } = visit;\n const common = {\n date,\n potentialBot,\n ...parseUserAgent(userAgent),\n referer: extractDomain(referer),\n country: visitLocation?.countryName || 'Unknown', // eslint-disable-line @typescript-eslint/prefer-nullish-coalescing\n city: visitLocation?.cityName || 'Unknown', // eslint-disable-line @typescript-eslint/prefer-nullish-coalescing\n latitude: visitLocation?.latitude,\n longitude: visitLocation?.longitude,\n };\n\n if (!isOrphanVisit(visit)) {\n return common;\n }\n\n return { ...common, type: visit.type, visitedUrl: visit.visitedUrl };\n});\n\nexport interface VisitsParser {\n processStatsFromVisits: (normalizedVisits: NormalizedVisit[]) => VisitsStats;\n normalizeVisits: (visits: Visit[]) => NormalizedVisit[];\n}\n","import { DropdownItem, DropdownItemProps } from 'reactstrap'; // eslint-disable-line import/named\nimport { OrphanVisitType, VisitsFilter } from '../types';\nimport { DropdownBtn } from '../../utils/DropdownBtn';\nimport { hasValue } from '../../utils/utils';\n\ninterface VisitsFilterDropdownProps {\n onChange: (filters: VisitsFilter) => void;\n selected?: VisitsFilter;\n className?: string;\n isOrphanVisits: boolean;\n botsSupported: boolean;\n}\n\nexport const VisitsFilterDropdown = (\n { onChange, selected = {}, className, isOrphanVisits, botsSupported }: VisitsFilterDropdownProps,\n) => {\n if (!botsSupported && !isOrphanVisits) {\n return null;\n }\n\n const { orphanVisitsType, excludeBots = false } = selected;\n const propsForOrphanVisitsTypeItem = (type: OrphanVisitType): DropdownItemProps => ({\n active: orphanVisitsType === type,\n onClick: () => onChange({ ...selected, orphanVisitsType: type === selected?.orphanVisitsType ? undefined : type }),\n });\n const onBotsClick = () => onChange({ ...selected, excludeBots: !selected?.excludeBots });\n\n return (\n <DropdownBtn text=\"Filters\" dropdownClassName={className} className=\"mr-3\" right minWidth={250}>\n {botsSupported && (\n <>\n <DropdownItem header>Bots:</DropdownItem>\n <DropdownItem active={excludeBots} onClick={onBotsClick}>Exclude potential bots</DropdownItem>\n </>\n )}\n\n {botsSupported && isOrphanVisits && <DropdownItem divider />}\n\n {isOrphanVisits && (\n <>\n <DropdownItem header>Orphan visits type:</DropdownItem>\n <DropdownItem {...propsForOrphanVisitsTypeItem('base_url')}>Base URL</DropdownItem>\n <DropdownItem {...propsForOrphanVisitsTypeItem('invalid_short_url')}>Invalid short URL</DropdownItem>\n <DropdownItem {...propsForOrphanVisitsTypeItem('regular_404')}>Regular 404</DropdownItem>\n </>\n )}\n\n <DropdownItem divider />\n <DropdownItem disabled={!hasValue(selected)} onClick={() => onChange({})}><i>Clear filters</i></DropdownItem>\n </DropdownBtn>\n );\n};\n","import { FC } from 'react';\nimport { Chart } from 'chart.js';\nimport './DoughnutChartLegend.scss';\n\ninterface DoughnutChartLegendProps {\n chart: Chart;\n}\n\nexport const DoughnutChartLegend: FC<DoughnutChartLegendProps> = ({ chart }) => {\n const { config } = chart;\n const { labels = [], datasets = [] } = config.data ?? {};\n const [{ backgroundColor: colors }] = datasets;\n const { defaultColor } = config.options ?? {} as any;\n\n return (\n <ul className=\"doughnut-chart-legend\">\n {(labels as string[]).map((label, index) => (\n <li key={label} className=\"doughnut-chart-legend__item d-flex\">\n <div\n className=\"doughnut-chart-legend__item-color\"\n style={{ backgroundColor: (colors as string[])[index] ?? defaultColor }}\n />\n <small className=\"doughnut-chart-legend__item-text flex-fill\">{label}</small>\n </li>\n ))}\n </ul>\n );\n};\n","import { FC, useState, memo } from 'react';\nimport { Chart, ChartData, ChartDataset, ChartOptions } from 'chart.js';\nimport { keys, values } from 'ramda';\nimport { Doughnut } from 'react-chartjs-2';\nimport { renderPieChartLabel } from '../../utils/helpers/charts';\nimport { isDarkThemeEnabled, PRIMARY_DARK_COLOR, PRIMARY_LIGHT_COLOR } from '../../utils/theme';\nimport { Stats } from '../types';\nimport { DoughnutChartLegend } from './DoughnutChartLegend';\n\ninterface DoughnutChartProps {\n stats: Stats;\n}\n\nconst generateChartDatasets = (data: number[]): ChartDataset[] => [\n {\n data,\n backgroundColor: [\n '#97BBCD',\n '#F7464A',\n '#46BFBD',\n '#FDB45C',\n '#949FB1',\n '#57A773',\n '#414066',\n '#08B2E3',\n '#B6C454',\n '#DCDCDC',\n '#463730',\n ],\n borderColor: isDarkThemeEnabled() ? PRIMARY_DARK_COLOR : PRIMARY_LIGHT_COLOR,\n borderWidth: 2,\n },\n];\nconst generateChartData = (labels: string[], data: number[]): ChartData => ({\n labels,\n datasets: generateChartDatasets(data),\n});\n\nexport const DoughnutChart: FC<DoughnutChartProps> = memo(({ stats }) => {\n const [ chartRef, setChartRef ] = useState<Chart | undefined>(); // Cannot use useRef here\n const labels = keys(stats);\n const data = values(stats);\n\n const options: ChartOptions = {\n plugins: {\n legend: { display: false },\n tooltip: {\n intersect: true,\n callbacks: { label: renderPieChartLabel },\n },\n },\n };\n const chartData = generateChartData(labels, data);\n\n return (\n <div className=\"row\">\n <div className=\"col-sm-12 col-md-7\">\n <Doughnut\n height={300}\n data={chartData}\n options={options}\n ref={(element) => {\n setChartRef(element ?? undefined);\n }}\n />\n </div>\n <div className=\"col-sm-12 col-md-5\">\n {chartRef && <DoughnutChartLegend chart={chartRef} />}\n </div>\n </div>\n );\n});\n","import { Card, CardHeader, CardBody, CardFooter } from 'reactstrap';\nimport { FC, ReactNode } from 'react';\nimport './ChartCard.scss';\n\ninterface ChartCardProps {\n title: Function | string;\n footer?: ReactNode;\n}\n\nexport const ChartCard: FC<ChartCardProps> = ({ title, footer, children }) => (\n <Card>\n <CardHeader className=\"chart-card__header\">{typeof title === 'function' ? title() : title}</CardHeader>\n <CardBody>{children}</CardBody>\n {footer && <CardFooter className=\"chart-card__footer--sticky\">{footer}</CardFooter>}\n </Card>\n);\n","import { FC } from 'react';\nimport { Stats } from '../types';\nimport { DoughnutChart } from './DoughnutChart';\nimport { ChartCard } from './ChartCard';\n\ninterface DoughnutChartCardProps {\n title: string;\n stats: Stats;\n}\n\nexport const DoughnutChartCard: FC<DoughnutChartCardProps> = ({ title, stats }) => (\n <ChartCard title={title}>\n <DoughnutChart stats={stats} />\n </ChartCard>\n);\n","import { DropdownItem, DropdownMenu, DropdownToggle, UncontrolledDropdown } from 'reactstrap';\n\ninterface PaginationDropdownProps {\n ranges: number[];\n value: number;\n setValue: (newValue: number) => void;\n toggleClassName?: string;\n}\n\nconst PaginationDropdown = ({ toggleClassName, ranges, value, setValue }: PaginationDropdownProps) => (\n <UncontrolledDropdown>\n <DropdownToggle caret color=\"link\" className={toggleClassName}>\n Paginate\n </DropdownToggle>\n <DropdownMenu right>\n {ranges.map((itemsPerPage) => (\n <DropdownItem key={itemsPerPage} active={itemsPerPage === value} onClick={() => setValue(itemsPerPage)}>\n <b>{itemsPerPage}</b> items per page\n </DropdownItem>\n ))}\n <DropdownItem divider />\n <DropdownItem disabled={value === Infinity} onClick={() => setValue(Infinity)}>\n <i>Clear pagination</i>\n </DropdownItem>\n </DropdownMenu>\n </UncontrolledDropdown>\n);\n\nexport default PaginationDropdown;\n","import { FC } from 'react';\nimport { ChartData, ChartDataset, ChartOptions } from 'chart.js';\nimport { keys, values } from 'ramda';\nimport { Bar } from 'react-chartjs-2';\nimport { fillTheGaps } from '../../utils/helpers/visits';\nimport { pointerOnHover, renderChartLabel } from '../../utils/helpers/charts';\nimport { prettify } from '../../utils/helpers/numbers';\nimport { Stats } from '../types';\nimport { HIGHLIGHTED_COLOR, HIGHLIGHTED_COLOR_ALPHA, MAIN_COLOR, MAIN_COLOR_ALPHA } from '../../utils/theme';\n\nexport interface HorizontalBarChartProps {\n stats: Stats;\n max?: number;\n highlightedStats?: Stats;\n highlightedLabel?: string;\n onClick?: (label: string) => void;\n}\n\nconst dropLabelIfHidden = (label: string) => label.startsWith('hidden') ? '' : label;\nconst statsAreDefined = (stats: Stats | undefined): stats is Stats => !!stats && Object.keys(stats).length > 0;\nconst determineHeight = (labels: string[]): number | undefined => labels.length > 20 ? labels.length * 10 : undefined;\n\nconst generateChartDatasets = (\n data: number[],\n highlightedData: number[],\n highlightedLabel?: string,\n): ChartDataset[] => {\n const mainDataset: ChartDataset = {\n data,\n label: highlightedLabel ? 'Non-selected' : 'Visits',\n backgroundColor: MAIN_COLOR_ALPHA,\n borderColor: MAIN_COLOR,\n borderWidth: 2,\n };\n\n if (highlightedData.every((value) => value === 0)) {\n return [ mainDataset ];\n }\n\n const highlightedDataset: ChartDataset = {\n label: highlightedLabel ?? 'Selected',\n data: highlightedData,\n backgroundColor: HIGHLIGHTED_COLOR_ALPHA,\n borderColor: HIGHLIGHTED_COLOR,\n borderWidth: 2,\n };\n\n return [ mainDataset, highlightedDataset ];\n};\nconst generateChartData = (\n labels: string[],\n data: number[],\n highlightedData: number[],\n highlightedLabel?: string,\n): ChartData => ({\n labels,\n datasets: generateChartDatasets(data, highlightedData, highlightedLabel),\n});\n\ntype ClickedCharts = [{ index: number }] | [];\nconst chartElementAtEvent = (labels: string[], onClick?: (label: string) => void) => ([ chart ]: ClickedCharts) => {\n if (!onClick || !chart) {\n return;\n }\n\n onClick(labels[chart.index]);\n};\n\nexport const HorizontalBarChart: FC<HorizontalBarChartProps> = (\n { stats, highlightedStats, highlightedLabel, onClick, max },\n) => {\n const labels = keys(stats).map(dropLabelIfHidden);\n const data = values(\n !statsAreDefined(highlightedStats) ? stats : keys(highlightedStats).reduce((acc, highlightedKey) => {\n if (acc[highlightedKey]) {\n acc[highlightedKey] -= highlightedStats[highlightedKey];\n }\n\n return acc;\n }, { ...stats }),\n );\n const highlightedData = fillTheGaps(highlightedStats ?? {}, labels);\n\n const options: ChartOptions = {\n plugins: {\n legend: { display: false },\n tooltip: {\n mode: 'y',\n // Do not show tooltip on items with empty label when in a bar chart\n filter: ({ label }) => label !== '',\n callbacks: { label: renderChartLabel },\n },\n },\n scales: {\n x: {\n beginAtZero: true,\n stacked: true,\n max,\n ticks: {\n precision: 0,\n callback: prettify,\n },\n },\n y: { stacked: true },\n },\n onHover: pointerOnHover,\n indexAxis: 'y',\n };\n const chartData = generateChartData(labels, data, highlightedData, highlightedLabel);\n const height = determineHeight(labels);\n\n // Provide a key based on the height, to force re-render every time the dataset changes (example, due to pagination)\n const renderChartComponent = (customKey: string) => (\n <Bar\n key={`${height}_${customKey}`}\n data={chartData}\n options={options}\n height={height}\n getElementAtEvent={chartElementAtEvent(labels, onClick) as any}\n />\n );\n\n return (\n <>\n {/* It's VERY IMPORTANT to render two different components here, as one has 1 dataset and the other has 2 */}\n {/* Using the same component causes a crash when switching from 1 to 2 datasets, and then back to 1 dataset */}\n {highlightedStats !== undefined && renderChartComponent('with_stats')}\n {highlightedStats === undefined && renderChartComponent('without_stats')}\n </>\n );\n};\n","import { FC, useState } from 'react';\nimport { fromPairs, pipe, reverse, sortBy, splitEvery, toLower, toPairs, type, zipObj } from 'ramda';\nimport { OrderDir, rangeOf } from '../../utils/utils';\nimport SimplePaginator from '../../common/SimplePaginator';\nimport { roundTen } from '../../utils/helpers/numbers';\nimport SortingDropdown from '../../utils/SortingDropdown';\nimport PaginationDropdown from '../../utils/PaginationDropdown';\nimport { Stats, StatsRow } from '../types';\nimport { HorizontalBarChart, HorizontalBarChartProps } from './HorizontalBarChart';\nimport { ChartCard } from './ChartCard';\n\ninterface SortableBarChartCardProps extends Omit<HorizontalBarChartProps, 'max'> {\n title: Function | string;\n sortingItems: Record<string, string>;\n withPagination?: boolean;\n extraHeaderContent?: Function;\n}\n\nconst toLowerIfString = (value: any) => type(value) === 'String' ? toLower(value) : value; // eslint-disable-line @typescript-eslint/no-unsafe-return\nconst pickKeyFromPair = ([ key ]: StatsRow) => key;\nconst pickValueFromPair = ([ , value ]: StatsRow) => value;\n\nexport const SortableBarChartCard: FC<SortableBarChartCardProps> = ({\n stats,\n highlightedStats,\n title,\n sortingItems,\n extraHeaderContent,\n withPagination = true,\n ...rest\n}) => {\n const [ order, setOrder ] = useState<{ orderField?: string; orderDir?: OrderDir }>({\n orderField: undefined,\n orderDir: undefined,\n });\n const [ currentPage, setCurrentPage ] = useState(1);\n const [ itemsPerPage, setItemsPerPage ] = useState(50);\n\n const getSortedPairsForStats = (stats: Stats, sortingItems: Record<string, string>) => {\n const pairs = toPairs(stats);\n const sortedPairs = !order.orderField ? pairs : sortBy(\n pipe<StatsRow, string | number, string | number>(\n order.orderField === Object.keys(sortingItems)[0] ? pickKeyFromPair : pickValueFromPair,\n toLowerIfString,\n ),\n pairs,\n );\n\n return !order.orderDir || order.orderDir === 'ASC' ? sortedPairs : reverse(sortedPairs);\n };\n const determineCurrentPagePairs = (pages: StatsRow[][]): StatsRow[] => {\n const page = pages[currentPage - 1];\n\n if (currentPage < pages.length) {\n return page;\n }\n\n const firstPageLength = pages[0].length;\n\n // Using the \"hidden\" key, the chart will just replace the label by an empty string\n return [ ...page, ...rangeOf(firstPageLength - page.length, (i): StatsRow => [ `hidden_${i}`, 0 ]) ];\n };\n const renderPagination = (pagesCount: number) =>\n <SimplePaginator currentPage={currentPage} pagesCount={pagesCount} setCurrentPage={setCurrentPage} />;\n const determineStats = (stats: Stats, highlightedStats: Stats | undefined, sortingItems: Record<string, string>) => {\n const sortedPairs = getSortedPairsForStats(stats, sortingItems);\n const sortedKeys = sortedPairs.map(pickKeyFromPair);\n // The highlighted stats have to be ordered based on the regular stats, not on its own values\n const sortedHighlightedPairs = highlightedStats && toPairs(\n { ...zipObj(sortedKeys, sortedKeys.map(() => 0)), ...highlightedStats },\n );\n\n if (sortedPairs.length <= itemsPerPage) {\n return {\n currentPageStats: fromPairs(sortedPairs),\n currentPageHighlightedStats: sortedHighlightedPairs && fromPairs(sortedHighlightedPairs),\n };\n }\n\n const pages = splitEvery(itemsPerPage, sortedPairs);\n const highlightedPages = sortedHighlightedPairs && splitEvery(itemsPerPage, sortedHighlightedPairs);\n\n return {\n currentPageStats: fromPairs(determineCurrentPagePairs(pages)),\n currentPageHighlightedStats: highlightedPages && fromPairs(determineCurrentPagePairs(highlightedPages)),\n pagination: renderPagination(pages.length),\n max: roundTen(Math.max(...sortedPairs.map(pickValueFromPair))),\n };\n };\n\n const { currentPageStats, currentPageHighlightedStats, pagination, max } = determineStats(\n stats,\n highlightedStats && Object.keys(highlightedStats).length > 0 ? highlightedStats : undefined,\n sortingItems,\n );\n const activeCities = Object.keys(currentPageStats);\n const computeTitle = () => (\n <>\n {title}\n <div className=\"float-right\">\n <SortingDropdown\n isButton={false}\n right\n items={sortingItems}\n orderField={order.orderField}\n orderDir={order.orderDir}\n onChange={(orderField, orderDir) => {\n setOrder({ orderField, orderDir });\n setCurrentPage(1);\n }}\n />\n </div>\n {withPagination && Object.keys(stats).length > 50 && (\n <div className=\"float-right\">\n <PaginationDropdown\n toggleClassName=\"btn-sm p-0 mr-3\"\n ranges={[ 50, 100, 200, 500 ]}\n value={itemsPerPage}\n setValue={(itemsPerPage) => {\n setItemsPerPage(itemsPerPage);\n setCurrentPage(1);\n }}\n />\n </div>\n )}\n {extraHeaderContent && (\n <div className=\"float-right\">\n {extraHeaderContent(pagination ? activeCities : undefined)}\n </div>\n )}\n </>\n );\n\n return (\n <ChartCard\n title={computeTitle}\n footer={pagination}\n >\n <HorizontalBarChart stats={currentPageStats} highlightedStats={currentPageHighlightedStats} max={max} {...rest} />\n </ChartCard>\n );\n};\n","import { useEffect } from 'react';\nimport { RouteComponentProps } from 'react-router';\nimport { boundToMercureHub } from '../mercure/helpers/boundToMercureHub';\nimport { ShlinkVisitsParams } from '../api/types';\nimport { parseQuery } from '../utils/helpers/query';\nimport { Topics } from '../mercure/helpers/Topics';\nimport { ShortUrlDetail } from '../short-urls/reducers/shortUrlDetail';\nimport { ShortUrlVisits as ShortUrlVisitsState } from './reducers/shortUrlVisits';\nimport ShortUrlVisitsHeader from './ShortUrlVisitsHeader';\nimport VisitsStats from './VisitsStats';\nimport { VisitsExporter } from './services/VisitsExporter';\nimport { NormalizedVisit, VisitsParams } from './types';\nimport { CommonVisitsProps } from './types/CommonVisitsProps';\nimport { toApiParams } from './types/helpers';\n\nexport interface ShortUrlVisitsProps extends CommonVisitsProps, RouteComponentProps<{ shortCode: string }> {\n getShortUrlVisits: (shortCode: string, query?: ShlinkVisitsParams) => void;\n shortUrlVisits: ShortUrlVisitsState;\n getShortUrlDetail: Function;\n shortUrlDetail: ShortUrlDetail;\n cancelGetShortUrlVisits: () => void;\n}\n\nconst ShortUrlVisits = ({ exportVisits }: VisitsExporter) => boundToMercureHub(({\n history: { goBack },\n match: { params, url },\n location: { search },\n shortUrlVisits,\n shortUrlDetail,\n getShortUrlVisits,\n getShortUrlDetail,\n cancelGetShortUrlVisits,\n settings,\n selectedServer,\n}: ShortUrlVisitsProps) => {\n const { shortCode } = params;\n const { domain } = parseQuery<{ domain?: string }>(search);\n const loadVisits = (params: VisitsParams) => getShortUrlVisits(shortCode, { ...toApiParams(params), domain });\n const exportCsv = (visits: NormalizedVisit[]) => exportVisits(\n `short-url_${shortUrlDetail.shortUrl?.shortUrl.replace(/https?:\\/\\//g, '')}_visits.csv`,\n visits,\n );\n\n useEffect(() => {\n getShortUrlDetail(shortCode, domain);\n }, []);\n\n return (\n <VisitsStats\n getVisits={loadVisits}\n cancelGetVisits={cancelGetShortUrlVisits}\n visitsInfo={shortUrlVisits}\n baseUrl={url}\n domain={domain}\n settings={settings}\n exportCsv={exportCsv}\n selectedServer={selectedServer}\n >\n <ShortUrlVisitsHeader shortUrlDetail={shortUrlDetail} shortUrlVisits={shortUrlVisits} goBack={goBack} />\n </VisitsStats>\n );\n}, ({ match }) => [ Topics.shortUrlVisits(match.params.shortCode) ]);\n\nexport default ShortUrlVisits;\n","import { flatten, prop, range, splitEvery } from 'ramda';\nimport { Action, Dispatch } from 'redux';\nimport { ShlinkPaginator, ShlinkVisits } from '../../api/types';\nimport { Visit } from '../types';\nimport { parseApiError } from '../../api/utils';\nimport { ApiErrorAction } from '../../api/types/actions';\n\nconst ITEMS_PER_PAGE = 5000;\nconst PARALLEL_REQUESTS_COUNT = 4;\nconst PARALLEL_STARTING_PAGE = 2;\n\nconst isLastPage = ({ currentPage, pagesCount }: ShlinkPaginator): boolean => currentPage >= pagesCount;\nconst calcProgress = (total: number, current: number): number => current * 100 / total;\n\ntype VisitsLoader = (page: number, itemsPerPage: number) => Promise<ShlinkVisits>;\ninterface ActionMap {\n start: string;\n large: string;\n finish: string;\n error: string;\n progress: string;\n}\n\nexport const getVisitsWithLoader = async <T extends Action<string> & { visits: Visit[] }>(\n visitsLoader: VisitsLoader,\n extraFinishActionData: Partial<T>,\n actionMap: ActionMap,\n dispatch: Dispatch,\n shouldCancel: () => boolean,\n) => {\n dispatch({ type: actionMap.start });\n\n const loadVisitsInParallel = async (pages: number[]): Promise<Visit[]> =>\n Promise.all(pages.map(async (page) => visitsLoader(page, ITEMS_PER_PAGE).then(prop('data')))).then(flatten);\n\n const loadPagesBlocks = async (pagesBlocks: number[][], index = 0): Promise<Visit[]> => {\n if (shouldCancel()) {\n return [];\n }\n\n const data = await loadVisitsInParallel(pagesBlocks[index]);\n\n dispatch({ type: actionMap.progress, progress: calcProgress(pagesBlocks.length, index + PARALLEL_STARTING_PAGE) });\n\n if (index < pagesBlocks.length - 1) {\n return data.concat(await loadPagesBlocks(pagesBlocks, index + 1));\n }\n\n return data;\n };\n\n const loadVisits = async (page = 1) => {\n const { pagination, data } = await visitsLoader(page, ITEMS_PER_PAGE);\n\n // If pagination was not returned, then this is an old shlink version. Just return data\n if (!pagination || isLastPage(pagination)) {\n return data;\n }\n\n // If there are more pages, make requests in blocks of 4\n const pagesRange = range(PARALLEL_STARTING_PAGE, pagination.pagesCount + 1);\n const pagesBlocks = splitEvery(PARALLEL_REQUESTS_COUNT, pagesRange);\n\n if (pagination.pagesCount - 1 > PARALLEL_REQUESTS_COUNT) {\n dispatch({ type: actionMap.large });\n }\n\n return data.concat(await loadPagesBlocks(pagesBlocks));\n };\n\n try {\n const visits = await loadVisits();\n\n dispatch({ ...extraFinishActionData, visits, type: actionMap.finish });\n } catch (e) {\n dispatch<ApiErrorAction>({ type: actionMap.error, errorData: parseApiError(e) });\n }\n};\n","import { Action, Dispatch } from 'redux';\nimport { shortUrlMatches } from '../../short-urls/helpers';\nimport { Visit, VisitsInfo, VisitsLoadProgressChangedAction } from '../types';\nimport { ShortUrlIdentifier } from '../../short-urls/data';\nimport { buildActionCreator, buildReducer } from '../../utils/helpers/redux';\nimport { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';\nimport { GetState } from '../../container/types';\nimport { ShlinkVisitsParams } from '../../api/types';\nimport { ApiErrorAction } from '../../api/types/actions';\nimport { getVisitsWithLoader } from './common';\nimport { CREATE_VISITS, CreateVisitsAction } from './visitCreation';\n\n/* eslint-disable padding-line-between-statements */\nexport const GET_SHORT_URL_VISITS_START = 'shlink/shortUrlVisits/GET_SHORT_URL_VISITS_START';\nexport const GET_SHORT_URL_VISITS_ERROR = 'shlink/shortUrlVisits/GET_SHORT_URL_VISITS_ERROR';\nexport const GET_SHORT_URL_VISITS = 'shlink/shortUrlVisits/GET_SHORT_URL_VISITS';\nexport const GET_SHORT_URL_VISITS_LARGE = 'shlink/shortUrlVisits/GET_SHORT_URL_VISITS_LARGE';\nexport const GET_SHORT_URL_VISITS_CANCEL = 'shlink/shortUrlVisits/GET_SHORT_URL_VISITS_CANCEL';\nexport const GET_SHORT_URL_VISITS_PROGRESS_CHANGED = 'shlink/shortUrlVisits/GET_SHORT_URL_VISITS_PROGRESS_CHANGED';\n/* eslint-enable padding-line-between-statements */\n\nexport interface ShortUrlVisits extends VisitsInfo, ShortUrlIdentifier {}\n\ninterface ShortUrlVisitsAction extends Action<string>, ShortUrlIdentifier {\n visits: Visit[];\n}\n\ntype ShortUrlVisitsCombinedAction = ShortUrlVisitsAction\n& VisitsLoadProgressChangedAction\n& CreateVisitsAction\n& ApiErrorAction;\n\nconst initialState: ShortUrlVisits = {\n visits: [],\n shortCode: '',\n domain: undefined,\n loading: false,\n loadingLarge: false,\n error: false,\n cancelLoad: false,\n progress: 0,\n};\n\nexport default buildReducer<ShortUrlVisits, ShortUrlVisitsCombinedAction>({\n [GET_SHORT_URL_VISITS_START]: () => ({ ...initialState, loading: true }),\n [GET_SHORT_URL_VISITS_ERROR]: (_, { errorData }) => ({ ...initialState, error: true, errorData }),\n [GET_SHORT_URL_VISITS]: (_, { visits, shortCode, domain }) => ({\n ...initialState,\n visits,\n shortCode,\n domain,\n }),\n [GET_SHORT_URL_VISITS_LARGE]: (state) => ({ ...state, loadingLarge: true }),\n [GET_SHORT_URL_VISITS_CANCEL]: (state) => ({ ...state, cancelLoad: true }),\n [GET_SHORT_URL_VISITS_PROGRESS_CHANGED]: (state, { progress }) => ({ ...state, progress }),\n [CREATE_VISITS]: (state, { createdVisits }) => {\n const { shortCode, domain, visits } = state;\n const newVisits = createdVisits\n .filter(({ shortUrl }) => shortUrl && shortUrlMatches(shortUrl, shortCode, domain))\n .map(({ visit }) => visit);\n\n return { ...state, visits: [ ...newVisits, ...visits ] };\n },\n}, initialState);\n\nexport const getShortUrlVisits = (buildShlinkApiClient: ShlinkApiClientBuilder) => (\n shortCode: string,\n query: ShlinkVisitsParams = {},\n) => async (dispatch: Dispatch, getState: GetState) => {\n const { getShortUrlVisits } = buildShlinkApiClient(getState);\n const visitsLoader = async (page: number, itemsPerPage: number) => getShortUrlVisits(\n shortCode,\n { ...query, page, itemsPerPage },\n );\n const shouldCancel = () => getState().shortUrlVisits.cancelLoad;\n const extraFinishActionData: Partial<ShortUrlVisitsAction> = { shortCode, domain: query.domain };\n const actionMap = {\n start: GET_SHORT_URL_VISITS_START,\n large: GET_SHORT_URL_VISITS_LARGE,\n finish: GET_SHORT_URL_VISITS,\n error: GET_SHORT_URL_VISITS_ERROR,\n progress: GET_SHORT_URL_VISITS_PROGRESS_CHANGED,\n };\n\n return getVisitsWithLoader(visitsLoader, extraFinishActionData, actionMap, dispatch, shouldCancel);\n};\n\nexport const cancelGetShortUrlVisits = buildActionCreator(GET_SHORT_URL_VISITS_CANCEL);\n","import Tag from '../tags/helpers/Tag';\nimport ColorGenerator from '../utils/services/ColorGenerator';\nimport VisitsHeader from './VisitsHeader';\nimport { TagVisits } from './reducers/tagVisits';\nimport './ShortUrlVisitsHeader.scss';\n\ninterface TagVisitsHeaderProps {\n tagVisits: TagVisits;\n goBack: () => void;\n colorGenerator: ColorGenerator;\n}\n\nconst TagVisitsHeader = ({ tagVisits, goBack, colorGenerator }: TagVisitsHeaderProps) => {\n const { visits, tag } = tagVisits;\n\n const visitsStatsTitle = (\n <span className=\"d-flex align-items-center justify-content-center\">\n <span className=\"mr-2\">Visits for</span>\n <Tag text={tag} colorGenerator={colorGenerator} />\n </span>\n );\n\n return <VisitsHeader title={visitsStatsTitle} goBack={goBack} visits={visits} />;\n};\n\nexport default TagVisitsHeader;\n","import { RouteComponentProps } from 'react-router';\nimport { boundToMercureHub } from '../mercure/helpers/boundToMercureHub';\nimport ColorGenerator from '../utils/services/ColorGenerator';\nimport { ShlinkVisitsParams } from '../api/types';\nimport { Topics } from '../mercure/helpers/Topics';\nimport { TagVisits as TagVisitsState } from './reducers/tagVisits';\nimport TagVisitsHeader from './TagVisitsHeader';\nimport VisitsStats from './VisitsStats';\nimport { VisitsExporter } from './services/VisitsExporter';\nimport { NormalizedVisit } from './types';\nimport { CommonVisitsProps } from './types/CommonVisitsProps';\nimport { toApiParams } from './types/helpers';\n\nexport interface TagVisitsProps extends CommonVisitsProps, RouteComponentProps<{ tag: string }> {\n getTagVisits: (tag: string, query?: ShlinkVisitsParams) => void;\n tagVisits: TagVisitsState;\n cancelGetTagVisits: () => void;\n}\n\nconst TagVisits = (colorGenerator: ColorGenerator, { exportVisits }: VisitsExporter) => boundToMercureHub(({\n history: { goBack },\n match: { params, url },\n getTagVisits,\n tagVisits,\n cancelGetTagVisits,\n settings,\n selectedServer,\n}: TagVisitsProps) => {\n const { tag } = params;\n const loadVisits = (params: ShlinkVisitsParams) => getTagVisits(tag, toApiParams(params));\n const exportCsv = (visits: NormalizedVisit[]) => exportVisits(`tag_${tag}_visits.csv`, visits);\n\n return (\n <VisitsStats\n getVisits={loadVisits}\n cancelGetVisits={cancelGetTagVisits}\n visitsInfo={tagVisits}\n baseUrl={url}\n settings={settings}\n exportCsv={exportCsv}\n selectedServer={selectedServer}\n >\n <TagVisitsHeader tagVisits={tagVisits} goBack={goBack} colorGenerator={colorGenerator} />\n </VisitsStats>\n );\n}, () => [ Topics.visits ]);\n\nexport default TagVisits;\n","import { Action, Dispatch } from 'redux';\nimport { Visit, VisitsInfo, VisitsLoadProgressChangedAction } from '../types';\nimport { buildActionCreator, buildReducer } from '../../utils/helpers/redux';\nimport { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';\nimport { GetState } from '../../container/types';\nimport { ShlinkVisitsParams } from '../../api/types';\nimport { ApiErrorAction } from '../../api/types/actions';\nimport { getVisitsWithLoader } from './common';\nimport { CREATE_VISITS, CreateVisitsAction } from './visitCreation';\n\n/* eslint-disable padding-line-between-statements */\nexport const GET_TAG_VISITS_START = 'shlink/tagVisits/GET_TAG_VISITS_START';\nexport const GET_TAG_VISITS_ERROR = 'shlink/tagVisits/GET_TAG_VISITS_ERROR';\nexport const GET_TAG_VISITS = 'shlink/tagVisits/GET_TAG_VISITS';\nexport const GET_TAG_VISITS_LARGE = 'shlink/tagVisits/GET_TAG_VISITS_LARGE';\nexport const GET_TAG_VISITS_CANCEL = 'shlink/tagVisits/GET_TAG_VISITS_CANCEL';\nexport const GET_TAG_VISITS_PROGRESS_CHANGED = 'shlink/tagVisits/GET_TAG_VISITS_PROGRESS_CHANGED';\n/* eslint-enable padding-line-between-statements */\n\nexport interface TagVisits extends VisitsInfo {\n tag: string;\n}\n\nexport interface TagVisitsAction extends Action<string> {\n visits: Visit[];\n tag: string;\n}\n\ntype TagsVisitsCombinedAction = TagVisitsAction\n& VisitsLoadProgressChangedAction\n& CreateVisitsAction\n& ApiErrorAction;\n\nconst initialState: TagVisits = {\n visits: [],\n tag: '',\n loading: false,\n loadingLarge: false,\n error: false,\n cancelLoad: false,\n progress: 0,\n};\n\nexport default buildReducer<TagVisits, TagsVisitsCombinedAction>({\n [GET_TAG_VISITS_START]: () => ({ ...initialState, loading: true }),\n [GET_TAG_VISITS_ERROR]: (_, { errorData }) => ({ ...initialState, error: true, errorData }),\n [GET_TAG_VISITS]: (_, { visits, tag }) => ({ ...initialState, visits, tag }),\n [GET_TAG_VISITS_LARGE]: (state) => ({ ...state, loadingLarge: true }),\n [GET_TAG_VISITS_CANCEL]: (state) => ({ ...state, cancelLoad: true }),\n [GET_TAG_VISITS_PROGRESS_CHANGED]: (state, { progress }) => ({ ...state, progress }),\n [CREATE_VISITS]: (state, { createdVisits }) => {\n const { tag, visits } = state;\n const newVisits = createdVisits\n .filter(({ shortUrl }) => shortUrl?.tags.includes(tag))\n .map(({ visit }) => visit);\n\n return { ...state, visits: [ ...newVisits, ...visits ] };\n },\n}, initialState);\n\nexport const getTagVisits = (buildShlinkApiClient: ShlinkApiClientBuilder) => (\n tag: string,\n query: ShlinkVisitsParams = {},\n) => async (dispatch: Dispatch, getState: GetState) => {\n const { getTagVisits } = buildShlinkApiClient(getState);\n const visitsLoader = async (page: number, itemsPerPage: number) => getTagVisits(\n tag,\n { ...query, page, itemsPerPage },\n );\n const shouldCancel = () => getState().tagVisits.cancelLoad;\n const extraFinishActionData: Partial<TagVisitsAction> = { tag };\n const actionMap = {\n start: GET_TAG_VISITS_START,\n large: GET_TAG_VISITS_LARGE,\n finish: GET_TAG_VISITS,\n error: GET_TAG_VISITS_ERROR,\n progress: GET_TAG_VISITS_PROGRESS_CHANGED,\n };\n\n return getVisitsWithLoader(visitsLoader, extraFinishActionData, actionMap, dispatch, shouldCancel);\n};\n\nexport const cancelGetTagVisits = buildActionCreator(GET_TAG_VISITS_CANCEL);\n","import VisitsHeader from './VisitsHeader';\nimport { VisitsInfo } from './types';\nimport './ShortUrlVisitsHeader.scss';\n\ninterface OrphanVisitsHeaderProps {\n orphanVisits: VisitsInfo;\n goBack: () => void;\n}\n\nexport const OrphanVisitsHeader = ({ orphanVisits, goBack }: OrphanVisitsHeaderProps) => {\n const { visits } = orphanVisits;\n\n return <VisitsHeader title=\"Orphan visits\" goBack={goBack} visits={visits} />;\n};\n","import { RouteComponentProps } from 'react-router';\nimport { boundToMercureHub } from '../mercure/helpers/boundToMercureHub';\nimport { ShlinkVisitsParams } from '../api/types';\nimport { Topics } from '../mercure/helpers/Topics';\nimport VisitsStats from './VisitsStats';\nimport { OrphanVisitsHeader } from './OrphanVisitsHeader';\nimport { NormalizedVisit, OrphanVisitType, VisitsInfo, VisitsParams } from './types';\nimport { VisitsExporter } from './services/VisitsExporter';\nimport { CommonVisitsProps } from './types/CommonVisitsProps';\nimport { toApiParams } from './types/helpers';\n\nexport interface OrphanVisitsProps extends CommonVisitsProps, RouteComponentProps {\n getOrphanVisits: (params?: ShlinkVisitsParams, orphanVisitsType?: OrphanVisitType) => void;\n orphanVisits: VisitsInfo;\n cancelGetOrphanVisits: () => void;\n}\n\nexport const OrphanVisits = ({ exportVisits }: VisitsExporter) => boundToMercureHub(({\n history: { goBack },\n match: { url },\n getOrphanVisits,\n orphanVisits,\n cancelGetOrphanVisits,\n settings,\n selectedServer,\n}: OrphanVisitsProps) => {\n const exportCsv = (visits: NormalizedVisit[]) => exportVisits('orphan_visits.csv', visits);\n const loadVisits = (params: VisitsParams) => getOrphanVisits(toApiParams(params), params.filter?.orphanVisitsType);\n\n return (\n <VisitsStats\n getVisits={loadVisits}\n cancelGetVisits={cancelGetOrphanVisits}\n visitsInfo={orphanVisits}\n baseUrl={url}\n settings={settings}\n exportCsv={exportCsv}\n selectedServer={selectedServer}\n isOrphanVisits\n >\n <OrphanVisitsHeader orphanVisits={orphanVisits} goBack={goBack} />\n </VisitsStats>\n );\n}, () => [ Topics.orphanVisits ]);\n","import { Action, Dispatch } from 'redux';\nimport { OrphanVisit, OrphanVisitType, Visit, VisitsInfo, VisitsLoadProgressChangedAction } from '../types';\nimport { buildActionCreator, buildReducer } from '../../utils/helpers/redux';\nimport { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';\nimport { GetState } from '../../container/types';\nimport { ShlinkVisitsParams } from '../../api/types';\nimport { isOrphanVisit } from '../types/helpers';\nimport { ApiErrorAction } from '../../api/types/actions';\nimport { getVisitsWithLoader } from './common';\nimport { CREATE_VISITS, CreateVisitsAction } from './visitCreation';\n\n/* eslint-disable padding-line-between-statements */\nexport const GET_ORPHAN_VISITS_START = 'shlink/orphanVisits/GET_ORPHAN_VISITS_START';\nexport const GET_ORPHAN_VISITS_ERROR = 'shlink/orphanVisits/GET_ORPHAN_VISITS_ERROR';\nexport const GET_ORPHAN_VISITS = 'shlink/orphanVisits/GET_ORPHAN_VISITS';\nexport const GET_ORPHAN_VISITS_LARGE = 'shlink/orphanVisits/GET_ORPHAN_VISITS_LARGE';\nexport const GET_ORPHAN_VISITS_CANCEL = 'shlink/orphanVisits/GET_ORPHAN_VISITS_CANCEL';\nexport const GET_ORPHAN_VISITS_PROGRESS_CHANGED = 'shlink/orphanVisits/GET_ORPHAN_VISITS_PROGRESS_CHANGED';\n/* eslint-enable padding-line-between-statements */\n\nexport interface OrphanVisitsAction extends Action<string> {\n visits: Visit[];\n}\n\ntype OrphanVisitsCombinedAction = OrphanVisitsAction\n& VisitsLoadProgressChangedAction\n& CreateVisitsAction\n& ApiErrorAction;\n\nconst initialState: VisitsInfo = {\n visits: [],\n loading: false,\n loadingLarge: false,\n error: false,\n cancelLoad: false,\n progress: 0,\n};\n\nexport default buildReducer<VisitsInfo, OrphanVisitsCombinedAction>({\n [GET_ORPHAN_VISITS_START]: () => ({ ...initialState, loading: true }),\n [GET_ORPHAN_VISITS_ERROR]: (_, { errorData }) => ({ ...initialState, error: true, errorData }),\n [GET_ORPHAN_VISITS]: (_, { visits }) => ({ ...initialState, visits }),\n [GET_ORPHAN_VISITS_LARGE]: (state) => ({ ...state, loadingLarge: true }),\n [GET_ORPHAN_VISITS_CANCEL]: (state) => ({ ...state, cancelLoad: true }),\n [GET_ORPHAN_VISITS_PROGRESS_CHANGED]: (state, { progress }) => ({ ...state, progress }),\n [CREATE_VISITS]: (state, { createdVisits }) => {\n const { visits } = state;\n const newVisits = createdVisits.map(({ visit }) => visit);\n\n return { ...state, visits: [ ...newVisits, ...visits ] };\n },\n}, initialState);\n\nconst matchesType = (visit: OrphanVisit, orphanVisitsType?: OrphanVisitType) =>\n !orphanVisitsType || orphanVisitsType === visit.type;\n\nexport const getOrphanVisits = (buildShlinkApiClient: ShlinkApiClientBuilder) => (\n query: ShlinkVisitsParams = {},\n orphanVisitsType?: OrphanVisitType,\n) => async (dispatch: Dispatch, getState: GetState) => {\n const { getOrphanVisits } = buildShlinkApiClient(getState);\n const visitsLoader = async (page: number, itemsPerPage: number) => getOrphanVisits({ ...query, page, itemsPerPage })\n .then((result) => {\n const visits = result.data.filter((visit) => isOrphanVisit(visit) && matchesType(visit, orphanVisitsType));\n\n return { ...result, data: visits };\n });\n const shouldCancel = () => getState().orphanVisits.cancelLoad;\n const actionMap = {\n start: GET_ORPHAN_VISITS_START,\n large: GET_ORPHAN_VISITS_LARGE,\n finish: GET_ORPHAN_VISITS,\n error: GET_ORPHAN_VISITS_ERROR,\n progress: GET_ORPHAN_VISITS_PROGRESS_CHANGED,\n };\n\n return getVisitsWithLoader(visitsLoader, {}, actionMap, dispatch, shouldCancel);\n};\n\nexport const cancelGetOrphanVisits = buildActionCreator(GET_ORPHAN_VISITS_CANCEL);\n","import { Action, Dispatch } from 'redux';\nimport { ShlinkVisitsOverview } from '../../api/types';\nimport { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';\nimport { GetState } from '../../container/types';\nimport { buildReducer } from '../../utils/helpers/redux';\nimport { groupNewVisitsByType } from '../types/helpers';\nimport { CREATE_VISITS, CreateVisitsAction } from './visitCreation';\n\n/* eslint-disable padding-line-between-statements */\nexport const GET_OVERVIEW_START = 'shlink/visitsOverview/GET_OVERVIEW_START';\nexport const GET_OVERVIEW_ERROR = 'shlink/visitsOverview/GET_OVERVIEW_ERROR';\nexport const GET_OVERVIEW = 'shlink/visitsOverview/GET_OVERVIEW';\n/* eslint-enable padding-line-between-statements */\n\nexport interface VisitsOverview {\n visitsCount: number;\n orphanVisitsCount?: number;\n loading: boolean;\n error: boolean;\n}\n\nexport type GetVisitsOverviewAction = ShlinkVisitsOverview & Action<string>;\n\nconst initialState: VisitsOverview = {\n visitsCount: 0,\n orphanVisitsCount: 0,\n loading: false,\n error: false,\n};\n\nexport default buildReducer<VisitsOverview, GetVisitsOverviewAction & CreateVisitsAction>({\n [GET_OVERVIEW_START]: () => ({ ...initialState, loading: true }),\n [GET_OVERVIEW_ERROR]: () => ({ ...initialState, error: true }),\n [GET_OVERVIEW]: (_, { visitsCount, orphanVisitsCount }) => ({ ...initialState, visitsCount, orphanVisitsCount }),\n [CREATE_VISITS]: ({ visitsCount, orphanVisitsCount = 0, ...rest }, { createdVisits }) => {\n const { regularVisits, orphanVisits } = groupNewVisitsByType(createdVisits);\n\n return {\n ...rest,\n visitsCount: visitsCount + regularVisits.length,\n orphanVisitsCount: orphanVisitsCount + orphanVisits.length,\n };\n },\n}, initialState);\n\nexport const loadVisitsOverview = (buildShlinkApiClient: ShlinkApiClientBuilder) => () => async (\n dispatch: Dispatch,\n getState: GetState,\n) => {\n dispatch({ type: GET_OVERVIEW_START });\n\n try {\n const { getVisitsOverview } = buildShlinkApiClient(getState);\n const result = await getVisitsOverview();\n\n dispatch({ type: GET_OVERVIEW, ...result });\n } catch (e) {\n dispatch({ type: GET_OVERVIEW_ERROR });\n }\n};\n","import { CsvJson } from 'csvjson';\nimport { NormalizedVisit } from '../types';\nimport { saveCsv } from '../../utils/helpers/files';\n\nexport class VisitsExporter {\n public constructor(\n private readonly window: Window,\n private readonly csvjson: CsvJson,\n ) {}\n\n public readonly exportVisits = (filename: string, visits: NormalizedVisit[]) => {\n if (!visits.length) {\n return;\n }\n\n const csv = this.csvjson.toCSV(visits, { headers: 'key' });\n\n saveCsv(this.window, csv, filename);\n };\n}\n","import Bottle from 'bottlejs';\nimport ShortUrlVisits from '../ShortUrlVisits';\nimport { cancelGetShortUrlVisits, getShortUrlVisits } from '../reducers/shortUrlVisits';\nimport MapModal from '../helpers/MapModal';\nimport { createNewVisits } from '../reducers/visitCreation';\nimport TagVisits from '../TagVisits';\nimport { cancelGetTagVisits, getTagVisits } from '../reducers/tagVisits';\nimport { OrphanVisits } from '../OrphanVisits';\nimport { cancelGetOrphanVisits, getOrphanVisits } from '../reducers/orphanVisits';\nimport { ConnectDecorator } from '../../container/types';\nimport { loadVisitsOverview } from '../reducers/visitsOverview';\nimport * as visitsParser from './VisitsParser';\nimport { VisitsExporter } from './VisitsExporter';\n\nconst provideServices = (bottle: Bottle, connect: ConnectDecorator) => {\n // Components\n bottle.serviceFactory('MapModal', () => MapModal);\n\n bottle.serviceFactory('ShortUrlVisits', ShortUrlVisits, 'VisitsExporter');\n bottle.decorator('ShortUrlVisits', connect(\n [ 'shortUrlVisits', 'shortUrlDetail', 'mercureInfo', 'settings', 'selectedServer' ],\n [ 'getShortUrlVisits', 'getShortUrlDetail', 'cancelGetShortUrlVisits', 'createNewVisits', 'loadMercureInfo' ],\n ));\n\n bottle.serviceFactory('TagVisits', TagVisits, 'ColorGenerator', 'VisitsExporter');\n bottle.decorator('TagVisits', connect(\n [ 'tagVisits', 'mercureInfo', 'settings', 'selectedServer' ],\n [ 'getTagVisits', 'cancelGetTagVisits', 'createNewVisits', 'loadMercureInfo' ],\n ));\n\n bottle.serviceFactory('OrphanVisits', OrphanVisits, 'VisitsExporter');\n bottle.decorator('OrphanVisits', connect(\n [ 'orphanVisits', 'mercureInfo', 'settings', 'selectedServer' ],\n [ 'getOrphanVisits', 'cancelGetOrphanVisits', 'createNewVisits', 'loadMercureInfo' ],\n ));\n\n // Services\n bottle.serviceFactory('VisitsParser', () => visitsParser);\n bottle.service('VisitsExporter', VisitsExporter, 'window', 'csvjson');\n\n // Actions\n bottle.serviceFactory('getShortUrlVisits', getShortUrlVisits, 'buildShlinkApiClient');\n bottle.serviceFactory('cancelGetShortUrlVisits', () => cancelGetShortUrlVisits);\n\n bottle.serviceFactory('getTagVisits', getTagVisits, 'buildShlinkApiClient');\n bottle.serviceFactory('cancelGetTagVisits', () => cancelGetTagVisits);\n\n bottle.serviceFactory('getOrphanVisits', getOrphanVisits, 'buildShlinkApiClient');\n bottle.serviceFactory('cancelGetOrphanVisits', () => cancelGetOrphanVisits);\n\n bottle.serviceFactory('createNewVisits', () => createNewVisits);\n bottle.serviceFactory('loadVisitsOverview', loadVisitsOverview, 'buildShlinkApiClient');\n};\n\nexport default provideServices;\n","import ColorGenerator from '../../utils/services/ColorGenerator';\nimport './TagBullet.scss';\n\ninterface TagBulletProps {\n tag: string;\n colorGenerator: ColorGenerator;\n}\n\nconst TagBullet = ({ tag, colorGenerator }: TagBulletProps) => (\n <div\n style={{ backgroundColor: colorGenerator.getColorForKey(tag) }}\n className=\"tag-bullet\"\n />\n);\n\nexport default TagBullet;\n","import { useEffect } from 'react';\nimport ReactTags, { SuggestionComponentProps, TagComponentProps } from 'react-tag-autocomplete';\nimport ColorGenerator from '../../utils/services/ColorGenerator';\nimport { Settings } from '../../settings/reducers/settings';\nimport { TagsList } from '../reducers/tagsList';\nimport TagBullet from './TagBullet';\nimport Tag from './Tag';\n\nexport interface TagsSelectorProps {\n selectedTags: string[];\n onChange: (tags: string[]) => void;\n placeholder?: string;\n}\n\ninterface TagsSelectorConnectProps extends TagsSelectorProps {\n listTags: Function;\n tagsList: TagsList;\n settings: Settings;\n}\n\nconst toComponentTag = (tag: string) => ({ id: tag, name: tag });\n\nconst TagsSelector = (colorGenerator: ColorGenerator) => (\n { selectedTags, onChange, placeholder, listTags, tagsList, settings }: TagsSelectorConnectProps,\n) => {\n useEffect(() => {\n listTags();\n }, []);\n\n const searchMode = settings.shortUrlCreation?.tagFilteringMode ?? 'startsWith';\n const ReactTagsTag = ({ tag, onDelete }: TagComponentProps) =>\n <Tag colorGenerator={colorGenerator} text={tag.name} clearable className=\"react-tags__tag\" onClose={onDelete} />;\n const ReactTagsSuggestion = ({ item }: SuggestionComponentProps) => (\n <>\n <TagBullet tag={`${item.name}`} colorGenerator={colorGenerator} />\n {item.name}\n </>\n );\n\n return (\n <ReactTags\n tags={selectedTags.map(toComponentTag)}\n tagComponent={ReactTagsTag}\n suggestions={tagsList.tags.filter((tag) => !selectedTags.includes(tag)).map(toComponentTag)}\n suggestionComponent={ReactTagsSuggestion}\n allowNew\n addOnBlur\n placeholderText={placeholder ?? 'Add tags to the URL'}\n minQueryLength={1}\n delimiters={[ 'Enter', 'Tab', ',' ]}\n suggestionsTransform={\n searchMode === 'includes'\n ? (query, suggestions) => suggestions.filter(({ name }) => name.includes(query))\n : undefined\n }\n onDelete={(removedTagIndex) => {\n const tagsCopy = [ ...selectedTags ];\n\n tagsCopy.splice(removedTagIndex, 1);\n onChange(tagsCopy);\n }}\n onAddition={({ name: newTag }) => onChange(\n // * Avoid duplicated tags (thanks to the Set),\n // * Split any of the new tags by comma, allowing to paste multiple comma-separated tags at once.\n [ ...new Set([ ...selectedTags, ...newTag.toLowerCase().split(',') ]) ],\n )}\n />\n );\n};\n\nexport default TagsSelector;\n","import { Card, CardHeader, CardBody, Button, Collapse } from 'reactstrap';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faTrash as deleteIcon, faPencilAlt as editIcon, faLink, faEye } from '@fortawesome/free-solid-svg-icons';\nimport { FC, useEffect, useRef } from 'react';\nimport { Link } from 'react-router-dom';\nimport { prettify } from '../utils/helpers/numbers';\nimport { useToggle } from '../utils/helpers/hooks';\nimport ColorGenerator from '../utils/services/ColorGenerator';\nimport { isServerWithId, SelectedServer } from '../servers/data';\nimport TagBullet from './helpers/TagBullet';\nimport { TagModalProps, TagStats } from './data';\nimport './TagCard.scss';\n\nexport interface TagCardProps {\n tag: string;\n tagStats?: TagStats;\n selectedServer: SelectedServer;\n displayed: boolean;\n toggle: () => void;\n}\n\nconst isTruncated = (el: HTMLElement | undefined): boolean => !!el && el.scrollWidth > el.clientWidth;\n\nconst TagCard = (\n DeleteTagConfirmModal: FC<TagModalProps>,\n EditTagModal: FC<TagModalProps>,\n colorGenerator: ColorGenerator,\n) => ({ tag, tagStats, selectedServer, displayed, toggle }: TagCardProps) => {\n const [ isDeleteModalOpen, toggleDelete ] = useToggle();\n const [ isEditModalOpen, toggleEdit ] = useToggle();\n const [ hasTitle,, displayTitle ] = useToggle();\n const titleRef = useRef<HTMLElement>();\n const serverId = isServerWithId(selectedServer) ? selectedServer.id : '';\n\n useEffect(() => {\n if (isTruncated(titleRef.current)) {\n displayTitle();\n }\n }, [ titleRef.current ]);\n\n return (\n <Card className=\"tag-card\">\n <CardHeader className=\"tag-card__header\">\n <Button color=\"link\" size=\"sm\" className=\"tag-card__btn tag-card__btn--last\" onClick={toggleDelete}>\n <FontAwesomeIcon icon={deleteIcon} />\n </Button>\n <Button color=\"link\" size=\"sm\" className=\"tag-card__btn\" onClick={toggleEdit}>\n <FontAwesomeIcon icon={editIcon} />\n </Button>\n <h5\n className=\"tag-card__tag-title text-ellipsis\"\n title={hasTitle ? tag : undefined}\n ref={(el) => {\n titleRef.current = el ?? undefined;\n }}\n >\n <TagBullet tag={tag} colorGenerator={colorGenerator} />\n <span className=\"tag-card__tag-name\" onClick={toggle}>{tag}</span>\n </h5>\n </CardHeader>\n\n {tagStats && (\n <Collapse isOpen={displayed}>\n <CardBody className=\"tag-card__body\">\n <Link\n to={`/server/${serverId}/list-short-urls/1?tag=${encodeURIComponent(tag)}`}\n className=\"btn btn-outline-secondary btn-block d-flex justify-content-between align-items-center mb-1\"\n >\n <span className=\"text-ellipsis\"><FontAwesomeIcon icon={faLink} className=\"mr-2\" />Short URLs</span>\n <b>{prettify(tagStats.shortUrlsCount)}</b>\n </Link>\n <Link\n to={`/server/${serverId}/tag/${tag}/visits`}\n className=\"btn btn-outline-secondary btn-block d-flex justify-content-between align-items-center\"\n >\n <span className=\"text-ellipsis\"><FontAwesomeIcon icon={faEye} className=\"mr-2\" />Visits</span>\n <b>{prettify(tagStats.visitsCount)}</b>\n </Link>\n </CardBody>\n </Collapse>\n )}\n\n <DeleteTagConfirmModal tag={tag} toggle={toggleDelete} isOpen={isDeleteModalOpen} />\n <EditTagModal tag={tag} toggle={toggleEdit} isOpen={isEditModalOpen} />\n </Card>\n );\n};\n\nexport default TagCard;\n","import { Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap';\nimport { TagDeletion } from '../reducers/tagDelete';\nimport { TagModalProps } from '../data';\nimport { Result } from '../../utils/Result';\nimport { ShlinkApiError } from '../../api/ShlinkApiError';\n\ninterface DeleteTagConfirmModalProps extends TagModalProps {\n deleteTag: (tag: string) => Promise<void>;\n tagDeleted: (tag: string) => void;\n tagDelete: TagDeletion;\n}\n\nconst DeleteTagConfirmModal = (\n { tag, toggle, isOpen, deleteTag, tagDelete, tagDeleted }: DeleteTagConfirmModalProps,\n) => {\n const { deleting, error, errorData } = tagDelete;\n const doDelete = async () => {\n await deleteTag(tag);\n tagDeleted(tag);\n toggle();\n };\n\n return (\n <Modal toggle={toggle} isOpen={isOpen} centered>\n <ModalHeader toggle={toggle}>\n <span className=\"text-danger\">Delete tag</span>\n </ModalHeader>\n <ModalBody>\n Are you sure you want to delete tag <b>{tag}</b>?\n {error && (\n <Result type=\"error\" small className=\"mt-2\">\n <ShlinkApiError errorData={errorData} fallbackMessage=\"Something went wrong while deleting the tag :(\" />\n </Result>\n )}\n </ModalBody>\n <ModalFooter>\n <button className=\"btn btn-link\" onClick={toggle}>Cancel</button>\n <button className=\"btn btn-danger\" disabled={deleting} onClick={doDelete}>\n {deleting ? 'Deleting tag...' : 'Delete tag'}\n </button>\n </ModalFooter>\n </Modal>\n );\n};\n\nexport default DeleteTagConfirmModal;\n","import { useState } from 'react';\nimport { Button, Input, Modal, ModalBody, ModalFooter, ModalHeader, Popover } from 'reactstrap';\nimport { ChromePicker } from 'react-color';\nimport { faPalette as colorIcon } from '@fortawesome/free-solid-svg-icons';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { useToggle } from '../../utils/helpers/hooks';\nimport { handleEventPreventingDefault } from '../../utils/utils';\nimport ColorGenerator from '../../utils/services/ColorGenerator';\nimport { TagModalProps } from '../data';\nimport { TagEdition } from '../reducers/tagEdit';\nimport { Result } from '../../utils/Result';\nimport { ShlinkApiError } from '../../api/ShlinkApiError';\nimport './EditTagModal.scss';\n\ninterface EditTagModalProps extends TagModalProps {\n tagEdit: TagEdition;\n editTag: (oldName: string, newName: string, color: string) => Promise<void>;\n tagEdited: (oldName: string, newName: string, color: string) => void;\n}\n\nconst EditTagModal = ({ getColorForKey }: ColorGenerator) => (\n { tag, editTag, toggle, tagEdited, isOpen, tagEdit }: EditTagModalProps,\n) => {\n const [ newTagName, setNewTagName ] = useState(tag);\n const [ color, setColor ] = useState(getColorForKey(tag));\n const [ showColorPicker, toggleColorPicker, , hideColorPicker ] = useToggle();\n const { editing, error, errorData } = tagEdit;\n const saveTag = handleEventPreventingDefault(\n async () => editTag(tag, newTagName, color)\n .then(() => tagEdited(tag, newTagName, color))\n .then(toggle)\n .catch(() => {}),\n );\n\n return (\n <Modal isOpen={isOpen} toggle={toggle} centered onClosed={hideColorPicker}>\n <form onSubmit={saveTag}>\n <ModalHeader toggle={toggle}>Edit tag</ModalHeader>\n <ModalBody>\n <div className=\"input-group\">\n <div className=\"input-group-prepend\" id=\"colorPickerBtn\" onClick={toggleColorPicker}>\n <div\n className=\"input-group-text edit-tag-modal__color-picker-toggle\"\n style={{ backgroundColor: color, borderColor: color }}\n >\n <FontAwesomeIcon icon={colorIcon} className=\"edit-tag-modal__color-icon\" />\n </div>\n </div>\n <Popover isOpen={showColorPicker} toggle={toggleColorPicker} target=\"colorPickerBtn\" placement=\"right\">\n <ChromePicker color={color} disableAlpha onChange={({ hex }) => setColor(hex)} />\n </Popover>\n <Input\n value={newTagName}\n placeholder=\"Tag\"\n required\n onChange={({ target }) => setNewTagName(target.value)}\n />\n </div>\n\n {error && (\n <Result type=\"error\" small className=\"mt-2\">\n <ShlinkApiError errorData={errorData} fallbackMessage=\"Something went wrong while editing the tag :(\" />\n </Result>\n )}\n </ModalBody>\n <ModalFooter>\n <Button type=\"button\" color=\"link\" onClick={toggle}>Cancel</Button>\n <Button color=\"primary\" disabled={editing}>{editing ? 'Saving...' : 'Save'}</Button>\n </ModalFooter>\n </form>\n </Modal>\n );\n};\n\nexport default EditTagModal;\n","import { FC } from 'react';\nimport { DropdownItem } from 'reactstrap';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faBars as listIcon, faThLarge as cardsIcon } from '@fortawesome/free-solid-svg-icons';\nimport { DropdownBtn } from '../utils/DropdownBtn';\nimport { TagsMode } from '../settings/reducers/settings';\n\ninterface TagsModeDropdownProps {\n mode: TagsMode;\n onChange: (newMode: TagsMode) => void;\n renderTitle?: (mode: TagsMode) => string;\n}\n\nexport const TagsModeDropdown: FC<TagsModeDropdownProps> = ({ mode, onChange, renderTitle }) => (\n <DropdownBtn text={renderTitle?.(mode) ?? `Display mode: ${mode}`}>\n <DropdownItem active={mode === 'cards'} onClick={() => onChange('cards')}>\n <FontAwesomeIcon icon={cardsIcon} fixedWidth className=\"mr-1\" /> Cards\n </DropdownItem>\n <DropdownItem active={mode === 'list'} onClick={() => onChange('list')}>\n <FontAwesomeIcon icon={listIcon} fixedWidth className=\"mr-1\" /> List\n </DropdownItem>\n </DropdownBtn>\n);\n","import { FC, useEffect, useState } from 'react';\nimport { Row } from 'reactstrap';\nimport Message from '../utils/Message';\nimport SearchField from '../utils/SearchField';\nimport { SelectedServer } from '../servers/data';\nimport { boundToMercureHub } from '../mercure/helpers/boundToMercureHub';\nimport { Result } from '../utils/Result';\nimport { ShlinkApiError } from '../api/ShlinkApiError';\nimport { Topics } from '../mercure/helpers/Topics';\nimport { Settings, TagsMode } from '../settings/reducers/settings';\nimport { TagsList as TagsListState } from './reducers/tagsList';\nimport { TagsListChildrenProps } from './data/TagsListChildrenProps';\nimport { TagsModeDropdown } from './TagsModeDropdown';\n\nexport interface TagsListProps {\n filterTags: (searchTerm: string) => void;\n forceListTags: Function;\n tagsList: TagsListState;\n selectedServer: SelectedServer;\n settings: Settings;\n}\n\nconst TagsList = (TagsCards: FC<TagsListChildrenProps>, TagsTable: FC<TagsListChildrenProps>) => boundToMercureHub((\n { filterTags, forceListTags, tagsList, selectedServer, settings }: TagsListProps,\n) => {\n const [ mode, setMode ] = useState<TagsMode>(settings.ui?.tagsMode ?? 'cards');\n\n useEffect(() => {\n forceListTags();\n }, []);\n\n if (tagsList.loading) {\n return <Message loading />;\n }\n\n const renderContent = () => {\n if (tagsList.error) {\n return (\n <Result type=\"error\">\n <ShlinkApiError errorData={tagsList.errorData} fallbackMessage=\"Error loading tags :(\" />\n </Result>\n );\n }\n\n if (tagsList.filteredTags.length < 1) {\n return <Message>No tags found</Message>;\n }\n\n return mode === 'cards'\n ? <TagsCards tagsList={tagsList} selectedServer={selectedServer} />\n : <TagsTable tagsList={tagsList} selectedServer={selectedServer} />;\n };\n\n return (\n <>\n <SearchField className=\"mb-3\" onChange={filterTags} />\n <Row className=\"mb-3\">\n <div className=\"col-lg-6 offset-lg-6\">\n <TagsModeDropdown mode={mode} onChange={setMode} />\n </div>\n </Row>\n {renderContent()}\n </>\n );\n}, () => [ Topics.visits ]);\n\nexport default TagsList;\n","import { Action, Dispatch } from 'redux';\nimport { buildReducer } from '../../utils/helpers/redux';\nimport { GetState } from '../../container/types';\nimport { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';\nimport { ProblemDetailsError } from '../../api/types';\nimport { parseApiError } from '../../api/utils';\nimport { ApiErrorAction } from '../../api/types/actions';\n\n/* eslint-disable padding-line-between-statements */\nexport const DELETE_TAG_START = 'shlink/deleteTag/DELETE_TAG_START';\nexport const DELETE_TAG_ERROR = 'shlink/deleteTag/DELETE_TAG_ERROR';\nexport const DELETE_TAG = 'shlink/deleteTag/DELETE_TAG';\nexport const TAG_DELETED = 'shlink/deleteTag/TAG_DELETED';\n/* eslint-enable padding-line-between-statements */\n\nexport interface TagDeletion {\n deleting: boolean;\n error: boolean;\n errorData?: ProblemDetailsError;\n}\n\nexport interface DeleteTagAction extends Action<string> {\n tag: string;\n}\n\nconst initialState: TagDeletion = {\n deleting: false,\n error: false,\n};\n\nexport default buildReducer<TagDeletion, ApiErrorAction>({\n [DELETE_TAG_START]: () => ({ deleting: true, error: false }),\n [DELETE_TAG_ERROR]: (_, { errorData }) => ({ deleting: false, error: true, errorData }),\n [DELETE_TAG]: () => ({ deleting: false, error: false }),\n}, initialState);\n\nexport const deleteTag = (buildShlinkApiClient: ShlinkApiClientBuilder) => (tag: string) => async (\n dispatch: Dispatch,\n getState: GetState,\n) => {\n dispatch({ type: DELETE_TAG_START });\n const { deleteTags } = buildShlinkApiClient(getState);\n\n try {\n await deleteTags([ tag ]);\n dispatch({ type: DELETE_TAG });\n } catch (e) {\n dispatch<ApiErrorAction>({ type: DELETE_TAG_ERROR, errorData: parseApiError(e) });\n\n throw e;\n }\n};\n\nexport const tagDeleted = (tag: string): DeleteTagAction => ({ type: TAG_DELETED, tag });\n","import { pick } from 'ramda';\nimport { Action, Dispatch } from 'redux';\nimport { buildReducer } from '../../utils/helpers/redux';\nimport { GetState } from '../../container/types';\nimport ColorGenerator from '../../utils/services/ColorGenerator';\nimport { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';\nimport { ProblemDetailsError } from '../../api/types';\nimport { parseApiError } from '../../api/utils';\nimport { ApiErrorAction } from '../../api/types/actions';\n\n/* eslint-disable padding-line-between-statements */\nexport const EDIT_TAG_START = 'shlink/editTag/EDIT_TAG_START';\nexport const EDIT_TAG_ERROR = 'shlink/editTag/EDIT_TAG_ERROR';\nexport const EDIT_TAG = 'shlink/editTag/EDIT_TAG';\n/* eslint-enable padding-line-between-statements */\n\nexport const TAG_EDITED = 'shlink/editTag/TAG_EDITED';\n\nexport interface TagEdition {\n oldName: string;\n newName: string;\n editing: boolean;\n error: boolean;\n errorData?: ProblemDetailsError;\n}\n\nexport interface EditTagAction extends Action<string> {\n oldName: string;\n newName: string;\n color: string;\n}\n\nconst initialState: TagEdition = {\n oldName: '',\n newName: '',\n editing: false,\n error: false,\n};\n\nexport default buildReducer<TagEdition, EditTagAction & ApiErrorAction>({\n [EDIT_TAG_START]: (state) => ({ ...state, editing: true, error: false }),\n [EDIT_TAG_ERROR]: (state, { errorData }) => ({ ...state, editing: false, error: true, errorData }),\n [EDIT_TAG]: (_, action) => ({\n ...pick([ 'oldName', 'newName' ], action),\n editing: false,\n error: false,\n }),\n}, initialState);\n\nexport const editTag = (buildShlinkApiClient: ShlinkApiClientBuilder, colorGenerator: ColorGenerator) => (\n oldName: string,\n newName: string,\n color: string,\n) => async (dispatch: Dispatch, getState: GetState) => {\n dispatch({ type: EDIT_TAG_START });\n const { editTag } = buildShlinkApiClient(getState);\n\n try {\n await editTag(oldName, newName);\n colorGenerator.setColorForKey(newName, color);\n dispatch({ type: EDIT_TAG, oldName, newName });\n } catch (e) {\n dispatch<ApiErrorAction>({ type: EDIT_TAG_ERROR, errorData: parseApiError(e) });\n\n throw e;\n }\n};\n\nexport const tagEdited = (oldName: string, newName: string, color: string): EditTagAction => ({\n type: TAG_EDITED,\n oldName,\n newName,\n color,\n});\n","import { isEmpty, reject } from 'ramda';\nimport { Action, Dispatch } from 'redux';\nimport { CREATE_VISITS, CreateVisitsAction } from '../../visits/reducers/visitCreation';\nimport { buildReducer } from '../../utils/helpers/redux';\nimport { ProblemDetailsError, ShlinkTags } from '../../api/types';\nimport { GetState } from '../../container/types';\nimport { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';\nimport { CreateVisit, Stats } from '../../visits/types';\nimport { parseApiError } from '../../api/utils';\nimport { TagStats } from '../data';\nimport { ApiErrorAction } from '../../api/types/actions';\nimport { DeleteTagAction, TAG_DELETED } from './tagDelete';\nimport { EditTagAction, TAG_EDITED } from './tagEdit';\n\n/* eslint-disable padding-line-between-statements */\nexport const LIST_TAGS_START = 'shlink/tagsList/LIST_TAGS_START';\nexport const LIST_TAGS_ERROR = 'shlink/tagsList/LIST_TAGS_ERROR';\nexport const LIST_TAGS = 'shlink/tagsList/LIST_TAGS';\nexport const FILTER_TAGS = 'shlink/tagsList/FILTER_TAGS';\n/* eslint-enable padding-line-between-statements */\n\ntype TagsStatsMap = Record<string, TagStats>;\n\nexport interface TagsList {\n tags: string[];\n filteredTags: string[];\n stats: TagsStatsMap;\n loading: boolean;\n error: boolean;\n errorData?: ProblemDetailsError;\n}\n\ninterface ListTagsAction extends Action<string> {\n tags: string[];\n stats: TagsStatsMap;\n}\n\ninterface FilterTagsAction extends Action<string> {\n searchTerm: string;\n}\n\ntype TagsCombinedAction = ListTagsAction\n& DeleteTagAction\n& CreateVisitsAction\n& EditTagAction\n& FilterTagsAction\n& ApiErrorAction;\n\nconst initialState = {\n tags: [],\n filteredTags: [],\n stats: {},\n loading: false,\n error: false,\n};\n\ntype TagIncrease = [string, number];\n\nconst renameTag = (oldName: string, newName: string) => (tag: string) => tag === oldName ? newName : tag;\nconst rejectTag = (tags: string[], tagToReject: string) => reject((tag) => tag === tagToReject, tags);\nconst increaseVisitsForTags = (tags: TagIncrease[], stats: TagsStatsMap) => tags.reduce((stats, [ tag, increase ]) => {\n if (!stats[tag]) {\n return stats;\n }\n\n const tagStats = stats[tag];\n\n tagStats.visitsCount = tagStats.visitsCount + increase;\n stats[tag] = tagStats;\n\n return stats;\n}, { ...stats });\nconst calculateVisitsPerTag = (createdVisits: CreateVisit[]): TagIncrease[] => Object.entries(\n createdVisits.reduce<Stats>((acc, { shortUrl }) => {\n shortUrl?.tags.forEach((tag) => {\n acc[tag] = (acc[tag] || 0) + 1;\n });\n\n return acc;\n }, {}),\n);\n\nexport default buildReducer<TagsList, TagsCombinedAction>({\n [LIST_TAGS_START]: () => ({ ...initialState, loading: true }),\n [LIST_TAGS_ERROR]: (_, { errorData }) => ({ ...initialState, error: true, errorData }),\n [LIST_TAGS]: (_, { tags, stats }) => ({ ...initialState, stats, tags, filteredTags: tags }),\n [TAG_DELETED]: (state, { tag }) => ({\n ...state,\n tags: rejectTag(state.tags, tag),\n filteredTags: rejectTag(state.filteredTags, tag),\n }),\n [TAG_EDITED]: (state, { oldName, newName }) => ({\n ...state,\n tags: state.tags.map(renameTag(oldName, newName)).sort(),\n filteredTags: state.filteredTags.map(renameTag(oldName, newName)).sort(),\n }),\n [FILTER_TAGS]: (state, { searchTerm }) => ({\n ...state,\n filteredTags: state.tags.filter((tag) => tag.toLowerCase().match(searchTerm)),\n }),\n [CREATE_VISITS]: (state, { createdVisits }) => ({\n ...state,\n stats: increaseVisitsForTags(calculateVisitsPerTag(createdVisits), state.stats),\n }),\n}, initialState);\n\nexport const listTags = (buildShlinkApiClient: ShlinkApiClientBuilder, force = true) => () => async (\n dispatch: Dispatch,\n getState: GetState,\n) => {\n const { tagsList } = getState();\n\n if (!force && (tagsList.loading || !isEmpty(tagsList.tags))) {\n return;\n }\n\n dispatch({ type: LIST_TAGS_START });\n\n try {\n const { listTags } = buildShlinkApiClient(getState);\n const { tags, stats = [] }: ShlinkTags = await listTags();\n const processedStats = stats.reduce<TagsStatsMap>((acc, { tag, shortUrlsCount, visitsCount }) => {\n acc[tag] = { shortUrlsCount, visitsCount };\n\n return acc;\n }, {});\n\n dispatch<ListTagsAction>({ tags, stats: processedStats, type: LIST_TAGS });\n } catch (e) {\n dispatch<ApiErrorAction>({ type: LIST_TAGS_ERROR, errorData: parseApiError(e) });\n }\n};\n\nexport const filterTags = (searchTerm: string): FilterTagsAction => ({ type: FILTER_TAGS, searchTerm });\n","import { FC, useState } from 'react';\nimport { splitEvery } from 'ramda';\nimport { Row } from 'reactstrap';\nimport { TagCardProps } from './TagCard';\nimport { TagsListChildrenProps } from './data/TagsListChildrenProps';\n\nconst { ceil } = Math;\nconst TAGS_GROUPS_AMOUNT = 4;\n\nexport const TagsCards = (TagCard: FC<TagCardProps>): FC<TagsListChildrenProps> => ({ tagsList, selectedServer }) => {\n const [ displayedTag, setDisplayedTag ] = useState<string | undefined>();\n const tagsCount = tagsList.filteredTags.length;\n const tagsGroups = splitEvery(ceil(tagsCount / TAGS_GROUPS_AMOUNT), tagsList.filteredTags);\n\n return (\n <Row>\n {tagsGroups.map((group, index) => (\n <div key={index} className=\"col-md-6 col-xl-3\">\n {group.map((tag) => (\n <TagCard\n key={tag}\n tag={tag}\n tagStats={tagsList.stats[tag]}\n selectedServer={selectedServer}\n displayed={displayedTag === tag}\n toggle={() => setDisplayedTag(displayedTag !== tag ? tag : undefined)}\n />\n ))}\n </div>\n ))}\n </Row>\n );\n};\n","import { FC, useEffect, useRef } from 'react';\nimport { splitEvery } from 'ramda';\nimport { RouteChildrenProps } from 'react-router';\nimport { SimpleCard } from '../utils/SimpleCard';\nimport ColorGenerator from '../utils/services/ColorGenerator';\nimport SimplePaginator from '../common/SimplePaginator';\nimport { useQueryState } from '../utils/helpers/hooks';\nimport { parseQuery } from '../utils/helpers/query';\nimport { TagsListChildrenProps } from './data/TagsListChildrenProps';\nimport { TagsTableRowProps } from './TagsTableRow';\n\nconst TAGS_PER_PAGE = 20; // TODO Allow customizing this value in settings\n\nexport const TagsTable = (colorGenerator: ColorGenerator, TagsTableRow: FC<TagsTableRowProps>) => (\n { tagsList, selectedServer, location }: TagsListChildrenProps & RouteChildrenProps,\n) => {\n const isFirstLoad = useRef(true);\n const { page: pageFromQuery = 1 } = parseQuery<{ page?: number | string }>(location.search);\n const [ page, setPage ] = useQueryState<number>('page', Number(pageFromQuery));\n const sortedTags = tagsList.filteredTags; // TODO Support sorting tags\n const pages = splitEvery(TAGS_PER_PAGE, sortedTags);\n const showPaginator = pages.length > 1;\n const currentPage = pages[page - 1] ?? [];\n\n useEffect(() => {\n !isFirstLoad.current && setPage(1);\n isFirstLoad.current = false;\n }, [ tagsList.filteredTags ]);\n useEffect(() => {\n scrollTo(0, 0);\n }, [ page ]);\n\n return (\n <SimpleCard key={page} bodyClassName={showPaginator ? 'pb-1' : ''}>\n <table className=\"table table-hover mb-0\">\n <thead className=\"responsive-table__header\">\n <tr>\n <th>Tag</th>\n <th className=\"text-lg-right\">Short URLs</th>\n <th className=\"text-lg-right\">Visits</th>\n <th />\n </tr>\n </thead>\n <tbody>\n {currentPage.length === 0 && <tr><td colSpan={4} className=\"text-center\">No results found</td></tr>}\n {currentPage.map((tag) => (\n <TagsTableRow\n key={tag}\n tag={tag}\n tagStats={tagsList.stats[tag]}\n selectedServer={selectedServer}\n colorGenerator={colorGenerator}\n />\n ))}\n </tbody>\n </table>\n\n {showPaginator && (\n <div className=\"sticky-card-paginator\">\n <SimplePaginator pagesCount={pages.length} currentPage={page} setCurrentPage={setPage} />\n </div>\n )}\n </SimpleCard>\n );\n};\n","import { FC } from 'react';\nimport { Link } from 'react-router-dom';\nimport { DropdownItem } from 'reactstrap';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faTrash as deleteIcon, faPencilAlt as editIcon } from '@fortawesome/free-solid-svg-icons';\nimport { getServerId, SelectedServer } from '../servers/data';\nimport ColorGenerator from '../utils/services/ColorGenerator';\nimport { prettify } from '../utils/helpers/numbers';\nimport { useToggle } from '../utils/helpers/hooks';\nimport { DropdownBtnMenu } from '../utils/DropdownBtnMenu';\nimport TagBullet from './helpers/TagBullet';\nimport { TagModalProps, TagStats } from './data';\n\nexport interface TagsTableRowProps {\n tag: string;\n tagStats?: TagStats;\n selectedServer: SelectedServer;\n colorGenerator: ColorGenerator;\n}\n\nexport const TagsTableRow = (DeleteTagConfirmModal: FC<TagModalProps>, EditTagModal: FC<TagModalProps>) => (\n { tag, tagStats, colorGenerator, selectedServer }: TagsTableRowProps,\n) => {\n const [ isDeleteModalOpen, toggleDelete ] = useToggle();\n const [ isEditModalOpen, toggleEdit ] = useToggle();\n const [ isDropdownOpen, toggleDropdown ] = useToggle();\n const serverId = getServerId(selectedServer);\n\n return (\n <tr className=\"responsive-table__row\">\n <th className=\"responsive-table__cell\" data-th=\"Tag\">\n <TagBullet tag={tag} colorGenerator={colorGenerator} /> {tag}\n </th>\n <td className=\"responsive-table__cell text-lg-right\" data-th=\"Short URLs\">\n <Link to={`/server/${serverId}/list-short-urls/1?tag=${encodeURIComponent(tag)}`}>\n {prettify(tagStats?.shortUrlsCount ?? 0)}\n </Link>\n </td>\n <td className=\"responsive-table__cell text-lg-right\" data-th=\"Visits\">\n <Link to={`/server/${serverId}/tag/${tag}/visits`}>\n {prettify(tagStats?.visitsCount ?? 0)}\n </Link>\n </td>\n <td className=\"responsive-table__cell text-lg-right\">\n <DropdownBtnMenu toggle={toggleDropdown} isOpen={isDropdownOpen}>\n <DropdownItem onClick={toggleEdit}>\n <FontAwesomeIcon icon={editIcon} fixedWidth className=\"mr-1\" /> Edit\n </DropdownItem>\n <DropdownItem onClick={toggleDelete}>\n <FontAwesomeIcon icon={deleteIcon} fixedWidth className=\"mr-1\" /> Delete\n </DropdownItem>\n </DropdownBtnMenu>\n </td>\n\n <EditTagModal tag={tag} toggle={toggleEdit} isOpen={isEditModalOpen} />\n <DeleteTagConfirmModal tag={tag} toggle={toggleDelete} isOpen={isDeleteModalOpen} />\n </tr>\n );\n};\n","import Bottle, { IContainer } from 'bottlejs';\nimport { withRouter } from 'react-router-dom';\nimport TagsSelector from '../helpers/TagsSelector';\nimport TagCard from '../TagCard';\nimport DeleteTagConfirmModal from '../helpers/DeleteTagConfirmModal';\nimport EditTagModal from '../helpers/EditTagModal';\nimport TagsList from '../TagsList';\nimport { filterTags, listTags } from '../reducers/tagsList';\nimport { deleteTag, tagDeleted } from '../reducers/tagDelete';\nimport { editTag, tagEdited } from '../reducers/tagEdit';\nimport { ConnectDecorator } from '../../container/types';\nimport { TagsCards } from '../TagsCards';\nimport { TagsTable } from '../TagsTable';\nimport { TagsTableRow } from '../TagsTableRow';\n\nconst provideServices = (bottle: Bottle, connect: ConnectDecorator) => {\n // Components\n bottle.serviceFactory('TagsSelector', TagsSelector, 'ColorGenerator');\n bottle.decorator('TagsSelector', connect([ 'tagsList', 'settings' ], [ 'listTags' ]));\n\n bottle.serviceFactory('TagCard', TagCard, 'DeleteTagConfirmModal', 'EditTagModal', 'ColorGenerator');\n\n bottle.serviceFactory('DeleteTagConfirmModal', () => DeleteTagConfirmModal);\n bottle.decorator('DeleteTagConfirmModal', connect([ 'tagDelete' ], [ 'deleteTag', 'tagDeleted' ]));\n\n bottle.serviceFactory('EditTagModal', EditTagModal, 'ColorGenerator');\n bottle.decorator('EditTagModal', connect([ 'tagEdit' ], [ 'editTag', 'tagEdited' ]));\n\n bottle.serviceFactory('TagsCards', TagsCards, 'TagCard');\n bottle.serviceFactory('TagsTableRow', TagsTableRow, 'DeleteTagConfirmModal', 'EditTagModal');\n\n bottle.serviceFactory('TagsTable', TagsTable, 'ColorGenerator', 'TagsTableRow');\n bottle.decorator('TagsTable', withRouter);\n\n bottle.serviceFactory('TagsList', TagsList, 'TagsCards', 'TagsTable');\n bottle.decorator('TagsList', connect(\n [ 'tagsList', 'selectedServer', 'mercureInfo', 'settings' ],\n [ 'forceListTags', 'filterTags', 'createNewVisits', 'loadMercureInfo' ],\n ));\n\n // Actions\n const listTagsActionFactory = (force: boolean) =>\n ({ buildShlinkApiClient }: IContainer) => listTags(buildShlinkApiClient, force);\n\n bottle.factory('listTags', listTagsActionFactory(false));\n bottle.factory('forceListTags', listTagsActionFactory(true));\n bottle.serviceFactory('filterTags', () => filterTags);\n bottle.serviceFactory('tagDeleted', () => tagDeleted);\n bottle.serviceFactory('tagEdited', () => tagEdited);\n\n bottle.serviceFactory('deleteTag', deleteTag, 'buildShlinkApiClient');\n bottle.serviceFactory('editTag', editTag, 'buildShlinkApiClient', 'ColorGenerator');\n};\n\nexport default provideServices;\n","import { Action, Dispatch } from 'redux';\nimport { ShlinkMercureInfo } from '../../api/types';\nimport { GetState } from '../../container/types';\nimport { buildReducer } from '../../utils/helpers/redux';\nimport { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';\n\n/* eslint-disable padding-line-between-statements */\nexport const GET_MERCURE_INFO_START = 'shlink/mercure/GET_MERCURE_INFO_START';\nexport const GET_MERCURE_INFO_ERROR = 'shlink/mercure/GET_MERCURE_INFO_ERROR';\nexport const GET_MERCURE_INFO = 'shlink/mercure/GET_MERCURE_INFO';\n/* eslint-enable padding-line-between-statements */\n\nexport interface MercureInfo {\n token?: string;\n mercureHubUrl?: string;\n interval?: number;\n loading: boolean;\n error: boolean;\n}\n\nexport type GetMercureInfoAction = Action<string> & ShlinkMercureInfo & { interval?: number };\n\nconst initialState: MercureInfo = {\n loading: true,\n error: false,\n};\n\nexport default buildReducer<MercureInfo, GetMercureInfoAction>({\n [GET_MERCURE_INFO_START]: (state) => ({ ...state, loading: true, error: false }),\n [GET_MERCURE_INFO_ERROR]: (state) => ({ ...state, loading: false, error: true }),\n [GET_MERCURE_INFO]: (_, action) => ({ ...action, loading: false, error: false }),\n}, initialState);\n\nexport const loadMercureInfo = (buildShlinkApiClient: ShlinkApiClientBuilder) =>\n () => async (dispatch: Dispatch, getState: GetState) => {\n dispatch({ type: GET_MERCURE_INFO_START });\n\n const { settings } = getState();\n const { mercureInfo } = buildShlinkApiClient(getState);\n\n if (!settings.realTimeUpdates.enabled) {\n dispatch({ type: GET_MERCURE_INFO_ERROR });\n\n return;\n }\n\n try {\n const info = await mercureInfo();\n\n dispatch<GetMercureInfoAction>({ type: GET_MERCURE_INFO, interval: settings.realTimeUpdates.interval, ...info });\n } catch (e) {\n dispatch({ type: GET_MERCURE_INFO_ERROR });\n }\n };\n","import Bottle from 'bottlejs';\nimport { loadMercureInfo } from '../reducers/mercureInfo';\n\nconst provideServices = (bottle: Bottle) => {\n // Actions\n bottle.serviceFactory('loadMercureInfo', loadMercureInfo, 'buildShlinkApiClient');\n};\n\nexport default provideServices;\n","import { FormGroup, Input } from 'reactstrap';\nimport classNames from 'classnames';\nimport ToggleSwitch from '../utils/ToggleSwitch';\nimport { SimpleCard } from '../utils/SimpleCard';\nimport { Settings } from './reducers/settings';\n\ninterface RealTimeUpdatesProps {\n settings: Settings;\n toggleRealTimeUpdates: (enabled: boolean) => void;\n setRealTimeUpdatesInterval: (interval: number) => void;\n}\n\nconst intervalValue = (interval?: number) => !interval ? '' : `${interval}`;\n\nconst RealTimeUpdates = (\n { settings: { realTimeUpdates }, toggleRealTimeUpdates, setRealTimeUpdatesInterval }: RealTimeUpdatesProps,\n) => (\n <SimpleCard title=\"Real-time updates\" className=\"h-100\">\n <FormGroup>\n <ToggleSwitch checked={realTimeUpdates.enabled} onChange={toggleRealTimeUpdates}>\n Enable or disable real-time updates, when using Shlink v2.2.0 or newer.\n <small className=\"form-text text-muted\">\n Real-time updates are currently being <b>{realTimeUpdates.enabled ? 'processed' : 'ignored'}</b>.\n </small>\n </ToggleSwitch>\n </FormGroup>\n <FormGroup className=\"mb-0\">\n <label className={classNames({ 'text-muted': !realTimeUpdates.enabled })}>\n Real-time updates frequency (in minutes):\n </label>\n <Input\n type=\"number\"\n min={0}\n placeholder=\"Immediate\"\n disabled={!realTimeUpdates.enabled}\n value={intervalValue(realTimeUpdates.interval)}\n onChange={({ target }) => setRealTimeUpdatesInterval(Number(target.value))}\n />\n {realTimeUpdates.enabled && (\n <small className=\"form-text text-muted\">\n {realTimeUpdates.interval !== undefined && realTimeUpdates.interval > 0 && (\n <span>\n Updates will be reflected in the UI every <b>{realTimeUpdates.interval}</b> minute{realTimeUpdates.interval > 1 && 's'}.\n </span>\n )}\n {!realTimeUpdates.interval && 'Updates will be reflected in the UI as soon as they happen.'}\n </small>\n )}\n </FormGroup>\n </SimpleCard>\n);\n\nexport default RealTimeUpdates;\n","import { FC, ReactNode } from 'react';\nimport { Row } from 'reactstrap';\nimport NoMenuLayout from '../common/NoMenuLayout';\n\nconst SettingsSections: FC<{ items: ReactNode[][] }> = ({ items }) => (\n <>\n {items.map((child, index) => (\n <Row key={index}>\n {child.map((subChild, subIndex) => (\n <div key={subIndex} className=\"col-lg-6 mb-3\">\n {subChild}\n </div>\n ))}\n </Row>\n ))}\n </>\n);\n\nconst Settings = (RealTimeUpdates: FC, ShortUrlCreation: FC, UserInterface: FC, Visits: FC) => () => (\n <NoMenuLayout>\n <SettingsSections\n items={[\n [ <UserInterface />, <Visits /> ], // eslint-disable-line react/jsx-key\n [ <ShortUrlCreation />, <RealTimeUpdates /> ], // eslint-disable-line react/jsx-key\n ]}\n />\n </NoMenuLayout>\n);\n\nexport default Settings;\n","import { Action } from 'redux';\nimport { dissoc, mergeDeepRight } from 'ramda';\nimport { buildReducer } from '../../utils/helpers/redux';\nimport { RecursivePartial } from '../../utils/utils';\nimport { Theme } from '../../utils/theme';\nimport { DateInterval } from '../../utils/dates/types';\n\nexport const SET_SETTINGS = 'shlink/realTimeUpdates/SET_SETTINGS';\n\n/**\n * Important! When adding new props in the main Settings interface or any of the nested props, they have to be set as\n * optional, as old instances of the app will load partial objects from local storage until it is saved again.\n */\n\nexport interface RealTimeUpdatesSettings {\n enabled: boolean;\n interval?: number;\n}\n\nexport type TagFilteringMode = 'startsWith' | 'includes';\n\nexport interface ShortUrlCreationSettings {\n validateUrls: boolean;\n tagFilteringMode?: TagFilteringMode;\n}\n\nexport type TagsMode = 'cards' | 'list';\n\nexport interface UiSettings {\n theme: Theme;\n tagsMode?: TagsMode;\n}\n\nexport interface VisitsSettings {\n defaultInterval: DateInterval;\n}\n\nexport interface Settings {\n realTimeUpdates: RealTimeUpdatesSettings;\n shortUrlCreation?: ShortUrlCreationSettings;\n ui?: UiSettings;\n visits?: VisitsSettings;\n}\n\nconst initialState: Settings = {\n realTimeUpdates: {\n enabled: true,\n },\n shortUrlCreation: {\n validateUrls: false,\n },\n ui: {\n theme: 'light',\n },\n visits: {\n defaultInterval: 'last30Days',\n },\n};\n\ntype SettingsAction = Action & Settings;\n\ntype PartialSettingsAction = Action & RecursivePartial<Settings>;\n\nexport default buildReducer<Settings, SettingsAction>({\n [SET_SETTINGS]: (state, action) => mergeDeepRight(state, dissoc('type', action)),\n}, initialState);\n\nexport const toggleRealTimeUpdates = (enabled: boolean): PartialSettingsAction => ({\n type: SET_SETTINGS,\n realTimeUpdates: { enabled },\n});\n\nexport const setRealTimeUpdatesInterval = (interval: number): PartialSettingsAction => ({\n type: SET_SETTINGS,\n realTimeUpdates: { interval },\n});\n\nexport const setShortUrlCreationSettings = (settings: ShortUrlCreationSettings): PartialSettingsAction => ({\n type: SET_SETTINGS,\n shortUrlCreation: settings,\n});\n\nexport const setUiSettings = (settings: UiSettings): PartialSettingsAction => ({\n type: SET_SETTINGS,\n ui: settings,\n});\n\nexport const setVisitsSettings = (settings: VisitsSettings): PartialSettingsAction => ({\n type: SET_SETTINGS,\n visits: settings,\n});\n","import { FC, ReactNode } from 'react';\nimport { DropdownItem, FormGroup } from 'reactstrap';\nimport { SimpleCard } from '../utils/SimpleCard';\nimport ToggleSwitch from '../utils/ToggleSwitch';\nimport { DropdownBtn } from '../utils/DropdownBtn';\nimport { Settings, ShortUrlCreationSettings, TagFilteringMode } from './reducers/settings';\n\ninterface ShortUrlCreationProps {\n settings: Settings;\n setShortUrlCreationSettings: (settings: ShortUrlCreationSettings) => void;\n}\n\nconst tagFilteringModeText = (tagFilteringMode: TagFilteringMode | undefined): string =>\n tagFilteringMode === 'includes' ? 'Suggest tags including input' : 'Suggest tags starting with input';\nconst tagFilteringModeHint = (tagFilteringMode: TagFilteringMode | undefined): ReactNode =>\n tagFilteringMode === 'includes'\n ? <>The list of suggested tags will contain existing ones <b>including</b> provided input.</>\n : <>The list of suggested tags will contain existing ones <b>starting with</b> provided input.</>;\n\nexport const ShortUrlCreation: FC<ShortUrlCreationProps> = ({ settings, setShortUrlCreationSettings }) => {\n const shortUrlCreation: ShortUrlCreationSettings = settings.shortUrlCreation ?? { validateUrls: false };\n const changeTagsFilteringMode = (tagFilteringMode: TagFilteringMode) => () => setShortUrlCreationSettings(\n { ...shortUrlCreation ?? { validateUrls: false }, tagFilteringMode },\n );\n\n return (\n <SimpleCard title=\"Short URLs creation\" className=\"h-100\">\n <FormGroup>\n <ToggleSwitch\n checked={shortUrlCreation.validateUrls ?? false}\n onChange={(validateUrls) => setShortUrlCreationSettings({ ...shortUrlCreation, validateUrls })}\n >\n By default, request validation on long URLs when creating new short URLs.\n <small className=\"form-text text-muted\">\n The initial state of the <b>Validate URL</b> checkbox will\n be <b>{shortUrlCreation.validateUrls ? 'checked' : 'unchecked'}</b>.\n </small>\n </ToggleSwitch>\n </FormGroup>\n <FormGroup className=\"mb-0\">\n <label>Tag suggestions search mode:</label>\n <DropdownBtn text={tagFilteringModeText(shortUrlCreation.tagFilteringMode)}>\n <DropdownItem\n active={!shortUrlCreation.tagFilteringMode || shortUrlCreation.tagFilteringMode === 'startsWith'}\n onClick={changeTagsFilteringMode('startsWith')}\n >\n {tagFilteringModeText('startsWith')}\n </DropdownItem>\n <DropdownItem\n active={shortUrlCreation.tagFilteringMode === 'includes'}\n onClick={changeTagsFilteringMode('includes')}\n >\n {tagFilteringModeText('includes')}\n </DropdownItem>\n </DropdownBtn>\n <small className=\"form-text text-muted\">\n {tagFilteringModeHint(shortUrlCreation.tagFilteringMode)}\n </small>\n </FormGroup>\n </SimpleCard>\n );\n};\n","import { FC } from 'react';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faSun, faMoon } from '@fortawesome/free-solid-svg-icons';\nimport { FormGroup } from 'reactstrap';\nimport { SimpleCard } from '../utils/SimpleCard';\nimport ToggleSwitch from '../utils/ToggleSwitch';\nimport { changeThemeInMarkup, Theme } from '../utils/theme';\nimport { TagsModeDropdown } from '../tags/TagsModeDropdown';\nimport { capitalize } from '../utils/utils';\nimport { Settings, UiSettings } from './reducers/settings';\nimport './UserInterface.scss';\n\ninterface UserInterfaceProps {\n settings: Settings;\n setUiSettings: (settings: UiSettings) => void;\n}\n\nexport const UserInterface: FC<UserInterfaceProps> = ({ settings: { ui }, setUiSettings }) => (\n <SimpleCard title=\"User interface\" className=\"h-100\">\n <FormGroup>\n <FontAwesomeIcon icon={ui?.theme === 'dark' ? faMoon : faSun} className=\"user-interface__theme-icon\" />\n <ToggleSwitch\n checked={ui?.theme === 'dark'}\n onChange={(useDarkTheme) => {\n const theme: Theme = useDarkTheme ? 'dark' : 'light';\n\n setUiSettings({ ...ui, theme });\n changeThemeInMarkup(theme);\n }}\n >\n Use dark theme.\n </ToggleSwitch>\n </FormGroup>\n <FormGroup className=\"mb-0\">\n <label>Default display mode when managing tags:</label>\n <TagsModeDropdown\n mode={ui?.tagsMode ?? 'cards'}\n renderTitle={(tagsMode) => capitalize(tagsMode)}\n onChange={(tagsMode) => setUiSettings({ ...ui ?? { theme: 'light' }, tagsMode })}\n />\n <small className=\"form-text text-muted\">Tags will be displayed as <b>{ui?.tagsMode ?? 'cards'}</b>.</small>\n </FormGroup>\n </SimpleCard>\n);\n","import { FC } from 'react';\nimport { DropdownBtn } from '../DropdownBtn';\nimport { rangeOrIntervalToString } from './types';\nimport { DateIntervalDropdownItems, DateIntervalDropdownProps } from './DateIntervalDropdownItems';\n\nexport const DateIntervalSelector: FC<DateIntervalDropdownProps> = ({ onChange, active }) => (\n <DropdownBtn text={rangeOrIntervalToString(active) ?? ''}>\n <DateIntervalDropdownItems active={active} onChange={onChange} />\n </DropdownBtn>\n);\n","import { FormGroup } from 'reactstrap';\nimport { FC } from 'react';\nimport { SimpleCard } from '../utils/SimpleCard';\nimport { DateIntervalSelector } from '../utils/dates/DateIntervalSelector';\nimport { Settings, VisitsSettings } from './reducers/settings';\n\ninterface VisitsProps {\n settings: Settings;\n setVisitsSettings: (settings: VisitsSettings) => void;\n}\n\nexport const Visits: FC<VisitsProps> = ({ settings, setVisitsSettings }) => (\n <SimpleCard title=\"Visits\" className=\"h-100\">\n <FormGroup className=\"mb-0\">\n <label>Default interval to load on visits sections:</label>\n <DateIntervalSelector\n active={settings.visits?.defaultInterval ?? 'last30Days'}\n onChange={(defaultInterval) => setVisitsSettings({ defaultInterval })}\n />\n </FormGroup>\n </SimpleCard>\n);\n","import Bottle from 'bottlejs';\nimport RealTimeUpdates from '../RealTimeUpdates';\nimport Settings from '../Settings';\nimport {\n setRealTimeUpdatesInterval,\n setShortUrlCreationSettings,\n setUiSettings,\n setVisitsSettings,\n toggleRealTimeUpdates,\n} from '../reducers/settings';\nimport { ConnectDecorator } from '../../container/types';\nimport { withoutSelectedServer } from '../../servers/helpers/withoutSelectedServer';\nimport { ShortUrlCreation } from '../ShortUrlCreation';\nimport { UserInterface } from '../UserInterface';\nimport { Visits } from '../Visits';\n\nconst provideServices = (bottle: Bottle, connect: ConnectDecorator) => {\n // Components\n bottle.serviceFactory('Settings', Settings, 'RealTimeUpdates', 'ShortUrlCreation', 'UserInterface', 'Visits');\n bottle.decorator('Settings', withoutSelectedServer);\n bottle.decorator('Settings', connect(null, [ 'resetSelectedServer' ]));\n\n bottle.serviceFactory('RealTimeUpdates', () => RealTimeUpdates);\n bottle.decorator(\n 'RealTimeUpdates',\n connect([ 'settings' ], [ 'toggleRealTimeUpdates', 'setRealTimeUpdatesInterval' ]),\n );\n\n bottle.serviceFactory('ShortUrlCreation', () => ShortUrlCreation);\n bottle.decorator('ShortUrlCreation', connect([ 'settings' ], [ 'setShortUrlCreationSettings' ]));\n\n bottle.serviceFactory('UserInterface', () => UserInterface);\n bottle.decorator('UserInterface', connect([ 'settings' ], [ 'setUiSettings' ]));\n\n bottle.serviceFactory('Visits', () => Visits);\n bottle.decorator('Visits', connect([ 'settings' ], [ 'setVisitsSettings' ]));\n\n // Actions\n bottle.serviceFactory('toggleRealTimeUpdates', () => toggleRealTimeUpdates);\n bottle.serviceFactory('setRealTimeUpdatesInterval', () => setRealTimeUpdatesInterval);\n bottle.serviceFactory('setShortUrlCreationSettings', () => setShortUrlCreationSettings);\n bottle.serviceFactory('setUiSettings', () => setUiSettings);\n bottle.serviceFactory('setVisitsSettings', () => setVisitsSettings);\n};\n\nexport default provideServices;\n","import { Action, Dispatch } from 'redux';\nimport { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';\nimport { ShlinkDomainRedirects } from '../../api/types';\nimport { GetState } from '../../container/types';\nimport { ApiErrorAction } from '../../api/types/actions';\nimport { parseApiError } from '../../api/utils';\n\n/* eslint-disable padding-line-between-statements */\nexport const EDIT_DOMAIN_REDIRECTS_START = 'shlink/domainRedirects/EDIT_DOMAIN_REDIRECTS_START';\nexport const EDIT_DOMAIN_REDIRECTS_ERROR = 'shlink/domainRedirects/EDIT_DOMAIN_REDIRECTS_ERROR';\nexport const EDIT_DOMAIN_REDIRECTS = 'shlink/domainRedirects/EDIT_DOMAIN_REDIRECTS';\n/* eslint-enable padding-line-between-statements */\n\nexport interface EditDomainRedirectsAction extends Action<string> {\n domain: string;\n redirects: ShlinkDomainRedirects;\n}\n\nexport const editDomainRedirects = (buildShlinkApiClient: ShlinkApiClientBuilder) => (\n domain: string,\n domainRedirects: Partial<ShlinkDomainRedirects>,\n) => async (dispatch: Dispatch, getState: GetState) => {\n dispatch({ type: EDIT_DOMAIN_REDIRECTS_START });\n const { editDomainRedirects } = buildShlinkApiClient(getState);\n\n try {\n const redirects = await editDomainRedirects({ domain, ...domainRedirects });\n\n dispatch<EditDomainRedirectsAction>({ type: EDIT_DOMAIN_REDIRECTS, domain, redirects });\n } catch (e) {\n dispatch<ApiErrorAction>({ type: EDIT_DOMAIN_REDIRECTS_ERROR, errorData: parseApiError(e) });\n }\n};\n","import { Action, Dispatch } from 'redux';\nimport { ProblemDetailsError, ShlinkDomain, ShlinkDomainRedirects } from '../../api/types';\nimport { buildReducer } from '../../utils/helpers/redux';\nimport { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';\nimport { GetState } from '../../container/types';\nimport { parseApiError } from '../../api/utils';\nimport { ApiErrorAction } from '../../api/types/actions';\nimport { EDIT_DOMAIN_REDIRECTS, EditDomainRedirectsAction } from './domainRedirects';\n\n/* eslint-disable padding-line-between-statements */\nexport const LIST_DOMAINS_START = 'shlink/domainsList/LIST_DOMAINS_START';\nexport const LIST_DOMAINS_ERROR = 'shlink/domainsList/LIST_DOMAINS_ERROR';\nexport const LIST_DOMAINS = 'shlink/domainsList/LIST_DOMAINS';\nexport const FILTER_DOMAINS = 'shlink/domainsList/FILTER_DOMAINS';\n/* eslint-enable padding-line-between-statements */\n\nexport interface DomainsList {\n domains: ShlinkDomain[];\n filteredDomains: ShlinkDomain[];\n loading: boolean;\n error: boolean;\n errorData?: ProblemDetailsError;\n}\n\nexport interface ListDomainsAction extends Action<string> {\n domains: ShlinkDomain[];\n}\n\ninterface FilterDomainsAction extends Action<string> {\n searchTerm: string;\n}\n\nconst initialState: DomainsList = {\n domains: [],\n filteredDomains: [],\n loading: false,\n error: false,\n};\n\nexport type DomainsCombinedAction = ListDomainsAction\n& ApiErrorAction\n& FilterDomainsAction\n& EditDomainRedirectsAction;\n\nexport const replaceRedirectsOnDomain = (domain: string, redirects: ShlinkDomainRedirects) =>\n (d: ShlinkDomain): ShlinkDomain => d.domain !== domain ? d : { ...d, redirects };\n\nexport default buildReducer<DomainsList, DomainsCombinedAction>({\n [LIST_DOMAINS_START]: () => ({ ...initialState, loading: true }),\n [LIST_DOMAINS_ERROR]: ({ errorData }) => ({ ...initialState, error: true, errorData }),\n [LIST_DOMAINS]: (_, { domains }) => ({ ...initialState, domains, filteredDomains: domains }),\n [FILTER_DOMAINS]: (state, { searchTerm }) => ({\n ...state,\n filteredDomains: state.domains.filter(({ domain }) => domain.toLowerCase().match(searchTerm)),\n }),\n [EDIT_DOMAIN_REDIRECTS]: (state, { domain, redirects }) => ({\n ...state,\n domains: state.domains.map(replaceRedirectsOnDomain(domain, redirects)),\n filteredDomains: state.filteredDomains.map(replaceRedirectsOnDomain(domain, redirects)),\n }),\n}, initialState);\n\nexport const listDomains = (buildShlinkApiClient: ShlinkApiClientBuilder) => () => async (\n dispatch: Dispatch,\n getState: GetState,\n) => {\n dispatch({ type: LIST_DOMAINS_START });\n const { listDomains } = buildShlinkApiClient(getState);\n\n try {\n const domains = await listDomains();\n\n dispatch<ListDomainsAction>({ type: LIST_DOMAINS, domains });\n } catch (e) {\n dispatch<ApiErrorAction>({ type: LIST_DOMAINS_ERROR, errorData: parseApiError(e) });\n }\n};\n\nexport const filterDomains = (searchTerm: string): FilterDomainsAction => ({ type: FILTER_DOMAINS, searchTerm });\n","import { useEffect } from 'react';\nimport { Button, DropdownItem, Input, InputGroup, InputGroupAddon, UncontrolledTooltip } from 'reactstrap';\nimport { InputProps } from 'reactstrap/lib/Input';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faUndo } from '@fortawesome/free-solid-svg-icons';\nimport { isEmpty, pipe } from 'ramda';\nimport { DropdownBtn } from '../utils/DropdownBtn';\nimport { useToggle } from '../utils/helpers/hooks';\nimport { DomainsList } from './reducers/domainsList';\nimport './DomainSelector.scss';\n\nexport interface DomainSelectorProps extends Omit<InputProps, 'onChange'> {\n value?: string;\n onChange: (domain: string) => void;\n}\n\ninterface DomainSelectorConnectProps extends DomainSelectorProps {\n listDomains: Function;\n domainsList: DomainsList;\n}\n\nexport const DomainSelector = ({ listDomains, value, domainsList, onChange }: DomainSelectorConnectProps) => {\n const [ inputDisplayed,, showInput, hideInput ] = useToggle();\n const { domains } = domainsList;\n const valueIsEmpty = isEmpty(value);\n const unselectDomain = () => onChange('');\n\n useEffect(() => {\n listDomains();\n }, []);\n\n return inputDisplayed ? (\n <InputGroup>\n <Input\n value={value}\n placeholder=\"Domain\"\n onChange={(e) => onChange(e.target.value)}\n />\n <InputGroupAddon addonType=\"append\">\n <Button\n id=\"backToDropdown\"\n outline\n type=\"button\"\n className=\"domains-dropdown__back-btn\"\n onClick={pipe(unselectDomain, hideInput)}\n >\n <FontAwesomeIcon icon={faUndo} />\n </Button>\n <UncontrolledTooltip target=\"backToDropdown\" placement=\"left\" trigger=\"hover\">\n Existing domains\n </UncontrolledTooltip>\n </InputGroupAddon>\n </InputGroup>\n ) : (\n <DropdownBtn\n text={valueIsEmpty ? 'Domain' : `Domain: ${value}`}\n className={!valueIsEmpty ? 'domains-dropdown__toggle-btn--active' : 'domains-dropdown__toggle-btn'}\n >\n {domains.map(({ domain, isDefault }) => (\n <DropdownItem\n key={domain}\n active={value === domain || isDefault && valueIsEmpty}\n onClick={() => onChange(domain)}\n >\n {domain}\n {isDefault && <span className=\"float-right text-muted\">default</span>}\n </DropdownItem>\n ))}\n <DropdownItem divider />\n <DropdownItem onClick={pipe(unselectDomain, showInput)}>\n <i>New domain</i>\n </DropdownItem>\n </DropdownBtn>\n );\n};\n","import { FC, useState } from 'react';\nimport { Button, Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap';\nimport { ShlinkDomain, ShlinkDomainRedirects } from '../../api/types';\nimport { FormGroupContainer, FormGroupContainerProps } from '../../utils/FormGroupContainer';\nimport { handleEventPreventingDefault, nonEmptyValueOrNull } from '../../utils/utils';\nimport { InfoTooltip } from '../../utils/InfoTooltip';\n\ninterface EditDomainRedirectsModalProps {\n domain: ShlinkDomain;\n isOpen: boolean;\n toggle: () => void;\n editDomainRedirects: (domain: string, redirects: Partial<ShlinkDomainRedirects>) => Promise<void>;\n}\n\nconst FormGroup: FC<FormGroupContainerProps & { isLast?: boolean }> = ({ isLast, ...rest }) => (\n <FormGroupContainer\n {...rest}\n required={false}\n type=\"url\"\n placeholder=\"No redirect\"\n className={isLast ? 'mb-0' : ''}\n />\n);\n\nexport const EditDomainRedirectsModal: FC<EditDomainRedirectsModalProps> = (\n { isOpen, toggle, domain, editDomainRedirects },\n) => {\n const [ baseUrlRedirect, setBaseUrlRedirect ] = useState(domain.redirects?.baseUrlRedirect ?? '');\n const [ regular404Redirect, setRegular404Redirect ] = useState(domain.redirects?.regular404Redirect ?? '');\n const [ invalidShortUrlRedirect, setInvalidShortUrlRedirect ] = useState(\n domain.redirects?.invalidShortUrlRedirect ?? '',\n );\n const handleSubmit = handleEventPreventingDefault(async () => editDomainRedirects(domain.domain, {\n baseUrlRedirect: nonEmptyValueOrNull(baseUrlRedirect),\n regular404Redirect: nonEmptyValueOrNull(regular404Redirect),\n invalidShortUrlRedirect: nonEmptyValueOrNull(invalidShortUrlRedirect),\n }).then(toggle));\n\n return (\n <Modal isOpen={isOpen} toggle={toggle} centered>\n <form onSubmit={handleSubmit}>\n <ModalHeader toggle={toggle}>Edit redirects for <b>{domain.domain}</b></ModalHeader>\n <ModalBody>\n <FormGroup value={baseUrlRedirect} onChange={setBaseUrlRedirect}>\n <InfoTooltip className=\"mr-2\" placement=\"bottom\">\n Visitors accessing the base url, as in <b>https://{domain.domain}/</b>, will be redirected to this URL.\n </InfoTooltip>\n Base URL\n </FormGroup>\n <FormGroup value={regular404Redirect} onChange={setRegular404Redirect}>\n <InfoTooltip className=\"mr-2\" placement=\"bottom\">\n Visitors accessing a url not matching a short URL pattern, as in <b>https://{domain.domain}/???/[...]</b>,\n will be redirected to this URL.\n </InfoTooltip>\n Regular 404\n </FormGroup>\n <FormGroup value={invalidShortUrlRedirect} isLast onChange={setInvalidShortUrlRedirect}>\n <InfoTooltip className=\"mr-2\" placement=\"bottom\">\n Visitors accessing a url matching a short URL pattern, but not matching an existing short code, will be\n redirected to this URL.\n </InfoTooltip>\n Invalid short URL\n </FormGroup>\n </ModalBody>\n <ModalFooter>\n <Button color=\"link\" type=\"button\" onClick={toggle}>Cancel</Button>\n <Button color=\"primary\">Save</Button>\n </ModalFooter>\n </form>\n </Modal>\n );\n};\n","import { FC } from 'react';\nimport { Button, UncontrolledTooltip } from 'reactstrap';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport {\n faBan as forbiddenIcon,\n faCheck as defaultDomainIcon,\n faEdit as editIcon,\n} from '@fortawesome/free-solid-svg-icons';\nimport { ShlinkDomain, ShlinkDomainRedirects } from '../api/types';\nimport { useToggle } from '../utils/helpers/hooks';\nimport { OptionalString } from '../utils/utils';\nimport { EditDomainRedirectsModal } from './helpers/EditDomainRedirectsModal';\n\ninterface DomainRowProps {\n domain: ShlinkDomain;\n defaultRedirects?: ShlinkDomainRedirects;\n editDomainRedirects: (domain: string, redirects: Partial<ShlinkDomainRedirects>) => Promise<void>;\n}\n\nconst Nr: FC<{ fallback: OptionalString }> = ({ fallback }) => (\n <span className=\"text-muted\">\n {!fallback && <small>No redirect</small>}\n {fallback && <>{fallback} <small>(as fallback)</small></>}\n </span>\n);\nconst DefaultDomain: FC = () => (\n <>\n <FontAwesomeIcon icon={defaultDomainIcon} className=\"text-primary\" id=\"defaultDomainIcon\" />\n <UncontrolledTooltip target=\"defaultDomainIcon\" placement=\"right\">Default domain</UncontrolledTooltip>\n </>\n);\n\nexport const DomainRow: FC<DomainRowProps> = ({ domain, editDomainRedirects, defaultRedirects }) => {\n const [ isOpen, toggle ] = useToggle();\n const { domain: authority, isDefault, redirects } = domain;\n const domainId = `domainEdit${authority.replace(/\\./g, '')}`;\n\n return (\n <tr className=\"responsive-table__row\">\n <td className=\"responsive-table__cell\" data-th=\"Is default domain\">{isDefault ? <DefaultDomain /> : ''}</td>\n <th className=\"responsive-table__cell\" data-th=\"Domain\">{authority}</th>\n <td className=\"responsive-table__cell\" data-th=\"Base path redirect\">\n {redirects?.baseUrlRedirect ?? <Nr fallback={defaultRedirects?.baseUrlRedirect} />}\n </td>\n <td className=\"responsive-table__cell\" data-th=\"Regular 404 redirect\">\n {redirects?.regular404Redirect ?? <Nr fallback={defaultRedirects?.regular404Redirect} />}\n </td>\n <td className=\"responsive-table__cell\" data-th=\"Invalid short URL redirect\">\n {redirects?.invalidShortUrlRedirect ?? <Nr fallback={defaultRedirects?.invalidShortUrlRedirect} />}\n </td>\n <td className=\"responsive-table__cell text-right\">\n <span id={domainId}>\n <Button outline size=\"sm\" disabled={isDefault} onClick={isDefault ? undefined : toggle}>\n <FontAwesomeIcon icon={isDefault ? forbiddenIcon : editIcon} />\n </Button>\n </span>\n {isDefault && (\n <UncontrolledTooltip target={domainId} placement=\"left\">\n Redirects for default domain cannot be edited here.\n <br />\n Use config options or env vars directly on the server.\n </UncontrolledTooltip>\n )}\n </td>\n <EditDomainRedirectsModal\n domain={domain}\n isOpen={isOpen}\n toggle={toggle}\n editDomainRedirects={editDomainRedirects}\n />\n </tr>\n );\n};\n","import { FC, useEffect } from 'react';\nimport Message from '../utils/Message';\nimport { Result } from '../utils/Result';\nimport { ShlinkApiError } from '../api/ShlinkApiError';\nimport { SimpleCard } from '../utils/SimpleCard';\nimport SearchField from '../utils/SearchField';\nimport { ShlinkDomainRedirects } from '../api/types';\nimport { DomainsList } from './reducers/domainsList';\nimport { DomainRow } from './DomainRow';\n\ninterface ManageDomainsProps {\n listDomains: Function;\n filterDomains: (searchTerm: string) => void;\n editDomainRedirects: (domain: string, redirects: Partial<ShlinkDomainRedirects>) => Promise<void>;\n domainsList: DomainsList;\n}\n\nconst headers = [ '', 'Domain', 'Base path redirect', 'Regular 404 redirect', 'Invalid short URL redirect', '' ];\n\nexport const ManageDomains: FC<ManageDomainsProps> = (\n { listDomains, domainsList, filterDomains, editDomainRedirects },\n) => {\n const { filteredDomains: domains, loading, error, errorData } = domainsList;\n const defaultRedirects = domains.find(({ isDefault }) => isDefault)?.redirects;\n\n useEffect(() => {\n listDomains();\n }, []);\n\n if (loading) {\n return <Message loading />;\n }\n\n const renderContent = () => {\n if (error) {\n return (\n <Result type=\"error\">\n <ShlinkApiError errorData={errorData} fallbackMessage=\"Error loading domains :(\" />\n </Result>\n );\n }\n\n return (\n <SimpleCard>\n <table className=\"table table-hover mb-0\">\n <thead className=\"responsive-table__header\">\n <tr>{headers.map((column, index) => <th key={index}>{column}</th>)}</tr>\n </thead>\n <tbody>\n {domains.length < 1 && <tr><td colSpan={headers.length} className=\"text-center\">No results found</td></tr>}\n {domains.map((domain) => (\n <DomainRow\n key={domain.domain}\n domain={domain}\n editDomainRedirects={editDomainRedirects}\n defaultRedirects={defaultRedirects}\n />\n ))}\n </tbody>\n </table>\n </SimpleCard>\n );\n };\n\n return (\n <>\n <SearchField className=\"mb-3\" onChange={filterDomains} />\n {renderContent()}\n </>\n );\n};\n","import Bottle from 'bottlejs';\nimport { ConnectDecorator } from '../../container/types';\nimport { filterDomains, listDomains } from '../reducers/domainsList';\nimport { DomainSelector } from '../DomainSelector';\nimport { ManageDomains } from '../ManageDomains';\nimport { editDomainRedirects } from '../reducers/domainRedirects';\n\nconst provideServices = (bottle: Bottle, connect: ConnectDecorator) => {\n // Components\n bottle.serviceFactory('DomainSelector', () => DomainSelector);\n bottle.decorator('DomainSelector', connect([ 'domainsList' ], [ 'listDomains' ]));\n\n bottle.serviceFactory('ManageDomains', () => ManageDomains);\n bottle.decorator('ManageDomains', connect(\n [ 'domainsList' ],\n [ 'listDomains', 'filterDomains', 'editDomainRedirects' ],\n ));\n\n // Actions\n bottle.serviceFactory('listDomains', listDomains, 'buildShlinkApiClient');\n bottle.serviceFactory('filterDomains', () => filterDomains);\n bottle.serviceFactory('editDomainRedirects', editDomainRedirects, 'buildShlinkApiClient');\n};\n\nexport default provideServices;\n","import { Action } from 'redux';\nimport { buildActionCreator, buildReducer } from '../../utils/helpers/redux';\n\n/* eslint-disable padding-line-between-statements */\nexport const APP_UPDATE_AVAILABLE = 'shlink/appUpdates/APP_UPDATE_AVAILABLE';\nexport const RESET_APP_UPDATE = 'shlink/appUpdates/RESET_APP_UPDATE';\n/* eslint-enable padding-line-between-statements */\n\nconst initialState = false;\n\nexport default buildReducer<boolean, Action<string>>({\n [APP_UPDATE_AVAILABLE]: () => true,\n [RESET_APP_UPDATE]: () => false,\n}, initialState);\n\nexport const appUpdateAvailable = buildActionCreator(APP_UPDATE_AVAILABLE);\n\nexport const resetAppUpdate = buildActionCreator(RESET_APP_UPDATE);\n","import { FC, MouseEventHandler } from 'react';\nimport { Alert, Button } from 'reactstrap';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faSyncAlt as reloadIcon } from '@fortawesome/free-solid-svg-icons';\nimport { SimpleCard } from '../utils/SimpleCard';\nimport { useToggle } from '../utils/helpers/hooks';\nimport './AppUpdateBanner.scss';\n\ninterface AppUpdateBannerProps {\n isOpen: boolean;\n toggle: MouseEventHandler<any>;\n forceUpdate: Function;\n}\n\nexport const AppUpdateBanner: FC<AppUpdateBannerProps> = ({ isOpen, toggle, forceUpdate }) => {\n const [ isUpdating,, setUpdating ] = useToggle();\n const update = () => {\n setUpdating();\n forceUpdate();\n };\n\n return (\n <Alert className=\"app-update-banner\" isOpen={isOpen} toggle={toggle} tag={SimpleCard} color=\"secondary\">\n <h4 className=\"mb-4\">This app has just been updated!</h4>\n <p className=\"mb-0\">\n Restart it to enjoy the new features.\n <Button disabled={isUpdating} className=\"ml-2\" color=\"secondary\" size=\"sm\" onClick={update}>\n {!isUpdating && <>Restart now <FontAwesomeIcon icon={reloadIcon} className=\"ml-1\" /></>}\n {isUpdating && <>Restarting...</>}\n </Button>\n </p>\n </Alert>\n );\n};\n","export const forceUpdate = async () => {\n const registrations = await navigator.serviceWorker?.getRegistrations() ?? [];\n\n for (const registration of registrations) {\n const { waiting } = registration;\n\n waiting?.addEventListener('statechange', (event) => {\n if ((event.target as any)?.state === 'activated') {\n window.location.reload();\n }\n });\n\n // The logic that makes skipWaiting to be called when this message is posted is in service-worker.ts\n waiting?.postMessage({ type: 'SKIP_WAITING' });\n }\n};\n","import { useEffect, FC } from 'react';\nimport { Route, Switch } from 'react-router-dom';\nimport NotFound from '../common/NotFound';\nimport { ServersMap } from '../servers/data';\nimport { Settings } from '../settings/reducers/settings';\nimport { changeThemeInMarkup } from '../utils/theme';\nimport { AppUpdateBanner } from '../common/AppUpdateBanner';\nimport { forceUpdate } from '../utils/helpers/sw';\nimport './App.scss';\n\ninterface AppProps {\n fetchServers: () => void;\n servers: ServersMap;\n settings: Settings;\n resetAppUpdate: () => void;\n appUpdated: boolean;\n}\n\nconst App = (\n MainHeader: FC,\n Home: FC,\n MenuLayout: FC,\n CreateServer: FC,\n EditServer: FC,\n Settings: FC,\n ShlinkVersionsContainer: FC,\n) => ({ fetchServers, servers, settings, appUpdated, resetAppUpdate }: AppProps) => {\n useEffect(() => {\n // On first load, try to fetch the remote servers if the list is empty\n if (Object.keys(servers).length === 0) {\n fetchServers();\n }\n\n changeThemeInMarkup(settings.ui?.theme ?? 'light');\n }, []);\n\n return (\n <div className=\"container-fluid app-container\">\n <MainHeader />\n\n <div className=\"app\">\n <div className=\"shlink-wrapper\">\n <Switch>\n <Route exact path=\"/\" component={Home} />\n <Route exact path=\"/settings\" component={Settings} />\n <Route exact path=\"/server/create\" component={CreateServer} />\n <Route exact path=\"/server/:serverId/edit\" component={EditServer} />\n <Route path=\"/server/:serverId\" component={MenuLayout} />\n <Route component={NotFound} />\n </Switch>\n </div>\n\n <div className=\"shlink-footer\">\n <ShlinkVersionsContainer />\n </div>\n </div>\n\n <AppUpdateBanner isOpen={appUpdated} toggle={resetAppUpdate} forceUpdate={forceUpdate} />\n </div>\n );\n};\n\nexport default App;\n","import Bottle from 'bottlejs';\nimport { appUpdateAvailable, resetAppUpdate } from '../reducers/appUpdates';\nimport App from '../App';\nimport { ConnectDecorator } from '../../container/types';\n\nconst provideServices = (bottle: Bottle, connect: ConnectDecorator) => {\n // Components\n bottle.serviceFactory(\n 'App',\n App,\n 'MainHeader',\n 'Home',\n 'MenuLayout',\n 'CreateServer',\n 'EditServer',\n 'Settings',\n 'ShlinkVersionsContainer',\n );\n bottle.decorator('App', connect([ 'servers', 'settings', 'appUpdated' ], [ 'fetchServers', 'resetAppUpdate' ]));\n\n // Actions\n bottle.serviceFactory('appUpdateAvailable', () => appUpdateAvailable);\n bottle.serviceFactory('resetAppUpdate', () => resetAppUpdate);\n};\n\nexport default provideServices;\n","import Bottle, { IContainer } from 'bottlejs';\nimport { withRouter } from 'react-router-dom';\nimport { connect as reduxConnect } from 'react-redux';\nimport { pick } from 'ramda';\nimport provideApiServices from '../api/services/provideServices';\nimport provideCommonServices from '../common/services/provideServices';\nimport provideShortUrlsServices from '../short-urls/services/provideServices';\nimport provideServersServices from '../servers/services/provideServices';\nimport provideVisitsServices from '../visits/services/provideServices';\nimport provideTagsServices from '../tags/services/provideServices';\nimport provideUtilsServices from '../utils/services/provideServices';\nimport provideMercureServices from '../mercure/services/provideServices';\nimport provideSettingsServices from '../settings/services/provideServices';\nimport provideDomainsServices from '../domains/services/provideServices';\nimport provideAppServices from '../app/services/provideServices';\nimport { ConnectDecorator } from './types';\n\ntype LazyActionMap = Record<string, Function>;\n\nconst bottle = new Bottle();\nconst { container } = bottle;\n\nconst lazyService = <T extends Function, K>(container: IContainer, serviceName: string) =>\n (...args: any[]) => (container[serviceName] as T)(...args) as K;\nconst mapActionService = (map: LazyActionMap, actionName: string): LazyActionMap => ({\n ...map,\n // Wrap actual action service in a function so that it is lazily created the first time it is called\n [actionName]: lazyService(container, actionName),\n});\nconst connect: ConnectDecorator = (propsFromState: string[] | null, actionServiceNames: string[] = []) =>\n reduxConnect(\n propsFromState ? pick(propsFromState) : null,\n actionServiceNames.reduce(mapActionService, {}),\n );\n\nprovideAppServices(bottle, connect);\nprovideCommonServices(bottle, connect, withRouter);\nprovideApiServices(bottle);\nprovideShortUrlsServices(bottle, connect);\nprovideServersServices(bottle, connect, withRouter);\nprovideTagsServices(bottle, connect);\nprovideVisitsServices(bottle, connect);\nprovideUtilsServices(bottle);\nprovideMercureServices(bottle);\nprovideSettingsServices(bottle, connect);\nprovideDomainsServices(bottle, connect);\n\nexport default container;\n","import { combineReducers } from 'redux';\nimport serversReducer from '../servers/reducers/servers';\nimport selectedServerReducer from '../servers/reducers/selectedServer';\nimport shortUrlsListReducer from '../short-urls/reducers/shortUrlsList';\nimport shortUrlsListParamsReducer from '../short-urls/reducers/shortUrlsListParams';\nimport shortUrlCreationReducer from '../short-urls/reducers/shortUrlCreation';\nimport shortUrlDeletionReducer from '../short-urls/reducers/shortUrlDeletion';\nimport shortUrlEditionReducer from '../short-urls/reducers/shortUrlEdition';\nimport shortUrlVisitsReducer from '../visits/reducers/shortUrlVisits';\nimport tagVisitsReducer from '../visits/reducers/tagVisits';\nimport orphanVisitsReducer from '../visits/reducers/orphanVisits';\nimport shortUrlDetailReducer from '../short-urls/reducers/shortUrlDetail';\nimport tagsListReducer from '../tags/reducers/tagsList';\nimport tagDeleteReducer from '../tags/reducers/tagDelete';\nimport tagEditReducer from '../tags/reducers/tagEdit';\nimport mercureInfoReducer from '../mercure/reducers/mercureInfo';\nimport settingsReducer from '../settings/reducers/settings';\nimport domainsListReducer from '../domains/reducers/domainsList';\nimport visitsOverviewReducer from '../visits/reducers/visitsOverview';\nimport appUpdatesReducer from '../app/reducers/appUpdates';\nimport { ShlinkState } from '../container/types';\n\nexport default combineReducers<ShlinkState>({\n servers: serversReducer,\n selectedServer: selectedServerReducer,\n shortUrlsList: shortUrlsListReducer,\n shortUrlsListParams: shortUrlsListParamsReducer,\n shortUrlCreationResult: shortUrlCreationReducer,\n shortUrlDeletion: shortUrlDeletionReducer,\n shortUrlEdition: shortUrlEditionReducer,\n shortUrlVisits: shortUrlVisitsReducer,\n tagVisits: tagVisitsReducer,\n orphanVisits: orphanVisitsReducer,\n shortUrlDetail: shortUrlDetailReducer,\n tagsList: tagsListReducer,\n tagDelete: tagDeleteReducer,\n tagEdit: tagEditReducer,\n mercureInfo: mercureInfoReducer,\n settings: settingsReducer,\n domainsList: domainsListReducer,\n visitsOverview: visitsOverviewReducer,\n appUpdated: appUpdatesReducer,\n});\n","import ReduxThunk from 'redux-thunk';\nimport { applyMiddleware, compose, createStore } from 'redux';\nimport { save, load, RLSOptions } from 'redux-localstorage-simple';\nimport reducers from '../reducers';\n\nconst isProduction = process.env.NODE_ENV !== 'production';\nconst composeEnhancers: Function = !isProduction && (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;\n\nconst localStorageConfig: RLSOptions = {\n states: [ 'settings', 'servers' ],\n namespace: 'shlink',\n namespaceSeparator: '.',\n debounce: 300,\n};\n\nconst store = createStore(reducers, load(localStorageConfig), composeEnhancers(\n applyMiddleware(save(localStorageConfig), ReduxThunk),\n));\n\nexport default store;\n","// This optional code is used to register a service worker.\n// register() is not called by default.\n\n// This lets the app load faster on subsequent visits in production, and gives\n// it offline capabilities. However, it also means that developers (and users)\n// will only see deployed updates on subsequent visits to a page, after all the\n// existing tabs open on the page have been closed, since previously cached\n// resources are updated in the background.\n\n// To learn more about the benefits of this model and instructions on how to\n// opt-in, read https://cra.link/PWA\n\nconst isLocalhost = Boolean(\n window.location.hostname === 'localhost' ||\n // [::1] is the IPv6 localhost address.\n window.location.hostname === '[::1]' ||\n // 127.0.0.0/8 are considered localhost for IPv4.\n window.location.hostname.match(/^127(?:\\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/)\n);\n\ntype Config = {\n onSuccess?: (registration: ServiceWorkerRegistration) => void;\n onUpdate?: (registration: ServiceWorkerRegistration) => void;\n};\n\nexport function register(config?: Config) {\n if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {\n // The URL constructor is available in all browsers that support SW.\n const publicUrl = new URL(process.env.PUBLIC_URL ?? '', window.location.href);\n if (publicUrl.origin !== window.location.origin) {\n // Our service worker won't work if PUBLIC_URL is on a different origin\n // from what our page is served on. This might happen if a CDN is used to\n // serve assets; see https://github.com/facebook/create-react-app/issues/2374\n return;\n }\n\n window.addEventListener('load', () => {\n const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;\n\n if (isLocalhost) {\n // This is running on localhost. Let's check if a service worker still exists or not.\n checkValidServiceWorker(swUrl, config);\n\n // Add some additional logging to localhost, pointing developers to the\n // service worker/PWA documentation.\n navigator.serviceWorker.ready.then(() => {\n console.log(\n 'This web app is being served cache-first by a service ' +\n 'worker. To learn more, visit https://cra.link/PWA'\n );\n });\n } else {\n // Is not localhost. Just register service worker\n registerValidSW(swUrl, config);\n }\n });\n }\n}\n\nfunction registerValidSW(swUrl: string, config?: Config) {\n navigator.serviceWorker\n .register(swUrl)\n .then((registration) => {\n registration.onupdatefound = () => {\n const installingWorker = registration.installing;\n if (installingWorker == null) {\n return;\n }\n installingWorker.onstatechange = () => {\n if (installingWorker.state === 'installed') {\n if (navigator.serviceWorker.controller) {\n // At this point, the updated precached content has been fetched,\n // but the previous service worker will still serve the older\n // content until all client tabs are closed.\n console.log(\n 'New content is available and will be used when all ' +\n 'tabs for this page are closed. See https://cra.link/PWA.'\n );\n\n // Execute callback\n if (config && config.onUpdate) {\n config.onUpdate(registration);\n }\n } else {\n // At this point, everything has been precached.\n // It's the perfect time to display a\n // \"Content is cached for offline use.\" message.\n console.log('Content is cached for offline use.');\n\n // Execute callback\n if (config && config.onSuccess) {\n config.onSuccess(registration);\n }\n }\n }\n };\n };\n })\n .catch((error) => {\n console.error('Error during service worker registration:', error);\n });\n}\n\nfunction checkValidServiceWorker(swUrl: string, config?: Config) {\n // Check if the service worker can be found. If it can't reload the page.\n fetch(swUrl, {\n headers: { 'Service-Worker': 'script' },\n })\n .then((response) => {\n // Ensure service worker exists, and that we really are getting a JS file.\n const contentType = response.headers.get('content-type');\n if (\n response.status === 404 ||\n (contentType != null && contentType.indexOf('javascript') === -1)\n ) {\n // No service worker found. Probably a different app. Reload the page.\n navigator.serviceWorker.ready.then((registration) => {\n registration.unregister().then(() => {\n window.location.reload();\n });\n });\n } else {\n // Service worker found. Proceed as normal.\n registerValidSW(swUrl, config);\n }\n })\n .catch(() => {\n console.log('No internet connection found. App is running in offline mode.');\n });\n}\n\nexport function unregister() {\n if ('serviceWorker' in navigator) {\n navigator.serviceWorker.ready\n .then((registration) => {\n registration.unregister();\n })\n .catch((error) => {\n console.error(error.message);\n });\n }\n}\n","import L from 'leaflet';\nimport marker2x from 'leaflet/dist/images/marker-icon-2x.png';\nimport marker from 'leaflet/dist/images/marker-icon.png';\nimport markerShadow from 'leaflet/dist/images/marker-shadow.png';\n\nexport const fixLeafletIcons = () => {\n delete (L.Icon.Default.prototype as any)._getIconUrl;\n\n L.Icon.Default.mergeOptions({\n iconRetinaUrl: marker2x,\n iconUrl: marker,\n shadowUrl: markerShadow,\n });\n};\n","import { render } from 'react-dom';\nimport { Provider } from 'react-redux';\nimport { BrowserRouter } from 'react-router-dom';\nimport { homepage } from '../package.json';\nimport container from './container';\nimport store from './container/store';\nimport { fixLeafletIcons } from './utils/helpers/leaflet';\nimport { register as registerServiceWorker } from './serviceWorkerRegistration';\nimport 'react-datepicker/dist/react-datepicker.css';\nimport 'leaflet/dist/leaflet.css';\nimport './index.scss';\n\n// This overwrites icons used for leaflet maps, fixing some issues caused by webpack while processing the CSS\nfixLeafletIcons();\n\nconst { App, ScrollToTop, ErrorHandler, appUpdateAvailable } = container;\n\nrender(\n <Provider store={store}>\n <BrowserRouter basename={homepage}>\n <ErrorHandler>\n <ScrollToTop>\n <App />\n </ScrollToTop>\n </ErrorHandler>\n </BrowserRouter>\n </Provider>,\n document.getElementById('root'),\n);\n\n// If you want your app to work offline and load faster, you can change\n// unregister() to register() below. Note this comes with some pitfalls.\n// Learn more about service workers: https://cra.link/PWA\nregisterServiceWorker({\n onUpdate() {\n store.dispatch(appUpdateAvailable()); // eslint-disable-line @typescript-eslint/no-unsafe-call\n },\n});\n","import { FC } from 'react';\nimport './NoMenuLayout.scss';\n\nconst NoMenuLayout: FC = ({ children }) => <div className=\"no-menu-wrapper container-xl\">{children}</div>;\n\nexport default NoMenuLayout;\n","import { compare } from 'compare-versions';\nimport { identity, memoizeWith } from 'ramda';\nimport { Empty, hasValue } from '../utils';\n\ntype SemVerPatternFragment = `${bigint | '*'}`;\n\nexport type SemVerPattern = SemVerPatternFragment\n| `${SemVerPatternFragment}.${SemVerPatternFragment}`\n| `${SemVerPatternFragment}.${SemVerPatternFragment}.${SemVerPatternFragment}`;\n\nexport interface Versions {\n maxVersion?: SemVerPattern;\n minVersion?: SemVerPattern;\n}\n\nexport type SemVer = `${bigint}.${bigint}.${bigint}` | 'latest';\n\nexport const versionMatch = (versionToMatch: SemVer | Empty, { maxVersion, minVersion }: Versions): boolean => {\n if (!hasValue(versionToMatch)) {\n return false;\n }\n\n const matchesMinVersion = !minVersion || compare(versionToMatch, minVersion, '>=');\n const matchesMaxVersion = !maxVersion || compare(versionToMatch, maxVersion, '<=');\n\n return matchesMaxVersion && matchesMinVersion;\n};\n\nconst versionIsValidSemVer = memoizeWith(identity, (version: string): version is SemVer => {\n try {\n return compare(version, version, '=');\n } catch (e) {\n return false;\n }\n});\n\nexport const versionToPrintable = (version: string) => !versionIsValidSemVer(version) ? version : `v${version}`;\n\nexport const versionToSemVer = (defaultValue: SemVer = 'latest') =>\n (version: string): SemVer => versionIsValidSemVer(version) ? version : defaultValue;\n"],"sourceRoot":""}