Migrate Traefik Proxy dashboard UI to React

This commit is contained in:
Gina A. 2025-05-28 11:26:04 +02:00 committed by GitHub
parent 4790e4910f
commit f16fff577a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
324 changed files with 28303 additions and 19567 deletions

View File

@ -12,6 +12,9 @@ jobs:
with:
fetch-depth: 0
- name: Enable corepack
run: corepack enable
- name: Setup node
uses: actions/setup-node@v4
with:

View File

@ -31,7 +31,9 @@ jobs:
go-version: ${{ env.GO_VERSION }}
- name: Avoid generating webui
run: touch webui/static/index.html
run: |
mkdir webui/static
touch webui/static/index.html
- name: K8s Gateway API conformance test and report
run: |

View File

@ -31,7 +31,9 @@ jobs:
check-latest: true
- name: Avoid generating webui
run: touch webui/static/index.html
run: |
mkdir webui/static
touch webui/static/index.html
- name: Build binary
run: make binary
@ -59,7 +61,9 @@ jobs:
check-latest: true
- name: Avoid generating webui
run: touch webui/static/index.html
run: |
mkdir webui/static
touch webui/static/index.html
- name: Build binary
run: make binary

View File

@ -13,7 +13,6 @@ env:
GO_VERSION: '1.23'
jobs:
test-unit:
runs-on: ubuntu-latest
@ -30,7 +29,9 @@ jobs:
check-latest: true
- name: Avoid generating webui
run: touch webui/static/index.html
run: |
mkdir webui/static
touch webui/static/index.html
- name: Tests
run: make test-unit
@ -44,6 +45,9 @@ jobs:
with:
fetch-depth: 0
- name: Enable corepack
run: corepack enable
- name: Set up Node.js ${{ env.NODE_VERSION }}
uses: actions/setup-node@v4
with:
@ -52,6 +56,9 @@ jobs:
cache-dependency-path: webui/yarn.lock
- name: UI unit tests
working-directory: ./webui
env:
VITE_APP_BASE_API_URL: "/api"
run: |
yarn --cwd webui install
yarn --cwd webui test:unit:ci
yarn install
yarn test:unit:ci

View File

@ -27,6 +27,11 @@ jobs:
go-version: ${{ env.GO_VERSION }}
check-latest: true
- name: Avoid generating webui
run: |
mkdir webui/static
touch webui/static/index.html
- name: golangci-lint
uses: golangci/golangci-lint-action@v7
with:
@ -51,7 +56,9 @@ jobs:
run: curl -sfL https://raw.githubusercontent.com/golangci/misspell/HEAD/install-misspell.sh | sh -s -- -b $(go env GOPATH)/bin ${MISSPELL_VERSION}
- name: Avoid generating webui
run: touch webui/static/index.html
run: |
mkdir webui/static
touch webui/static/index.html
- name: Validate
run: make validate-files

View File

@ -30,18 +30,16 @@ dist:
.PHONY: build-webui-image
#? build-webui-image: Build WebUI Docker image
build-webui-image:
docker build -t traefik-webui -f webui/Dockerfile webui
docker build -t traefik-webui -f webui/buildx.Dockerfile webui
.PHONY: clean-webui
#? clean-webui: Clean WebUI static generated assets
clean-webui:
rm -r webui/static
mkdir -p webui/static
printf 'For more information see `webui/readme.md`' > webui/static/DONT-EDIT-FILES-IN-THIS-DIRECTORY.md
rm -rf webui/static
webui/static/index.html:
$(MAKE) build-webui-image
docker run --rm -v "$(PWD)/webui/static":'/src/webui/static' traefik-webui npm run build:nc
docker run --rm -v "$(PWD)/webui/static":'/src/webui/static' traefik-webui yarn build:prod
docker run --rm -v "$(PWD)/webui/static":'/src/webui/static' traefik-webui chown -R $(shell id -u):$(shell id -g) ./static
.PHONY: generate-webui

Binary file not shown.

Before

Width:  |  Height:  |  Size: 125 KiB

After

Width:  |  Height:  |  Size: 241 KiB

View File

@ -1,5 +0,0 @@
# compiled output
/dist
# dependencies
/node_modules

View File

@ -1,9 +1,22 @@
# Editor configuration, see http://editorconfig.org
root = true
[*]
charset = utf-8
[*.{js,ts,tsx}]
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
max_line_length = off
trim_trailing_whitespace = false
[Makefile]
indent_style = tab
[{package.json}]
indent_style = space
indent_size = 2

2
webui/.env.sample Normal file
View File

@ -0,0 +1,2 @@
VITE_APP_BASE_API_URL=/api
VITE_APP_BASE_URL=

View File

@ -1,7 +0,0 @@
/dist
/src-capacitor
/src-cordova
/.quasar
/node_modules
.eslintrc.cjs
/quasar.config.*.temporary.compiled*

View File

@ -1,68 +0,0 @@
module.exports = {
root: true,
parserOptions: {
parser: '@babel/eslint-parser',
ecmaVersion: 2021, // Allows for the parsing of modern ECMAScript features
},
env: {
node: true,
browser: true,
'vue/setup-compiler-macros': true
},
extends: [
// https://github.com/vuejs/eslint-plugin-vue#priority-a-essential-error-prevention
// consider switching to `plugin:vue/strongly-recommended` or `plugin:vue/recommended` for stricter rules.
'plugin:vue/vue3-essential',
'plugin:vue/vue3-recommended',
'standard'
],
// required to lint *.vue files
plugins: [
'vue',
],
globals: {
ga: 'readonly', // Google Analytics
cordova: 'readonly',
__statics: 'readonly',
__QUASAR_SSR__: 'readonly',
__QUASAR_SSR_SERVER__: 'readonly',
__QUASAR_SSR_CLIENT__: 'readonly',
__QUASAR_SSR_PWA__: 'readonly',
process: 'readonly',
Capacitor: 'readonly',
chrome: 'readonly'
},
// add your custom rules here
rules: {
// allow async-await
'generator-star-spacing': 'off',
// allow paren-less arrow functions
'arrow-parens': 'off',
'one-var': 'off',
'no-void': 'off',
'multiline-ternary': 'off',
'import/first': 'off',
'import/named': 'error',
'import/namespace': 'error',
'import/default': 'error',
'import/export': 'error',
'import/extensions': 'off',
'import/no-unresolved': 'off',
'import/no-extraneous-dependencies': 'off',
'prefer-promise-reject-errors': 'off',
'vue/multi-word-component-names': 'off',
// allow console.log during development only
//'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
// allow debugger during development only
//'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
}
}

81
webui/.gitignore vendored
View File

@ -1,32 +1,61 @@
.quasar
.DS_Store
.thumbs.db
node_modules
# See http://help.github.com/ignore-files/ for more about ignoring files.
# compiled output
/dist
/dev_local
/src-cordova/node_modules
/src-cordova/platforms
/src-cordova/plugins
/src-cordova/www
/build
/dist-server
/tmp
/out-tsc
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# dependencies
/node_modules
.yalc
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
# IDEs and editors
/.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# local env files
.env.local
.env.*.local
# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
# static assets (ignore all except the DO NOT EDIT file)
# misc
/.sass-cache
/connect.lock
/coverage
/libpeerconnection.log
npm-debug.log
yarn-error.log
testem.log
/typings
# e2e
/e2e/*.js
/e2e/*.map
# System Files
.DS_Store
Thumbs.db
# env
.env
# yarn berry with no zero-installs
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions
# static assets
static/*
!static/DONT-EDIT-FILES-IN-THIS-DIRECTORY.md

View File

@ -1 +1 @@
20.11.0
v22.15.1

View File

@ -1,8 +0,0 @@
// https://github.com/michael-ciniawsky/postcss-load-config
module.exports = {
plugins: [
// to edit target browsers: use "browserslist" field in package.json
require('autoprefixer')
]
}

6
webui/.prettierrc.json Normal file
View File

@ -0,0 +1,6 @@
{
"semi": false,
"trailingComma": "all",
"singleQuote": true,
"printWidth": 120
}

View File

@ -1,35 +0,0 @@
{
"blocks": "never",
"brackets": "never",
"colons": "never",
"colors": "always",
"commaSpace": "always",
"commentSpace": "always",
"cssLiteral": "never",
"depthLimit": false,
"duplicates": true,
"efficient": "always",
"extendPref": false,
"globalDupe": true,
"indentPref": 2,
"leadingZero": "never",
"maxErrors": false,
"maxWarnings": false,
"mixed": false,
"namingConvention": false,
"namingConventionStrict": false,
"none": "never",
"noImportant": false,
"parenSpace": "never",
"placeholder": false,
"prefixVarsWithDollar": "always",
"quotePref": "single",
"semicolons": "never",
"sortOrder": false,
"stackedProperties": "never",
"trailingWhitespace": "never",
"universal": "never",
"valid": true,
"zeroUnits": "never",
"zIndexNormalize": false
}

1
webui/.yarnrc.yml Normal file
View File

@ -0,0 +1 @@
nodeLinker: node-modules

View File

@ -1,17 +0,0 @@
FROM node:22.9-alpine3.20
# Current Active LTS release according to (https://nodejs.org/en/about/releases/)
ENV WEBUI_DIR=/src/webui
RUN mkdir -p $WEBUI_DIR
COPY package.json $WEBUI_DIR/
COPY yarn.lock $WEBUI_DIR/
WORKDIR $WEBUI_DIR
RUN yarn install
COPY . $WEBUI_DIR/
EXPOSE 8080
RUN yarn lint

View File

@ -1,16 +0,0 @@
/* eslint-disable */
module.exports = api => {
return {
presets: [
[
'@quasar/babel-preset-app',
api.caller(caller => caller && caller.target === 'node')
? { targets: { node: 'current' } }
: {}
]
]
}
}

18
webui/buildx.Dockerfile Normal file
View File

@ -0,0 +1,18 @@
FROM node:22.15.1-alpine3.20
ENV WEBUI_DIR=/src/webui
RUN mkdir -p $WEBUI_DIR
COPY package.json yarn.lock .yarnrc.yml $WEBUI_DIR/
ENV VITE_APP_BASE_URL=""
ENV VITE_APP_BASE_API_URL="/api"
WORKDIR $WEBUI_DIR
RUN corepack enable
RUN yarn workspaces focus --all --production
COPY . $WEBUI_DIR/
EXPOSE 8080

View File

@ -1,17 +0,0 @@
const fs = require('fs-extra')
const folder = process.argv[2]
async function execute () {
try {
await fs.emptyDir('./static')
await fs.outputFile('./static/DONT-EDIT-FILES-IN-THIS-DIRECTORY.md', 'For more information see `webui/readme.md`')
console.log('Deleted static folder contents!')
await fs.copy(`./dist/${folder}`, './static', { overwrite: true })
console.log('Installed new files in static folder!')
} catch (err) {
console.error(err)
}
}
execute()

57
webui/eslint.config.mjs Normal file
View File

@ -0,0 +1,57 @@
import js from '@eslint/js'
import eslintConfigPrettier from 'eslint-config-prettier'
import importPlugin from 'eslint-plugin-import'
import jsxA11y from 'eslint-plugin-jsx-a11y'
import react from 'eslint-plugin-react'
import reactHooks from 'eslint-plugin-react-hooks'
import globals from 'globals'
import tseslint from 'typescript-eslint'
export default tseslint.config(
{ ignores: ['dist'] },
{
extends: [js.configs.recommended, ...tseslint.configs.recommended],
files: ['**/*.{ts,tsx}'],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
parserOptions: {
ecmaFeatures: {
jsx: true,
},
},
},
plugins: {
react: react,
'react-hooks': reactHooks,
},
rules: {
...reactHooks.configs.recommended.rules,
"@typescript-eslint/no-explicit-any": "warn",
},
},
eslintConfigPrettier,
{
files: ['**/*.{ts,tsx}'],
extends: [importPlugin.flatConfigs.recommended, importPlugin.flatConfigs.typescript],
rules: {
'import/order': [
'error',
{
alphabetize: {
order: 'asc',
caseInsensitive: true,
},
'newlines-between': 'always',
},
],
},
settings: {
'import/resolver': {
typescript: true,
node: true,
},
},
},
jsxA11y.flatConfigs.recommended,
)

25
webui/index.dev.html Normal file
View File

@ -0,0 +1,25 @@
<!-- Entry point for local development -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#ddee6d" />
<meta
name="description"
content="Traefik Proxy"
/>
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="/manifest.json" />
<title>Traefik Proxy</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script type="module" src="/src/index.tsx"></script>
</body>
</html>

View File

@ -1,32 +1,31 @@
<!DOCTYPE html>
<html>
<html lang="en">
<head>
{{if .APIUrl}}
<script>
window.APIURL = "{{.APIUrl}}"
window.APIUrl = "{{.APIUrl}}"
</script>
{{end}}
<title><%= productName %></title>
<meta charset="utf-8">
<meta name="description" content="<%= productDescription %>">
<meta name="format-detection" content="telephone=no">
<meta name="msapplication-tap-highlight" content="no">
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width<% if (ctx.mode.cordova || ctx.mode.capacitor) { %>, viewport-fit=cover<% } %>">
<link rel="icon" type="image/png" href="app-logo-128x128.png">
<link rel="icon" type="image/png" sizes="16x16" href="icons/favicon-16x16.png">
<link rel="icon" type="image/png" sizes="32x32" href="icons/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="96x96" href="icons/favicon-96x96.png">
<link rel="icon" type="image/ico" href="icons/favicon.ico">
<link rel="apple-touch-icon" href="icons/apple-icon-152x152.png">
<link rel="apple-touch-icon" sizes="152x152" href="icons/apple-icon-152x152.png">
<link rel="apple-touch-icon" sizes="167x167" href="icons/apple-icon-167x167.png">
<link rel="apple-touch-icon" sizes="180x180" href="icons/apple-icon-180x180.png">
<meta charset="utf-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#ddee6d" />
<meta
name="description"
content="Traefik Proxy"
/>
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="/manifest.json" />
<title>Traefik Proxy</title>
</head>
<body>
<!-- quasar:entry-point -->
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script type="module" src="/src/index.tsx"></script>
</body>
</html>

View File

@ -1,39 +0,0 @@
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"src/*": [
"src/*"
],
"app/*": [
"*"
],
"components/*": [
"src/components/*"
],
"layouts/*": [
"src/layouts/*"
],
"pages/*": [
"src/pages/*"
],
"assets/*": [
"src/assets/*"
],
"boot/*": [
"src/boot/*"
],
"stores/*": [
"src/stores/*"
],
"vue$": [
"node_modules/vue/dist/vue.runtime.esm-bundler.js"
]
}
},
"exclude": [
"dist",
".quasar",
"node_modules"
]
}

View File

@ -1,62 +1,101 @@
{
"name": "traefik-ui",
"version": "2.0.0",
"description": "Traefik UI",
"productName": "Traefik",
"cordovaId": "io.traefik.traefik",
"name": "traefik-proxy-dashboard",
"version": "0.1.0",
"private": true,
"homepage": ".",
"scripts": {
"transfer": "node dev/scripts/transfer.js",
"lint": "eslint src/**/*.{js,vue}",
"dev": "APP_ENV=development quasar dev",
"build-quasar": "quasar build",
"build-staging": "NODE_ENV=production APP_ENV=development yarn build-quasar",
"build": "NODE_ENV=production APP_ENV=production yarn build-quasar && yarn transfer spa",
"build:nc": "yarn build",
"test": "echo \"See package.json => scripts for available tests.\" && exit 0",
"test:unit": "vitest",
"build": "vite build",
"build:prod": "yarn test && yarn tsc && yarn lint && yarn build",
"dev": "vite",
"format": "prettier './src/**/*.{ts,tsx}' --config .prettierrc.json --write",
"lint": "eslint './src/**/*.{ts,tsx}'",
"lint:fix": "eslint --fix './src/**/*.{ts,tsx}'",
"preview": "vite preview",
"test": "vitest run",
"test:coverage": "vitest run --coverage",
"test:watch": "vitest",
"test:unit:ci": "vitest run"
},
"lint-staged": {
"**/*.{ts,tsx}": [
"yarn format",
"eslint --fix",
"git add"
]
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"type": "module",
"dependencies": {
"@quasar/extras": "^1.16.12",
"axios": "^1.7.4",
"@eslint/js": "^9.23.0",
"@testing-library/jest-dom": "^6.4.2",
"@testing-library/react": "^14.2.1",
"@testing-library/user-event": "^14.5.2",
"@traefiklabs/faency": "11.1.4",
"@types/lodash": "^4.17.16",
"@types/node": "^22.15.18",
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.19",
"@types/react-router-dom": "^5.1.3",
"@typescript-eslint/parser": "^8.29.0",
"@vitejs/plugin-react": "^4.2.1",
"@vitest/coverage-v8": "^1.3.1",
"chart.js": "^4.4.1",
"core-js": "^3.35.1",
"dot-prop": "^8.0.2",
"lodash.isequal": "4.5.0",
"moment": "^2.30.1",
"quasar": "^2.16.6",
"query-string": "^8.1.0",
"vue": "^3.0.0",
"vue-chartjs": "^5.3.0",
"vue-router": "^4.0.12",
"vuex": "^4.1.0",
"vuex-map-fields": "^1.4.1"
"eslint": "^9.23.0",
"eslint-config-prettier": "^10.0.2",
"eslint-import-resolver-typescript": "^3.8.3",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-jsx-a11y": "^6.10.2",
"eslint-plugin-react": "^7.37.4",
"eslint-plugin-react-hooks": "^5.1.0",
"framer-motion": "^11.18.2",
"globals": "^16.0.0",
"jest-extended": "^4.0.2",
"jsdom": "^24.0.0",
"lodash": "^4.17.21",
"msw": "^2.1.7",
"query-string": "^6.9.0",
"react": "^18.2.0",
"react-chartjs-2": "^5.2.0",
"react-dom": "^18.2.0",
"react-error-boundary": "^4.0.12",
"react-helmet-async": "^2.0.4",
"react-icons": "^5.0.1",
"react-infinite-scroll-hook": "^4.1.1",
"react-router-dom": "6.22.1",
"swr": "^2.2.4",
"typescript": "^5.2.2",
"typescript-eslint": "^8.24.1",
"usehooks-ts": "^2.14.0",
"vite": "^5.1.4",
"vite-tsconfig-paths": "^4.3.1",
"vitest": "^1.3.1",
"vitest-canvas-mock": "^0.3.3"
},
"devDependencies": {
"@babel/core": "^7.23.9",
"@babel/eslint-parser": "^7.23.10",
"@quasar/app-vite": "^2.0.0-beta.15",
"@quasar/babel-preset-app": "^2.0.3",
"@quasar/quasar-app-extension-testing-unit-vitest": "^1.0.0",
"@vue/test-utils": "^2.4.4",
"autoprefixer": "^10.4.2",
"eslint": "^8.11.0",
"eslint-config-standard": "^17.0.0",
"eslint-plugin-import": "^2.19.1",
"eslint-plugin-n": "^16.6.2",
"eslint-plugin-promise": "^6.0.0",
"eslint-plugin-vue": "^9.0.0",
"postcss": "^8.4.14",
"vitest": "^1.6.0"
"husky": "^3.1.0",
"lint-staged": "^9.5.0",
"prettier": "^3.5.3"
},
"resolutions": {
"cookie": "^0.7.0"
"msw": {
"workerDirectory": [
"public"
]
},
"engines": {
"node": "^22 || ^20 || ^18 || ^16",
"npm": ">= 6.13.4",
"yarn": ">= 1.22.22"
},
"packageManager": "yarn@1.22.22"
"packageManager": "yarn@4.9.1"
}

View File

@ -1,27 +0,0 @@
/* eslint-disable */
// https://github.com/michael-ciniawsky/postcss-load-config
module.exports = {
plugins: [
// https://github.com/postcss/autoprefixer
require('autoprefixer')({
overrideBrowserslist: [
'last 4 Chrome versions',
'last 4 Firefox versions',
'last 4 Edge versions',
'last 4 Safari versions',
'last 4 Android versions',
'last 4 ChromeAndroid versions',
'last 4 FirefoxAndroid versions',
'last 4 iOS versions'
]
})
// https://github.com/elchininet/postcss-rtlcss
// If you want to support RTL css, then
// 1. yarn/npm install postcss-rtlcss
// 2. optionally set quasar.config.js > framework > lang to an RTL language
// 3. uncomment the following line:
// require('postcss-rtlcss')
]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square150x150logo src="/favicon-96x96.png" />
<TileColor>#ddee6d</TileColor>
</tile>
</msapplication>
</browserconfig>

Binary file not shown.

After

Width:  |  Height:  |  Size: 664 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
webui/public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -0,0 +1,25 @@
{
"short_name": "Traefik Proxy",
"name": "Traefik Proxy",
"icons": [
{
"src": "favicon-16x16.png",
"sizes": "16x16",
"type": "image/png"
},
{
"src": "favicon-32x32.png",
"sizes": "32x32",
"type": "image/png"
},
{
"src": "favicon-96x96.png",
"sizes": "96x96",
"type": "image/png"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#ddee6d",
"background_color": "#091827"
}

View File

@ -0,0 +1,307 @@
/* eslint-disable */
/* tslint:disable */
/**
* Mock Service Worker.
* @see https://github.com/mswjs/msw
* - Please do NOT modify this file.
* - Please do NOT serve this file on production.
*/
const PACKAGE_VERSION = '2.7.3'
const INTEGRITY_CHECKSUM = '00729d72e3b82faf54ca8b9621dbb96f'
const IS_MOCKED_RESPONSE = Symbol('isMockedResponse')
const activeClientIds = new Set()
self.addEventListener('install', function () {
self.skipWaiting()
})
self.addEventListener('activate', function (event) {
event.waitUntil(self.clients.claim())
})
self.addEventListener('message', async function (event) {
const clientId = event.source.id
if (!clientId || !self.clients) {
return
}
const client = await self.clients.get(clientId)
if (!client) {
return
}
const allClients = await self.clients.matchAll({
type: 'window',
})
switch (event.data) {
case 'KEEPALIVE_REQUEST': {
sendToClient(client, {
type: 'KEEPALIVE_RESPONSE',
})
break
}
case 'INTEGRITY_CHECK_REQUEST': {
sendToClient(client, {
type: 'INTEGRITY_CHECK_RESPONSE',
payload: {
packageVersion: PACKAGE_VERSION,
checksum: INTEGRITY_CHECKSUM,
},
})
break
}
case 'MOCK_ACTIVATE': {
activeClientIds.add(clientId)
sendToClient(client, {
type: 'MOCKING_ENABLED',
payload: {
client: {
id: client.id,
frameType: client.frameType,
},
},
})
break
}
case 'MOCK_DEACTIVATE': {
activeClientIds.delete(clientId)
break
}
case 'CLIENT_CLOSED': {
activeClientIds.delete(clientId)
const remainingClients = allClients.filter((client) => {
return client.id !== clientId
})
// Unregister itself when there are no more clients
if (remainingClients.length === 0) {
self.registration.unregister()
}
break
}
}
})
self.addEventListener('fetch', function (event) {
const { request } = event
// Bypass navigation requests.
if (request.mode === 'navigate') {
return
}
// Opening the DevTools triggers the "only-if-cached" request
// that cannot be handled by the worker. Bypass such requests.
if (request.cache === 'only-if-cached' && request.mode !== 'same-origin') {
return
}
// Bypass all requests when there are no active clients.
// Prevents the self-unregistered worked from handling requests
// after it's been deleted (still remains active until the next reload).
if (activeClientIds.size === 0) {
return
}
// Generate unique request ID.
const requestId = crypto.randomUUID()
event.respondWith(handleRequest(event, requestId))
})
async function handleRequest(event, requestId) {
const client = await resolveMainClient(event)
const response = await getResponse(event, client, requestId)
// Send back the response clone for the "response:*" life-cycle events.
// Ensure MSW is active and ready to handle the message, otherwise
// this message will pend indefinitely.
if (client && activeClientIds.has(client.id)) {
;(async function () {
const responseClone = response.clone()
sendToClient(
client,
{
type: 'RESPONSE',
payload: {
requestId,
isMockedResponse: IS_MOCKED_RESPONSE in response,
type: responseClone.type,
status: responseClone.status,
statusText: responseClone.statusText,
body: responseClone.body,
headers: Object.fromEntries(responseClone.headers.entries()),
},
},
[responseClone.body],
)
})()
}
return response
}
// Resolve the main client for the given event.
// Client that issues a request doesn't necessarily equal the client
// that registered the worker. It's with the latter the worker should
// communicate with during the response resolving phase.
async function resolveMainClient(event) {
const client = await self.clients.get(event.clientId)
if (activeClientIds.has(event.clientId)) {
return client
}
if (client?.frameType === 'top-level') {
return client
}
const allClients = await self.clients.matchAll({
type: 'window',
})
return allClients
.filter((client) => {
// Get only those clients that are currently visible.
return client.visibilityState === 'visible'
})
.find((client) => {
// Find the client ID that's recorded in the
// set of clients that have registered the worker.
return activeClientIds.has(client.id)
})
}
async function getResponse(event, client, requestId) {
const { request } = event
// Clone the request because it might've been already used
// (i.e. its body has been read and sent to the client).
const requestClone = request.clone()
function passthrough() {
// Cast the request headers to a new Headers instance
// so the headers can be manipulated with.
const headers = new Headers(requestClone.headers)
// Remove the "accept" header value that marked this request as passthrough.
// This prevents request alteration and also keeps it compliant with the
// user-defined CORS policies.
const acceptHeader = headers.get('accept')
if (acceptHeader) {
const values = acceptHeader.split(',').map((value) => value.trim())
const filteredValues = values.filter(
(value) => value !== 'msw/passthrough',
)
if (filteredValues.length > 0) {
headers.set('accept', filteredValues.join(', '))
} else {
headers.delete('accept')
}
}
return fetch(requestClone, { headers })
}
// Bypass mocking when the client is not active.
if (!client) {
return passthrough()
}
// Bypass initial page load requests (i.e. static assets).
// The absence of the immediate/parent client in the map of the active clients
// means that MSW hasn't dispatched the "MOCK_ACTIVATE" event yet
// and is not ready to handle requests.
if (!activeClientIds.has(client.id)) {
return passthrough()
}
// Notify the client that a request has been intercepted.
const requestBuffer = await request.arrayBuffer()
const clientMessage = await sendToClient(
client,
{
type: 'REQUEST',
payload: {
id: requestId,
url: request.url,
mode: request.mode,
method: request.method,
headers: Object.fromEntries(request.headers.entries()),
cache: request.cache,
credentials: request.credentials,
destination: request.destination,
integrity: request.integrity,
redirect: request.redirect,
referrer: request.referrer,
referrerPolicy: request.referrerPolicy,
body: requestBuffer,
keepalive: request.keepalive,
},
},
[requestBuffer],
)
switch (clientMessage.type) {
case 'MOCK_RESPONSE': {
return respondWithMock(clientMessage.data)
}
case 'PASSTHROUGH': {
return passthrough()
}
}
return passthrough()
}
function sendToClient(client, message, transferrables = []) {
return new Promise((resolve, reject) => {
const channel = new MessageChannel()
channel.port1.onmessage = (event) => {
if (event.data && event.data.error) {
return reject(event.data.error)
}
resolve(event.data)
}
client.postMessage(
message,
[channel.port2].concat(transferrables.filter(Boolean)),
)
})
}
async function respondWithMock(response) {
// Setting response status code to 0 is a no-op.
// However, when responding with a "Response.error()", the produced Response
// instance will have status code set to 0. Since it's not possible to create
// a Response instance with status code 0, handle that use-case separately.
if (response.status === 0) {
return Response.error()
}
const mockedResponse = new Response(response.body, response)
Reflect.defineProperty(mockedResponse, IS_MOCKED_RESPONSE, {
value: true,
enumerable: true,
})
return mockedResponse
}

View File

@ -1,6 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
<g fill="none">
<circle cx="16" cy="16" r="16" fill="#CA2170"/>
<path fill="#FFF" d="M11.4584691,13.9059027 C10.1039643,13.9073677 9.00383358,12.8130959 9.00001,11.4597195 C8.9961853,10.1066373 10.0901428,9.00589931 11.4449417,9.00002359 C12.7994476,8.99415233 13.9028137,10.0851921 13.9110468,11.4382755 C13.9169293,12.0913154 13.6604964,12.719091 13.1999766,13.1832409 C12.7391627,13.6465085 12.1119026,13.9067839 11.4584691,13.9059027 Z M16.1321856,12.6563312 C15.5069844,12.6563312 15,12.1498792 15,11.5253345 C15,10.9007897 15.5069844,10.3943388 16.1321856,10.3943388 C16.7573868,10.3943388 17.26437,10.9007897 17.26437,11.5253345 C17.2652647,11.8255635 17.1461532,12.1137469 16.9335378,12.3258457 C16.7212154,12.5382374 16.4327288,12.6572125 16.1321856,12.6563312 Z M20.2756886,13.7226995 C20.0998328,14.2855536 19.5052147,14.6048759 18.9382407,14.440955 C18.3712656,14.2770341 18.0392557,13.6900911 18.1912921,13.1201859 C18.3436226,12.5502819 18.9235368,12.2065765 19.4969804,12.3455272 C20.0710134,12.4856533 20.4271367,13.0579081 20.299215,13.6336879 C20.299215,13.6630643 20.299215,13.689504 20.2756886,13.7218171 L20.2756886,13.7226995 Z M19.4758081,10.8076661 C19.0288146,10.919297 18.5588851,10.7503816 18.2859836,10.3796506 C18.0130833,10.0095067 17.9913217,9.51098701 18.2306977,9.11822256 C18.4703689,8.72516511 18.923831,8.51600424 19.3787636,8.58797574 C19.8334021,8.6608296 20.1992304,9.00042286 20.3050963,9.44812099 C20.3333275,9.59500296 20.3333275,9.74482391 20.3050963,9.89170588 C20.2433408,10.3470422 19.9022154,10.7151306 19.4522817,10.811191 L19.4758081,10.8076661 Z M23.5046227,13.5990241 C23.3964026,14.2138739 22.8094317,14.6248516 22.1939343,14.5170397 C21.5781427,14.4089349 21.1667334,13.8231661 21.2743652,13.2080221 C21.3819959,12.5922898 21.9683797,12.1810192 22.5841702,12.2885369 C23.1684963,12.3813665 23.5840222,12.9060317 23.5399117,13.4959125 C23.5263843,13.5273444 23.5184442,13.5611282 23.5163853,13.5957921 L23.5046227,13.5990241 Z M22.5812301,10.7586081 C21.9660268,10.8605442 21.3843478,10.4448662 21.2825984,9.83030935 C21.1805549,9.21633958 21.5960819,8.63527231 22.2112841,8.53304206 C22.8258991,8.43081192 23.4081664,8.84590155 23.510504,9.46016544 C23.5222666,9.55769534 23.5222666,9.65640061 23.510504,9.7539305 C23.4646288,10.2603814 23.0832144,10.6728285 22.5812301,10.7586081 Z M21.7931111,17.5152078 C21.5078599,18.0263591 20.8823635,18.2408086 20.3433266,18.0122592 C19.8034061,17.7831215 19.523448,17.1850164 19.6934225,16.624512 C19.8639852,16.0643016 20.430078,15.7226528 21.0058745,15.8322272 C21.5816722,15.9426828 21.9822012,16.4682293 21.9342672,17.0513532 C21.9254436,17.2158612 21.8769224,17.3744946 21.7931111,17.515502 L21.7931111,17.5152078 Z M21.3843478,7.12208774 C20.8379589,7.42936619 20.1462963,7.23606866 19.8386952,6.69025284 C19.5310941,6.14473081 19.7245938,5.45350117 20.2709838,5.14622272 C20.8167855,4.83894427 21.5090353,5.03165434 21.8166375,5.57717637 C21.9333848,5.77488035 21.9830836,6.00460481 21.9577925,6.23227287 C21.9233858,6.60182954 21.7101822,6.93084661 21.387289,7.1135685 L21.3843478,7.12208774 Z M11.5666684,22.7418333 C7.45668969,22.8079313 3.63019739,20.6552191 1.55579888,17.1103546 C-0.518599627,13.5651948 -0.518599627,9.17810524 1.55579888,5.63294615 C3.63019739,2.08837486 7.45668969,-0.0643368804 11.5666684,0.00146655576 C14.0674744,-0.00264555789 16.4982905,0.824009284 18.4774093,2.35158849 L17.086439,4.16412007 C14.3397875,2.0636986 10.6379827,1.70236727 7.53638328,3.23229666 C4.43478381,4.76193226 2.47095732,7.91785222 2.47095732,11.3731195 C2.47272205,14.8286795 4.4359603,17.9843057 7.5366774,19.5162911 C10.6373945,21.0468082 14.3397875,20.689883 17.0893791,18.5938681 L18.4774093,20.4093377 C16.4959386,21.929867 14.0651214,22.7500586 11.5666684,22.7418333 Z" transform="translate(4 5)"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.8 KiB

View File

@ -1,10 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="72" height="72" viewBox="0 0 72 72">
<circle cx="36" cy="36" r="36" fill="#c62a71"/>
<g fill="#fff">
<g fill-rule="evenodd">
<path d="M34.886 42.4a6.47 6.47 0 116.46-6.48 6.46 6.46 0 01-6.46 6.48M47.476 38.92a3 3 0 113-3 3 3 0 01-3 3M58.396 41.73a2.86 2.86 0 11.06-.24c0 .07 0 .15-.06.24M56.286 34a3 3 0 112.22-3.59 3.14 3.14 0 010 1.17 2.87 2.87 0 01-2.22 2.42M66.906 41.4a3 3 0 11-2.42-3.46 3 3 0 012.51 3.19.77.77 0 00-.06.27M64.476 33.91a3 3 0 112.45-3.43 3.32 3.32 0 010 .77 3 3 0 01-2.48 2.66M62.396 51.74a3 3 0 11.37-1.23 2.69 2.69 0 01-.37 1.23M61.316 24.31a3 3 0 111.14-4.08 2.79 2.79 0 01.37 1.77 3 3 0 01-1.51 2.35"/>
</g>
<path
d="M34.996 66a30 30 0 110-60 29.71 29.71 0 0118.22 6.17L49.546 17a24 24 0 00-38.55 19 24 24 0 0038.56 19.06l3.66 4.79A29.74 29.74 0 0134.996 66z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 877 B

View File

@ -1,6 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="52" height="52" viewBox="0 0 52 52">
<g fill="none" fill-rule="evenodd">
<circle cx="26" cy="26" r="26" fill="#007BFF"/>
<path fill="#FFF" fill-rule="nonzero" d="M22.749 13v3.94h-8.125v3.939h-4.062v3.94H7.414a.785.785 0 0 0-.787.64 8.97 8.97 0 0 0-.127 1.526c0 .55.054 1.15.152 1.748.93-.215 2.634-.539 2.336-1.6 1.603 1.8 5.449 1.255 6.423.369 1.089 1.53 7.43.945 7.87-.246 1.365 1.55 5.596 1.55 6.957 0 .441 1.19 6.757 1.775 7.845.246.346.314 1.066.575 1.904.714.283-.52.543-1.043.787-1.6 5.16-.062 6.274-3.66 6.322-3.817.089-.301-.032-.612-.28-.812-.085-.071-1.99-1.57-5.077-1.059-.866-2.736-3.097-3.982-3.199-4.038a.826.826 0 0 0-.914.074c-.082.065-2.002 1.643-1.701 4.875.076.813.295 1.53.635 2.167-.667.36-1.812.812-3.656.812h-.406v-3.94h-4.063V13H22.75zm17.238 15.216c-.098.185-.225.363-.33.542h7.337c-.882-.216-2.777-.505-2.462-1.625-1.038 1.163-3.009 1.335-4.545 1.083zm-.33.542H6.652a12.07 12.07 0 0 0 1.219 3.545c4.411 1.006 9.041-.526 9.089-.542a.8.8 0 0 1 1.016.493.78.78 0 0 1-.483 1.01c-.155.052-2.945.96-6.372.96-.68 0-1.394-.037-2.108-.124 2.133 2.743 5.748 4.9 11.298 4.9 8.778 0 15.528-3.616 19.346-10.242zm-33.005 0c-.003-.013.004-.013 0-.025-.054.012-.104.012-.152.025h.152zm17.721-14.182h2.438v2.363h-2.438v-2.363zm-8.124 3.94h2.437v2.363H16.25v-2.364zm4.062 0h2.438v2.363H20.31v-2.364zm4.062 0h2.438v2.363h-2.438v-2.364zm-12.186 3.939h2.437v2.363h-2.437v-2.363zm4.062 0h2.437v2.363H16.25v-2.363zm4.062 0h2.438v2.363H20.31v-2.363zm4.062 0h2.438v2.363h-2.438v-2.363zm4.062 0h2.438v2.363h-2.438v-2.363zM19.5 30.333c.105 0 .212.016.304.05-.098.055-.177.15-.177.27 0 .179.146.345.33.345a.367.367 0 0 0 .304-.172.7.7 0 0 1 .051.295.802.802 0 0 1-.812.788.802.802 0 0 1-.813-.788c0-.434.365-.788.813-.788z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -1,36 +0,0 @@
<svg xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 120" fill="#fff"
fill-rule="evenodd" stroke="#000" stroke-linecap="round" stroke-linejoin="round">
<style><![CDATA[.B{stroke:none}.C{fill:#9d5025}.D{fill:#f58536}]]></style>
<circle cx="60" cy="60" r="60" fill="#FFFFFF" stroke="none"/>
<use xlink:href="#A" x="20" y="20"/>
<symbol id="A" overflow="visible">
<path
d="M4.282 5.345L0 7.627v64.746l4.282 2.282 16.87-33.306L4.282 5.345zM17.318 17.03l6.306-9.568 28.26 13.464-6.588 1.122L17.32 17.03zm-4.894 46.632l6.94 10.224 32.518-15.04L45.6 57.8l-33.176 5.862z"
class="B C"/>
<path d="M14.258 72.146l-9.976 2.51v-69.3l9.976 2.433v64.368z" class="B D"/>
<path
d="M9.012 2.8L14.26 0l9.882 44.488L14.26 80l-5.247-2.8V2.8zm36.235 54.94l6.635 1.097 6.07-18.115-6.07-19.805-6.635 1.122v35.7z"
class="B C"/>
<g class="D">
<path d="M24.47 76.912L14.26 80V0L24.47 3.1v73.8z" class="B"/>
<path d="M58.836 57.447L14.26 66.322V80l44.577-13.5v-9.064zm.082-35.097l-44.66-9.1V0l44.66 13.577v8.774z"
class="B"/>
<path d="M51.882 11.434l7.165 2.118v52.96l-7.165 2.105V11.434z" class="B"/>
</g>
<path d="M80 33.003l-19.177.97-6.776-.492 19.388-16.74L80 33.003z" fill="#6b3a19" class="B"/>
<path d="M54.047 33.482L73.435 32.3V16.74l-19.388 3.366v13.375z" class="B C"/>
<path d="M35.8 32.172l19.647-21.217 9.988 20.498L45.07 32.84l-9.27-.668z" fill="#6b3a19" class="B"/>
<g class="C">
<path
d="M35.8 32.172l19.647-1.8V10.955L35.8 15.884V32.17zm18.247 14.623l25.953.48-6.565 16.262-19.388-3.366V46.795z"
class="B"/>
<path d="M35.8 48.106l29.635.73-9.988 20.485L35.8 64.406v-16.3z" class="B"/>
</g>
<path
d="M35.8 48.106l19.647 1.803 9.988-1.072-20.365-1.4-9.27.668zm44.2-.832l-19.177-.958-6.776.48 19.388 1.185L80 47.274z"
class="B" fill="#fbbf93"/>
<path
d="M73.435 32.3l6.565.693V18.846l-6.565-2.105V32.3zm-8-.847l-9.988-1.072V10.955l9.988 3.215v17.283zm8 16.527L80 47.274V61.43l-6.565 2.105V47.98zm-8 .857l-9.988 1.072v19.414l9.988-3.202V48.837z"
class="B D"/>
</symbol>
</svg>

Before

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -1,6 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
<g fill="none">
<circle cx="16" cy="16" r="16" fill="#419EDA"/>
<path fill="#FFF" d="M15.2941176,14.587756 C15.2941176,15.4465307 14.5982287,16.1411765 13.7405374,16.1411765 C12.8822069,16.1411765 12.1882353,15.4466372 12.1882353,14.587756 C12.1882353,13.7326026 12.8823134,13.0352941 13.7405374,13.0352941 C14.5982287,13.0352941 15.2941176,13.7326026 15.2941176,14.587756 Z M17.5529412,14.5879158 C17.5529412,13.7325308 18.2488173,13.0352941 19.1063616,13.0352941 C19.9636929,13.0352941 20.6588235,13.7325308 20.6588235,14.5879158 C20.6588235,15.4467087 19.9636929,16.1411765 19.1063616,16.1411765 C18.2488173,16.1411765 17.5529412,15.4466022 17.5529412,14.5879158 Z M28.4963286,16.4275595 L28.8470588,16.4005593 L28.8136083,16.7562292 C28.6413549,18.5561348 28.0815868,20.2707062 27.1497512,21.8521653 L26.9690518,22.1596126 L26.6964468,21.9286105 C26.0607761,21.3912721 25.2930814,21.0362689 24.4788227,20.8941564 C23.9428367,21.9894999 23.3080549,23.0179539 22.5879244,23.9729627 C21.4441616,24.3731886 20.2525012,24.6721914 19.0221671,24.8506375 C18.9037011,25.667534 18.9980516,26.5133196 19.3194432,27.2944379 L19.4556901,27.6261076 L19.1058489,27.7029972 L16.4248074,28 C15.5407583,28 14.637928,27.8997768 13.742988,27.7029972 L13.3934802,27.6261076 L13.5293938,27.2951046 C13.8516744,26.5139862 13.9460248,25.6692006 13.8275589,24.8524153 C12.592335,24.6740803 11.3962294,24.3744109 10.2482435,23.9729627 C9.52877981,23.0187317 8.89455375,21.9909444 8.35945677,20.8970453 C7.5477541,21.0400467 6.78439353,21.3948277 6.15261236,21.9306105 L5.8800074,22.1619459 L5.69841893,21.8537209 C4.76825035,20.2742618 4.2083711,18.5595793 4.03345051,16.7567848 L4,16.4004482 L4.35695358,16.4276706 C4.4715299,16.4372263 4.58944016,16.4417819 4.715463,16.4417819 C5.43337089,16.4417819 6.13060837,16.2742248 6.76005579,15.9667775 C6.54846188,14.7422106 6.46344647,13.5164214 6.49011797,12.3045213 C7.17535328,11.31729 7.95827295,10.3845036 8.8403217,9.52571783 C8.45714114,8.81004454 7.89126081,8.19459439 7.18513283,7.75725701 L6.88129998,7.56925527 L7.11900973,7.30147501 C8.32011631,5.94712914 9.81760994,4.85545237 11.4491279,4.14466801 L11.7774096,4.00200002 L11.8616471,4.35011435 C12.0579049,5.15934407 12.4687571,5.88968416 13.0318592,6.47646737 C14.1181671,5.89979537 15.2514837,5.43434661 16.4194731,5.08156557 C17.5902409,5.4351244 18.7255577,5.9019065 19.8123103,6.4794674 C20.3777461,5.89190641 20.7895985,5.15978852 20.9866342,4.34822545 L21.070316,4 L21.3998202,4.14333466 C23.0521197,4.86456356 24.5094949,5.92746229 25.7306051,7.3022528 L25.9676481,7.5694775 L25.6634818,7.75747924 C24.9551312,8.1964833 24.3876951,8.81560014 24.0038477,9.53516236 C24.8885636,10.3972815 25.6723723,11.3330679 26.3581633,12.3248549 C26.381612,13.5373105 26.2920402,14.7542107 26.0814465,15.9621108 C26.7140056,16.272447 27.4151326,16.441893 28.1378192,16.441893 C28.2623973,16.441893 28.3796408,16.4373374 28.4963286,16.4275595 Z M20.2563907,20.7843776 C20.9539616,19.7022565 21.5063951,18.539468 21.9016889,17.3193455 C22.2969828,16.1066677 22.5306918,14.8414337 22.6009268,13.5385328 C21.7771108,12.5187455 20.8407189,11.6240706 19.8066426,10.8727303 C18.7623422,10.1147233 17.6256917,9.49716201 16.4194731,9.03182437 C15.2112541,9.4970509 14.0724922,10.1155011 13.0257469,10.8767303 C11.9956714,11.6240706 11.0633913,12.5118566 10.243576,13.5253104 C10.3105882,14.8356559 10.5415189,16.1082232 10.936146,17.3229011 C11.33244,18.5432458 11.8830954,19.7023676 12.579555,20.7843776 C13.8490073,21.1293808 15.1355738,21.3033824 16.4194731,21.3033824 C17.6999274,21.3033824 18.9880498,21.1292697 20.2563907,20.7843776 Z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -1,6 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
<g fill="none" fill-rule="evenodd">
<circle cx="16" cy="16" r="16" fill="#5E7D89"/>
<path fill="#FFF" fill-rule="nonzero" d="M20.625 11c-.621 0-1.125-.56-1.125-1.25V6.5a.209.209 0 0 1 .117-.19.174.174 0 0 1 .203.047l3.863 4.287c.054.06.07.15.04.227a.188.188 0 0 1-.173.129h-2.925zm3.188.833c.05 0 .097.022.132.062a.22.22 0 0 1 .055.147v12.291c0 .92-.672 1.667-1.5 1.667h-12c-.828 0-1.5-.746-1.5-1.667V7.667C9 6.747 9.672 6 10.5 6h8.063c.05 0 .097.022.132.061a.22.22 0 0 1 .055.148V9.75c0 1.15.84 2.083 1.875 2.083h3.188z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 644 B

View File

@ -1,11 +0,0 @@
<svg width="32" height="32"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<path d="M18.748 23.93a13.78 13.78 0 002.476-6.88h3.102a8.413 8.413 0 01-5.578 6.88zM7.672 17.05h3.142a13.547 13.547 0 002.463 6.89 8.416 8.416 0 01-5.605-6.89zm5.638-9a13.801 13.801 0 00-2.492 6.9H7.672a8.414 8.414 0 015.638-6.9zm-.377 6.9c.321-3.436 2.079-5.827 3.094-6.933 1.05 1.124 2.78 3.494 3.08 6.933h-6.174zm.001 2.1h6.176c-.321 3.44-2.083 5.833-3.097 6.938a11.57 11.57 0 01-3.079-6.938zm11.393-2.1h-3.1a13.537 13.537 0 00-2.445-6.866 8.409 8.409 0 015.544 6.866zM26.5 16c0-5.78-4.695-10.481-10.47-10.498h-.014L16 5.5C10.21 5.5 5.5 10.211 5.5 16c0 5.79 4.71 10.5 10.5 10.5l.016-.001.005.001.008-.002C21.805 26.482 26.5 21.779 26.5 16z" id="a"/>
</defs>
<g fill-rule="nonzero" fill="none">
<circle fill="#45BBEA" cx="16" cy="16" r="16"/>
<use fill="#FFF" xlink:href="#a"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 918 B

View File

@ -1,10 +0,0 @@
<svg width="128" height="128" viewBox="0 0 128 128" xmlns="http://www.w3.org/2000/svg">
<g fill="none" fill-rule="evenodd">
<g fill="#dfdfdf">
<path d="M128 0H0v128h128V0z"/>
<path d="M48 0H0v48h48V0zM128 0H80v48h48V0zM128 80H80v48h48V80zM48 80H0v48h48V80z"/>
</g>
<path d="M27.429 27.429h73.142v73.142H27.43V27.43z"/>
<path d="m65.323 31.205 16.89 9.164a2.905 2.905 0 0 1 1.516 2.557l-.014 14.763 15.34 8.323a2.905 2.905 0 0 1 1.516 2.558l-.016 16.47a2.905 2.905 0 0 1-1.51 2.55L82.17 96.792a2.873 2.873 0 0 1-2.776-.013l-15.279-8.512-15.63 8.525a2.873 2.873 0 0 1-2.775-.013l-16.794-9.356a2.906 2.906 0 0 1-1.488-2.539V68.606c0-1.063.577-2.041 1.505-2.55l15.337-8.403v-14.69c0-1.064.577-2.041 1.505-2.55l16.794-9.202a2.873 2.873 0 0 1 2.753-.006zM79.888 63.21l-11.997 6.57a1.937 1.937 0 0 0-1.004 1.7v10.554c0 .704.38 1.352.992 1.693l12.006 6.688c.575.32 1.273.324 1.85.009l12.042-6.566a1.937 1.937 0 0 0 1.007-1.7l.01-10.703c0-.712-.388-1.367-1.01-1.705l-12.061-6.544a1.916 1.916 0 0 0-1.835.004zm-33.69 0-11.991 6.57a1.937 1.937 0 0 0-1.004 1.7v10.554c0 .704.38 1.352.992 1.693l12.006 6.688c.575.32 1.273.324 1.85.009l12.041-6.566a1.937 1.937 0 0 0 1.007-1.7l.01-10.672c.001-.71-.385-1.365-1.007-1.703l-12.066-6.576a1.916 1.916 0 0 0-1.838.003zm16.844-25.645L51.05 44.137a1.937 1.937 0 0 0-1.004 1.699v10.552c0 .705.381 1.355.996 1.695l12.036 6.673c.575.319 1.271.321 1.848.007l12.01-6.554a1.937 1.937 0 0 0 1.007-1.699l.01-10.699c0-.712-.388-1.367-1.01-1.705l-12.065-6.545a1.916 1.916 0 0 0-1.835.004z" fill="#7F8C2B" fill-rule="nonzero"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -1,4 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="72" height="72" viewBox="0 0 72 72">
<circle cx="36" cy="36" r="36" fill="#dfdfdf"/>
<path d="m20.79 54.774c-4.1802-0.36038-7.3744-1.6213-9.6977-3.8282-2.3638-2.2454-3.378-5.1728-2.9777-8.5946 0.46062-3.9378 2.3319-6.7185 5.6126-8.3408 2.5286-1.2503 5.0511-1.7259 9.1591-1.7269 2.9187-0.0012 5.3644 0.23777 9.0946 0.88675 0.92236 0.16048 1.7209 0.29185 1.7746 0.29196 0.07803 0 0.1399-0.29356 0.30914-1.4672 0.30621-2.1235 0.36109-2.8562 0.27767-3.7069-0.0971-0.99016-0.22383-1.4618-0.59895-2.2291-0.96784-1.9798-3.2653-3.1911-6.9547-3.6667-1.0551-0.13602-3.4903-0.15505-4.5473-0.0356-1.7709 0.20021-2.7591 0.45532-4.963 1.2811-1.2894 0.48314-1.2953 0.48463-1.8096 0.45444-0.88418-0.05181-1.4878-0.45212-1.8749-1.2434-0.15944-0.32586-0.18748-0.46038-0.18748-0.89945 0-0.65913 0.17166-1.009 0.76939-1.5682 1.3404-1.2539 3.596-2.3217 5.8726-2.7802 1.4577-0.29355 2.1753-0.35527 4.0958-0.35232 1.9873 0.0052 3.258 0.11526 5.024 0.44365 2.9374 0.54614 5.1678 1.5088 6.8497 2.9563 0.49904 0.42948 1.2515 1.2748 1.574 1.7681 0.09855 0.15078 0.20008 0.27415 0.2256 0.27415 0.02554 0 0.18857-0.18117 0.36231-0.40254 2.5467-3.2452 6.8359-5.082 11.861-5.0794 3.5543 0 6.8581 0.901 9.3207 2.5369 1.9533 1.2976 3.5402 3.2965 4.1812 5.267 0.36807 1.1314 0.42403 1.5495 0.42742 3.1928 0.0021 1.0225-0.02612 1.7122-0.08315 2.0318-0.57634 3.2298-1.9492 5.4674-4.332 7.0607-1.917 1.2818-4.3245 2.0318-7.4732 2.328-1.585 0.14912-4.4841 0.13504-6.3622-0.03097-1.5939-0.14085-3.5511-0.3887-4.386-0.55536-0.69888-0.13953-3.0921-0.53913-3.1118-0.51957-0.0087 0.0088-0.12256 0.72447-0.25302 1.5908-0.20832 1.3833-0.23783 1.7285-0.2422 2.833-0.0047 1.123 0.01128 1.32 0.14678 1.8383 0.43569 1.6665 1.3958 2.7813 3.1378 3.6431 1.7136 0.8478 3.51 1.2147 6.2243 1.2712 1.2017 0.02528 1.8171 0.0077 2.5689-0.07192 1.8225-0.19325 2.653-0.40528 5.0744-1.2954 0.60308-0.22174 1.2186-0.42349 1.3677-0.44836 0.31967-0.0533 0.91586 0.05677 1.2633 0.23329 0.62718 0.31853 1.1541 1.168 1.1508 1.8552-0.0036 0.80285-0.27442 1.2891-1.0693 1.9215-1.9005 1.5121-4.3271 2.4394-7.2238 2.7606-1.0329 0.11455-3.3912 0.13142-4.5304 0.0325-3.208-0.27863-5.4352-0.82731-7.4706-1.8403-1.5882-0.79041-2.7999-1.771-3.705-2.9982-0.22238-0.30156-0.41127-0.55579-0.41977-0.56509-0.0085-0.0093-0.15631 0.16492-0.32849 0.38701-0.76108 0.98176-1.9249 2.037-3.0623 2.7765-1.642 1.0676-3.9992 1.8821-6.3844 2.206-0.71132 0.09655-3.0714 0.17621-3.6765 0.12405zm4.0958-4.5958c1.9474-0.43158 3.6827-1.4044 4.9426-2.7705 1.1492-1.2461 2.0917-3.1129 2.6105-5.1701 0.2924-1.1597 0.77845-4.3872 0.67071-4.4538-0.04252-0.02632-0.29939-0.06785-0.57075-0.09242-0.27137-0.02477-1.0449-0.11589-1.7189-0.20305-4.0037-0.51781-6.4599-0.719-7.8368-0.6418-2.6178 0.14664-3.6851 0.37518-5.2568 1.1258-0.80521 0.38453-1.361 0.80183-1.8007 1.352-0.63087 0.78938-1.0117 1.5738-1.2771 2.6308-0.19315 0.76915-0.21286 2.7831-0.03359 3.432 0.30199 1.093 0.66048 1.7117 1.4666 2.5308 1.1038 1.1216 2.5589 1.8699 4.3639 2.2441 0.92293 0.19134 0.89562 0.18948 2.4409 0.16621 1.1213-0.01703 1.5408-0.04851 1.9995-0.15006zm25.51-15.133c1.6286-0.1437 2.6301-0.39655 3.8605-0.97459 1.0233-0.48081 1.6181-0.9722 2.1809-1.8019 0.82864-1.2215 1.1513-2.3775 1.143-4.0951-0.0059-1.2242-0.10967-1.7334-0.53228-2.6123-0.94425-1.9636-3.1624-3.3701-6.0716-3.85-0.72595-0.11971-2.6744-0.09845-3.4185 0.03717-1.4315 0.26119-2.6416 0.73727-3.7088 1.4591-1.9717 1.3336-3.3325 3.3439-4.0902 6.0426-0.29764 1.06-0.37698 1.4669-0.64234 3.2941l-0.24478 1.6855 0.32789 0.03611c0.99033 0.10981 3.2235 0.38021 4.5204 0.54739 0.81593 0.10517 1.8173 0.2174 2.2253 0.24944 1.1794 0.09258 3.2939 0.08396 4.4505-0.01807z" fill="#37abc8"/>
</svg>

Before

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -1,6 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
<g fill="none" fill-rule="evenodd">
<circle cx="16" cy="16" r="16" fill="#326CE6"/>
<path fill="#FFF" fill-rule="nonzero" d="M27.35 18.155c-.036 0-.073 0-.073-.037s-.072-.037-.144-.037c-.145-.037-.289-.037-.434-.037-.072 0-.144 0-.216-.037h-.036a7.13 7.13 0 0 1-1.229-.223.442.442 0 0 1-.253-.26c.037 0 0 0 0 0l-.289-.074c.145-1.075.073-2.187-.144-3.263a10.189 10.189 0 0 0-1.265-3.04l.217-.223v-.037c0-.112.036-.26.109-.334.325-.297.65-.52 1.011-.742l.217-.111c.144-.074.253-.148.397-.222.036-.038.073-.038.109-.075.036-.037 0-.037 0-.074.325-.26.397-.704.144-1.038a.684.684 0 0 0-.506-.26.85.85 0 0 0-.505.186l-.036.037c-.037.037-.073.074-.109.074a2.38 2.38 0 0 0-.289.334c-.036.074-.108.11-.144.148a4.791 4.791 0 0 1-.904.816c-.072.037-.144.074-.216.074-.036 0-.109 0-.145-.037h-.036l-.289.185c-.289-.296-.614-.593-.903-.89a9.125 9.125 0 0 0-4.696-1.928l-.037-.297v.037c-.108-.074-.144-.185-.18-.296 0-.408 0-.816.072-1.261v-.037c0-.074.036-.148.036-.223.036-.148.036-.296.072-.445v-.222c.037-.371-.252-.742-.614-.779-.216-.037-.433.074-.614.26a.742.742 0 0 0-.217.519v.185c0 .149.037.297.073.445a.481.481 0 0 1 .036.223v.037c.072.408.072.816.072 1.26-.036.112-.072.223-.18.297v.075l-.037.296c-.397.037-.795.111-1.228.186-1.698.37-3.251 1.298-4.444 2.595l-.216-.148H9.25c-.037 0-.073.037-.145.037s-.144-.037-.217-.074a6.73 6.73 0 0 1-.903-.853c-.036-.074-.108-.111-.144-.148-.109-.111-.181-.223-.29-.334-.035-.037-.072-.037-.108-.074l-.036-.037a.85.85 0 0 0-.506-.186c-.216 0-.397.075-.505.26a.813.813 0 0 0 .144 1.038c.036 0 .036.037.036.037s.073.075.109.075c.108.074.253.148.397.222l.217.111c.361.223.722.445 1.011.742.073.074.145.222.109.334v-.037l.216.222c-.036.074-.072.111-.108.186-1.12 1.817-1.59 3.967-1.264 6.081l-.29.074c0 .037-.035.037-.035.037-.037.112-.145.186-.253.26a6.554 6.554 0 0 1-1.229.223c-.072 0-.144 0-.216.037-.145 0-.29.037-.434.037-.036 0-.072.037-.144.037-.037 0-.037 0-.073.037a.722.722 0 0 0-.578.853.672.672 0 0 0 .723.519c.072 0 .108 0 .18-.037.037 0 .037 0 .037-.037s.108 0 .144 0c.145-.037.29-.111.397-.149.073-.037.145-.074.217-.074h.036a6.31 6.31 0 0 1 1.193-.333h.036c.108 0 .216.037.289.11.036 0 .036.038.036.038l.325-.037c.542 1.706 1.553 3.226 2.962 4.339.325.26.614.482.976.667l-.181.26c0 .037.036.037.036.037.072.11.072.26.036.37-.144.371-.361.742-.578 1.076v.037c-.036.074-.072.111-.144.185-.073.075-.145.223-.253.371-.036.037-.036.074-.072.112 0 0 0 .037-.037.037-.18.37-.036.815.29 1 .072.038.18.075.252.075.29 0 .542-.185.687-.445 0 0 0-.037.036-.037 0-.037.036-.074.072-.111.036-.149.109-.26.145-.408l.072-.223c.108-.408.289-.778.47-1.15a.563.563 0 0 1 .289-.222c.036 0 .036 0 .036-.037l.144-.297a8.31 8.31 0 0 0 3.143.594c.65 0 1.3-.074 1.951-.26.397-.074.795-.222 1.156-.334l.144.26c.037 0 .037 0 .037.037a.563.563 0 0 1 .289.223c.18.37.36.741.47 1.15v.036l.072.223c.036.148.072.296.144.408.036.037.036.074.072.11 0 0 0 .038.036.038.145.26.398.445.687.445.108 0 .18-.037.289-.074a.617.617 0 0 0 .325-.408.978.978 0 0 0-.036-.556c0-.037-.036-.037-.036-.037 0-.037-.036-.075-.073-.112a1.333 1.333 0 0 0-.252-.37.649.649 0 0 0-.145-.186v-.074a4.417 4.417 0 0 1-.578-1.075.449.449 0 0 1 .036-.371c0-.037.036-.037.036-.037l-.108-.297a9.128 9.128 0 0 0 3.902-5.043l.289.037c.036 0 .036-.037.036-.037a.404.404 0 0 1 .289-.112h.036c.397.075.795.186 1.156.334h.036c.072.037.144.074.217.074.144.074.253.149.397.186.036 0 .072.037.145.037.036 0 .036 0 .072.037a.319.319 0 0 0 .18.037.787.787 0 0 0 .723-.52.867.867 0 0 0-.65-.778zm-10.44-1.15l-.976.483-.976-.483-.252-1.075.686-.89h1.084l.686.89-.253 1.075zm5.888-2.41c.18.779.217 1.558.144 2.336L19.51 15.93c-.325-.074-.505-.408-.433-.742a.602.602 0 0 1 .144-.26l2.71-2.52c.397.667.686 1.408.867 2.187zm-1.951-3.56l-2.962 2.15c-.253.15-.614.112-.795-.147a.34.34 0 0 1-.108-.26l-.217-3.745a6.73 6.73 0 0 1 4.082 2.002zm-6.539-1.891l.723-.149-.18 3.709c0 .334-.29.593-.615.593-.108 0-.18-.037-.289-.074l-2.998-2.188c.939-.927 2.095-1.595 3.36-1.891zm-4.407 3.263l2.673 2.448a.607.607 0 0 1 .072.853c-.072.11-.144.148-.289.185L8.853 16.93a7.972 7.972 0 0 1 1.048-4.524zm-.614 6.267l3.576-.63c.29 0 .578.185.614.482a.449.449 0 0 1-.036.37l-1.373 3.412a7.268 7.268 0 0 1-2.781-3.634zm8.2 4.599a7.13 7.13 0 0 1-1.553.185c-.759 0-1.554-.148-2.276-.37l1.77-3.301c.18-.223.47-.297.723-.149.108.075.18.149.289.26l1.734 3.226c-.217.037-.434.074-.687.149zm4.408-3.227a6.992 6.992 0 0 1-2.168 2.225l-1.409-3.486a.608.608 0 0 1 .325-.704c.109-.037.217-.074.325-.074l3.613.63c-.18.52-.397 1.001-.686 1.41z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.5 KiB

View File

@ -1,6 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
<g fill="none" fill-rule="evenodd">
<circle cx="16" cy="16" r="16" fill="#326CE6"/>
<path fill="#FFF" fill-rule="nonzero" d="M27.35 18.155c-.036 0-.073 0-.073-.037s-.072-.037-.144-.037c-.145-.037-.289-.037-.434-.037-.072 0-.144 0-.216-.037h-.036a7.13 7.13 0 0 1-1.229-.223.442.442 0 0 1-.253-.26c.037 0 0 0 0 0l-.289-.074c.145-1.075.073-2.187-.144-3.263a10.189 10.189 0 0 0-1.265-3.04l.217-.223v-.037c0-.112.036-.26.109-.334.325-.297.65-.52 1.011-.742l.217-.111c.144-.074.253-.148.397-.222.036-.038.073-.038.109-.075.036-.037 0-.037 0-.074.325-.26.397-.704.144-1.038a.684.684 0 0 0-.506-.26.85.85 0 0 0-.505.186l-.036.037c-.037.037-.073.074-.109.074a2.38 2.38 0 0 0-.289.334c-.036.074-.108.11-.144.148a4.791 4.791 0 0 1-.904.816c-.072.037-.144.074-.216.074-.036 0-.109 0-.145-.037h-.036l-.289.185c-.289-.296-.614-.593-.903-.89a9.125 9.125 0 0 0-4.696-1.928l-.037-.297v.037c-.108-.074-.144-.185-.18-.296 0-.408 0-.816.072-1.261v-.037c0-.074.036-.148.036-.223.036-.148.036-.296.072-.445v-.222c.037-.371-.252-.742-.614-.779-.216-.037-.433.074-.614.26a.742.742 0 0 0-.217.519v.185c0 .149.037.297.073.445a.481.481 0 0 1 .036.223v.037c.072.408.072.816.072 1.26-.036.112-.072.223-.18.297v.075l-.037.296c-.397.037-.795.111-1.228.186-1.698.37-3.251 1.298-4.444 2.595l-.216-.148H9.25c-.037 0-.073.037-.145.037s-.144-.037-.217-.074a6.73 6.73 0 0 1-.903-.853c-.036-.074-.108-.111-.144-.148-.109-.111-.181-.223-.29-.334-.035-.037-.072-.037-.108-.074l-.036-.037a.85.85 0 0 0-.506-.186c-.216 0-.397.075-.505.26a.813.813 0 0 0 .144 1.038c.036 0 .036.037.036.037s.073.075.109.075c.108.074.253.148.397.222l.217.111c.361.223.722.445 1.011.742.073.074.145.222.109.334v-.037l.216.222c-.036.074-.072.111-.108.186-1.12 1.817-1.59 3.967-1.264 6.081l-.29.074c0 .037-.035.037-.035.037-.037.112-.145.186-.253.26a6.554 6.554 0 0 1-1.229.223c-.072 0-.144 0-.216.037-.145 0-.29.037-.434.037-.036 0-.072.037-.144.037-.037 0-.037 0-.073.037a.722.722 0 0 0-.578.853.672.672 0 0 0 .723.519c.072 0 .108 0 .18-.037.037 0 .037 0 .037-.037s.108 0 .144 0c.145-.037.29-.111.397-.149.073-.037.145-.074.217-.074h.036a6.31 6.31 0 0 1 1.193-.333h.036c.108 0 .216.037.289.11.036 0 .036.038.036.038l.325-.037c.542 1.706 1.553 3.226 2.962 4.339.325.26.614.482.976.667l-.181.26c0 .037.036.037.036.037.072.11.072.26.036.37-.144.371-.361.742-.578 1.076v.037c-.036.074-.072.111-.144.185-.073.075-.145.223-.253.371-.036.037-.036.074-.072.112 0 0 0 .037-.037.037-.18.37-.036.815.29 1 .072.038.18.075.252.075.29 0 .542-.185.687-.445 0 0 0-.037.036-.037 0-.037.036-.074.072-.111.036-.149.109-.26.145-.408l.072-.223c.108-.408.289-.778.47-1.15a.563.563 0 0 1 .289-.222c.036 0 .036 0 .036-.037l.144-.297a8.31 8.31 0 0 0 3.143.594c.65 0 1.3-.074 1.951-.26.397-.074.795-.222 1.156-.334l.144.26c.037 0 .037 0 .037.037a.563.563 0 0 1 .289.223c.18.37.36.741.47 1.15v.036l.072.223c.036.148.072.296.144.408.036.037.036.074.072.11 0 0 0 .038.036.038.145.26.398.445.687.445.108 0 .18-.037.289-.074a.617.617 0 0 0 .325-.408.978.978 0 0 0-.036-.556c0-.037-.036-.037-.036-.037 0-.037-.036-.075-.073-.112a1.333 1.333 0 0 0-.252-.37.649.649 0 0 0-.145-.186v-.074a4.417 4.417 0 0 1-.578-1.075.449.449 0 0 1 .036-.371c0-.037.036-.037.036-.037l-.108-.297a9.128 9.128 0 0 0 3.902-5.043l.289.037c.036 0 .036-.037.036-.037a.404.404 0 0 1 .289-.112h.036c.397.075.795.186 1.156.334h.036c.072.037.144.074.217.074.144.074.253.149.397.186.036 0 .072.037.145.037.036 0 .036 0 .072.037a.319.319 0 0 0 .18.037.787.787 0 0 0 .723-.52.867.867 0 0 0-.65-.778zm-10.44-1.15l-.976.483-.976-.483-.252-1.075.686-.89h1.084l.686.89-.253 1.075zm5.888-2.41c.18.779.217 1.558.144 2.336L19.51 15.93c-.325-.074-.505-.408-.433-.742a.602.602 0 0 1 .144-.26l2.71-2.52c.397.667.686 1.408.867 2.187zm-1.951-3.56l-2.962 2.15c-.253.15-.614.112-.795-.147a.34.34 0 0 1-.108-.26l-.217-3.745a6.73 6.73 0 0 1 4.082 2.002zm-6.539-1.891l.723-.149-.18 3.709c0 .334-.29.593-.615.593-.108 0-.18-.037-.289-.074l-2.998-2.188c.939-.927 2.095-1.595 3.36-1.891zm-4.407 3.263l2.673 2.448a.607.607 0 0 1 .072.853c-.072.11-.144.148-.289.185L8.853 16.93a7.972 7.972 0 0 1 1.048-4.524zm-.614 6.267l3.576-.63c.29 0 .578.185.614.482a.449.449 0 0 1-.036.37l-1.373 3.412a7.268 7.268 0 0 1-2.781-3.634zm8.2 4.599a7.13 7.13 0 0 1-1.553.185c-.759 0-1.554-.148-2.276-.37l1.77-3.301c.18-.223.47-.297.723-.149.108.075.18.149.289.26l1.734 3.226c-.217.037-.434.074-.687.149zm4.408-3.227a6.992 6.992 0 0 1-2.168 2.225l-1.409-3.486a.608.608 0 0 1 .325-.704c.109-.037.217-.074.325-.074l3.613.63c-.18.52-.397 1.001-.686 1.41z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.5 KiB

View File

@ -1,6 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
<g fill="none" fill-rule="evenodd">
<circle cx="16" cy="16" r="16" fill="#326CE6"/>
<path fill="#FFF" fill-rule="nonzero" d="M27.35 18.155c-.036 0-.073 0-.073-.037s-.072-.037-.144-.037c-.145-.037-.289-.037-.434-.037-.072 0-.144 0-.216-.037h-.036a7.13 7.13 0 0 1-1.229-.223.442.442 0 0 1-.253-.26c.037 0 0 0 0 0l-.289-.074c.145-1.075.073-2.187-.144-3.263a10.189 10.189 0 0 0-1.265-3.04l.217-.223v-.037c0-.112.036-.26.109-.334.325-.297.65-.52 1.011-.742l.217-.111c.144-.074.253-.148.397-.222.036-.038.073-.038.109-.075.036-.037 0-.037 0-.074.325-.26.397-.704.144-1.038a.684.684 0 0 0-.506-.26.85.85 0 0 0-.505.186l-.036.037c-.037.037-.073.074-.109.074a2.38 2.38 0 0 0-.289.334c-.036.074-.108.11-.144.148a4.791 4.791 0 0 1-.904.816c-.072.037-.144.074-.216.074-.036 0-.109 0-.145-.037h-.036l-.289.185c-.289-.296-.614-.593-.903-.89a9.125 9.125 0 0 0-4.696-1.928l-.037-.297v.037c-.108-.074-.144-.185-.18-.296 0-.408 0-.816.072-1.261v-.037c0-.074.036-.148.036-.223.036-.148.036-.296.072-.445v-.222c.037-.371-.252-.742-.614-.779-.216-.037-.433.074-.614.26a.742.742 0 0 0-.217.519v.185c0 .149.037.297.073.445a.481.481 0 0 1 .036.223v.037c.072.408.072.816.072 1.26-.036.112-.072.223-.18.297v.075l-.037.296c-.397.037-.795.111-1.228.186-1.698.37-3.251 1.298-4.444 2.595l-.216-.148H9.25c-.037 0-.073.037-.145.037s-.144-.037-.217-.074a6.73 6.73 0 0 1-.903-.853c-.036-.074-.108-.111-.144-.148-.109-.111-.181-.223-.29-.334-.035-.037-.072-.037-.108-.074l-.036-.037a.85.85 0 0 0-.506-.186c-.216 0-.397.075-.505.26a.813.813 0 0 0 .144 1.038c.036 0 .036.037.036.037s.073.075.109.075c.108.074.253.148.397.222l.217.111c.361.223.722.445 1.011.742.073.074.145.222.109.334v-.037l.216.222c-.036.074-.072.111-.108.186-1.12 1.817-1.59 3.967-1.264 6.081l-.29.074c0 .037-.035.037-.035.037-.037.112-.145.186-.253.26a6.554 6.554 0 0 1-1.229.223c-.072 0-.144 0-.216.037-.145 0-.29.037-.434.037-.036 0-.072.037-.144.037-.037 0-.037 0-.073.037a.722.722 0 0 0-.578.853.672.672 0 0 0 .723.519c.072 0 .108 0 .18-.037.037 0 .037 0 .037-.037s.108 0 .144 0c.145-.037.29-.111.397-.149.073-.037.145-.074.217-.074h.036a6.31 6.31 0 0 1 1.193-.333h.036c.108 0 .216.037.289.11.036 0 .036.038.036.038l.325-.037c.542 1.706 1.553 3.226 2.962 4.339.325.26.614.482.976.667l-.181.26c0 .037.036.037.036.037.072.11.072.26.036.37-.144.371-.361.742-.578 1.076v.037c-.036.074-.072.111-.144.185-.073.075-.145.223-.253.371-.036.037-.036.074-.072.112 0 0 0 .037-.037.037-.18.37-.036.815.29 1 .072.038.18.075.252.075.29 0 .542-.185.687-.445 0 0 0-.037.036-.037 0-.037.036-.074.072-.111.036-.149.109-.26.145-.408l.072-.223c.108-.408.289-.778.47-1.15a.563.563 0 0 1 .289-.222c.036 0 .036 0 .036-.037l.144-.297a8.31 8.31 0 0 0 3.143.594c.65 0 1.3-.074 1.951-.26.397-.074.795-.222 1.156-.334l.144.26c.037 0 .037 0 .037.037a.563.563 0 0 1 .289.223c.18.37.36.741.47 1.15v.036l.072.223c.036.148.072.296.144.408.036.037.036.074.072.11 0 0 0 .038.036.038.145.26.398.445.687.445.108 0 .18-.037.289-.074a.617.617 0 0 0 .325-.408.978.978 0 0 0-.036-.556c0-.037-.036-.037-.036-.037 0-.037-.036-.075-.073-.112a1.333 1.333 0 0 0-.252-.37.649.649 0 0 0-.145-.186v-.074a4.417 4.417 0 0 1-.578-1.075.449.449 0 0 1 .036-.371c0-.037.036-.037.036-.037l-.108-.297a9.128 9.128 0 0 0 3.902-5.043l.289.037c.036 0 .036-.037.036-.037a.404.404 0 0 1 .289-.112h.036c.397.075.795.186 1.156.334h.036c.072.037.144.074.217.074.144.074.253.149.397.186.036 0 .072.037.145.037.036 0 .036 0 .072.037a.319.319 0 0 0 .18.037.787.787 0 0 0 .723-.52.867.867 0 0 0-.65-.778zm-10.44-1.15l-.976.483-.976-.483-.252-1.075.686-.89h1.084l.686.89-.253 1.075zm5.888-2.41c.18.779.217 1.558.144 2.336L19.51 15.93c-.325-.074-.505-.408-.433-.742a.602.602 0 0 1 .144-.26l2.71-2.52c.397.667.686 1.408.867 2.187zm-1.951-3.56l-2.962 2.15c-.253.15-.614.112-.795-.147a.34.34 0 0 1-.108-.26l-.217-3.745a6.73 6.73 0 0 1 4.082 2.002zm-6.539-1.891l.723-.149-.18 3.709c0 .334-.29.593-.615.593-.108 0-.18-.037-.289-.074l-2.998-2.188c.939-.927 2.095-1.595 3.36-1.891zm-4.407 3.263l2.673 2.448a.607.607 0 0 1 .072.853c-.072.11-.144.148-.289.185L8.853 16.93a7.972 7.972 0 0 1 1.048-4.524zm-.614 6.267l3.576-.63c.29 0 .578.185.614.482a.449.449 0 0 1-.036.37l-1.373 3.412a7.268 7.268 0 0 1-2.781-3.634zm8.2 4.599a7.13 7.13 0 0 1-1.553.185c-.759 0-1.554-.148-2.276-.37l1.77-3.301c.18-.223.47-.297.723-.149.108.075.18.149.289.26l1.734 3.226c-.217.037-.434.074-.687.149zm4.408-3.227a6.992 6.992 0 0 1-2.168 2.225l-1.409-3.486a.608.608 0 0 1 .325-.704c.109-.037.217-.074.325-.074l3.613.63c-.18.52-.397 1.001-.686 1.41z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.5 KiB

View File

@ -1,6 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
<g fill="none" fill-rule="evenodd">
<circle cx="16" cy="16" r="16" fill="#326CE6"/>
<path fill="#FFF" fill-rule="nonzero" d="M27.35 18.155c-.036 0-.073 0-.073-.037s-.072-.037-.144-.037c-.145-.037-.289-.037-.434-.037-.072 0-.144 0-.216-.037h-.036a7.13 7.13 0 0 1-1.229-.223.442.442 0 0 1-.253-.26c.037 0 0 0 0 0l-.289-.074c.145-1.075.073-2.187-.144-3.263a10.189 10.189 0 0 0-1.265-3.04l.217-.223v-.037c0-.112.036-.26.109-.334.325-.297.65-.52 1.011-.742l.217-.111c.144-.074.253-.148.397-.222.036-.038.073-.038.109-.075.036-.037 0-.037 0-.074.325-.26.397-.704.144-1.038a.684.684 0 0 0-.506-.26.85.85 0 0 0-.505.186l-.036.037c-.037.037-.073.074-.109.074a2.38 2.38 0 0 0-.289.334c-.036.074-.108.11-.144.148a4.791 4.791 0 0 1-.904.816c-.072.037-.144.074-.216.074-.036 0-.109 0-.145-.037h-.036l-.289.185c-.289-.296-.614-.593-.903-.89a9.125 9.125 0 0 0-4.696-1.928l-.037-.297v.037c-.108-.074-.144-.185-.18-.296 0-.408 0-.816.072-1.261v-.037c0-.074.036-.148.036-.223.036-.148.036-.296.072-.445v-.222c.037-.371-.252-.742-.614-.779-.216-.037-.433.074-.614.26a.742.742 0 0 0-.217.519v.185c0 .149.037.297.073.445a.481.481 0 0 1 .036.223v.037c.072.408.072.816.072 1.26-.036.112-.072.223-.18.297v.075l-.037.296c-.397.037-.795.111-1.228.186-1.698.37-3.251 1.298-4.444 2.595l-.216-.148H9.25c-.037 0-.073.037-.145.037s-.144-.037-.217-.074a6.73 6.73 0 0 1-.903-.853c-.036-.074-.108-.111-.144-.148-.109-.111-.181-.223-.29-.334-.035-.037-.072-.037-.108-.074l-.036-.037a.85.85 0 0 0-.506-.186c-.216 0-.397.075-.505.26a.813.813 0 0 0 .144 1.038c.036 0 .036.037.036.037s.073.075.109.075c.108.074.253.148.397.222l.217.111c.361.223.722.445 1.011.742.073.074.145.222.109.334v-.037l.216.222c-.036.074-.072.111-.108.186-1.12 1.817-1.59 3.967-1.264 6.081l-.29.074c0 .037-.035.037-.035.037-.037.112-.145.186-.253.26a6.554 6.554 0 0 1-1.229.223c-.072 0-.144 0-.216.037-.145 0-.29.037-.434.037-.036 0-.072.037-.144.037-.037 0-.037 0-.073.037a.722.722 0 0 0-.578.853.672.672 0 0 0 .723.519c.072 0 .108 0 .18-.037.037 0 .037 0 .037-.037s.108 0 .144 0c.145-.037.29-.111.397-.149.073-.037.145-.074.217-.074h.036a6.31 6.31 0 0 1 1.193-.333h.036c.108 0 .216.037.289.11.036 0 .036.038.036.038l.325-.037c.542 1.706 1.553 3.226 2.962 4.339.325.26.614.482.976.667l-.181.26c0 .037.036.037.036.037.072.11.072.26.036.37-.144.371-.361.742-.578 1.076v.037c-.036.074-.072.111-.144.185-.073.075-.145.223-.253.371-.036.037-.036.074-.072.112 0 0 0 .037-.037.037-.18.37-.036.815.29 1 .072.038.18.075.252.075.29 0 .542-.185.687-.445 0 0 0-.037.036-.037 0-.037.036-.074.072-.111.036-.149.109-.26.145-.408l.072-.223c.108-.408.289-.778.47-1.15a.563.563 0 0 1 .289-.222c.036 0 .036 0 .036-.037l.144-.297a8.31 8.31 0 0 0 3.143.594c.65 0 1.3-.074 1.951-.26.397-.074.795-.222 1.156-.334l.144.26c.037 0 .037 0 .037.037a.563.563 0 0 1 .289.223c.18.37.36.741.47 1.15v.036l.072.223c.036.148.072.296.144.408.036.037.036.074.072.11 0 0 0 .038.036.038.145.26.398.445.687.445.108 0 .18-.037.289-.074a.617.617 0 0 0 .325-.408.978.978 0 0 0-.036-.556c0-.037-.036-.037-.036-.037 0-.037-.036-.075-.073-.112a1.333 1.333 0 0 0-.252-.37.649.649 0 0 0-.145-.186v-.074a4.417 4.417 0 0 1-.578-1.075.449.449 0 0 1 .036-.371c0-.037.036-.037.036-.037l-.108-.297a9.128 9.128 0 0 0 3.902-5.043l.289.037c.036 0 .036-.037.036-.037a.404.404 0 0 1 .289-.112h.036c.397.075.795.186 1.156.334h.036c.072.037.144.074.217.074.144.074.253.149.397.186.036 0 .072.037.145.037.036 0 .036 0 .072.037a.319.319 0 0 0 .18.037.787.787 0 0 0 .723-.52.867.867 0 0 0-.65-.778zm-10.44-1.15l-.976.483-.976-.483-.252-1.075.686-.89h1.084l.686.89-.253 1.075zm5.888-2.41c.18.779.217 1.558.144 2.336L19.51 15.93c-.325-.074-.505-.408-.433-.742a.602.602 0 0 1 .144-.26l2.71-2.52c.397.667.686 1.408.867 2.187zm-1.951-3.56l-2.962 2.15c-.253.15-.614.112-.795-.147a.34.34 0 0 1-.108-.26l-.217-3.745a6.73 6.73 0 0 1 4.082 2.002zm-6.539-1.891l.723-.149-.18 3.709c0 .334-.29.593-.615.593-.108 0-.18-.037-.289-.074l-2.998-2.188c.939-.927 2.095-1.595 3.36-1.891zm-4.407 3.263l2.673 2.448a.607.607 0 0 1 .072.853c-.072.11-.144.148-.289.185L8.853 16.93a7.972 7.972 0 0 1 1.048-4.524zm-.614 6.267l3.576-.63c.29 0 .578.185.614.482a.449.449 0 0 1-.036.37l-1.373 3.412a7.268 7.268 0 0 1-2.781-3.634zm8.2 4.599a7.13 7.13 0 0 1-1.553.185c-.759 0-1.554-.148-2.276-.37l1.77-3.301c.18-.223.47-.297.723-.149.108.075.18.149.289.26l1.734 3.226c-.217.037-.434.074-.687.149zm4.408-3.227a6.992 6.992 0 0 1-2.168 2.225l-1.409-3.486a.608.608 0 0 1 .325-.704c.109-.037.217-.074.325-.074l3.613.63c-.18.52-.397 1.001-.686 1.41z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.5 KiB

View File

@ -1,19 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32" viewBox="0 0 32 32">
<defs>
<path id="a" d="M12 24C5.373 24 0 18.627 0 12S5.373 0 12 0s12 5.373 12 12-5.373 12-12 12zm0-7a5 5 0 1 0 0-10 5 5 0 0 0 0 10z"/>
</defs>
<g fill="none" fill-rule="evenodd">
<circle cx="16" cy="16" r="16" fill="#1E2022"/>
<g transform="translate(4 4)">
<mask id="b" fill="#fff">
<use xlink:href="#a"/>
</mask>
<use fill="#00F99A" xlink:href="#a"/>
<path fill="#72FF00" d="M-4-4l36 9.61L12 12H-4z" mask="url(#b)"/>
<path fill="#0077FC" d="M-4-4l29.488.644L12 12l7.736 15.37C7.17 24.444.073 20.988-1.557 17-3.187 13.012-4.001 6.012-4-4z" mask="url(#b)"/>
<path fill="#00BEFF" d="M-4-4l29.488.644L12 12 9.08 28C3.62 24.654.074 20.988-1.556 17-3.187 13.012-4.001 6.012-4-4z" mask="url(#b)"/>
<path fill="#0077FC" d="M-4-4l29.488.644L12 12l-14.043 8.516z" mask="url(#b)"/>
<path fill="#00DAA5" d="M-4-4l29.488.644L12 12H-4z" mask="url(#b)"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -1,7 +0,0 @@
<svg id="LOGOS" xmlns="http://www.w3.org/2000/svg" width="68" height="68" viewBox="27 38 68 68">
<defs>
<style>.cls-1{fill:#00ca8e;}</style>
</defs>
<path class="cls-1"
d="M61.14,38.19,32,55V88.63l29.12,16.81L90.26,88.63V55Zm13,37-7.76,4.48L57,74.54V85.26l-8.81,5.59V68.45l7-4.28,9.7,5.11V58.34l9.25-5.56Z"/>
</svg>

Before

Width:  |  Height:  |  Size: 334 B

View File

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="32px" height="32px" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>plugin</title>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="plugin" fill-rule="nonzero">
<circle id="Oval" fill="#6DC4A8" cx="16" cy="16" r="16"></circle>
<path d="M10.7517313,10.1738295 L22.2621133,19.1941905 L21.8304412,19.7449978 C20.0202381,22.0549461 17.2269562,23.0792113 14.836947,22.5465569 L14.5702202,22.8869226 C14.1903807,23.3716261 13.5380774,23.5005798 13.1206478,23.1734862 L12.1087414,22.3804984 L10.0368349,25.0243619 C9.65696684,25.5090655 9.00463498,25.6380191 8.58723393,25.3109255 L8.33426446,25.1126429 C7.9168634,24.7855208 7.88612346,24.1213154 8.26599153,23.6366119 L10.3379265,20.9927484 L9.32602009,20.199732 C8.90861904,19.8726385 8.87790764,19.2084045 9.25774716,18.723701 L9.43776279,18.4939934 C8.15541907,16.2757226 8.42328756,13.1450149 10.3200591,10.7246368 L10.7517313,10.1738295 Z M23.5543041,11.5531311 C24.1108484,11.9892558 24.1518349,12.8748916 23.6453537,13.5211725 L20.8654425,17.2106062 L18.8915999,15.6278127 L21.6215408,11.9351683 C22.1280221,11.2888874 22.9977598,11.1169778 23.5543041,11.5531311 Z M18.0521111,7.2411761 C18.6086553,7.67732938 18.6496134,8.56296514 18.1431321,9.20924605 L15.2398281,12.8891125 L13.3222617,11.3618714 L16.1193478,7.62324192 C16.6258005,6.97696101 17.4955668,6.80505137 18.0521111,7.2411761 Z" id="Shape" fill="#FFFFFF"></path>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -1,6 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
<g fill="none" fill-rule="evenodd">
<circle cx="16" cy="16" r="16" fill="#0075A8"/>
<path fill="#FFF" fill-rule="nonzero" d="M27.988 12.417c.08.482-.252.881-.734.881h-1.56v-1.096H26.167c.483 0 .885-.41.885-.901v-.4c0-.491.121-.901.272-.901.14 0 .332.4.412.891l.252 1.526zm-3.531-1.29c.493 0 .885.4.905.911v4.691a.901.901 0 0 1-.885.901h-2.384a.901.901 0 0 1-.885-.9v-1.845a.902.902 0 0 0-.352.717v1.547c0 .492.402.901.885.901h1.55v2.397a.546.546 0 0 1-.544.553h-2.918a.546.546 0 0 1-.543-.553v-2.233a.546.546 0 0 0-.543-.553H11.46a.546.546 0 0 0-.543.553v2.233a.546.546 0 0 1-.544.553H7.456a.546.546 0 0 1-.543-.553v-6.412L5.595 15.09c-.06.041-.14.041-.191-.02l-.372-.45a.141.141 0 0 1-.01-.165l1.931-3a.542.542 0 0 1 .493-.328h10.281c.332 0 .583.307.533.645l-.211 1.28c-.05.338.201.645.533.645h2.062a.543.543 0 0 0 .534-.45c-.131.04-.272.061-.423.061h-1.469c-.493 0-.825-.4-.744-.89l.251-1.527c.08-.492.262-.891.413-.891.15 0 .271.41.271.901v.236c.02-.01.05-.01.08-.01h4.9z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -1,17 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32">
<g fill="none">
<circle cx="16" cy="16" r="16" fill="#000"/>
<path fill="#A41E11" d="M26.04 21.21c-1.214.634-7.504 3.22-8.843 3.918-1.34.698-2.083.691-3.141.186-1.058-.506-7.752-3.21-8.959-3.787-.603-.288-.919-.53-.919-.76v-2.3s8.715-1.897 10.123-2.402c1.407-.505 1.894-.523 3.092-.084 1.198.438 8.357 1.73 9.54 2.163v2.269c0 .227-.273.482-.891.798h-.001l-.001-.001z"/>
<path fill="#D82C20" d="M26.04 18.909c-1.214.633-7.504 3.22-8.843 3.918-1.34.698-2.083.69-3.141.185-1.058-.505-7.752-3.209-8.959-3.786-1.206-.576-1.23-.973-.046-1.437l9.249-3.58c1.407-.505 1.894-.524 3.092-.085 1.198.439 7.45 2.927 8.633 3.367 1.182.44 1.229.79.014 1.424l.002-.006h-.001z"/>
<path fill="#A41E11" d="M26.04 17.46c-1.214.633-7.504 3.219-8.843 3.917-1.34.698-2.083.691-3.141.186-1.058-.506-7.752-3.21-8.959-3.787-.603-.288-.919-.53-.919-.76v-2.3s8.715-1.897 10.123-2.402c1.407-.505 1.894-.523 3.092-.084 1.198.438 8.357 1.73 9.54 2.163v2.269c0 .227-.273.482-.891.798h-.002z"/>
<path fill="#D82C20" d="M26.04 15.158c-1.214.634-7.504 3.22-8.843 3.918-1.34.698-2.083.691-3.141.186-1.058-.506-7.752-3.21-8.959-3.786-1.206-.577-1.23-.974-.046-1.437l9.249-3.58c1.407-.506 1.894-.524 3.092-.085 1.198.438 7.45 2.927 8.634 3.36 1.184.432 1.229.79.015 1.424h-.001z"/>
<path fill="#A41E11" d="M26.04 13.569c-1.214.633-7.504 3.22-8.843 3.918-1.34.699-2.083.692-3.141.186-1.058-.506-7.752-3.21-8.959-3.786-.603-.288-.919-.53-.919-.76v-2.302s8.715-1.897 10.123-2.402c1.407-.505 1.894-.523 3.092-.084 1.198.438 8.357 1.73 9.54 2.164v2.268c0 .227-.273.483-.891.799l-.001-.001h-.001z"/>
<path fill="#D82C20" d="M26.04 11.268c-1.214.634-7.504 3.22-8.843 3.918-1.34.698-2.083.691-3.141.186-1.058-.506-7.752-3.21-8.959-3.786-1.206-.577-1.23-.974-.046-1.437l9.249-3.58c1.407-.506 1.894-.524 3.092-.085 1.198.438 7.45 2.927 8.634 3.36 1.184.432 1.229.79.015 1.424h-.001z"/>
<g fill="#FFF" transform="translate(8 7)">
<path d="M8.503 3.446L7.79 2.26l-2.276-.205 1.699-.613-.51-.94 1.59.62 1.5-.49-.406.972 1.529.573-1.972.205-.44 1.064h-.001zm-3.798 2.36l5.273-.81-1.593 2.336-3.68-1.526z"/>
<ellipse cx="3.284" cy="3.862" rx="2.818" ry="1.092"/>
</g>
<path fill="#7A0C00" d="M23.987 10.577l-3.119 1.232-.002-2.466z"/>
<path fill="#AD2115" d="M20.869 11.809l-.338.132-3.116-1.231 3.452-1.366z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -1,6 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
<g fill="none" fill-rule="evenodd">
<circle cx="16" cy="16" r="16" fill="#815E89"/>
<path fill="#FFF" fill-rule="nonzero" d="M26.5 13.5A1.5 1.5 0 0 1 28 15v2a1.5 1.5 0 0 1-1.5 1.502h-1.862a8.909 8.909 0 0 1-.763 1.84l1.317 1.317a1.5 1.5 0 0 1 0 2.121l-1.414 1.414a1.5 1.5 0 0 1-2.121 0l-1.318-1.317c-.583.322-1.2.578-1.839.763v1.86A1.5 1.5 0 0 1 17 28h-2a1.5 1.5 0 0 1-1.5-1.5v-1.86a8.977 8.977 0 0 1-1.84-.764l-1.318 1.317a1.545 1.545 0 0 1-2.122 0l-1.414-1.414a1.5 1.5 0 0 1 0-2.121l1.319-1.319a8.878 8.878 0 0 1-.763-1.839H5.5A1.5 1.5 0 0 1 4 17v-2a1.5 1.5 0 0 1 1.5-1.5h1.862c.185-.64.44-1.256.763-1.838l-1.318-1.317a1.5 1.5 0 0 1 0-2.122l1.415-1.414a1.5 1.5 0 0 1 2.121 0l1.318 1.317a8.969 8.969 0 0 1 1.839-.763V5.5A1.5 1.5 0 0 1 15 4h2a1.5 1.5 0 0 1 1.5 1.5v1.863c.64.185 1.256.44 1.838.763l1.318-1.317a1.5 1.5 0 0 1 2.121 0l1.415 1.413a1.5 1.5 0 0 1 0 2.122l-1.317 1.316c.322.583.578 1.2.763 1.84H26.5zm-11.379 4.805l-2.447-4.962a.551.551 0 0 0-.242-.255.726.726 0 0 0-.35-.088c-.123 0-.24.03-.348.088a.551.551 0 0 0-.243.255l-2.438 4.962a.493.493 0 0 0-.053.218c0 .128.056.237.168.326a.581.581 0 0 0 .645.063.482.482 0 0 0 .194-.222l.53-1.121h3.11l.529 1.121c.047.1.112.175.194.222.083.048.171.071.265.071a.575.575 0 0 0 .376-.134.408.408 0 0 0 .163-.326.493.493 0 0 0-.053-.218zm-4.195-1.573l1.165-2.485 1.166 2.485h-2.331zM16.596 19a.585.585 0 0 0 .42-.146.521.521 0 0 0 .154-.398v-1.8h1.581c.666 0 1.184-.158 1.555-.476.371-.318.556-.762.556-1.33 0-.57-.185-1.012-.556-1.327-.371-.315-.89-.473-1.555-.473H16.58a.572.572 0 0 0-.402.134.486.486 0 0 0-.146.377v4.895c0 .167.051.3.154.398.104.097.24.146.411.146zm2.014-3.172h-1.44v-1.941h1.44c.783 0 1.175.324 1.175.97 0 .648-.392.971-1.175.971zM22.426 19c.177 0 .316-.05.42-.15a.525.525 0 0 0 .154-.394v-4.912a.51.51 0 0 0-.155-.39.585.585 0 0 0-.42-.146.573.573 0 0 0-.41.147.51.51 0 0 0-.154.389v4.912c0 .162.051.293.154.393.103.1.24.151.41.151z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -1,6 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="52" height="52" viewBox="0 0 52 52">
<g fill="none" fill-rule="evenodd">
<circle cx="26" cy="26" r="26" fill="#007BFF"/>
<path fill="#FFF" fill-rule="nonzero" d="M22.749 13v3.94h-8.125v3.939h-4.062v3.94H7.414a.785.785 0 0 0-.787.64 8.97 8.97 0 0 0-.127 1.526c0 .55.054 1.15.152 1.748.93-.215 2.634-.539 2.336-1.6 1.603 1.8 5.449 1.255 6.423.369 1.089 1.53 7.43.945 7.87-.246 1.365 1.55 5.596 1.55 6.957 0 .441 1.19 6.757 1.775 7.845.246.346.314 1.066.575 1.904.714.283-.52.543-1.043.787-1.6 5.16-.062 6.274-3.66 6.322-3.817.089-.301-.032-.612-.28-.812-.085-.071-1.99-1.57-5.077-1.059-.866-2.736-3.097-3.982-3.199-4.038a.826.826 0 0 0-.914.074c-.082.065-2.002 1.643-1.701 4.875.076.813.295 1.53.635 2.167-.667.36-1.812.812-3.656.812h-.406v-3.94h-4.063V13H22.75zm17.238 15.216c-.098.185-.225.363-.33.542h7.337c-.882-.216-2.777-.505-2.462-1.625-1.038 1.163-3.009 1.335-4.545 1.083zm-.33.542H6.652a12.07 12.07 0 0 0 1.219 3.545c4.411 1.006 9.041-.526 9.089-.542a.8.8 0 0 1 1.016.493.78.78 0 0 1-.483 1.01c-.155.052-2.945.96-6.372.96-.68 0-1.394-.037-2.108-.124 2.133 2.743 5.748 4.9 11.298 4.9 8.778 0 15.528-3.616 19.346-10.242zm-33.005 0c-.003-.013.004-.013 0-.025-.054.012-.104.012-.152.025h.152zm17.721-14.182h2.438v2.363h-2.438v-2.363zm-8.124 3.94h2.437v2.363H16.25v-2.364zm4.062 0h2.438v2.363H20.31v-2.364zm4.062 0h2.438v2.363h-2.438v-2.364zm-12.186 3.939h2.437v2.363h-2.437v-2.363zm4.062 0h2.437v2.363H16.25v-2.363zm4.062 0h2.438v2.363H20.31v-2.363zm4.062 0h2.438v2.363h-2.438v-2.363zm4.062 0h2.438v2.363h-2.438v-2.363zM19.5 30.333c.105 0 .212.016.304.05-.098.055-.177.15-.177.27 0 .179.146.345.33.345a.367.367 0 0 0 .304-.172.7.7 0 0 1 .051.295.802.802 0 0 1-.812.788.802.802 0 0 1-.813-.788c0-.434.365-.788.813-.788z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 864 KiB

2
webui/public/robots.txt Normal file
View File

@ -0,0 +1,2 @@
User-agent: *
Disallow: /

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,263 +0,0 @@
// Configuration for your app
// https://quasar.dev/quasar-cli/quasar-conf-js
const { configure } = require('quasar/wrappers')
module.exports = configure(function (ctx) {
return {
eslint: {
warnings: true,
errors: true
},
// app boot file (/src/boot)
// --> boot files are part of "main.js"
boot: [
'api'
],
css: [
'sass/app.scss'
],
extras: [
// 'ionicons-v4',
// 'mdi-v3',
// 'fontawesome-v5',
'eva-icons',
// 'themify',
// 'roboto-font-latin-ext', // this or either 'roboto-font', NEVER both!
'roboto-font', // optional, you are not bound to it
'material-icons' // optional, you are not bound to it
],
framework: {
// iconSet: 'ionicons-v4',
// lang: 'de', // Quasar language
// all: true, // --- includes everything; for dev only!
components: [
'QLayout',
'QHeader',
'QFooter',
'QDrawer',
'QPageContainer',
'QPage',
'QPageSticky',
'QPageScroller',
'QToolbar',
'QSpace',
'QToolbarTitle',
'QTooltip',
'QBtn',
'QIcon',
'QList',
'QItem',
'QExpansionItem',
'QItemSection',
'QItemLabel',
'QTabs',
'QTab',
'QRouteTab',
'QAvatar',
'QSeparator',
'QScrollArea',
'QImg',
'QBadge',
'QCard',
'QCardSection',
'QCardActions',
'QBreadcrumbs',
'QBreadcrumbsEl',
'QInput',
'QToggle',
'QForm',
'QField',
'QSelect',
'QCheckbox',
'QRadio',
'QMenu',
'QAjaxBar',
'QTable',
'QTh',
'QTr',
'QTd',
'QFab',
'QFabAction',
'QDialog',
'QUploader',
'QTree',
'QChip',
'QBtnToggle'
],
directives: [
'ClosePopup',
'Ripple'
],
// Quasar plugins
plugins: [
'Notify',
'Dialog',
'LoadingBar'
],
config: {
notify: { /* Notify defaults */ },
loadingBar: {
position: 'top',
color: 'accent',
size: '2px'
}
}
},
supportIE: false,
build: {
// Needed to have relative assets in the index.html
// https://github.com/quasarframework/quasar/issues/8513#issuecomment-1127654470
extendViteConf (viteConf, { isServer, isClient }) {
viteConf.base = ''
},
viteVuePluginOptions: {
template: {
compilerOptions: {
isCustomElement: (tag) => tag.startsWith('hub-')
}
}
},
target: {
browser: ['edge88', 'firefox78', 'chrome87', 'safari13.1'],
node: 'node20'
},
publicPath: process.env.APP_PUBLIC_PATH || '',
env: process.env.APP_ENV === 'development'
? { // staging:
APP_ENV: process.env.APP_ENV,
APP_API: process.env.APP_API || '/api'
}
: { // production:
APP_ENV: process.env.APP_ENV,
APP_API: process.env.APP_API || '/api'
},
uglifyOptions: {
compress: {
drop_console: process.env.APP_ENV === 'production',
drop_debugger: process.env.APP_ENV === 'production'
}
},
scopeHoisting: true,
vueRouterMode: 'hash' // available values: 'hash', 'history'
},
devServer: {
// https: true,
port: 8081,
open: true, // opens browser window automatically
proxy: {
// proxy all API requests to real Traefik
'/api': {
target: 'http://localhost:8080',
changeOrigin: true
}
}
},
// animations: 'all', // --- includes all animations
animations: [],
ssr: {
pwa: false
},
pwa: {
workboxMode: 'injectManifest', // or 'generateSW'
// workboxPluginMode: 'InjectManifest',
// workboxOptions: {}, // only for NON InjectManifest
workboxOptions: {
skipWaiting: true,
clientsClaim: true
},
chainWebpackCustomSW (chain) {
chain.plugin('eslint-webpack-plugin')
.use(ESLintPlugin, [{ extensions: ['js'] }])
},
manifest: {
// name: 'Traefik',
// short_name: 'Traefik',
// description: 'Traefik UI',
display: 'standalone',
orientation: 'portrait',
background_color: '#ffffff',
theme_color: '#027be3',
icons: [
{
src: 'icons/icon-128x128.png',
sizes: '128x128',
type: 'image/png'
},
{
src: 'icons/icon-192x192.png',
sizes: '192x192',
type: 'image/png'
},
{
src: 'icons/icon-256x256.png',
sizes: '256x256',
type: 'image/png'
},
{
src: 'icons/icon-384x384.png',
sizes: '384x384',
type: 'image/png'
},
{
src: 'icons/icon-512x512.png',
sizes: '512x512',
type: 'image/png'
}
]
}
},
cordova: {
// id: 'us.containo.traefik',
// noIosLegacyBuildFlag: true, // uncomment only if you know what you are doing
},
electron: {
// bundler: 'builder', // or 'packager'
extendWebpack (cfg) {
// do something with Electron main process Webpack cfg
// chainWebpack also available besides this extendWebpack
},
packager: {
// https://github.com/electron-userland/electron-packager/blob/master/docs/api.md#options
// OS X / Mac App Store
// appBundleId: '',
// appCategoryType: '',
// osxSign: '',
// protocol: 'myapp://path',
// Windows only
// win32metadata: { ... }
},
builder: {
// https://www.electron.build/configuration/configuration
// appId: 'traefik-ui'
}
}
}
})

View File

@ -1,5 +0,0 @@
{
"@quasar/testing-unit-vitest": {
"options": []
}
}

View File

@ -11,7 +11,7 @@ Traefik Web UI provide 2 types of information:
## How to build (for backend developer)
Use the make file :
Use the Makefile :
```shell
make build-image # Generate Docker image.
@ -20,10 +20,14 @@ make clean-webui generate-webui # Generate static contents in `webui/static/` fo
## How to build (only for frontend developer)
- prerequisite: [Node 20.14+](https://nodejs.org) [Yarn 1.22.22](https://yarnpkg.com/)
- prerequisite: [Node 22](https://nodejs.org) [Yarn](https://yarnpkg.com/)
- Go to the `webui/` directory
- As we use Yarn v4, you will need to enable corepack before installing dependencies:
- `corepack enable`
- To install dependencies, execute the following commands:
- `yarn install`
@ -36,7 +40,7 @@ make clean-webui generate-webui # Generate static contents in `webui/static/` fo
**Do not manually change the files in the `webui/static/` directory**
- The build allows to:
The build allows to:
- optimize all JavaScript
- optimize all CSS
- add vendor prefixes to CSS (cross-browser support)
@ -50,15 +54,23 @@ make clean-webui generate-webui # Generate static contents in `webui/static/` fo
- Go to the `webui/` directory
- Edit files in `webui/src/`
- Create and populate the `.env` file using the values inside `.env.sample` file.
- Run in development mode :
- `yarn dev`
- The application will be available at `http://localhost:3000/`. On development mode, the application will run with mocked data served by [Mock Service Worker](https://mswjs.io/).
## How to run tests
- Execute the following commands:
- `yarn test`
- or `yarn test:watch` if you want them in watch mode
## Libraries
- [Node](https://nodejs.org)
- [Yarn](https://yarnpkg.com/)
- [Quasar](https://quasar.dev/)
- [Vue](https://vuejs.org/)
- [Bulma](https://bulma.io)
- [D3](https://d3js.org)
- [D3 - Documentation](https://github.com/mbostock/d3/wiki)
- [React](https://reactjs.org/)
- [Vite](https://vitejs.dev/)
- [Faency](https://github.com/containous/faency)
- [Vitest](https://vitest.dev/)
- [Mock Service Worker](https://mswjs.io/)

View File

@ -1,5 +0,0 @@
/*
* This file (which will be your service worker)
* is picked up by the build system ONLY if
* quasar.conf > pwa > workboxPluginMode is set to "InjectManifest"
*/

View File

@ -1,10 +0,0 @@
/* eslint-disable */
// THIS FEATURE-FLAG FILE IS AUTOGENERATED,
// REMOVAL OR CHANGES WILL CAUSE RELATED TYPES TO STOP WORKING
import "quasar/dist/types/feature-flag";
declare module "quasar/dist/types/feature-flag" {
interface QuasarFeatureFlags {
pwa: true;
}
}

View File

@ -1,42 +0,0 @@
import { register } from 'register-service-worker'
// The ready(), registered(), cached(), updatefound() and updated()
// events passes a ServiceWorkerRegistration instance in their arguments.
// ServiceWorkerRegistration: https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration
register(process.env.SERVICE_WORKER_FILE, {
// The registrationOptions object will be passed as the second argument
// to ServiceWorkerContainer.register()
// https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerContainer/register#Parameter
// registrationOptions: { scope: './' },
ready () {
console.log('App is being served from cache by a service worker.')
},
registered (registration) {
console.log('Service worker has been registered.')
},
cached (registration) {
console.log('Content has been cached for offline use.')
},
updatefound (registration) {
console.log('New content is downloading.')
},
updated (registration) {
console.log('New content is available; please refresh.')
window.location.reload()
},
offline () {
console.log('No internet connection found. App is running in offline mode.')
},
error (err) {
console.error('Error during service worker registration:', err)
}
})

10
webui/src/App.spec.tsx Normal file
View File

@ -0,0 +1,10 @@
import App from './App'
import { render } from 'utils/test'
describe('<App />', () => {
test('renders without crashing the initial page (dashboard)', () => {
const { getByTestId } = render(<App />)
expect(getByTestId('proxy-main-nav')).toBeInTheDocument()
})
})

113
webui/src/App.tsx Normal file
View File

@ -0,0 +1,113 @@
import { Box, darkTheme, FaencyProvider, lightTheme } from '@traefiklabs/faency'
import { Suspense, useEffect } from 'react'
import { Helmet, HelmetProvider } from 'react-helmet-async'
import { HashRouter, Navigate, Route, Routes as RouterRoutes, useLocation } from 'react-router-dom'
import { SWRConfig } from 'swr'
import Page from './layout/Page'
import fetch from './libs/fetch'
import { useIsDarkMode } from 'hooks/use-theme'
import useVersion from 'hooks/use-version'
import ErrorSuspenseWrapper from 'layout/ErrorSuspenseWrapper'
import { Dashboard, HTTPPages, NotFound, TCPPages, UDPPages } from 'pages'
import { DashboardSkeleton } from 'pages/dashboard/Dashboard'
export const LIGHT_THEME = lightTheme('blue')
export const DARK_THEME = darkTheme('blue')
// TODO: Restore the loader.
const PageLoader = () => (
<Page>
<Box css={{ position: 'absolute', top: 0, left: 0, right: 0 }}>{/*<Loading />*/}</Box>
</Page>
)
const ScrollToTop = () => {
const { pathname } = useLocation()
useEffect(() => {
window.scrollTo(0, 0)
}, [pathname])
return null
}
export const Routes = () => {
const { showHubButton } = useVersion()
return (
<Suspense fallback={<PageLoader />}>
{showHubButton && (
<Helmet>
<script src="https://traefik.github.io/traefiklabs-hub-button-app/main-v1.js"></script>
</Helmet>
)}
<RouterRoutes>
<Route
path="/"
element={
<ErrorSuspenseWrapper suspenseFallback={<DashboardSkeleton />}>
<Dashboard />
</ErrorSuspenseWrapper>
}
/>
<Route path="/http/routers" element={<HTTPPages.HttpRouters />} />
<Route path="/http/services" element={<HTTPPages.HttpServices />} />
<Route path="/http/middlewares" element={<HTTPPages.HttpMiddlewares />} />
<Route path="/tcp/routers" element={<TCPPages.TcpRouters />} />
<Route path="/tcp/services" element={<TCPPages.TcpServices />} />
<Route path="/tcp/middlewares" element={<TCPPages.TcpMiddlewares />} />
<Route path="/udp/routers" element={<UDPPages.UdpRouters />} />
<Route path="/udp/services" element={<UDPPages.UdpServices />} />
<Route path="/http/routers/:name" element={<HTTPPages.HttpRouter />} />
<Route path="/http/services/:name" element={<HTTPPages.HttpService />} />
<Route path="/http/middlewares/:name" element={<HTTPPages.HttpMiddleware />} />
<Route path="/tcp/routers/:name" element={<TCPPages.TcpRouter />} />
<Route path="/tcp/services/:name" element={<TCPPages.TcpService />} />
<Route path="/tcp/middlewares/:name" element={<TCPPages.TcpMiddleware />} />
<Route path="/udp/routers/:name" element={<UDPPages.UdpRouter />} />
<Route path="/udp/services/:name" element={<UDPPages.UdpService />} />
<Route path="/http" element={<Navigate to="/http/routers" replace />} />
<Route path="/tcp" element={<Navigate to="/tcp/routers" replace />} />
<Route path="/udp" element={<Navigate to="/udp/routers" replace />} />
<Route path="*" element={<NotFound />} />
</RouterRoutes>
</Suspense>
)
}
const isDev = import.meta.env.NODE_ENV === 'development'
const App = () => {
const isDarkMode = useIsDarkMode()
useEffect(() => {
if (isDarkMode) {
document.documentElement.classList.remove(LIGHT_THEME)
document.documentElement.classList.add(DARK_THEME)
} else {
document.documentElement.classList.remove(DARK_THEME)
document.documentElement.classList.add(LIGHT_THEME)
}
}, [isDarkMode])
return (
<FaencyProvider>
<HelmetProvider>
<SWRConfig
value={{
revalidateOnFocus: !isDev,
fetcher: fetch,
}}
>
<HashRouter basename={import.meta.env.VITE_APP_BASE_URL || ''}>
<ScrollToTop />
<Routes />
</HashRouter>
</SWRConfig>
</HelmetProvider>
</FaencyProvider>
)
}
export default App

View File

@ -1,44 +0,0 @@
<template>
<div id="q-app">
<router-view />
</div>
</template>
<script>
import { APP } from './_helpers/APP'
import { mapGetters } from 'vuex'
export default {
name: 'App',
computed: {
...mapGetters('core', { coreVersion: 'version' })
},
watch: {
'$q.dark.mode' (val) {
if (val !== null) {
localStorage.setItem('traefik-dark', val)
}
}
},
beforeCreate () {
// Set vue instance
APP.vue = () => this.$root
// debug
console.log('Quasar -> ', this.$q.version)
// Get stored theme or default to 'auto'
const storedTheme = localStorage.getItem('traefik-dark')
if (storedTheme === 'true') {
this.$q.dark.set(true)
} else if (storedTheme === 'false') {
this.$q.dark.set(false)
} else {
this.$q.dark.set('auto')
}
}
}
</script>
<style>
</style>

View File

@ -1,8 +0,0 @@
const APP = {
config: {
env: process.env.APP_ENV,
apiUrl: process.env.APP_API
}
}
export { APP }

View File

@ -1,41 +0,0 @@
import { Notify } from 'quasar'
class Errors {
// Getters
// ------------------------------------------------------------------------
// Public
// ------------------------------------------------------------------------
// Static
// ------------------------------------------------------------------------
static showError (body) {
body = typeof body === 'string' ? JSON.parse(body) : body
Notify.create({
color: 'negative',
position: 'top',
message: body.message, // TODO - get correct error message
icon: 'report_problem'
})
}
static handleResponse (error) {
console.log('handleResponse', error, error.response)
const body = error.response.data
if (error.response.status === 401) {
// TODO - actions...
}
// Avoid to notify when reaching end of an infinite scroll
if (!error.response.data.message.includes('invalid request: page:')) {
Errors.showError(body)
}
return Promise.reject(body)
}
// Static Private
// ------------------------------------------------------------------------
}
export default Errors

View File

@ -1,132 +0,0 @@
import { getProperty } from 'dot-prop'
class Helps {
// Getters
// ------------------------------------------------------------------------
// Public
// ------------------------------------------------------------------------
// Static
// ------------------------------------------------------------------------
static get (obj, prop, def = undefined) {
return getProperty(obj, prop, def)
}
static hasIn (obj, prop) {
return Helps.get(obj, prop) !== undefined && Helps.get(obj, prop) !== null
}
static toggleBodyClass (addRemoveClass, className) {
const el = document.body
if (addRemoveClass === 'addClass') {
el.classList.add(className)
} else {
el.classList.remove(className)
}
}
static getName (obj, val) {
let name = ''
for (let i = 0; i < obj.length; i += 1) {
if (obj[i].value === val || obj[i].iso2 === val) {
name = obj[i].name
}
}
return name
}
static removeEmptyObjects (objects) {
Object.entries(objects)
.filter(item => item[1] !== '')
.reduce((acc, item) => {
acc[item[0]] = item[1]
return acc
}, {})
}
// Helps -> Numbers
// ------------------------------------------------------------------------
static getPercent (value, total) {
return (value * 100) / total
}
// Helps -> Array
// ------------------------------------------------------------------------
// Add or remove values
static toggleArray (array, value) {
if (array.includes(value)) {
array.splice(array.indexOf(value), 1)
} else {
array.push(value)
}
}
// Helps -> Strings
// ------------------------------------------------------------------------
// Basename
static basename (path, suffix) {
let b = path
const lastChar = b.charAt(b.length - 1)
if (lastChar === '/' || lastChar === '\\') {
b = b.slice(0, -1)
}
// eslint-disable-next-line no-useless-escape
b = b.replace(/^.*[\/\\]/g, '')
if (typeof suffix === 'string' && b.substr(b.length - suffix.length) === suffix) {
b = b.substr(0, b.length - suffix.length)
}
return b
}
// Slug
static slug (str) {
str = str.replace(/^\s+|\s+$/g, '') // trim
str = str.toLowerCase()
// remove accents, swap ñ for n, etc
const from = 'ãàáäâẽèéëêìíïîõòóöôùúüûñç·/_,:;'
const to = 'aaaaaeeeeeiiiiooooouuuunc------'
for (let i = 0, l = from.length; i < l; i += 1) {
str = str.replace(new RegExp(from.charAt(i), 'g'), to.charAt(i))
}
str = str.replace(/[^a-z0-9 -]/g, '') // remove invalid chars
.replace(/\s+/g, '-') // collapse whitespace and replace by -
.replace(/-+/g, '-') // collapse dashes
return str
}
// Capitalize first letter
static capFirstLetter (string) {
return string.charAt(0).toUpperCase() + string.slice(1)
}
// Repeat
static repeat (string, times) {
return new Array(times + 1).join(string)
}
// Get Attribute
static getAttribute (string, key) {
const _key = `${key}="`
const start = string.indexOf(_key) + _key.length
const end = string.indexOf('"', start + 1)
return string.substring(start, end)
}
// Private
// ------------------------------------------------------------------------
}
export default Helps

View File

@ -1,45 +0,0 @@
import { setProperty, getProperty } from 'dot-prop'
export const withPagination = (type, opts = {}) => (state, data) => {
const { isSameContext, statePath } = opts
const currentState = getProperty(state, statePath)
let newState
switch (type) {
case 'request':
newState = {
...currentState,
loading: true
}
break
case 'success': {
const { body, page } = data
newState = {
...currentState,
items: [
...(isSameContext && currentState.items && page !== 1 ? currentState.items : []),
...(body.data || [])
],
currentPage: page,
total: isSameContext && currentState.items && page !== 1
? body.total + currentState.total
: body.total,
loading: false
}
break
}
case 'failure':
newState = {
...currentState,
loading: false,
error: data,
endReached: data.message.includes('invalid request: page:')
}
break
}
if (newState) {
setProperty(state, statePath, newState)
}
}

View File

@ -1,44 +0,0 @@
import { APP } from '../_helpers/APP'
import Helps from '../_helpers/Helps'
const Boot = {
install (Vue, options) {
Vue.mixin({
filters: {
capFirstLetter (value) {
return Helps.capFirstLetter(value)
}
},
data () {
return {
}
},
computed: {
api () {
return APP.config.apiUrl
},
env () {
return APP.config.env
},
platformUrl () {
return APP.config.platformUrl
},
appThumbStyle () {
return {
right: '2px',
borderRadius: '2px',
backgroundColor: '#dcdcdc',
width: '6px',
opacity: 0.75
}
}
},
created () {
},
methods: {
}
})
}
}
export default Boot

View File

@ -1,175 +0,0 @@
import { getProperty } from 'dot-prop'
import { QChip } from 'quasar'
import Chips from '../components/_commons/Chips.vue'
import ProviderIcon from '../components/_commons/ProviderIcon.vue'
import AvatarState from '../components/_commons/AvatarState.vue'
import TLSState from '../components/_commons/TLSState.vue'
const allColumns = [
{
name: 'status',
required: true,
label: 'Status',
align: 'left',
sortable: true,
fieldToProps: row => ({
state: row.status === 'enabled' ? 'positive' : 'negative'
}),
component: AvatarState
},
{
name: 'tls',
align: 'left',
label: 'TLS',
sortable: false,
fieldToProps: row => ({ isTLS: row.tls }),
component: TLSState
},
{
name: 'rule',
align: 'left',
label: 'Rule',
sortable: true,
component: QChip,
fieldToProps: () => ({ class: 'app-chip app-chip-rule', dense: true }),
content: row => row.rule
},
{
name: 'entryPoints',
align: 'left',
label: 'Entrypoints',
sortable: true,
component: Chips,
fieldToProps: row => ({
classNames: 'app-chip app-chip-entry-points',
dense: true,
list: row.entryPoints
})
},
{
name: 'name',
align: 'left',
label: 'Name',
sortable: true,
component: QChip,
fieldToProps: () => ({ class: 'app-chip app-chip-name', dense: true }),
content: row => row.name
},
{
name: 'type',
align: 'left',
label: 'Type',
sortable: true,
component: QChip,
fieldToProps: () => ({
class: 'app-chip app-chip-entry-points',
dense: true
}),
content: row => row.type
},
{
name: 'servers',
align: 'right',
label: 'Servers',
sortable: true,
fieldToProps: () => ({ class: 'servers-label' }),
content: function (value) {
if (value.loadBalancer && value.loadBalancer.servers) {
return value.loadBalancer.servers.length
}
return 0
}
},
{
name: 'service',
align: 'left',
label: 'Service',
component: QChip,
sortable: true,
fieldToProps: () => ({ class: 'app-chip app-chip-service', dense: true }),
content: row => row.service
},
{
name: 'provider',
align: 'center',
label: 'Provider',
sortable: true,
fieldToProps: row => ({ name: row.provider }),
component: ProviderIcon
},
{
name: 'priority',
align: 'left',
label: 'Priority',
sortable: true,
component: QChip,
fieldToProps: () => ({ class: 'app-chip app-chip-accent', dense: true }),
content: row => {
return {
short: String(row.priority).length > 10 ? String(row.priority).substring(0, 10) + '...' : row.priority,
long: row.priority
}
}
}
]
const columnsByResource = {
routers: [
'status',
'rule',
'entryPoints',
'name',
'service',
'tls',
'provider',
'priority'
],
udpRouters: ['status', 'entryPoints', 'name', 'service', 'provider'],
services: ['status', 'name', 'type', 'servers', 'provider'],
middlewares: ['status', 'name', 'type', 'provider']
}
const propsByType = {
'http-routers': {
columns: columnsByResource.routers
},
'tcp-routers': {
columns: columnsByResource.routers
},
'udp-routers': {
columns: columnsByResource.udpRouters
},
'http-services': {
columns: columnsByResource.services
},
'tcp-services': {
columns: columnsByResource.services
},
'udp-services': {
columns: columnsByResource.services
},
'http-middlewares': {
columns: columnsByResource.middlewares
},
'tcp-middlewares': {
columns: columnsByResource.middlewares
}
}
const GetTablePropsMixin = {
methods: {
getTableProps ({ type }) {
return {
onRowClick: row =>
this.$router.push({
path: `/${type.replace('-', '/', 'gi')}/${encodeURIComponent(row.name)}`
}),
columns: allColumns.filter(c =>
getProperty(propsByType, `${type}.columns`, []).includes(c.name)
)
}
}
}
}
export default GetTablePropsMixin

View File

@ -1,74 +0,0 @@
import { getProperty } from 'dot-prop'
export default function PaginationMixin (opts = {}) {
const { pollingIntervalTime, rowsPerPage = 10 } = opts
let listLength = 0
let currentPage = 1
let currentLimit = rowsPerPage
return {
methods: {
fetchWithInterval () {
this.initFetch({ limit: listLength })
this.pollingInterval = setInterval(
() => {
this.fetchMore({
limit: Math.ceil(listLength / rowsPerPage) * rowsPerPage, // round up to multiple of rowsPerPage
refresh: true
})
},
pollingIntervalTime
)
},
fetchMore ({ page = 1, limit = rowsPerPage, refresh, ...params } = {}) {
if (page === currentPage && limit === currentLimit && !refresh) {
return Promise.resolve()
}
currentPage = page
currentLimit = limit || rowsPerPage
const fetchMethod = getProperty(this, opts.fetchMethod)
return fetchMethod({
...params,
page,
limit: limit || rowsPerPage
}).then(res => {
listLength = page > 1
? listLength += res.data.length
: res.data.length
})
},
initFetch (params) {
const scrollerRef = getProperty(this.$refs, opts.scrollerRef)
if (scrollerRef) {
scrollerRef.stop()
scrollerRef.reset()
}
return this.fetchMore({
page: 1,
refresh: true,
...params
}).then(() => {
if (scrollerRef) {
scrollerRef.resume()
scrollerRef.poll()
}
})
}
},
mounted () {
if (pollingIntervalTime) {
this.fetchWithInterval()
} else {
this.fetchMore()
}
},
beforeUnmount () {
clearInterval(this.pollingInterval)
}
}
}

View File

@ -1,24 +0,0 @@
import { APP } from '../_helpers/APP'
const apiBase = ''
function getOverview () {
return APP.api.get(`${apiBase}/overview`)
.then(body => {
console.log('Success -> CoreService -> getOverview', body.data)
return body.data
})
}
function getVersion () {
return APP.api.get(`${apiBase}/version`)
.then(body => {
console.log('Success -> CoreService -> getVersion', body.data)
return body.data
})
}
export default {
getOverview,
getVersion
}

View File

@ -1,24 +0,0 @@
import { APP } from '../_helpers/APP'
const apiBase = '/entrypoints'
function getAll () {
return APP.api.get(`${apiBase}`)
.then(body => {
console.log('Success -> EntrypointsService -> getAll', body.data)
return body.data
})
}
function getByName (name) {
return APP.api.get(`${apiBase}/${name}`)
.then(body => {
console.log('Success -> EntrypointsService -> getByName', body.data)
return body.data
})
}
export default {
getAll,
getByName
}

View File

@ -1,67 +0,0 @@
import { APP } from '../_helpers/APP'
import { getTotal } from './utils'
const apiBase = '/http'
function getAllRouters (params) {
return APP.api.get(`${apiBase}/routers?search=${params.query}&status=${params.status}&per_page=${params.limit}&page=${params.page}&sortBy=${params.sortBy}&direction=${params.direction}&serviceName=${params.serviceName}&middlewareName=${params.middlewareName}`)
.then(response => {
const { data = [], headers } = response
const total = getTotal(headers, params)
console.log('Success -> HttpService -> getAllRouters', response, response.data)
return { data, total }
})
}
function getRouterByName (name) {
return APP.api.get(`${apiBase}/routers/${encodeURIComponent(name)}`)
.then(body => {
console.log('Success -> HttpService -> getRouterByName', body.data)
return body.data
})
}
function getAllServices (params) {
return APP.api.get(`${apiBase}/services?search=${params.query}&status=${params.status}&per_page=${params.limit}&page=${params.page}&sortBy=${params.sortBy}&direction=${params.direction}`)
.then(response => {
const { data = [], headers } = response
const total = getTotal(headers, params)
console.log('Success -> HttpService -> getAllServices', response.data)
return { data, total }
})
}
function getServiceByName (name) {
return APP.api.get(`${apiBase}/services/${encodeURIComponent(name)}`)
.then(body => {
console.log('Success -> HttpService -> getServiceByName', body.data)
return body.data
})
}
function getAllMiddlewares (params) {
return APP.api.get(`${apiBase}/middlewares?search=${params.query}&status=${params.status}&per_page=${params.limit}&page=${params.page}&sortBy=${params.sortBy}&direction=${params.direction}`)
.then(response => {
const { data = [], headers } = response
const total = getTotal(headers, params)
console.log('Success -> HttpService -> getAllMiddlewares', response.data)
return { data, total }
})
}
function getMiddlewareByName (name) {
return APP.api.get(`${apiBase}/middlewares/${encodeURIComponent(name)}`)
.then(body => {
console.log('Success -> HttpService -> getMiddlewareByName', body.data)
return body.data
})
}
export default {
getAllRouters,
getRouterByName,
getAllServices,
getServiceByName,
getAllMiddlewares,
getMiddlewareByName
}

View File

@ -1,67 +0,0 @@
import { APP } from '../_helpers/APP'
import { getTotal } from './utils'
const apiBase = '/tcp'
function getAllRouters (params) {
return APP.api.get(`${apiBase}/routers?search=${params.query}&status=${params.status}&per_page=${params.limit}&page=${params.page}&sortBy=${params.sortBy}&direction=${params.direction}&serviceName=${params.serviceName}&middlewareName=${params.middlewareName}`)
.then(response => {
const { data = [], headers } = response
const total = getTotal(headers, params)
console.log('Success -> TcpService -> getAllRouters', response.data)
return { data, total }
})
}
function getRouterByName (name) {
return APP.api.get(`${apiBase}/routers/${encodeURIComponent(name)}`)
.then(body => {
console.log('Success -> TcpService -> getRouterByName', body.data)
return body.data
})
}
function getAllServices (params) {
return APP.api.get(`${apiBase}/services?search=${params.query}&status=${params.status}&per_page=${params.limit}&page=${params.page}&sortBy=${params.sortBy}&direction=${params.direction}`)
.then(response => {
const { data = [], headers } = response
const total = getTotal(headers, params)
console.log('Success -> TcpService -> getAllServices', response.data)
return { data, total }
})
}
function getServiceByName (name) {
return APP.api.get(`${apiBase}/services/${encodeURIComponent(name)}`)
.then(body => {
console.log('Success -> TcpService -> getServiceByName', body.data)
return body.data
})
}
function getAllMiddlewares (params) {
return APP.api.get(`${apiBase}/middlewares?search=${params.query}&status=${params.status}&per_page=${params.limit}&page=${params.page}&sortBy=${params.sortBy}&direction=${params.direction}`)
.then(response => {
const { data = [], headers } = response
const total = getTotal(headers, params)
console.log('Success -> TcpService -> getAllMiddlewares', response.data)
return { data, total }
})
}
function getMiddlewareByName (name) {
return APP.api.get(`${apiBase}/middlewares/${encodeURIComponent(name)}`)
.then(body => {
console.log('Success -> TcpService -> getMiddlewareByName', body.data)
return body.data
})
}
export default {
getAllRouters,
getRouterByName,
getAllServices,
getServiceByName,
getAllMiddlewares,
getMiddlewareByName
}

View File

@ -1,47 +0,0 @@
import { APP } from '../_helpers/APP'
import { getTotal } from './utils'
const apiBase = '/udp'
function getAllRouters (params) {
return APP.api.get(`${apiBase}/routers?search=${params.query}&status=${params.status}&per_page=${params.limit}&page=${params.page}&sortBy=${params.sortBy}&direction=${params.direction}&serviceName=${params.serviceName}`)
.then(response => {
const { data = [], headers } = response
const total = getTotal(headers, params)
console.log('Success -> UdpService -> getAllRouters', response.data)
return { data, total }
})
}
function getRouterByName (name) {
return APP.api.get(`${apiBase}/routers/${encodeURIComponent(name)}`)
.then(body => {
console.log('Success -> UdpService -> getRouterByName', body.data)
return body.data
})
}
function getAllServices (params) {
return APP.api.get(`${apiBase}/services?search=${params.query}&status=${params.status}&per_page=${params.limit}&page=${params.page}&sortBy=${params.sortBy}&direction=${params.direction}`)
.then(response => {
const { data = [], headers } = response
const total = getTotal(headers, params)
console.log('Success -> UdpService -> getAllServices', response.data)
return { data, total }
})
}
function getServiceByName (name) {
return APP.api.get(`${apiBase}/services/${encodeURIComponent(name)}`)
.then(body => {
console.log('Success -> UdpService -> getServiceByName', body.data)
return body.data
})
}
export default {
getAllRouters,
getRouterByName,
getAllServices,
getServiceByName
}

View File

@ -1,8 +0,0 @@
export const getTotal = (headers, params) => {
const nextPage = parseInt(headers['x-next-page'], 10) || 1
const hasNextPage = nextPage > 1
return hasNextPage
? (params.page + 1) * params.limit
: params.page * params.limit
}

View File

@ -1,6 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="84" height="24" viewBox="0 0 84 24">
<g fill="none" fill-rule="nonzero">
<path fill="#FFF" d="M7.142 24c-1.241 0-2.23-.406-2.963-1.217-.735-.822-1.102-2.082-1.102-3.781v-9.47H1.101c-.356 0-.631-.088-.826-.263C.092 9.093 0 8.858 0 8.562c0-.285.092-.516.275-.691.184-.186.454-.28.81-.28h1.992l.389-4.669c.022-.35.173-.652.453-.904.292-.252.61-.378.956-.378.324 0 .594.104.81.312.216.197.324.488.324.872v4.768h2.98c.356 0 .62.093.793.279.184.186.276.428.276.723 0 .625-.357.938-1.07.938h-2.98v8.96c0 1.13.157 1.946.47 2.45.314.493.81.74 1.49.74h.179l1.101-.05h.097c.356 0 .637.116.842.346.205.23.308.498.308.805 0 .274-.06.5-.178.674-.119.165-.302.285-.55.362a3.31 3.31 0 0 1-.73.148c-.237.022-.55.033-.939.033h-.956zm7.771 0c-.405 0-.75-.12-1.035-.358-.284-.238-.427-.574-.427-1.007V9.228c0-.434.148-.764.444-.992a1.623 1.623 0 0 1 1.051-.357c.405 0 .75.119 1.035.357.295.228.443.547.443.96l-.016 1.95a4.815 4.815 0 0 1 1.642-2.52c.832-.682 1.829-1.024 2.99-1.024.35 0 .624.13.82.39.209.26.313.564.313.91 0 .326-.093.607-.28.846-.186.227-.454.34-.804.34-1.478 0-2.628.38-3.45 1.139-.81.758-1.215 1.77-1.215 3.038v8.37c0 .433-.153.77-.46 1.007a1.623 1.623 0 0 1-1.05.358zm40.61-.383a1.522 1.522 0 0 1-1.037.383c-.4 0-.745-.128-1.037-.383-.28-.267-.42-.633-.42-1.1V9.578h-2.123c-.357 0-.621-.09-.794-.267a.997.997 0 0 1-.26-.7c0-.288.087-.527.26-.715.173-.19.437-.284.794-.284h2.122V5.496c0-1.987.41-3.397 1.232-4.23C55.08.422 56.215 0 57.662 0h1.977c.313 0 .556.117.729.35.183.222.275.488.275.8 0 .31-.092.577-.275.799-.173.222-.421.333-.745.333h-1.378c-.464 0-.826.044-1.085.133-.26.078-.492.26-.697.55-.194.277-.33.682-.405 1.215-.065.522-.097 1.233-.097 2.132v1.3h2.738c.356 0 .616.094.778.283.173.188.259.427.259.716 0 .644-.346.966-1.037.966h-2.738v12.94c0 .467-.146.833-.438 1.1zm9.557-20.04c-.58 0-1.045-.161-1.396-.485-.35-.335-.525-.766-.525-1.295 0-.529.175-.96.525-1.295.362-.335.832-.502 1.413-.502.57 0 1.03.167 1.38.502.35.324.525.755.525 1.295 0 .529-.175.96-.526 1.295-.35.324-.815.486-1.396.486zM65.056 24a1.49 1.49 0 0 1-1.03-.38c-.282-.263-.424-.637-.424-1.121V9.087c0-.462.147-.825.441-1.089a1.573 1.573 0 0 1 1.062-.396c.392 0 .73.132 1.013.396.294.264.44.627.44 1.09v13.41c0 .463-.152.831-.457 1.106a1.513 1.513 0 0 1-1.045.396zm8.44-.407a1.53 1.53 0 0 1-1.048.39c-.403 0-.747-.124-1.03-.374-.284-.26-.426-.629-.426-1.106V1.464c0-.455.147-.813.442-1.073.305-.26.66-.391 1.063-.391.393 0 .731.13 1.015.39.294.26.442.619.442 1.074V14.66l7.428-6.768c.24-.207.496-.31.77-.31.348 0 .654.136.915.407.273.271.41.575.41.911 0 .304-.132.58-.393.83l-5.94 5.288 6.496 6.802c.24.25.36.531.36.846 0 .347-.142.656-.425.927-.273.271-.59.407-.95.407-.381 0-.708-.152-.981-.456l-7.69-8.135v7.094c0 .466-.153.83-.459 1.09z"/>
<path fill="#4B76DD" d="M28.93 23.993c-1.942-.163-3.427-.734-4.506-1.732-1.1-1.016-1.57-2.34-1.384-3.888.214-1.781 1.083-3.039 2.608-3.773 1.175-.565 2.348-.78 4.257-.781 1.357 0 2.493.108 4.227.401.429.073.8.132.825.132.036 0 .065-.133.144-.664.142-.96.167-1.292.129-1.676-.046-.448-.104-.662-.279-1.009-.45-.895-1.517-1.443-3.232-1.658-.49-.062-1.622-.07-2.114-.016-.823.09-1.282.206-2.306.58-.6.218-.602.218-.841.205-.411-.024-.692-.205-.872-.563-.074-.147-.087-.208-.087-.407 0-.298.08-.456.358-.709.623-.567 1.671-1.05 2.73-1.258.677-.132 1.01-.16 1.903-.159.923.002 1.514.052 2.335.2 1.365.248 2.402.683 3.183 1.338.232.194.582.577.732.8a.433.433 0 0 0 .105.124c.012 0 .087-.082.168-.182C38.197 7.83 40.19 6.998 42.526 7c1.652 0 3.187.408 4.332 1.148.908.587 1.645 1.49 1.943 2.382.171.512.197.701.199 1.444 0 .463-.012.775-.039.92-.268 1.46-.906 2.473-2.013 3.193-.891.58-2.01.92-3.474 1.053-.736.068-2.084.061-2.957-.014-.74-.063-1.65-.175-2.038-.25a34.12 34.12 0 0 0-1.446-.236 22.15 22.15 0 0 0-.118.72c-.097.625-.11.782-.113 1.281-.002.508.006.597.069.832.202.754.648 1.258 1.458 1.648.797.383 1.631.55 2.893.575.559.011.845.003 1.194-.033.847-.087 1.233-.183 2.358-.586.28-.1.567-.191.636-.203.149-.024.426.026.587.106.292.144.537.528.535.84-.001.362-.127.582-.497.868-.883.684-2.01 1.104-3.357 1.25-.48.05-1.576.059-2.106.014-1.49-.126-2.526-.374-3.472-.833-.738-.357-1.301-.8-1.722-1.356a24.69 24.69 0 0 0-.195-.255 1.301 1.301 0 0 0-.153.175 6.104 6.104 0 0 1-1.423 1.256c-.763.482-1.859.85-2.967.997-.331.044-1.428.08-1.71.057zm1.904-2.08c.906-.195 1.712-.635 2.298-1.253.534-.563.972-1.408 1.213-2.338.136-.525.362-1.985.312-2.015-.02-.012-.14-.03-.266-.042a31.364 31.364 0 0 1-.799-.092c-1.86-.234-3.002-.325-3.642-.29-1.217.066-1.713.17-2.443.51-.374.173-.633.362-.837.61-.293.358-.47.713-.594 1.191-.09.348-.099 1.259-.015 1.552.14.495.307.775.681 1.145.513.508 1.19.846 2.029 1.015.429.087.416.086 1.134.076.521-.008.716-.022.93-.068zm11.857-6.845c.757-.065 1.222-.18 1.794-.44.476-.218.752-.44 1.014-.816.385-.552.535-1.075.531-1.852-.003-.554-.05-.784-.247-1.182-.44-.888-1.47-1.524-2.822-1.741-.338-.055-1.243-.045-1.59.016-.664.119-1.227.334-1.723.66-.916.604-1.549 1.513-1.9 2.734-.14.48-.176.663-.3 1.49l-.113.762.152.017c.46.05 1.498.172 2.101.247.38.048.845.099 1.034.113.549.042 1.531.038 2.069-.008z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 5.0 KiB

View File

@ -1,7 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="88" height="96" viewBox="0 0 88 96">
<g fill="none" fill-rule="nonzero" stroke="#7A7A7A" stroke-width="4">
<path fill="#3D3D3D" d="M41.05 42.807zm0 0l-.006.003 1.917 3.508-1.876-3.532c1.866-1.05 4.007-1.044 5.82-.006 8.058 4.62 22.413 13.097 37.112 21.84C85.14 65.299 86 66.39 86 68c0 1.612-.866 2.71-1.993 3.383-15.424 9.173-29.305 17.368-37.1 21.836a5.813 5.813 0 0 1-5.812 0C33.322 88.765 19.88 80.83 3.983 71.38 2.86 70.7 2 69.61 2 67.999c0-1.615.869-2.72 1.993-3.382a8052.42 8052.42 0 0 1 17.004-10.023l.05-.03a33723.823 33723.823 0 0 1 18.288-10.75l1.27-.746.334-.196.085-.05.022-.013.004-.002z"/>
<path fill="#1D1D1D" stroke-dasharray="0,10" stroke-linecap="round" d="M4 48c0-.96.707-1.483 1.012-1.662 9.254-5.48 37.058-21.81 37.054-21.809 1.274-.717 2.664-.69 3.844-.014 10.211 5.854 30.961 18.182 37.074 21.819.305.183 1.016.71 1.016 1.666 0 .955-.71 1.482-1.016 1.664-7.914 4.707-27.37 16.26-37.07 21.818a3.813 3.813 0 0 1-3.824.002c-9.703-5.56-29.16-17.113-37.074-21.818C4.71 49.482 4 48.955 4 48z"/>
<path fill="#3D3D3D" d="M41.05 2.807zm0 0l-.006.003 1.917 3.508-1.876-3.532c1.866-1.05 4.007-1.044 5.82-.006 8.058 4.62 22.413 13.097 37.112 21.84C85.14 25.299 86 26.39 86 28c0 1.612-.866 2.71-1.993 3.383-15.424 9.173-29.305 17.368-37.1 21.836a5.813 5.813 0 0 1-5.812 0C33.322 48.765 19.88 40.83 3.983 31.38 2.86 30.7 2 29.61 2 27.999c0-1.615.869-2.72 1.993-3.382a8052.42 8052.42 0 0 1 17.004-10.023l.05-.03a33723.375 33723.375 0 0 1 18.288-10.75l1.27-.746.334-.196.085-.05.022-.013.004-.002z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -1,7 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="88" height="96" viewBox="0 0 88 96">
<g fill="none" fill-rule="nonzero" stroke="#DCDCDC" stroke-width="4">
<path fill="#F2F3F5" d="M41.05 42.807zm0 0l-.006.003 1.917 3.508-1.876-3.532c1.866-1.05 4.007-1.044 5.82-.006 8.058 4.62 22.413 13.097 37.112 21.84C85.14 65.299 86 66.39 86 68c0 1.612-.866 2.71-1.993 3.383-15.424 9.173-29.305 17.368-37.1 21.836a5.813 5.813 0 0 1-5.812 0C33.322 88.765 19.88 80.83 3.983 71.38 2.86 70.7 2 69.61 2 67.999c0-1.615.869-2.72 1.993-3.382a8052.42 8052.42 0 0 1 17.004-10.023l.05-.03a33723.823 33723.823 0 0 1 18.288-10.75l1.27-.746.334-.196.085-.05.022-.013.004-.002z"/>
<path fill="#FFF" stroke-dasharray="0,10" stroke-linecap="round" d="M4 48c0-.96.707-1.483 1.012-1.662 9.254-5.48 37.058-21.81 37.054-21.809 1.274-.717 2.664-.69 3.844-.014 10.211 5.854 30.961 18.182 37.074 21.819.305.183 1.016.71 1.016 1.666 0 .955-.71 1.482-1.016 1.664-7.914 4.707-27.37 16.26-37.07 21.818a3.813 3.813 0 0 1-3.824.002c-9.703-5.56-29.16-17.113-37.074-21.818C4.71 49.482 4 48.955 4 48z"/>
<path fill="#F2F3F5" d="M41.05 2.807zm0 0l-.006.003 1.917 3.508-1.876-3.532c1.866-1.05 4.007-1.044 5.82-.006 8.058 4.62 22.413 13.097 37.112 21.84C85.14 25.299 86 26.39 86 28c0 1.612-.866 2.71-1.993 3.383-15.424 9.173-29.305 17.368-37.1 21.836a5.813 5.813 0 0 1-5.812 0C33.322 48.765 19.88 40.83 3.983 31.38 2.86 30.7 2 29.61 2 27.999c0-1.615.869-2.72 1.993-3.382a8052.42 8052.42 0 0 1 17.004-10.023l.05-.03a33723.375 33723.375 0 0 1 18.288-10.75l1.27-.746.334-.196.085-.05.022-.013.004-.002z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -1,90 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="259px" height="296px" viewBox="0 0 259 296" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: sketchtool 50.2 (55047) - http://www.bohemiancoding.com/sketch -->
<title>35600C78-FD43-44A0-A2D3-2D9D8078107C@3x</title>
<desc>Created with sketchtool.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Traefik---Bandeau-top" transform="translate(-271.000000, -208.000000)">
<g id="Group-5" transform="translate(-6.000000, 60.000000)">
<g id="Group-4" transform="translate(277.000000, 148.000000)">
<g id="traefik.logo.bright">
<path d="M39.8037726,116.53974 C39.8037726,116.53974 60.9593043,98.1480553 123.573394,98.1480553 C181.014826,98.1480553 197.157241,111.161081 213.552404,116.53974 L128.016891,158.279645 L39.8037726,116.53974 Z" id="path3156" fill="#C9781F" fill-rule="nonzero"></path>
<g id="g3158" transform="translate(28.709554, 26.010842)">
<path d="M2.16336011,145.886272 C2.5509667,153.86447 10.5317151,150.173212 14.1468181,147.678793 C17.5782604,145.310847 18.5815419,147.279116 18.8825264,142.60564 C19.0798932,139.534154 19.4346053,136.462668 19.2597164,133.37859 C14.0711608,132.908833 8.42701681,134.142902 4.17321267,137.229171 C1.98244049,138.819664 -2.12607971,143.894459 2.16336011,145.886272" id="path3160" fill="#F6D2A2" fill-rule="nonzero"></path>
<path d="M2.16336011,145.886272 C3.3250834,145.45484 4.55588509,145.148239 5.34425606,144.099225" id="path3162" fill="#C6B198" fill-rule="nonzero"></path>
<path d="M20.6072935,50.8415775 C-9.97579844,42.2529146 12.7652501,3.39834453 37.3242667,19.3799261 L20.6072935,50.8415775 Z" id="path3164" fill="#37ABC8" fill-rule="nonzero"></path>
<path d="M156.4878,16.4639308 C180.695394,-0.516294328 202.570769,37.7940588 174.437219,47.4333779 L156.4878,16.4639308 Z" id="path3166" fill="#37ABC8" fill-rule="nonzero"></path>
<path d="M161.694995,244.076364 C167.84407,247.876028 179.083016,259.364261 169.858856,264.935093 C160.995988,273.039217 156.035501,256.039829 148.256505,253.684476 C151.606808,249.141305 155.852936,244.998357 161.694995,244.076364 Z" id="path3168" fill="#F6D2A2" fill-rule="nonzero"></path>
<path d="M169.858856,264.934546 C168.491543,262.218936 168.032116,259.049995 165.74924,256.861082" id="path3170"></path>
<path d="M51.8422442,257.059825 C44.625196,258.175087 40.562728,264.677767 34.5463282,267.979751 C28.876965,271.355648 26.7081225,266.898983 26.1971616,265.993962 C25.3084625,265.589358 25.3830233,266.370643 24.0113236,264.991486 C18.7553344,256.707781 29.4877058,250.652957 35.0759292,246.537933 C42.859859,244.966055 47.73811,251.705256 51.8422442,257.059825 Z" id="path3172" fill="#F6D2A2" fill-rule="nonzero"></path>
<path d="M26.1977098,265.993414 C26.4723787,262.836518 28.9794861,260.722066 30.1730074,258.052446" id="path3174"></path>
<path d="M21.8835992,40.109992 C17.8485433,37.978567 14.8885886,35.0839242 17.3567709,30.4230402 C19.6418406,26.1087249 23.8868728,26.5768391 27.9219287,28.7082641 L21.8835992,40.109992 Z" id="path3176" fill="#077E91" fill-rule="nonzero"></path>
<path d="M168.062818,36.0579302 C172.097874,33.9265051 175.057829,31.0318624 172.589646,26.3709784 C170.304577,22.0561156 166.060093,22.5247773 162.024488,24.6562023 L168.062818,36.0579302 Z" id="path3178" fill="#077E91" fill-rule="nonzero"></path>
<path d="M195.83727,144.872845 C195.449663,152.851044 187.468915,149.159786 183.853812,146.665367 C180.42237,144.297421 179.419088,146.26569 179.118104,141.592761 C178.920737,138.521275 178.566025,135.44979 178.740913,132.365711 C183.929469,131.895955 189.573613,133.130024 193.827417,136.216292 C196.018189,137.806238 200.12671,142.881581 195.83727,144.872845" id="path3180" fill="#F6D2A2" fill-rule="nonzero"></path>
<path d="M195.83727,144.872845 C194.675546,144.441414 193.444745,144.134813 192.656374,143.085799" id="path3182" fill="#C6B198" fill-rule="nonzero"></path>
<g id="g3184" transform="translate(15.350756, 0.000000)" fill="#37ABC8" fill-rule="nonzero">
<path d="M80.5848901,0.325763653 C111.202521,0.325763653 139.904597,4.69866164 154.867198,34.0748782 C168.296917,67.0021922 163.521187,102.508788 165.569417,137.308011 C167.328175,167.189024 171.228363,201.710117 157.347442,229.400575 C142.745035,258.533153 106.256288,265.861466 76.1934774,264.787815 C52.580177,263.944115 24.0551829,256.250617 10.7285337,234.705869 C-4.90675951,209.430442 2.49559433,171.847171 3.63100204,143.722544 C4.97638615,110.407598 -5.40511084,76.9919126 5.55423247,44.3920047 C16.923112,10.5755474 47.5851507,2.93296788 80.5848901,0.325763653" id="path3186"></path>
</g>
<path d="M101.340757,41.373079 C106.837972,73.285872 159.072757,64.8483196 151.570075,32.6623231 C144.842607,3.80021096 99.514017,11.7893592 101.340757,41.373079" id="path3188" fill="#FFFFFF" fill-rule="nonzero"></path>
<path d="M38.9207454,46.5343798 C46.0456891,74.3173656 90.5870042,67.2042205 88.9082893,39.3352768 C86.8967921,5.95736859 32.1088474,12.3981814 38.9207454,46.5343798" id="path3190" fill="#FFFFFF" fill-rule="nonzero"></path>
<path d="M111.481028,78.5725507 C111.50515,82.8375908 112.491437,87.0057231 111.63947,91.7936275 C110.578623,93.7952946 108.498595,94.0071779 106.70475,94.8158382 C104.224506,94.4271118 102.138996,92.8010311 101.143938,90.4840029 C100.50743,85.44589 101.381327,80.5681953 101.541962,75.5284399 L111.481028,78.5725507 Z" id="path3192" fill="#FFFFFF" fill-rule="nonzero"></path>
<g id="g3194" transform="translate(43.311062, 33.397618)" fill-rule="nonzero">
<ellipse id="ellipse3196" fill="#000000" cx="7.89466904" cy="8.60563" rx="7.5213222" ry="8.13587881"></ellipse>
<ellipse id="ellipse3198" fill="#FFFFFF" cx="11.3157001" cy="10.4414149" rx="1.77301232" ry="2.06791482"></ellipse>
</g>
<g id="g3200" transform="translate(106.358809, 31.755112)" fill-rule="nonzero">
<ellipse id="ellipse3202" fill="#000000" cx="7.86616049" cy="8.22183661" rx="7.39632319" ry="8.13587881"></ellipse>
<ellipse id="ellipse3204" fill="#FFFFFF" cx="11.2307173" cy="10.0581581" rx="1.74395553" ry="2.06791482"></ellipse>
</g>
<path d="M89.98668,79.215318 C86.7049076,87.1579286 91.8167094,103.039865 100.720696,91.3255134 C100.084188,86.2874005 100.958085,81.4097058 101.118719,76.3699504 L89.98668,79.215318 Z" id="path3206" fill="#FFFFFF" fill-rule="nonzero"></path>
<g id="g3208" transform="translate(80.043228, 62.962723)" fill="#F6D2A2" fill-rule="nonzero">
<path d="M9.4215265,0.957033389 C3.30534671,1.47770773 -1.69461381,8.74032095 1.48573388,14.4858063 C5.69732344,22.0960832 15.0974685,13.8123789 20.9521372,14.5887367 C27.6905709,14.7267071 33.2113606,21.7040718 38.6235986,15.8501811 C44.6427397,9.33928807 36.032062,2.99812062 29.3024003,0.163155578 L9.4215265,0.957033389 Z" id="path3210"></path>
</g>
</g>
<g id="g3212" transform="translate(36.933174, 116.348662)" fill-rule="nonzero">
<path d="M2.87059137,0.191078177 C2.87059137,0.191078177 4.8069796,21.1390498 4.6743052,30.1689993 C4.54163081,39.1984013 13.2049396,33.4972636 13.6544975,47.6978214 C14.1040553,61.8983792 8.40673188,59.2052171 5.40511084,66.1557542 C2.4034898,73.1057438 0.363483973,105.655282 0.363483973,105.655282 C0.363483973,105.655282 3.44350352,111.736933 13.0640416,117.213048 C22.6845797,122.689162 38.1543041,125.765028 51.5494834,125.158943 C64.9446627,124.552859 74.5125697,121.687233 76.9050946,120.102215 C79.2970714,118.517745 83.2674348,113.504817 84.760844,109.627956 C86.2542533,105.751094 89.3742944,73.8202339 89.1566426,55.5484517 C88.9389909,37.2766695 85.9159884,20.4174423 85.9159884,20.4174423 L2.87059137,0.191078177 Z" id="path3214" fill="#EF9325"></path>
<path d="M87.7224434,89.1557632 C48.2753864,93.5532987 2.50436619,81.3965657 2.50436619,81.3965657 C2.50436619,81.3965657 3.17651001,69.0662745 6.13701296,64.7267742 C47.1635531,77.4206066 88.5535772,73.3959199 88.5535772,73.3959199 C89.1676075,79.1523553 88.7350451,83.7283765 87.7224434,89.1557632 Z" id="path3216" fill="#E5E5E5"></path>
<path d="M82.7570221,113.457732 C43.3099651,117.855267 0.363483973,105.210163 0.363483973,105.210163 C0.363483973,105.210163 0.22587541,93.3671481 1.79274901,88.1664272 C42.8192892,100.86026 86.6402151,97.6967934 86.6402151,97.6967934 C86.2712488,103.945433 85.3913215,110.095522 82.7570221,113.457732 Z" id="path3218" fill="#E5E5E5"></path>
</g>
<g id="g3220" transform="translate(131.230675, 116.348662)" fill-rule="nonzero">
<path d="M82.3217185,0.191078177 C82.3217185,0.191078177 82.0541768,21.1390498 82.1884959,30.1689993 C82.322815,39.1984013 76.9374409,33.4972636 76.4818524,47.6978214 C76.0262638,61.8983792 81.7954069,59.2052171 84.8348566,66.1557542 C87.8743063,73.1057438 89.9400794,105.655282 89.9400794,105.655282 C89.9400794,105.655282 86.8211348,111.736933 77.0799836,117.213048 C67.3388324,122.689162 51.6744824,125.765028 38.110993,125.158943 C24.5475036,124.552859 14.8595318,121.687233 12.4368536,120.102215 C10.0141753,118.517197 5.99447022,113.504817 4.48242075,109.627956 C2.97037129,105.751094 -0.189143244,73.8202339 0.0312497533,55.5484517 C0.25164275,37.2766695 3.31247385,20.4174423 3.31247385,20.4174423 L82.3217185,0.191078177 Z" id="path3222" fill="#EF9325"></path>
<path d="M1.48354092,89.1557632 C41.426208,93.5532987 87.7723334,81.3965657 87.7723334,81.3965657 C87.7723334,81.3965657 87.0914177,69.0662745 84.0941826,64.7267742 C42.5517474,77.4206066 0.641990546,73.3959199 0.641990546,73.3959199 C0.0202849276,79.1523553 0.458329715,83.7283765 1.48354092,89.1557632 Z" id="path3224" fill="#E5E5E5"></path>
<path d="M6.51091351,113.457732 C46.4535806,117.855267 89.9395312,105.210163 89.9395312,105.210163 C89.9395312,105.210163 90.0787845,93.3671481 88.4921742,88.1664272 C46.949739,100.86026 2.57892701,97.6967934 2.57892701,97.6967934 C2.95282757,103.945433 3.84371966,110.095522 6.51091351,113.457732 Z" id="path3226" fill="#E5E5E5"></path>
</g>
<g id="g3228" transform="translate(207.984455, 94.996087)" fill-rule="nonzero">
<path d="M21.5025715,59.9651498 C20.2613532,62.3040781 17.804684,63.4330271 16.0152244,62.4858487 L14.5815735,61.7275586 C12.7921139,60.7809277 12.346942,58.1167833 13.5881603,55.777855 L41.5402422,3.08955344 C42.7809123,0.750625158 45.2381297,-0.37832384 47.0275893,0.568854514 L48.4612402,1.3271447 C50.2506998,2.27377555 50.6958717,4.93791998 49.4546534,7.27684827 L21.5025715,59.9651498 Z" id="path3230" fill="#D2E261"></path>
<path d="M8.30201779,84.8474704 C7.57888754,86.2102027 5.54217116,86.5474639 3.7527116,85.6002856 L2.31906064,84.8419954 C0.529601082,83.8953646 -0.335523667,82.0229079 0.387606589,80.6601756 L13.5015381,55.9410106 C14.2246684,54.5782782 16.2613848,54.2410171 18.0508443,55.1881954 L19.4844953,55.9464856 C21.2739549,56.8931164 22.1390796,58.7655731 21.4159494,60.1283054 L8.30201779,84.8474704 Z" id="path3232" fill="#000000"></path>
<path d="M19.9620135,55.0458449 L18.5283625,54.2875547 C16.7389029,53.3409239 14.907777,53.2894587 14.4390307,54.1725793 L13.6007698,55.7526699 C14.0695161,54.8690018 15.9000938,54.920467 17.6901016,55.8676453 L19.1237525,56.6259355 C20.9132121,57.5725663 21.9844756,59.0568441 21.5157293,59.9399647 L22.3539902,58.3598741 C22.8227365,57.4767535 21.751473,55.9930233 19.9620135,55.0458449 Z" id="path3234" fill="#9B9B9B"></path>
</g>
<ellipse id="ellipse3236" fill="#F6D2A2" fill-rule="nonzero" transform="translate(216.136985, 164.336270) rotate(20.413879) translate(-216.136985, -164.336270) " cx="216.136985" cy="164.33627" rx="6.15347641" ry="4.75397164"></ellipse>
<g id="g3238" transform="translate(0.749249, 94.996087)" fill-rule="nonzero">
<path d="M26.1944204,60.8154203 C27.3265387,63.2090988 29.728932,64.4491907 31.5600579,63.5852326 L33.0266033,62.8931902 C34.8577292,62.0292321 35.4246107,59.3886303 34.2924924,56.9949518 L8.7894043,3.08188841 C7.65728604,0.688209937 5.25489273,-0.551881954 3.42376683,0.312076105 L1.95722139,1.00411856 C0.126095496,1.86807661 -0.440785994,4.50867846 0.691332262,6.90235694 L26.1944204,60.8154203 Z" id="path3240" fill="#D2E261"></path>
<path d="M38.2387332,86.2764505 C38.8982675,87.6709379 40.9174401,88.1007269 42.7491143,87.2373164 L44.2156597,86.5452739 C46.0467856,85.6813159 46.9968878,83.8504694 46.3368052,82.455982 L34.3714392,57.1619399 C33.7119049,55.7674525 31.6927323,55.3376634 29.8610581,56.201074 L28.3945127,56.8931164 C26.5633868,57.7570745 25.6132846,59.587921 26.2733671,60.9824084 L38.2387332,86.2764505 Z" id="path3242" fill="#000000"></path>
<path d="M27.9592091,55.9722182 L29.4257545,55.2801757 C31.2568804,54.4162177 33.0880063,54.4485203 33.5156345,55.352446 L34.2804311,56.9697667 C33.8528029,56.065841 32.021677,56.0335384 30.1905511,56.896949 L28.7240057,57.5889914 C26.8928798,58.4529495 25.7547309,59.8863095 26.1823591,60.7902352 L25.4175625,59.1729145 C24.9904825,58.2695363 26.1280832,56.8361762 27.9592091,55.9722182 Z" id="path3244" fill="#9B9B9B"></path>
</g>
<ellipse id="ellipse3246" fill="#F6D2A2" fill-rule="nonzero" transform="translate(41.089114, 165.024431) rotate(159.586121) translate(-41.089114, -165.024431) " cx="41.0891136" cy="165.024431" rx="6.15347641" ry="4.75397164"></ellipse>
<g id="g3248" transform="translate(26.516589, 0.825753)" fill-rule="nonzero">
<g id="g3250" transform="translate(2.192965, 25.732591)">
<path d="M24.1949844,62.2684905 C22.9789853,64.4765658 20.1105869,65.232666 17.7876885,63.9569865 L15.1161087,62.4902288 C12.7932104,61.2145492 11.8962877,58.3905342 13.1117386,56.1824589 L40.9152472,5.68635513 C42.1312463,3.47827982 44.9996448,2.72217964 47.3225431,3.99785916 L49.9941229,5.46461685 C52.3170212,6.74029637 52.9162489,9.12685732 51.998493,11.7723867 C42.2589866,39.836241 24.1949844,62.2684905 24.1949844,62.2684905 Z" id="path3252" fill="#960000"></path>
<path d="M31.5496413,33.4255409 C40.0046184,18.069754 45.5599473,4.86291222 44.2364929,3.36494691 L44.2677426,3.30855421 C44.2315587,3.28884414 44.1931818,3.2757041 44.1569979,3.25599403 C44.152612,3.25325652 44.1515155,3.24449649 44.1465813,3.24175898 L44.1427436,3.24942401 C31.1499734,-3.78104839 13.6698482,3.18153376 5.03449973,18.8652743 C-3.60084877,34.5490148 -0.124450772,53.0189927 12.7800526,60.2093357 L12.7762149,60.2170007 C12.7811491,60.2197382 12.7888245,60.2159057 12.7937586,60.2180957 C12.8299426,60.2383533 12.8611923,60.2635384 12.8973763,60.2832484 L12.928626,60.2268557 C14.9033911,60.5405744 23.0946642,48.7813277 31.5496413,33.4255409 Z" id="path3254" fill="#595959"></path>
</g>
<g id="g3256" transform="translate(146.380423, 25.732591)">
<path d="M26.6955129,62.3741584 C27.8468196,64.6161788 30.6927402,65.4549518 33.0512742,64.246615 L35.763972,62.8570551 C38.1225061,61.6492658 39.1011168,58.8520784 37.9498101,56.6100579 L11.6172328,5.33376389 C10.4659261,3.09174345 7.62000563,2.25297048 5.26147162,3.46130726 L2.54877374,4.85086718 C0.190239726,6.05865645 -0.478066401,8.42769734 0.362935731,11.0978643 C9.28775563,39.4305421 26.6955129,62.3741584 26.6955129,62.3741584 Z" id="path3258" fill="#960000"></path>
<path d="M20.1774723,33.3313705 C12.1698601,17.7385153 6.99830002,4.3767305 8.3645173,2.91763783 L8.33491227,2.86015013 C8.37164444,2.84153506 8.41056957,2.82949002 8.44730173,2.81087495 C8.45223591,2.80813744 8.45333239,2.79937741 8.45826656,2.7971874 L8.46210425,2.80485243 C21.6522413,-3.84839113 38.9240348,3.6151553 47.1026983,19.5414392 C55.2813618,35.4677231 51.2726215,53.8298431 38.1658171,60.6451472 L38.1696548,60.6528123 C38.1647206,60.6550023 38.1570453,60.6511698 38.1521111,60.6533598 C38.1153789,60.6725223 38.0835809,60.6971599 38.0468488,60.715775 L38.0172437,60.6582873 C36.0337068,60.9145182 28.1850845,48.9242257 20.1774723,33.3313705 Z" id="path3260" fill="#595959"></path>
</g>
<path d="M192.630058,52.4884633 C192.630058,52.4884633 182.900968,28.1541922 171.618163,15.2884441 C160.335357,2.42324358 49.9431364,-1.96443696 31.8149901,15.2884441 C13.6868437,32.5413252 6.85191959,52.4884633 6.85191959,52.4884633 L6.85191959,47.0988543 C6.85191959,47.0988543 15.2372701,23.4095404 31.8149901,9.89883505 C48.3927101,-3.61187029 157.33264,-2.90066527 171.387353,9.89883505 C185.441518,22.6983354 192.630058,47.0988543 192.630058,47.0988543 L192.630058,52.4884633 Z" id="path3262" fill="#353535"></path>
<ellipse id="ellipse3264" fill="#960000" transform="translate(192.490339, 46.095741) rotate(152.850710) translate(-192.490339, -46.095741) " cx="192.490339" cy="46.0957411" rx="3.8096405" ry="9.29363039"></ellipse>
<ellipse id="ellipse3266" fill="#960000" transform="translate(8.209378, 45.461228) rotate(28.802510) translate(-8.209378, -45.461228) " cx="8.20937794" cy="45.4612284" rx="3.80979137" ry="9.29399843"></ellipse>
</g>
<g id="g3268" transform="translate(59.959308, 47.910920)" fill="#FFFFFF" fill-rule="nonzero">
<path d="M117.592273,0.269370954 L97.1949564,0.269370954 L81.0251279,0.269370954 L56.2248851,0.269370954 L42.214579,0.269370954 L14.6270775,0.269370954 C-3.85961865,0.269370954 -3.79602266,49.3288297 13.5607482,52.1566772 L49.4519122,49.851694 C53.791242,49.851694 62.4556473,33.0680221 64.0811827,31.7485424 C65.7067181,30.4290627 71.059746,30.2680972 73.168282,31.7485424 C75.276818,33.2289877 80.0722845,48.1604605 84.4110661,48.1604605 L120.30223,52.1561297 C137.0669,44.4516824 132.840508,0.269370954 117.592273,0.269370954 Z" id="path3270" opacity="0.6"></path>
<path d="M41.9651292,10.4129394 C30.6247582,10.1599935 12.880929,10.2629238 3.18857132,10.3417641 C1.56358415,15.6629355 -0.248353303,22.3999468 0.650214165,28.9415 C9.45277625,28.9415 28.5885901,28.9842051 42.1970353,28.9842051 C50.3910496,28.9842051 57.2802496,30.5281606 63.6869972,32.200779 C63.8448907,31.9992983 63.9775651,31.8509253 64.0811827,31.7671575 C65.7067181,30.4476778 71.059746,30.2867122 73.168282,31.7671575 C73.7137821,32.1504088 74.4418465,33.4414184 75.2921688,35.1337469 C78.5635245,35.8225043 81.8398144,36.2982835 85.2443928,36.3409887 C94.5178942,36.4581541 116.251275,36.420924 130.236362,36.3815038 C132.017598,30.4372753 130.704012,24.0654477 130.304892,18.077419 C116.650395,18.077419 94.9504566,17.7697229 84.5470299,17.7697229 C69.8881544,17.7691754 57.0894616,10.7502006 41.9651292,10.4129394 Z" id="path3272" opacity="0.5"></path>
</g>
<path d="M117.40458,89.6124959 C116.951733,79.0303842 137.154428,77.707617 139.540375,86.5651023 C141.920294,95.4023323 118.399097,97.4549142 117.40458,89.6124959 C116.610728,83.3507162 117.40458,89.6124959 117.40458,89.6124959 Z" id="path3274" fill="#000000" fill-rule="nonzero"></path>
</g>
</g>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 20 KiB

View File

@ -1,16 +0,0 @@
import { boot } from 'quasar/wrappers'
import axios from 'axios'
import { APP } from '../_helpers/APP'
// Set config defaults when creating the instance
const api = axios.create({
baseURL: window.APIURL || APP.config.apiUrl
})
export default boot(({ app }) => {
app.config.globalProperties.$axios = axios
app.config.globalProperties.$api = api
APP.api = api
})
export { api }

View File

@ -0,0 +1,28 @@
import { AriaTr, VariantProps, styled } from '@traefiklabs/faency'
import { ComponentProps, forwardRef, ReactNode } from 'react'
import { useHref } from 'react-router-dom'
const UnstyledLink = styled('a', {
color: 'inherit',
textDecoration: 'inherit',
fontWeight: 'inherit',
'&:hover': {
cursor: 'pointer',
},
})
type ClickableRowProps = ComponentProps<typeof AriaTr> &
VariantProps<typeof AriaTr> & {
children: ReactNode
to: string
}
export default forwardRef<HTMLTableRowElement | null, ClickableRowProps>(({ children, css, to, ...props }, ref) => {
const href = useHref(to)
return (
<AriaTr asChild interactive ref={ref} css={css} {...props}>
<UnstyledLink href={href}>{children}</UnstyledLink>
</AriaTr>
)
})

View File

@ -0,0 +1,29 @@
import { Button } from '@traefiklabs/faency'
import { useCallback, useEffect, useState } from 'react'
export const ScrollTopButton = () => {
const [showOnScroll, setShowOnScroll] = useState<boolean>(false)
const handleScroll = useCallback(() => {
const position = window?.scrollY || 0
setShowOnScroll(position >= 160)
}, [setShowOnScroll])
useEffect(() => {
window.addEventListener('scroll', handleScroll, { passive: true })
return () => {
window.removeEventListener('scroll', handleScroll)
}
}, [handleScroll])
if (!showOnScroll) {
return null
}
return (
<Button variant="primary" onClick={(): void => window.scrollTo({ top: 0, behavior: 'smooth' })}>
Scroll to top
</Button>
)
}

View File

@ -0,0 +1,18 @@
import { Flex } from '@traefiklabs/faency'
import { motion } from 'framer-motion'
import { FiLoader } from 'react-icons/fi'
export const SpinnerLoader = () => (
<motion.div
animate={{
rotate: 360,
}}
transition={{ ease: 'linear', duration: 1, repeat: Infinity }}
style={{ width: 24, height: 24 }}
data-testid="loading"
>
<Flex css={{ color: '$primary' }}>
<FiLoader size={24} />
</Flex>
</motion.div>
)

View File

@ -0,0 +1,116 @@
import { Box, Button, Flex, TextField } from '@traefiklabs/faency'
// eslint-disable-next-line import/no-unresolved
import { InputHandle } from '@traefiklabs/faency/dist/components/Input'
import { isUndefined, omitBy } from 'lodash'
import { useCallback, useRef, useState } from 'react'
import { FiSearch, FiXCircle } from 'react-icons/fi'
import { URLSearchParamsInit, useSearchParams } from 'react-router-dom'
import { useDebounceCallback } from 'usehooks-ts'
import IconButton from 'components/buttons/IconButton'
type State = {
search?: string
status?: string
sortBy?: string
direction?: string
}
export const searchParamsToState = (searchParams: URLSearchParams): State => {
if (searchParams.size <= 0) return {}
return omitBy(
{
direction: searchParams.get('direction') || undefined,
search: searchParams.get('search') || undefined,
sortBy: searchParams.get('sortBy') || undefined,
status: searchParams.get('status') || undefined,
},
isUndefined,
)
}
type Status = {
id: string
value?: string
name: string
}
const statuses: Status[] = [
{ id: 'all', value: undefined, name: 'All status' },
{ id: 'enabled', value: 'enabled', name: 'Success' },
{ id: 'warning', value: 'warning', name: 'Warnings' },
{ id: 'disabled', value: 'disabled', name: 'Errors' },
]
export const TableFilter = ({ hideStatusFilter }: { hideStatusFilter?: boolean }) => {
const [searchParams, setSearchParams] = useSearchParams()
const [state, setState] = useState(searchParamsToState(searchParams))
const searchInputRef = useRef<InputHandle>(null)
const onSearch = useDebounceCallback((search?: string) => {
const newState = omitBy({ ...state, search: search || undefined }, isUndefined)
setState(newState)
setSearchParams(newState as URLSearchParamsInit)
}, 500)
const onStatusClick = useCallback(
(status?: string) => {
const newState = omitBy({ ...state, status: status || undefined }, isUndefined)
setState(newState)
setSearchParams(newState as URLSearchParamsInit)
},
[setSearchParams, state],
)
return (
<Flex css={{ alignItems: 'center', justifyContent: 'space-between', mb: '$5' }}>
<Flex>
{!hideStatusFilter &&
statuses.map(({ id, value, name }) => (
<Button
key={id}
css={{ marginRight: '$3', boxShadow: 'none' }}
ghost={state.status !== value}
variant={state.status !== value ? 'secondary' : 'primary'}
onClick={() => onStatusClick(value)}
>
{name}
</Button>
))}
</Flex>
<Box css={{ maxWidth: 200, position: 'relative' }}>
<TextField
ref={searchInputRef}
data-testid="table-search-input"
defaultValue={state.search || ''}
onChange={(e) => {
onSearch(e.target?.value)
}}
placeholder="Search"
css={{ input: { paddingRight: '$6' } }}
endAdornment={
state.search ? (
<IconButton
type="button"
css={{ height: '20px', p: 0, color: 'currentColor', '&:before, &:after': { borderRadius: '10px' } }}
ghost
icon={<FiXCircle size={20} />}
onClick={() => {
onSearch('')
searchInputRef.current?.clear()
}}
title="Clear search"
/>
) : (
<FiSearch color="hsl(0, 0%, 56%)" size={20} />
)
}
/>
</Box>
</Flex>
)
}
export default TableFilter

View File

@ -0,0 +1,29 @@
import { AccessibleIcon, Button } from '@traefiklabs/faency'
import { FiMoon, FiSun } from 'react-icons/fi'
import { AutoThemeIcon } from 'components/icons/AutoThemeIcon'
import { useTheme } from 'hooks/use-theme'
export default function ThemeSwitcher() {
const { selectedTheme, setTheme } = useTheme()
return (
<Button
ghost
css={{ px: '$2', color: '$buttonSecondaryText' }}
onClick={setTheme}
type="button"
data-testid="theme-switcher"
>
<AccessibleIcon label="toggle theme">
{selectedTheme === 'dark' ? (
<FiMoon size={20} />
) : selectedTheme === 'light' ? (
<FiSun size={20} />
) : (
<AutoThemeIcon />
)}
</AccessibleIcon>
</Button>
)
}

View File

@ -0,0 +1,102 @@
import { Box, Button, Flex, styled, Text } from '@traefiklabs/faency'
import { AnimatePresence, motion } from 'framer-motion'
import { ReactNode, useEffect } from 'react'
import { FiX } from 'react-icons/fi'
import { colorByStatus, iconByStatus, StatusType } from 'components/resources/Status'
const CloseButton = styled(Button, {
position: 'absolute',
top: 0,
right: 0,
padding: 0,
})
const ToastContainer = styled(Flex, {
marginBottom: '$3',
width: '100%',
position: 'relative',
padding: '$5 $6',
borderRadius: '$2',
})
const AnimatedToastContainer = motion.create(ToastContainer)
const toastVariants = {
create: {
opacity: 0,
y: 100,
},
visible: {
opacity: 1,
y: 0,
},
hidden: {
opacity: 0,
x: '100%',
scale: 0,
},
}
export type ToastState = {
severity: StatusType
message?: string
isVisible?: boolean
key?: string
}
type ToastProps = ToastState & {
dismiss: () => void
icon?: ReactNode
timeout?: number
}
export const Toast = ({ message, dismiss, severity = 'error', icon, isVisible = true, timeout = 0 }: ToastProps) => {
useEffect(() => {
if (timeout) {
setTimeout(() => dismiss(), timeout)
}
}, [timeout, dismiss])
const propsBySeverity = {
info: {
color: colorByStatus.info,
icon: iconByStatus.info,
},
success: {
color: colorByStatus.success,
icon: iconByStatus.success,
},
warning: {
color: colorByStatus.warning,
icon: iconByStatus.warning,
},
error: {
color: colorByStatus.error,
icon: iconByStatus.error,
},
}
return (
<AnimatePresence>
{isVisible && (
<AnimatedToastContainer
css={{ backgroundColor: propsBySeverity[severity].color }}
gap={2}
initial="create"
animate="visible"
exit="hidden"
variants={toastVariants}
>
<Box css={{ width: '$4', height: '$4' }}>{icon ? icon : propsBySeverity[severity].icon}</Box>
<Text css={{ color: 'white', fontWeight: 600, lineHeight: '$4' }}>{message}</Text>
{!timeout && (
<CloseButton ghost onClick={dismiss} css={{ px: '$2' }}>
<FiX color="#fff" size={20} />
</CloseButton>
)}
</AnimatedToastContainer>
)}
</AnimatePresence>
)
}

View File

@ -0,0 +1,79 @@
import { waitFor } from '@testing-library/react'
import { useContext, useEffect } from 'react'
import { ToastPool } from './ToastPool'
import { ToastContext, ToastProvider } from 'contexts/toasts'
import { renderWithProviders } from 'utils/test'
describe('<ToastPool />', () => {
it('should render the toast pool', () => {
renderWithProviders(<ToastPool />)
})
it('should render toasts from context', async () => {
const Component = () => {
const { addToast } = useContext(ToastContext)
useEffect(() => {
addToast({
message: 'Test 1',
severity: 'success',
})
}, [addToast])
return <ToastPool />
}
const { getByTestId } = renderWithProviders(
<ToastProvider>
<Component />
</ToastProvider>,
)
await waitFor(() => getByTestId('toast-pool'))
const toastPool = getByTestId('toast-pool')
expect(toastPool.childNodes.length).toBe(1)
expect(toastPool.innerHTML).toContain('Test 1')
})
it('should render all valid severities of toasts', async () => {
const Component = () => {
const { addToast } = useContext(ToastContext)
useEffect(() => {
addToast({
message: 'Test 2',
severity: 'error',
})
addToast({
message: 'Test 3',
severity: 'warning',
})
addToast({
message: 'Test 4',
severity: 'info',
})
}, [addToast])
return <ToastPool />
}
const { getByTestId } = renderWithProviders(
<ToastProvider>
<Component />
</ToastProvider>,
)
await waitFor(() => getByTestId('toast-pool'))
const toastPool = getByTestId('toast-pool')
expect(toastPool.childNodes.length).toBe(3)
expect(toastPool.innerHTML).toContain('Test 2')
expect(toastPool.innerHTML).toContain('Test 3')
expect(toastPool.innerHTML).toContain('Test 4')
})
})

View File

@ -0,0 +1,37 @@
import { Flex } from '@traefiklabs/faency'
import { useContext } from 'react'
import { Toast } from './Toast'
import { ToastContext } from 'contexts/toasts'
import { getPositionValues, PositionXProps, PositionYProps } from 'utils/position'
export type ToastPoolProps = {
positionX?: PositionXProps
positionY?: PositionYProps
toastTimeout?: number
}
export const ToastPool = ({ positionX = 'right', positionY = 'bottom', toastTimeout = 5000 }: ToastPoolProps) => {
const { toasts, hideToast } = useContext(ToastContext)
return (
<Flex
{...getPositionValues(positionX, positionY)}
css={{
position: 'fixed',
bottom: 0,
flexDirection: 'column',
maxWidth: '380px',
zIndex: 2,
px: '$3',
margin: positionX === 'center' ? 'auto' : 0,
}}
data-testid="toast-pool"
>
{toasts?.map((toast, key) => (
<Toast key={`toast-${key}`} {...toast} dismiss={(): void => hideToast(toast)} timeout={toastTimeout} />
))}
</Flex>
)
}

View File

@ -0,0 +1,47 @@
import { Button, Flex, Text, Tooltip as FaencyTooltip } from '@traefiklabs/faency'
import { MouseEvent, ReactNode, useMemo, useState } from 'react'
import { FiCheck, FiCopy } from 'react-icons/fi'
type TooltipProps = {
action?: 'copy'
children: ReactNode
label: string
}
export default function Tooltip({ action, children, label }: TooltipProps) {
const [showConfirmation, setShowConfirmation] = useState(false)
const actionComponent = useMemo(() => {
if (action === 'copy') {
return (
<Button
css={{ padding: '0 $2 !important' }}
onClick={async (e: MouseEvent) => {
e.preventDefault()
e.stopPropagation()
await navigator.clipboard.writeText(label)
setShowConfirmation(true)
setTimeout(() => setShowConfirmation(false), 1500)
}}
>
{showConfirmation ? <FiCheck size={16} /> : <FiCopy size={16} />}
</Button>
)
}
return null
}, [action, label, showConfirmation])
return (
<FaencyTooltip
content={
<Flex align="center" gap={2} css={{ px: '$1' }}>
<Text css={{ maxWidth: '240px !important', color: '$contrast', wordBreak: 'break-word' }}>{label}</Text>{' '}
{actionComponent}
</Flex>
}
>
{children}
</FaencyTooltip>
)
}

View File

@ -0,0 +1,28 @@
import { CSS, Text } from '@traefiklabs/faency'
import { useMemo } from 'react'
import Tooltip from 'components/Tooltip'
type TooltipTextProps = {
isTruncated?: boolean
text?: string
css?: CSS
}
export default function TooltipText({ isTruncated = false, text, css }: TooltipTextProps) {
const appliedCss = useMemo(
() =>
isTruncated
? { whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', maxWidth: '100%', ...css }
: css,
[isTruncated, css],
)
if (typeof text === 'undefined') return <Text>-</Text>
return (
<Tooltip label={text} action="copy">
<Text css={appliedCss}>{text}</Text>
</Tooltip>
)
}

View File

@ -1,43 +0,0 @@
<template>
<q-avatar
:color="state"
text-color="white"
>
<q-icon
v-if="state === 'positive'"
name="eva-checkmark-circle-2"
/>
<q-icon
v-if="state === 'warning'"
name="eva-alert-circle"
/>
<q-icon
v-if="state === 'negative'"
name="eva-alert-triangle"
/>
</q-avatar>
</template>
<script>
import { defineComponent } from 'vue'
export default defineComponent({
name: 'AvatarState',
props: {
state: { type: String, default: undefined, required: false }
}
})
</script>
<style scoped lang="scss">
@import "../../css/sass/variables";
.q-avatar{
font-size: 32px;
border-radius: 4px;
.q-icon {
font-size: 22px;
margin: 0 0 0 1px;
}
}
</style>

View File

@ -1,71 +0,0 @@
<template>
<div class="block-right-text">
<q-avatar
:color="value ? 'positive' : 'negative'"
text-color="white"
>
<q-icon
v-if="value"
name="eva-toggle-right"
/>
<q-icon
v-if="!value"
name="eva-toggle-left"
/>
</q-avatar>
<div :class="['block-right-text-label', `block-right-text-label-${!!value}`]">
{{ value ? 'True' : 'False' }}
</div>
</div>
</template>
<script>
import { defineComponent } from 'vue'
export default defineComponent({
name: 'BooleanState',
props: {
value: {
type: Boolean,
default: true
}
}
})
</script>
<style scoped lang="scss">
@import "../../css/sass/variables";
.q-avatar{
font-size: 32px;
border-radius: 4px;
.q-icon {
font-size: 22px;
margin: 0 0 0 1px;
}
}
.block-right-text{
height: 32px;
line-height: 32px;
.q-avatar{
float: left;
}
&-label{
font-size: 14px;
font-weight: 600;
color: $app-text-grey;
float: left;
margin-left: 10px;
text-transform: capitalize;
&-true {
color: $positive;
}
&-false {
color: $negative;
}
}
}
</style>

View File

@ -1,34 +0,0 @@
<script>
import { Doughnut } from 'vue-chartjs'
import isEqual from 'lodash.isequal'
export default {
extends: Doughnut,
props: {
chartdata: {
type: Object,
default: null
},
options: {
type: Object,
default: null
}
},
watch: {
chartdata: function (newData, oldData) {
// TODO - bug, 'update()' not update the chart, replace for renderChart()
// console.log('new data from watcher...', newData, oldData, isEqual(newData.datasets[0].data, oldData.datasets[0].data))
if (!isEqual(newData.datasets[0].data, oldData.datasets[0].data)) {
// this.$data._chart.update()
this.renderChart(this.chartdata, this.options)
}
},
'$q.dark.isActive' (val) {
this.renderChart(this.chartdata, this.options)
}
},
mounted () {
this.renderChart(this.chartdata, this.options)
}
}
</script>

View File

@ -1,22 +0,0 @@
<template>
<div>
<q-chip
v-for="(chip, index) in list"
:key="index"
:dense="dense"
:class="classNames"
>
{{ chip }}
</q-chip>
</div>
</template>
<script>
export default {
props: {
dense: { type: Boolean, default: undefined },
classNames: Array[String],
list: Array[Object]
}
}
</script>

Some files were not shown because too many files have changed in this diff Show More