diff --git a/.env.example b/.env.example
index 7e5ce58..ee5dc77 100644
--- a/.env.example
+++ b/.env.example
@@ -1,3 +1,7 @@
-# Example
-KUBE_CLUSTER_NAME=example-cluster
-GITHUB_TOKEN=example-token
\ No newline at end of file
+GITHUB_TOKEN=
+
+# Plausible
+BASE_URL=http://plausible.localhost
+PLAUSIBLE_DOMAIN=http://plausible.localhost
+SECRET_KEY_BASE=
+TOTP_VAULT_KEY=
\ No newline at end of file
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 665b634..985c2a4 100755
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -34,6 +34,8 @@ jobs:
- uses: asdf-vm/actions/install@v3
+ - run: make lint
+
- run: make test
- run: make build
diff --git a/Makefile b/Makefile
index 12a3097..6918462 100644
--- a/Makefile
+++ b/Makefile
@@ -12,10 +12,10 @@ endif
docker login ghcr.io -u default -p $(GITHUB_TOKEN)
init:
- cp .env.example .env
- cp app-config.example.yaml app-config.local.yaml
+ cp -n .env.example .env || true
+ cp -n app-config.example.yaml app-config.local.yaml || true
-install:
+install: init
ifneq ($(shell which asdf),)
asdf install
corepack enable
@@ -24,6 +24,10 @@ ifneq ($(shell which asdf),)
endif
yarn install
+lint: install
+ yarn lint:all
+ yarn tsc
+
test: install
yarn test
@@ -37,7 +41,8 @@ dev-app:
dev-backend:
yarn workspace backend start
-docker-dev:
+dev-docker:
+ @echo "Starting the server at http://localhost:7007"
docker compose up
logs:
@@ -46,14 +51,17 @@ logs:
exec:
docker compose exec backstage bash
-up:
- @echo "Starting the server at http://localhost:7007"
- docker compose up -d
- open http://localhost:7007
+plausible-up: init
+ @echo "Plausible is running at http://localhost:8000 or http://plausible.localhost"
+ docker compose -f compose.plausible.yaml up -d
-up-logs:
- @echo "Starting the server at http://localhost:7007"
- docker compose up
+plausible-down:
+ docker compose -f compose.plausible.yaml down
+
+up: init
+ @echo "Backstage is running at http://localhost:7007 or http://backstage.localhost"
+ @echo "Traefik is running at http://localhost:8080 or http://traefik.localhost"
+ docker compose up -d
down:
docker compose down
@@ -61,7 +69,7 @@ down:
run:
docker compose run --rm backstage $(filter-out $@,$(MAKECMDGOALS))
-build:
+build: init
docker compose build backstage
publish: login-github version
@@ -103,15 +111,15 @@ help:
@echo "Available commands:"
@echo " init: Initialize the project"
@echo " install: Install dependencies"
+ @echo " lint: Run linting and type checking"
@echo " test: Run tests"
@echo " dev: Start the development server"
@echo " dev-app: Start the app development server"
@echo " dev-backend: Start the backend development server"
- @echo " docker-dev: Start the development server using Docker"
+ @echo " dev-docker: Start the development server using Docker"
@echo " logs: Show logs"
@echo " exec: Execute a command in the backstage container"
@echo " up: Start the server"
- @echo " up-logs: Start the server and show logs"
@echo " down: Stop the server"
@echo " run: Run a command in the backstage container"
@echo " build: Build the Docker image"
diff --git a/app-config.example.yaml b/app-config.example.yaml
index 596a532..da03f0e 100644
--- a/app-config.example.yaml
+++ b/app-config.example.yaml
@@ -20,3 +20,6 @@ catalog:
target: ../../examples/all.yaml
- type: file
target: ../../examples/acme-corp.yaml
+
+plausible:
+ enabled: false
diff --git a/app-config.production.yaml b/app-config.production.yaml
index e397c3b..31c2ad5 100644
--- a/app-config.production.yaml
+++ b/app-config.production.yaml
@@ -32,3 +32,6 @@ catalog:
target: ../../examples/all.yaml
- type: file
target: ../../examples/acme-corp.yaml
+
+plausible:
+ domain: ${PLAUSIBLE_DOMAIN}
diff --git a/app-config.yaml b/app-config.yaml
index 33e5334..ac2ace1 100644
--- a/app-config.yaml
+++ b/app-config.yaml
@@ -71,3 +71,7 @@ catalog:
pullRequestBranchName: backstage-integration
rules:
- allow: [Component, System, API, Resource, Location, Template, User, Group]
+
+plausible:
+ enabled: true
+ domain: ${PLAUSIBLE_DOMAIN}
diff --git a/compose.plausible.yaml b/compose.plausible.yaml
new file mode 100644
index 0000000..631a1f4
--- /dev/null
+++ b/compose.plausible.yaml
@@ -0,0 +1,65 @@
+services:
+ traefik:
+ image: traefik:v3.1
+ command:
+ - '--api.insecure=true'
+ - '--api.dashboard=true'
+ - '--providers.docker=true'
+ - '--entrypoints.web.address=:80'
+ - '--entrypoints.traefik.address=:8080'
+ ports:
+ - 80:80
+ - 8080:8080
+ volumes:
+ - /var/run/docker.sock:/var/run/docker.sock
+ labels:
+ - 'traefik.enable=true'
+ - 'traefik.http.routers.traefik.rule=Host(`traefik.localhost`)'
+ - 'traefik.http.routers.traefik.service=api@internal'
+
+ plausible_db:
+ # Plausible v2.1.1 was tested against PostgreSQL versions 15 and 16
+ # https://github.com/plausible/analytics/blob/v2.1.1/.github/workflows/elixir.yml#L21-L32
+ image: postgres:16-alpine
+ restart: always
+ volumes:
+ - db-data:/var/lib/postgresql/data
+ environment:
+ - POSTGRES_PASSWORD=postgres
+
+ plausible_events_db:
+ image: clickhouse/clickhouse-server:24.3.3.102-alpine
+ restart: always
+ volumes:
+ - event-data:/var/lib/clickhouse
+ - event-logs:/var/log/clickhouse-server
+ - ./clickhouse/clickhouse-config.xml:/etc/clickhouse-server/config.d/logging.xml:ro
+ - ./clickhouse/clickhouse-user-config.xml:/etc/clickhouse-server/users.d/logging.xml:ro
+ ulimits:
+ nofile:
+ soft: 262144
+ hard: 262144
+
+ plausible:
+ image: ghcr.io/plausible/community-edition:v2.1.1
+ restart: always
+ command: sh -c "sleep 10 && /entrypoint.sh db createdb && /entrypoint.sh db migrate && /entrypoint.sh run"
+ labels:
+ - 'traefik.enable=true'
+ - 'traefik.http.routers.plausible.rule=Host(`plausible.localhost`)'
+ - 'traefik.http.services.plausible.loadbalancer.server.port=8000'
+ depends_on:
+ - plausible_db
+ - plausible_events_db
+ ports:
+ - 127.0.0.1:8000:8000
+ env_file:
+ - .env
+
+volumes:
+ db-data:
+ driver: local
+ event-data:
+ driver: local
+ event-logs:
+ driver: local
diff --git a/compose.yaml b/compose.yaml
index 69bc36b..bae6907 100644
--- a/compose.yaml
+++ b/compose.yaml
@@ -1,13 +1,35 @@
services:
+ traefik:
+ image: traefik:v3.1
+ command:
+ - '--api.insecure=true'
+ - '--api.dashboard=true'
+ - '--providers.docker=true'
+ - '--entrypoints.web.address=:80'
+ - '--entrypoints.traefik.address=:8080'
+ ports:
+ - 80:80
+ - 8080:8080
+ volumes:
+ - /var/run/docker.sock:/var/run/docker.sock
+ labels:
+ - 'traefik.enable=true'
+ - 'traefik.http.routers.traefik.rule=Host(`traefik.localhost`)'
+ - 'traefik.http.routers.traefik.service=api@internal'
+
backstage:
image: ghcr.io/echohello-dev/backstage:${VERSION:-latest}
build:
context: .
dockerfile: Dockerfile
+ labels:
+ - 'traefik.enable=true'
+ - 'traefik.http.routers.backstage.rule=Host(`backstage.localhost`)'
+ - 'traefik.http.services.backstage.loadbalancer.server.port=7007'
ports:
- 7007:7007
volumes:
- ./app-config.production.yaml:/app/app-config.production.yaml
- ./app-config.yaml:/app/app-config.yaml
- # env_file:
- # - .env
+ env_file:
+ - .env
diff --git a/docs/development.md b/docs/development.md
index 7f5c473..694632a 100644
--- a/docs/development.md
+++ b/docs/development.md
@@ -1,5 +1,29 @@
# Development
+## Creating a New Plugin
+
+On the command line, run the following command to create a new plugin.
+
+```bash
+yarn new
+```
+
+[Documentation](https://backstage.io/docs/conf/defining/)
+
+### Validating Configuration
+
+Schemas can be validated using the command:
+
+```bash
+backstage-cli config:check
+```
+
+To validate and examine the frontend configuration, use the command:
+
+```bash
+backstage-cli config:print --frontend
+```
+
## Using Storybook
There's a Backstage Storybook site that can be used to view and develop components.
diff --git a/docs/tracking.md b/docs/tracking.md
new file mode 100644
index 0000000..69f7104
--- /dev/null
+++ b/docs/tracking.md
@@ -0,0 +1,25 @@
+# Tracking
+
+We use Plausible Analytics to track visits to our website. Plausible is a privacy-friendly alternative to Google Analytics. It does not use cookies and does not collect any personal data. You can read more about Plausible's data policy [here](https://plausible.io/data-policy).
+
+## Local Development
+
+To run the Plausible Analytics server locally, you can use the following command:
+
+```bash
+make plausible-up
+```
+
+Build the app and start the server:
+
+```bash
+make build
+make up
+```
+
+To tear down the server:
+
+```bash
+make plausible-down
+make down
+```
diff --git a/packages/app/.eslintrc.js b/packages/app/.eslintrc.js
index e2a53a6..5073122 100644
--- a/packages/app/.eslintrc.js
+++ b/packages/app/.eslintrc.js
@@ -1 +1,5 @@
-module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
+module.exports = require('@backstage/cli/config/eslint-factory')(__dirname, {
+ rules: {
+ 'no-unused-vars': ['error', { varsIgnorePattern: '^_' }],
+ },
+});
diff --git a/packages/app/package.json b/packages/app/package.json
index b2aa984..14d2de6 100644
--- a/packages/app/package.json
+++ b/packages/app/package.json
@@ -41,6 +41,7 @@
"@emotion/react": "^11.11.4",
"@emotion/styled": "^11.11.5",
"@fontsource/inter": "^5.0.18",
+ "@internal/backstage-plugin-plausible": "^0.1.0",
"@mui/icons-material": "^5.15.19",
"@mui/joy": "^5.0.0-beta.36",
"@mui/material": "^5.15.19",
diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx
index f67cdcb..bff2d1a 100644
--- a/packages/app/src/App.tsx
+++ b/packages/app/src/App.tsx
@@ -41,6 +41,7 @@ import { UnifiedThemeProvider } from '@backstage/theme';
import { backstageTheme } from './theme';
import { HomePage } from './components/home/HomePage';
import CssBaseline from '@mui/material/CssBaseline';
+import { PlausibleAnalytics } from '@internal/backstage-plugin-plausible';
const app = createApp({
apis,
@@ -119,6 +120,7 @@ const routes = (
export default app.createRoot(
<>
+
diff --git a/packages/app/src/components/Root/Root.tsx b/packages/app/src/components/Root/Root.tsx
index 16cce8f..42d0b73 100644
--- a/packages/app/src/components/Root/Root.tsx
+++ b/packages/app/src/components/Root/Root.tsx
@@ -1,7 +1,6 @@
-import React, { PropsWithChildren, useState } from 'react';
+import React, { PropsWithChildren } from 'react';
import { styled } from '@mui/material/styles';
import Home from '@mui/icons-material/Home';
-import CreateComponent from '@mui/icons-material/AddCircleOutline';
import LogoFull from './LogoFull';
import LogoIcon from './LogoIcon';
import {
@@ -33,6 +32,7 @@ import ScoreRoundedIcon from '@mui/icons-material/ScoreRounded';
import { IconComponent } from '@backstage/core-plugin-api';
export enum LocalStorageKeys {
+ // eslint-disable-next-line no-unused-vars
SIDEBAR_PIN_STATE = 'sidebarPinState',
}
diff --git a/packages/app/src/components/home/HomePage.tsx b/packages/app/src/components/home/HomePage.tsx
index 3345a94..f71b676 100644
--- a/packages/app/src/components/home/HomePage.tsx
+++ b/packages/app/src/components/home/HomePage.tsx
@@ -15,7 +15,7 @@ import Groups3Icon from '@mui/icons-material/Groups3';
import ArrowForwardIcon from '@mui/icons-material/ArrowForward';
import TrendingUpIcon from '@mui/icons-material/TrendingUp';
import TrendingDownIcon from '@mui/icons-material/TrendingDown';
-import React, { useRef } from 'react';
+import React from 'react';
import Box from '@mui/material/Box';
import Typography from '@mui/material/Typography';
import CardContent from '@mui/material/CardContent';
@@ -76,26 +76,6 @@ export const HomePage = () => {
const [isSquad, setIsSquad] = React.useState(true);
const theme = useTheme();
- const scrollContainerRef = useRef(null);
-
- const scrollLeft = () => {
- if (scrollContainerRef.current) {
- scrollContainerRef.current.scrollBy({
- left: -300, // Adjust the scroll amount as needed
- behavior: 'smooth',
- });
- }
- };
-
- const scrollRight = () => {
- if (scrollContainerRef.current) {
- scrollContainerRef.current.scrollBy({
- left: 300, // Adjust the scroll amount as needed
- behavior: 'smooth',
- });
- }
- };
-
const months = [
new Date(2021, 7, 1),
new Date(2021, 8, 1),
diff --git a/packages/backend/.eslintrc.js b/packages/backend/.eslintrc.js
index e2a53a6..5073122 100644
--- a/packages/backend/.eslintrc.js
+++ b/packages/backend/.eslintrc.js
@@ -1 +1,5 @@
-module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
+module.exports = require('@backstage/cli/config/eslint-factory')(__dirname, {
+ rules: {
+ 'no-unused-vars': ['error', { varsIgnorePattern: '^_' }],
+ },
+});
diff --git a/plugins/plausible/.eslintrc.js b/plugins/plausible/.eslintrc.js
new file mode 100644
index 0000000..e2a53a6
--- /dev/null
+++ b/plugins/plausible/.eslintrc.js
@@ -0,0 +1 @@
+module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
diff --git a/plugins/plausible/README.md b/plugins/plausible/README.md
new file mode 100644
index 0000000..8b35e20
--- /dev/null
+++ b/plugins/plausible/README.md
@@ -0,0 +1,13 @@
+# plausible
+
+Welcome to the plausible plugin!
+
+_This plugin was created through the Backstage CLI_
+
+## Getting started
+
+Your plugin has been added to the example app in this repository, meaning you'll be able to access it by running `yarn start` in the root directory, and then navigating to [/plausible](http://localhost:3000/plausible).
+
+You can also serve the plugin in isolation by running `yarn start` in the plugin directory.
+This method of serving the plugin provides quicker iteration speed and a faster startup and hot reloads.
+It is only meant for local development, and the setup for it can be found inside the [/dev](./dev) directory.
diff --git a/plugins/plausible/config.d.ts b/plugins/plausible/config.d.ts
new file mode 100644
index 0000000..e809364
--- /dev/null
+++ b/plugins/plausible/config.d.ts
@@ -0,0 +1,13 @@
+export interface Config {
+ plausible?: {
+ /**
+ * @visibility frontend
+ */
+ enabled: boolean;
+
+ /**
+ * @visibility frontend
+ */
+ domain: string;
+ };
+}
diff --git a/plugins/plausible/dev/index.tsx b/plugins/plausible/dev/index.tsx
new file mode 100644
index 0000000..f0c5e37
--- /dev/null
+++ b/plugins/plausible/dev/index.tsx
@@ -0,0 +1,5 @@
+import React from 'react';
+import { createDevApp } from '@backstage/dev-utils';
+import { plausiblePlugin } from '../src/plugin';
+
+createDevApp().registerPlugin(plausiblePlugin).render();
diff --git a/plugins/plausible/package.json b/plugins/plausible/package.json
new file mode 100644
index 0000000..95818ed
--- /dev/null
+++ b/plugins/plausible/package.json
@@ -0,0 +1,54 @@
+{
+ "name": "@internal/backstage-plugin-plausible",
+ "version": "0.1.0",
+ "main": "src/index.ts",
+ "types": "src/index.ts",
+ "license": "Apache-2.0",
+ "private": true,
+ "publishConfig": {
+ "access": "public",
+ "main": "dist/index.esm.js",
+ "types": "dist/index.d.ts"
+ },
+ "backstage": {
+ "role": "frontend-plugin"
+ },
+ "sideEffects": false,
+ "scripts": {
+ "start": "backstage-cli package start",
+ "build": "backstage-cli package build",
+ "lint": "backstage-cli package lint",
+ "test": "backstage-cli package test",
+ "clean": "backstage-cli package clean",
+ "prepack": "backstage-cli package prepack",
+ "postpack": "backstage-cli package postpack"
+ },
+ "dependencies": {
+ "@backstage/core-components": "^0.14.8",
+ "@backstage/core-plugin-api": "^1.9.3",
+ "@backstage/theme": "^0.5.6",
+ "@material-ui/core": "^4.9.13",
+ "@material-ui/icons": "^4.9.1",
+ "@material-ui/lab": "4.0.0-alpha.61",
+ "react-use": "^17.2.4"
+ },
+ "peerDependencies": {
+ "react": "^16.13.1 || ^17.0.0 || ^18.0.0"
+ },
+ "devDependencies": {
+ "@backstage/cli": "^0.26.10",
+ "@backstage/core-app-api": "^1.13.0",
+ "@backstage/dev-utils": "^1.0.34",
+ "@backstage/test-utils": "^1.5.7",
+ "@testing-library/jest-dom": "^6.0.0",
+ "@testing-library/react": "^14.0.0",
+ "@testing-library/user-event": "^14.0.0",
+ "msw": "^1.0.0",
+ "react": "^16.13.1 || ^17.0.0 || ^18.0.0"
+ },
+ "files": [
+ "dist",
+ "config.d.ts"
+ ],
+ "configSchema": "config.d.ts"
+}
diff --git a/plugins/plausible/src/components/PlausibleAnalytics.tsx b/plugins/plausible/src/components/PlausibleAnalytics.tsx
new file mode 100644
index 0000000..c2ec17c
--- /dev/null
+++ b/plugins/plausible/src/components/PlausibleAnalytics.tsx
@@ -0,0 +1,20 @@
+import { useApi, configApiRef } from '@backstage/core-plugin-api';
+import React from 'react';
+
+export const PlausibleAnalytics = () => {
+ const config = useApi(configApiRef);
+ const enabled = config.getOptionalBoolean('plausible.enabled') ?? false;
+ const domain = config.getOptionalString('plausible.domain');
+
+ if (!enabled || !domain) {
+ return null;
+ }
+
+ return (
+
+ );
+};
diff --git a/plugins/plausible/src/index.ts b/plugins/plausible/src/index.ts
new file mode 100644
index 0000000..6460e13
--- /dev/null
+++ b/plugins/plausible/src/index.ts
@@ -0,0 +1,2 @@
+export { PlausibleAnalytics } from './components/PlausibleAnalytics';
+export { plausiblePlugin } from './plugin';
diff --git a/plugins/plausible/src/plugin.test.tsx b/plugins/plausible/src/plugin.test.tsx
new file mode 100644
index 0000000..84b8f73
--- /dev/null
+++ b/plugins/plausible/src/plugin.test.tsx
@@ -0,0 +1,58 @@
+import React from 'react';
+import { render } from '@testing-library/react';
+import { ConfigApi, configApiRef } from '@backstage/core-plugin-api';
+import { TestApiProvider } from '@backstage/test-utils';
+import { PlausibleAnalytics } from './components/PlausibleAnalytics';
+import { ConfigReader } from '@backstage/core-app-api';
+
+describe('PlausibleAnalytics', () => {
+ const mockConfigApi = (config: object): ConfigApi => {
+ return ConfigReader.fromConfigs([
+ { data: config, context: 'mock-context' },
+ ]);
+ };
+
+ it('renders nothing when plausible is disabled', () => {
+ const config = mockConfigApi({ plausible: { enabled: false } });
+ const { container } = render(
+
+
+ ,
+ );
+ expect(container.firstChild).toBeNull();
+ });
+
+ it('renders nothing when domain is provided but disabled', () => {
+ const config = mockConfigApi({
+ plausible: { enabled: false, domain: 'example.com' },
+ });
+ const { container } = render(
+
+
+ ,
+ );
+ expect(container.firstChild).toBeNull();
+ });
+
+ it('renders script tag when plausible is enabled and domain is provided', () => {
+ const config = mockConfigApi({
+ plausible: {
+ enabled: true,
+ domain: 'example.com',
+ },
+ });
+ const { container } = render(
+
+
+ ,
+ );
+ const scriptTag = container.querySelector('script');
+ expect(scriptTag).toBeInTheDocument();
+ expect(scriptTag).toHaveAttribute('data-domain', 'example.com');
+ expect(scriptTag).toHaveAttribute(
+ 'src',
+ 'https://plausible.io/js/script.js',
+ );
+ expect(scriptTag).toHaveAttribute('defer');
+ });
+});
diff --git a/plugins/plausible/src/plugin.ts b/plugins/plausible/src/plugin.ts
new file mode 100644
index 0000000..a790648
--- /dev/null
+++ b/plugins/plausible/src/plugin.ts
@@ -0,0 +1,10 @@
+import { createPlugin } from '@backstage/core-plugin-api';
+
+import { rootRouteRef } from './routes';
+
+export const plausiblePlugin = createPlugin({
+ id: 'plausible',
+ routes: {
+ root: rootRouteRef,
+ },
+});
diff --git a/plugins/plausible/src/routes.ts b/plugins/plausible/src/routes.ts
new file mode 100644
index 0000000..b4311ed
--- /dev/null
+++ b/plugins/plausible/src/routes.ts
@@ -0,0 +1,5 @@
+import { createRouteRef } from '@backstage/core-plugin-api';
+
+export const rootRouteRef = createRouteRef({
+ id: 'plausible',
+});
diff --git a/plugins/plausible/src/setupTests.ts b/plugins/plausible/src/setupTests.ts
new file mode 100644
index 0000000..7b0828b
--- /dev/null
+++ b/plugins/plausible/src/setupTests.ts
@@ -0,0 +1 @@
+import '@testing-library/jest-dom';
diff --git a/yarn.lock b/yarn.lock
index 9f7b50c..c29abb4 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3349,6 +3349,30 @@ __metadata:
languageName: node
linkType: hard
+"@backstage/dev-utils@npm:^1.0.34":
+ version: 1.0.34
+ resolution: "@backstage/dev-utils@npm:1.0.34"
+ dependencies:
+ "@backstage/app-defaults": "npm:^1.5.7"
+ "@backstage/catalog-model": "npm:^1.5.0"
+ "@backstage/core-app-api": "npm:^1.13.0"
+ "@backstage/core-components": "npm:^0.14.8"
+ "@backstage/core-plugin-api": "npm:^1.9.3"
+ "@backstage/integration-react": "npm:^1.1.28"
+ "@backstage/plugin-catalog-react": "npm:^1.12.1"
+ "@backstage/theme": "npm:^0.5.6"
+ "@material-ui/core": "npm:^4.12.2"
+ "@material-ui/icons": "npm:^4.9.1"
+ "@types/react": "npm:^16.13.1 || ^17.0.0 || ^18.0.0"
+ react-use: "npm:^17.2.4"
+ peerDependencies:
+ react: ^16.13.1 || ^17.0.0 || ^18.0.0
+ react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0
+ react-router-dom: 6.0.0-beta.0 || ^6.3.0
+ checksum: 10c0/a1affd1bd6a3457f4e25b4a254498db5ee74dcc6b308d9444ad8959b622347e24d66be8a1271b48a6eac266a7cbd3d2fb5dde3a4e8c927ebadddee5be8058657
+ languageName: node
+ linkType: hard
+
"@backstage/e2e-test-utils@npm:^0.1.1":
version: 0.1.1
resolution: "@backstage/e2e-test-utils@npm:0.1.1"
@@ -6111,6 +6135,31 @@ __metadata:
languageName: node
linkType: hard
+"@internal/backstage-plugin-plausible@npm:^0.1.0, @internal/backstage-plugin-plausible@workspace:plugins/plausible":
+ version: 0.0.0-use.local
+ resolution: "@internal/backstage-plugin-plausible@workspace:plugins/plausible"
+ dependencies:
+ "@backstage/cli": "npm:^0.26.10"
+ "@backstage/core-app-api": "npm:^1.13.0"
+ "@backstage/core-components": "npm:^0.14.8"
+ "@backstage/core-plugin-api": "npm:^1.9.3"
+ "@backstage/dev-utils": "npm:^1.0.34"
+ "@backstage/test-utils": "npm:^1.5.7"
+ "@backstage/theme": "npm:^0.5.6"
+ "@material-ui/core": "npm:^4.9.13"
+ "@material-ui/icons": "npm:^4.9.1"
+ "@material-ui/lab": "npm:4.0.0-alpha.61"
+ "@testing-library/jest-dom": "npm:^6.0.0"
+ "@testing-library/react": "npm:^14.0.0"
+ "@testing-library/user-event": "npm:^14.0.0"
+ msw: "npm:^1.0.0"
+ react: "npm:^16.13.1 || ^17.0.0 || ^18.0.0"
+ react-use: "npm:^17.2.4"
+ peerDependencies:
+ react: ^16.13.1 || ^17.0.0 || ^18.0.0
+ languageName: unknown
+ linkType: soft
+
"@ioredis/commands@npm:^1.1.1":
version: 1.2.0
resolution: "@ioredis/commands@npm:1.2.0"
@@ -6988,6 +7037,32 @@ __metadata:
languageName: node
linkType: hard
+"@mswjs/cookies@npm:^0.2.2":
+ version: 0.2.2
+ resolution: "@mswjs/cookies@npm:0.2.2"
+ dependencies:
+ "@types/set-cookie-parser": "npm:^2.4.0"
+ set-cookie-parser: "npm:^2.4.6"
+ checksum: 10c0/f950062538d431674d581309cf19884fc4d3f57e2a276164cac0c9a3250071d42464ba7825d13be14c703ca5a912d62a62626f4a068d8f36d1629dbb63bde740
+ languageName: node
+ linkType: hard
+
+"@mswjs/interceptors@npm:^0.17.10":
+ version: 0.17.10
+ resolution: "@mswjs/interceptors@npm:0.17.10"
+ dependencies:
+ "@open-draft/until": "npm:^1.0.3"
+ "@types/debug": "npm:^4.1.7"
+ "@xmldom/xmldom": "npm:^0.8.3"
+ debug: "npm:^4.3.3"
+ headers-polyfill: "npm:3.2.5"
+ outvariant: "npm:^1.2.1"
+ strict-event-emitter: "npm:^0.2.4"
+ web-encoding: "npm:^1.1.5"
+ checksum: 10c0/0343a93711b60c321c40733d6bf2720a736d8e0730f5d0d9916ee4a24abfcfca4a83d1e4b2e21c3affef4fc61f04588104be002fbc8258dc4b0d202c384ade33
+ languageName: node
+ linkType: hard
+
"@mui/base@npm:5.0.0-beta.40, @mui/base@npm:^5.0.0-beta.40":
version: 5.0.0-beta.40
resolution: "@mui/base@npm:5.0.0-beta.40"
@@ -8272,6 +8347,13 @@ __metadata:
languageName: node
linkType: hard
+"@open-draft/until@npm:^1.0.3":
+ version: 1.0.3
+ resolution: "@open-draft/until@npm:1.0.3"
+ checksum: 10c0/f88bcd774b55359d14a4fa80f7bfe7d9d6d26a5995e94e823e43b211656daae3663e983f0a996937da286d22f6f5da2087b661845302f236ba27f8529dcd14fb
+ languageName: node
+ linkType: hard
+
"@openapi-contrib/openapi-schema-to-json-schema@npm:~3.2.0":
version: 3.2.0
resolution: "@openapi-contrib/openapi-schema-to-json-schema@npm:3.2.0"
@@ -11511,6 +11593,13 @@ __metadata:
languageName: node
linkType: hard
+"@types/cookie@npm:^0.4.1":
+ version: 0.4.1
+ resolution: "@types/cookie@npm:0.4.1"
+ checksum: 10c0/f96afe12bd51be1ec61410b0641243d93fa3a494702407c787a4c872b5c8bcd39b224471452055e44a9ce42af1a636e87d161994226eaf4c2be9c30f60418409
+ languageName: node
+ linkType: hard
+
"@types/cors@npm:^2.8.6":
version: 2.8.17
resolution: "@types/cors@npm:2.8.17"
@@ -11719,6 +11808,13 @@ __metadata:
languageName: node
linkType: hard
+"@types/js-levenshtein@npm:^1.1.1":
+ version: 1.1.3
+ resolution: "@types/js-levenshtein@npm:1.1.3"
+ checksum: 10c0/025f2bd8d865cfa7a996799a1a2f2a77fa2fc74a28971aa035a103de35d7c1e3d949721a88f57fdb532815bbcb2bf7019196a608ed0a8bbd1023d64c52bb251b
+ languageName: node
+ linkType: hard
+
"@types/js-yaml@npm:^4.0.1":
version: 4.0.9
resolution: "@types/js-yaml@npm:4.0.9"
@@ -12116,6 +12212,15 @@ __metadata:
languageName: node
linkType: hard
+"@types/set-cookie-parser@npm:^2.4.0":
+ version: 2.4.9
+ resolution: "@types/set-cookie-parser@npm:2.4.9"
+ dependencies:
+ "@types/node": "npm:*"
+ checksum: 10c0/98db3e78a5181ecc7f855816bdc9c66cd7c0299766124b537b3dd777c8a76824d1d67e9fc6ecb7ec19230940f71ffb919360d8c5520554027e85e037163ff064
+ languageName: node
+ linkType: hard
+
"@types/sockjs@npm:^0.3.36":
version: 0.3.36
resolution: "@types/sockjs@npm:0.3.36"
@@ -12689,7 +12794,7 @@ __metadata:
languageName: node
linkType: hard
-"@xmldom/xmldom@npm:^0.8.5, @xmldom/xmldom@npm:^0.8.6, @xmldom/xmldom@npm:^0.8.8":
+"@xmldom/xmldom@npm:^0.8.3, @xmldom/xmldom@npm:^0.8.5, @xmldom/xmldom@npm:^0.8.6, @xmldom/xmldom@npm:^0.8.8":
version: 0.8.10
resolution: "@xmldom/xmldom@npm:0.8.10"
checksum: 10c0/c7647c442502720182b0d65b17d45d2d95317c1c8c497626fe524bda79b4fb768a9aa4fae2da919f308e7abcff7d67c058b102a9d641097e9a57f0b80187851f
@@ -12755,6 +12860,13 @@ __metadata:
languageName: node
linkType: hard
+"@zxing/text-encoding@npm:0.9.0":
+ version: 0.9.0
+ resolution: "@zxing/text-encoding@npm:0.9.0"
+ checksum: 10c0/d15bff181d46c2ab709e7242801a8d40408aa8c19b44462e5f60e766bf59105b44957914ab6baab60d10d466a5e965f21fe890c67dfdb7d5c7f940df457b4d0d
+ languageName: node
+ linkType: hard
+
"JSONStream@npm:^1.3.5":
version: 1.3.5
resolution: "JSONStream@npm:1.3.5"
@@ -13163,6 +13275,7 @@ __metadata:
"@emotion/react": "npm:^11.11.4"
"@emotion/styled": "npm:^11.11.5"
"@fontsource/inter": "npm:^5.0.18"
+ "@internal/backstage-plugin-plausible": "npm:^0.1.0"
"@mui/icons-material": "npm:^5.15.19"
"@mui/joy": "npm:^5.0.0-beta.36"
"@mui/material": "npm:^5.15.19"
@@ -15454,6 +15567,13 @@ __metadata:
languageName: node
linkType: hard
+"cookie@npm:^0.4.2":
+ version: 0.4.2
+ resolution: "cookie@npm:0.4.2"
+ checksum: 10c0/beab41fbd7c20175e3a2799ba948c1dcc71ef69f23fe14eeeff59fc09f50c517b0f77098db87dbb4c55da802f9d86ee86cdc1cd3efd87760341551838d53fca2
+ languageName: node
+ linkType: hard
+
"copy-to-clipboard@npm:^3.2.0, copy-to-clipboard@npm:^3.3.1":
version: 3.3.3
resolution: "copy-to-clipboard@npm:3.3.3"
@@ -17873,7 +17993,7 @@ __metadata:
languageName: node
linkType: hard
-"events@npm:3.3.0, events@npm:^3.0.0, events@npm:^3.2.0":
+"events@npm:3.3.0, events@npm:^3.0.0, events@npm:^3.2.0, events@npm:^3.3.0":
version: 3.3.0
resolution: "events@npm:3.3.0"
checksum: 10c0/d6b6f2adbccbcda74ddbab52ed07db727ef52e31a61ed26db9feb7dc62af7fc8e060defa65e5f8af9449b86b52cc1a1f6a79f2eafcf4e62add2b7a1fa4a432f6
@@ -19399,6 +19519,13 @@ __metadata:
languageName: node
linkType: hard
+"graphql@npm:^16.8.1":
+ version: 16.9.0
+ resolution: "graphql@npm:16.9.0"
+ checksum: 10c0/a8850f077ff767377237d1f8b1da2ec70aeb7623cdf1dfc9e1c7ae93accc0c8149c85abe68923be9871a2934b1bce5a2496f846d4d56e1cfb03eaaa7ddba9b6a
+ languageName: node
+ linkType: hard
+
"gtoken@npm:^7.0.0":
version: 7.1.0
resolution: "gtoken@npm:7.1.0"
@@ -19610,6 +19737,13 @@ __metadata:
languageName: node
linkType: hard
+"headers-polyfill@npm:3.2.5":
+ version: 3.2.5
+ resolution: "headers-polyfill@npm:3.2.5"
+ checksum: 10c0/10202f4ebfaecd6aa31305f29664f876ac01d9174a3fb8fcc5a0df3eaf9c1767fb0d6cf6f961484f2bfd2101b6768090976f146bd88aeedd07af4e741cb2dcb7
+ languageName: node
+ linkType: hard
+
"helmet@npm:^6.0.0":
version: 6.2.0
resolution: "helmet@npm:6.2.0"
@@ -20610,6 +20744,13 @@ __metadata:
languageName: node
linkType: hard
+"is-node-process@npm:^1.2.0":
+ version: 1.2.0
+ resolution: "is-node-process@npm:1.2.0"
+ checksum: 10c0/5b24fda6776d00e42431d7bcd86bce81cb0b6cabeb944142fe7b077a54ada2e155066ad06dbe790abdb397884bdc3151e04a9707b8cd185099efbc79780573ed
+ languageName: node
+ linkType: hard
+
"is-number-object@npm:^1.0.4":
version: 1.0.7
resolution: "is-number-object@npm:1.0.7"
@@ -21609,6 +21750,13 @@ __metadata:
languageName: node
linkType: hard
+"js-levenshtein@npm:^1.1.6":
+ version: 1.1.6
+ resolution: "js-levenshtein@npm:1.1.6"
+ checksum: 10c0/14045735325ea1fd87f434a74b11d8a14380f090f154747e613529c7cff68b5ee607f5230fa40665d5fb6125a3791f4c223f73b9feca754f989b059f5c05864f
+ languageName: node
+ linkType: hard
+
"js-tokens@npm:^3.0.0 || ^4.0.0, js-tokens@npm:^4.0.0":
version: 4.0.0
resolution: "js-tokens@npm:4.0.0"
@@ -24178,6 +24326,40 @@ __metadata:
languageName: node
linkType: hard
+"msw@npm:^1.0.0":
+ version: 1.3.3
+ resolution: "msw@npm:1.3.3"
+ dependencies:
+ "@mswjs/cookies": "npm:^0.2.2"
+ "@mswjs/interceptors": "npm:^0.17.10"
+ "@open-draft/until": "npm:^1.0.3"
+ "@types/cookie": "npm:^0.4.1"
+ "@types/js-levenshtein": "npm:^1.1.1"
+ chalk: "npm:^4.1.1"
+ chokidar: "npm:^3.4.2"
+ cookie: "npm:^0.4.2"
+ graphql: "npm:^16.8.1"
+ headers-polyfill: "npm:3.2.5"
+ inquirer: "npm:^8.2.0"
+ is-node-process: "npm:^1.2.0"
+ js-levenshtein: "npm:^1.1.6"
+ node-fetch: "npm:^2.6.7"
+ outvariant: "npm:^1.4.0"
+ path-to-regexp: "npm:^6.2.0"
+ strict-event-emitter: "npm:^0.4.3"
+ type-fest: "npm:^2.19.0"
+ yargs: "npm:^17.3.1"
+ peerDependencies:
+ typescript: ">= 4.4.x"
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ bin:
+ msw: cli/index.js
+ checksum: 10c0/0c63b282a53a1a69194729bf9cb77005a682dfbbb1dac6b1a33c9bfecde7f6df1dfaabdff9336b97ed6c29ebd52d6debdae7e506d7baa8eb8fd1e05683dbc398
+ languageName: node
+ linkType: hard
+
"multer@npm:^1.4.5-lts.1":
version: 1.4.5-lts.1
resolution: "multer@npm:1.4.5-lts.1"
@@ -25325,6 +25507,13 @@ __metadata:
languageName: node
linkType: hard
+"outvariant@npm:^1.2.1, outvariant@npm:^1.4.0":
+ version: 1.4.3
+ resolution: "outvariant@npm:1.4.3"
+ checksum: 10c0/5976ca7740349cb8c71bd3382e2a762b1aeca6f33dc984d9d896acdf3c61f78c3afcf1bfe9cc633a7b3c4b295ec94d292048f83ea2b2594fae4496656eba992c
+ languageName: node
+ linkType: hard
+
"p-cancelable@npm:^2.0.0":
version: 2.1.1
resolution: "p-cancelable@npm:2.1.1"
@@ -27689,7 +27878,7 @@ __metadata:
languageName: node
linkType: hard
-"react@npm:^18.0.2":
+"react@npm:^16.13.1 || ^17.0.0 || ^18.0.0, react@npm:^18.0.2":
version: 18.3.1
resolution: "react@npm:18.3.1"
dependencies:
@@ -28922,6 +29111,13 @@ __metadata:
languageName: node
linkType: hard
+"set-cookie-parser@npm:^2.4.6":
+ version: 2.6.0
+ resolution: "set-cookie-parser@npm:2.6.0"
+ checksum: 10c0/739da029f0e56806a103fcd5501d9c475e19e77bd8274192d7ae5c374ae714a82bba9a7ac00b0330a18227c5644b08df9e442240527be578f5a6030f9bb2bb80
+ languageName: node
+ linkType: hard
+
"set-function-length@npm:^1.2.1":
version: 1.2.2
resolution: "set-function-length@npm:1.2.2"
@@ -29664,6 +29860,22 @@ __metadata:
languageName: node
linkType: hard
+"strict-event-emitter@npm:^0.2.4":
+ version: 0.2.8
+ resolution: "strict-event-emitter@npm:0.2.8"
+ dependencies:
+ events: "npm:^3.3.0"
+ checksum: 10c0/6891e19fea4f0289e4da2fe7050d85906eaca7f774aa38fe674f0e58fdece1b63b868614fa23974c4cb862aa99358caa987523b705fdfff4639231c62e384394
+ languageName: node
+ linkType: hard
+
+"strict-event-emitter@npm:^0.4.3":
+ version: 0.4.6
+ resolution: "strict-event-emitter@npm:0.4.6"
+ checksum: 10c0/d0231ef081cb1937b1445da59a1ec202d1c097d825c504f398600532490a4104e200b0dce4137467a8eaac5f8f9718d01c99869687afad78cad3b14c4b2e6a39
+ languageName: node
+ linkType: hard
+
"strict-uri-encode@npm:^2.0.0":
version: 2.0.0
resolution: "strict-uri-encode@npm:2.0.0"
@@ -31856,6 +32068,19 @@ __metadata:
languageName: node
linkType: hard
+"web-encoding@npm:^1.1.5":
+ version: 1.1.5
+ resolution: "web-encoding@npm:1.1.5"
+ dependencies:
+ "@zxing/text-encoding": "npm:0.9.0"
+ util: "npm:^0.12.3"
+ dependenciesMeta:
+ "@zxing/text-encoding":
+ optional: true
+ checksum: 10c0/59d5413338ec0894c690006f5d8508b0c88cae1d8c78606c3f326e351c672196461ed808b849fe08d0900fa56a61fcacb9ff576499068d2ead0a7bc04afa7d34
+ languageName: node
+ linkType: hard
+
"web-streams-polyfill@npm:^3.0.3":
version: 3.3.3
resolution: "web-streams-polyfill@npm:3.3.3"