Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
JonathanTurnock committed Aug 16, 2024
0 parents commit 227b9d5
Show file tree
Hide file tree
Showing 94 changed files with 33,228 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules
dist
.env
Dockerfile
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
node_modules/
/packages/api-client/dist/
build
**/*.sqlite
.idea
dist
1 change: 1 addition & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
registry=https://registry.npmjs.org/
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
18
10 changes: 10 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
FROM ubuntu:22.04
ENV WC__DATABASE=/var/lib/db.sqlite

COPY ./build/watchtower-linux /usr/local/bin/watchtower

RUN chmod +x /usr/local/bin/watchtower

VOLUME /var/lib

ENTRYPOINT ["/usr/local/bin/watchtower"]
24 changes: 24 additions & 0 deletions apps/client/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
50 changes: 50 additions & 0 deletions apps/client/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# React + TypeScript + Vite

This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.

Currently, two official plugins are available:

- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh

## Expanding the ESLint configuration

If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:

- Configure the top-level `parserOptions` property like this:

```js
export default tseslint.config({
languageOptions: {
// other options...
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
},
})
```

- Replace `tseslint.configs.recommended` to `tseslint.configs.recommendedTypeChecked` or `tseslint.configs.strictTypeChecked`
- Optionally add `...tseslint.configs.stylisticTypeChecked`
- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and update the config:

```js
// eslint.config.js
import react from 'eslint-plugin-react'

export default tseslint.config({
// Set the react version
settings: { react: { version: '18.3' } },
plugins: {
// Add the react plugin
react,
},
rules: {
// other rules...
// Enable its recommended rules
...react.configs.recommended.rules,
...react.configs['jsx-runtime'].rules,
},
})
```
26 changes: 26 additions & 0 deletions apps/client/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import tseslint from 'typescript-eslint'

export default tseslint.config({
extends: [js.configs.recommended, ...tseslint.configs.recommended],
files: ['**/*.{ts,tsx}'],
ignores: ['dist'],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
},
plugins: {
'react-hooks': reactHooks,
'react-refresh': reactRefresh,
},
rules: {
...reactHooks.configs.recommended.rules,
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
},
})
13 changes: 13 additions & 0 deletions apps/client/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Watchtower</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
62 changes: 62 additions & 0 deletions apps/client/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
{
"name": "@watchtower/client",
"private": true,
"version": "0.0.1",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"lint": "eslint .",
"preview": "vite preview"
},
"dependencies": {
"@mantine/charts": "^7.12.1",
"@mantine/core": "^7.12.1",
"@mantine/dates": "^7.12.1",
"@mantine/form": "^7.12.1",
"@mantine/hooks": "^7.12.1",
"@mantine/modals": "^7.12.1",
"@mantine/notifications": "^7.12.1",
"@mantine/tiptap": "^7.12.1",
"@monaco-editor/react": "4.6.0",
"@tabler/icons-react": "^3.12.0",
"@tiptap/extension-link": "^2.6.4",
"@tiptap/pm": "^2.6.4",
"@tiptap/react": "^2.6.4",
"@tiptap/starter-kit": "^2.6.4",
"@types/json-schema": "^7.0.15",
"@types/lodash": "^4.17.7",
"@types/ms": "^0.7.34",
"@watchtower/api-client": "^0.0.1",
"axios": "^1.7.4",
"date-fns": "^3.6.0",
"dayjs": "^1.11.12",
"dracula-mantine": "^1.1.0",
"fuse.js": "^7.0.0",
"lodash": "^4.17.21",
"mantine-form-zod-resolver": "^1.1.0",
"marked": "^14.0.0",
"monaco-editor": "^0.50.0",
"ms": "^2.1.3",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-icons": "^5.2.1",
"react-router-dom": "^6.26.0",
"recharts": "^2.12.7",
"zod": "^3.23.8",
"zod-to-json-schema": "^3.23.2"
},
"devDependencies": {
"@eslint/js": "^9.8.0",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@vitejs/plugin-react": "^4.3.1",
"eslint": "^9.8.0",
"eslint-plugin-react-hooks": "^5.1.0-rc.0",
"eslint-plugin-react-refresh": "^0.4.9",
"globals": "^15.9.0",
"typescript": "^5.5.3",
"typescript-eslint": "^8.0.0",
"vite": "^5.4.0"
}
}
1 change: 1 addition & 0 deletions apps/client/public/vite.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
147 changes: 147 additions & 0 deletions apps/client/src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
import {
ActionIcon,
AppShell,
Burger,
Card,
Group,
Text,
ThemeIcon,
useMantineColorScheme,
useMantineTheme,
} from "@mantine/core";
import { useDisclosure } from "@mantine/hooks";
import { FC } from "react";
import { FaWatchmanMonitoring } from "react-icons/fa";
import {
TbActivityHeartbeat,
TbAlertHexagon,
TbCircle,
TbCircleFilled,
TbCircleHalf,
TbShare,
} from "react-icons/tb";
import { Route, Routes } from "react-router-dom";
import { AppNavigationButton } from "./components/app-navigation-button.tsx";
import { AppNavigationLink } from "./components/app-navigation-link.tsx";
import { MonitorEditPage } from "./pages/monitor-edit.page.tsx";
import { MonitorPage } from "./pages/monitor.page.tsx";
import { MonitorsPage } from "./pages/monitors.page.tsx";

const navigation = [
{
path: "/monitors",
label: "Monitoring",
leftSection: <TbActivityHeartbeat />,
},
{
path: "/incidents",
label: "Incidents",
leftSection: <TbAlertHexagon />,
},
{
path: "/integrations",
label: "Integrations",
leftSection: <TbShare />,
},
];

export const App: FC = () => {
const theme = useMantineTheme();
const scheme = useMantineColorScheme();
const [opened, { toggle }] = useDisclosure();

return (
<AppShell
header={{ height: 82 }}
navbar={{
width: 300,
breakpoint: "md",
collapsed: { desktop: true, mobile: !opened },
}}
>
<AppShell.Header
bg={
scheme.colorScheme === "dark"
? theme.colors.dark[8]
: theme.colors.gray[2]
}
withBorder={false}
>
<Card style={{ borderRadius: 0, height: 82 }}>
<Group h={"100%"} align={"center"} justify={"space-between"}>
<Group gap={"sm"}>
<ThemeIcon
variant={"transparent"}
gradient={{ from: "orange", to: "pink" }}
>
<FaWatchmanMonitoring size={32} />
</ThemeIcon>
<Text
style={{
userSelect: "none",
fontSize: "xx-large",
fontFamily: "Portentous Distorted",
}}
variant="gradient"
gradient={{ from: "orange", to: "pink" }}
>
watchtower
</Text>
</Group>
<Burger
opened={opened}
onClick={toggle}
hiddenFrom="md"
size="sm"
/>
<Group visibleFrom={"md"}>
{navigation.map(({ path, label, leftSection }) => (
<AppNavigationButton
key={path}
path={path}
label={label}
leftSection={leftSection}
/>
))}
<ActionIcon
variant={"default"}
onClick={scheme.toggleColorScheme}
>
{scheme.colorScheme === "auto" ? (
<TbCircleHalf />
) : scheme.colorScheme === "light" ? (
<TbCircle />
) : (
<TbCircleFilled />
)}
</ActionIcon>
</Group>
</Group>
</Card>
</AppShell.Header>
<AppShell.Main
bg={
scheme.colorScheme === "dark"
? theme.colors.dark[8]
: theme.colors.gray[1]
}
>
<Routes>
<Route path={"/monitors"} element={<MonitorsPage />} />
<Route path={"/monitors/:id/edit"} element={<MonitorEditPage />} />
<Route path={"/monitors/:id"} element={<MonitorPage />} />
</Routes>
</AppShell.Main>
<AppShell.Navbar>
{navigation.map(({ path, label, leftSection }) => (
<AppNavigationLink
key={path}
path={path}
label={label}
leftSection={leftSection}
/>
))}
</AppShell.Navbar>
</AppShell>
);
};
Binary file added apps/client/src/assets/Portentous Distorted.otf
Binary file not shown.
6 changes: 6 additions & 0 deletions apps/client/src/assets/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
@font-face {
font-family: 'Portentous Distorted';
src:
local('Portentous Distorted'),
url('./Portentous Distorted.otf') format('opentype');
}
23 changes: 23 additions & 0 deletions apps/client/src/components/app-navigation-button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Button } from "@mantine/core";
import { FC, ReactNode } from "react";
import { useLocation, useNavigate } from "react-router-dom";

export const AppNavigationButton: FC<{
path: string;
label: ReactNode;
leftSection: ReactNode;
}> = ({ label, path, leftSection }) => {
const navigate = useNavigate();
const location = useLocation();

return (
<Button
justify={"start"}
variant={location.pathname.startsWith(path) ? "outline" : "subtle"}
onClick={() => navigate(path)}
leftSection={leftSection}
>
{label}
</Button>
);
};
Loading

0 comments on commit 227b9d5

Please sign in to comment.