diff --git a/dashboard/README.md b/dashboard/README.md
index ef3fbb7d9..1b423fcb3 100644
--- a/dashboard/README.md
+++ b/dashboard/README.md
@@ -1,60 +1,193 @@
+# ๐ Komiser Dashboard
+
Komiser dashboard is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
-Full frontend stack: `Next.js`, `Typescript`, `Tailwind`, `Storybook`, `Jest` & `React Testing Library.`
+**Full frontend stack:**
+
+- ๐ฅ [`Next.js`](https://nextjs.org/)
+- ๐ [`Typescript`](https://www.typescriptlang.org/)
+- ๐จ [`Tailwind`](https://tailwindcss.com/)
+- ๐ [`Storybook`](https://storybook.js.org/)
+- ๐งช [`Jest`](https://jestjs.io/)
+- ๐ [`React Testing Library`](https://testing-library.com/docs/react-testing-library/intro)
-## Getting Started
+## ๐ Getting Started
Follow the [Contribution Guide](https://github.com/tailwarden/komiser/blob/develop/CONTRIBUTING.md#contributing-to-komiser-dashboard-ui) first if you haven't done so already. Then come back here and follow the next steps:
-1. Run the development server:
+#### 1. Run the development server:
-```bash
-# From the Komiser root folder start the Komiser server, run:
-go run *.go start --config /path/to/config.toml
+From the Komiser root folder start the Komiser server by running:
+
+```shell
+go run \*.go start --config /path/to/config.toml
+```
+
+In a different terminal tab navigate to the `/dashboard` folder:
+
+```shell
+cd dashboard
+```
+
+and run:
+
+```shell
+npm install
-# In a different terminal tab in the dashboard folder, run:
NEXT_PUBLIC_API_URL=http://localhost:3000 npm run dev
+```
+
+Alternatively, you can create an .env file with it, either manually or by running:
-# Alternatively, you can create an .env file with it:
-NEXT_PUBLIC_API_URL=http://localhost:3000
+```shell
+echo "NEXT_PUBLIC_API_URL=http://localhost:3000" > .env
```
-2. Open [http://localhost:3002/](http://localhost:3002). If you see the dashboard, congrats! It's all up and running correctly.
-
+and simply run:
-> If you get an error page such as this, please refer to the logs and our [docs](https://docs.komiser.io/docs/introduction/getting-started).
->
+```shell
+npm run dev
+```
+
+#### 2. Open [http://localhost:3002/](http://localhost:3002). If you see the dashboard, ๐ congrats! It's all up and running correctly.
-## Components
+โ If you get an error page such as this, please refer to the logs and our [docs](https://docs.komiser.io/docs/introduction/getting-started).
+
+
+## ๐งฉ Components
Komiser components are documented under `/components`
+> ๐ก **Hint:**
+> We have the following import aliases defined in `tsconfig.json`
+>
+> ```json
+> {
+> "@components/": "/dashboard/components/",
+> "@services/": "/dashboard/services/",
+> "@environments/": "/dashboard/environments/",
+> "@utils/": "/dashboard/utils/",
+> "@styles/": "/dashboard/styles/"
+> }
+> ```
+
You can find all the shared Components also inside [Storybook](https://storybook.komiser.io/). If you're implementing a new Story, please check for existing or new components with Storybook.
We will require a story for new shared components like icons, inputs or similar.
-Component convention:
+**Component convention:**
-- Component folder: component name in `kebab-case`
-- Component file: component name in `UpperCamelCase.*`
-- Component story: component name in `UpperCamelCase.stories.*`
-- Component story mock (if needed): component name in `UpperCamelCase.mocks.*`
-- Component unit test: component name in `UpperCamelCase.test.*`
-- Check `Card` example for more details:
+- ๐ Component folder: component name in `kebab-case`
+- ๐ Component file: component name in `UpperCamelCase.*`
+- ๐ Component story: component name in `UpperCamelCase.stories.*`
+- ๐ญ Component story mock (if needed): component name in `UpperCamelCase.mocks.*`
+- ๐งช Component unit test: component name in `UpperCamelCase.test.*`
+- ๐ง Check `Card` example for more details:
-
+
-Additional instructions:
+**Additional instructions:**
+
+- ๐ To view this component on Storybook, run: `npm run storybook`, then pick `Card`
+
+
+
+- ๐งช To run the unit tests, run: `npm run test:watch`, hit `p`, then `card`
+
+
+
+## ๐งช Testing
+
+We use Jest & React Testing Library for our unit tests.
+
+- To run the unit tests, run: `npm run test`
+
+**Testing convention:**
+
+- โ
All new Utils need to be tested. Existing ones when being changed
+- โ
All tests should be wrapped in a `describe`
+- โ
If it's a unit test for a function: `describe('[replace with function name]', () => { ... })`
+- โ
If it's a unit test for a util: `describe('[replace with util name] util', () => { ... })`
+- โ
If it's a unit test for a component: `describe('[replace with component name]', () => { ... })`
+- โ
A test should use 'it' for the test function: `it('should do something', () => { ... })`
+
+**Testing examples:**
+
+- Simple Jest unit test example (snippet from `/utils/formatNumber.test.ts`):
+
+```typescript
+import formatNumber from './formatNumber';
+
+describe('formatNumber util', () => {
+ it('should format number (over a thousand) in short notation', () => {
+ const result = formatNumber(12345);
+ expect(result).toBe('12K');
+ });
+ ...
+});
+```
+
+- Jest & Testing library example (snippet from `/components/card/Card.test.tsx`):
+
+```typescript
+import { render, screen } from '@testing-library/react';
+import RefreshIcon from '../icons/RefreshIcon';
+import Card from './Card';
+
+describe('Card', () => {
+ it('should render card component without crashing', () => {
+ render(
+ }
+ />
+ );
+ });
+
+ it('should display the value formatted', () => {
+ render(
+ }
+ />
+ );
+ const formattedNumber = screen.getByTestId('formattedNumber');
+ expect(formattedNumber).toHaveTextContent('5K');
+ });
+ ...
+});
+```
-- To view this component on Storybook locally, run: `npm run storybook`, then pick `Card`
-
+If you're looking for an example with event firing and state updates, have a look at `components/select-checkbox/SelectCheckbox.test.tsx`:
-- To run the unit tests, run: `npm run test:watch`, hit `p`, then `card`
-
+```typescript
+it('opens the dropdown when clicked', () => {
+ const { getByRole, getByText } = render(
+ {}}
+ />
+ );
+
+ fireEvent.click(getByRole('button'));
+
+ expect(getByText('Item 1')).toBeInTheDocument();
+ expect(getByText('Item 2')).toBeInTheDocument();
+ expect(getByText('Item 3')).toBeInTheDocument();
+});
+```
-## Adding to Storybook
+## ๐จ Adding to Storybook
[**Storybook**](https://storybook.komiser.io/) is a tool for UI development. It makes development faster by isolating components. This allows you to work on one component at a time. If you create a new shared component or want to visualize variations of an existing one, follow these steps:
+- To view this component on Storybook locally, run: `npm run storybook`, then pick an example (`Card`) or your new component story
+
+
+
### 1. **Create the Story**:
In the same directory as your component, create a Storybook story:
@@ -129,82 +262,18 @@ export default {
---
-Remember: Storybook is not just a tool but also a way to document components. Ensure you provide meaningful names, descriptions, and use cases to help other developers understand the use and purpose of each component.
-
-## Testing
-
-We use Jest & React Testing Library for our unit tests.
-
-Testing convention:
-
-- All tests should be wrapped in a `describe`
-- If it's a unit test for a function: `describe('functionName outputs', () => { ... })`
-- If it's a unit test for a component: `describe('Component Name', () => { ... })`
-- A test should use 'it' for the test function: `it('should do something', () => { ... })`
-
-Testing examples:
-
-- Simple Jest unit test example (snippet from `/utils/formatNumber.test.ts`):
-
-```typescript
-import formatNumber from './formatNumber';
-
-describe('formatNumber outputs', () => {
- it('should format number (over a thousand) in short notation', () => {
- const result = formatNumber(12345);
- expect(result).toBe('12K');
- });
-
- ...
-
-});
-```
-
-- Jest & Testing library example (snippet from `/components/card/Card.test.tsx`):
-
-```typescript
-import { render, screen } from '@testing-library/react';
-import RefreshIcon from '../icons/RefreshIcon';
-import Card from './Card';
-
-describe('Card', () => {
- it('should render card component without crashing', () => {
- render(
- }
- />
- );
- });
-
- it('should display the value formatted', () => {
- render(
- }
- />
- );
- const formattedNumber = screen.getByTestId('formattedNumber');
- expect(formattedNumber).toHaveTextContent('5K');
- });
-
- ...
-
-});
-```
+> Remember: Storybook is not just a tool but also a way to document components. Ensure you provide meaningful names, descriptions, and use cases to help other developers understand the use and purpose of each component.
-## Contributing
+## ๐ค Contributing
We welcome all contributors to join us on the mission of improving Komiser, especially when it comes to writing tests and adding documentation.
Not sure where to start?
-- Read the [contributor guidelines](https://docs.komiser.io/docs/introduction/community)
-- [Join our Discord](https://discord.tailwarden.com/) and hang with us on #contributors channel.
+- ๐ Read the [contributor guidelines](https://docs.komiser.io/docs/introduction/community)
+- ๐ฌ [Join our Discord](https://discord.tailwarden.com/) and hang with us on #contributors channel.
-## Learn More
+## ๐ Learn More
To learn more about our stack, take a look at the following resources:
@@ -215,6 +284,6 @@ To learn more about our stack, take a look at the following resources:
- [Jest documentation](https://jestjs.io/docs/getting-started)
- [React testing library documentation](https://testing-library.com/docs/dom-testing-library/intro)
-## Walkthrough video
+## ๐ฅ Walkthrough video
[![Watch the video](https://komiser-assets-cdn.s3.eu-central-1.amazonaws.com/images/dashboard-contrib-video-thumb.png)](https://www.youtube.com/watch?v=uwxj11-eRt8)
diff --git a/dashboard/tsconfig.json b/dashboard/tsconfig.json
index a5e48f892..15d7d31d3 100644
--- a/dashboard/tsconfig.json
+++ b/dashboard/tsconfig.json
@@ -21,7 +21,12 @@
"@environments/*": ["environments/*"],
"@utils/*": ["utils/*"],
"@styles/*": ["styles/*"]
- }
+ },
+ "plugins": [
+ {
+ "name": "next"
+ }
+ ]
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
"exclude": ["node_modules"]
diff --git a/dashboard/utils/formatNumber.test.ts b/dashboard/utils/formatNumber.test.ts
index 33bd449f6..ff7add422 100644
--- a/dashboard/utils/formatNumber.test.ts
+++ b/dashboard/utils/formatNumber.test.ts
@@ -1,6 +1,6 @@
import formatNumber from './formatNumber';
-describe('formatNumber outputs', () => {
+describe('formatNumber util', () => {
it('should format number (over a thousand) in short notation', () => {
const result = formatNumber(12345);
expect(result).toBe('12K');
diff --git a/dashboard/utils/regex.test.ts b/dashboard/utils/regex.test.ts
index c6b279f1a..8466d9f6a 100644
--- a/dashboard/utils/regex.test.ts
+++ b/dashboard/utils/regex.test.ts
@@ -1,6 +1,6 @@
import regex, { required } from './regex';
-describe('regex outputs', () => {
+describe('regex util', () => {
it('should return the required regex', () => {
const result = required;
expect(result).toStrictEqual(/./);