Skip to content

Commit

Permalink
Merge pull request #1100 from tailwarden/improve-dashboard-readme
Browse files Browse the repository at this point in the history
Improve dashboard readme
  • Loading branch information
mlabouardy authored Oct 17, 2023
2 parents 4b89403 + 36055d3 commit 06747b2
Show file tree
Hide file tree
Showing 4 changed files with 175 additions and 101 deletions.
265 changes: 167 additions & 98 deletions dashboard/README.md
Original file line number Diff line number Diff line change
@@ -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.
<img width="1411" alt="image" src="https://user-images.githubusercontent.com/13384559/224318056-3d2c68bc-aa56-49c8-841a-bb297e380dc9.png">
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).
> <img width="1411" alt="image" src="https://user-images.githubusercontent.com/13384559/224320642-0bf6814b-d97a-4ad9-95a0-ca82e353c5d0.png">
```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).
<img alt="Error Image" src="https://user-images.githubusercontent.com/13384559/224320642-0bf6814b-d97a-4ad9-95a0-ca82e353c5d0.png" width="600"/>

## 🧩 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:
<img width="220" alt="image" src="https://user-images.githubusercontent.com/13384559/224307211-2ce62245-de24-4ee7-a156-fb54d8d34b4f.png">
<img alt="Component Example" src="https://user-images.githubusercontent.com/13384559/224307211-2ce62245-de24-4ee7-a156-fb54d8d34b4f.png" width="200"/>
Additional instructions:
**Additional instructions:**
- 📖 To view this component on Storybook, run: `npm run storybook`, then pick `Card`
<img alt="Storybook Image" src="https://user-images.githubusercontent.com/13384559/224320112-e21d2ed4-1e22-4a33-adb3-6c236c4d4208.png" width="600"/>
- 🧪 To run the unit tests, run: `npm run test:watch`, hit `p`, then `card`
<img alt="Unit Test Image" src="https://user-images.githubusercontent.com/13384559/224320260-19b1359e-1bfb-4db5-8379-918dacd7da44.png" width="400"/>
## 🧪 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(
<Card
label="Test card"
value={500}
icon={<RefreshIcon width={24} height={24} />}
/>
);
});

it('should display the value formatted', () => {
render(
<Card
label="Test card"
value={5000}
icon={<RefreshIcon width={24} height={24} />}
/>
);
const formattedNumber = screen.getByTestId('formattedNumber');
expect(formattedNumber).toHaveTextContent('5K');
});
...
});
```

- To view this component on Storybook locally, run: `npm run storybook`, then pick `Card`
<img width="1411" alt="image" src="https://user-images.githubusercontent.com/13384559/224320112-e21d2ed4-1e22-4a33-adb3-6c236c4d4208.png">
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`
<img width="668" alt="image" src="https://user-images.githubusercontent.com/13384559/224320260-19b1359e-1bfb-4db5-8379-918dacd7da44.png">
```typescript
it('opens the dropdown when clicked', () => {
const { getByRole, getByText } = render(
<SelectCheckbox
label="Test Label"
query="provider"
exclude={[]}
setExclude={() => {}}
/>
);

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

<img width="600" alt="image" src="https://user-images.githubusercontent.com/13384559/224320112-e21d2ed4-1e22-4a33-adb3-6c236c4d4208.png">

### 1. **Create the Story**:

In the same directory as your component, create a Storybook story:
Expand Down Expand Up @@ -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(
<Card
label="Test card"
value={500}
icon={<RefreshIcon width={24} height={24} />}
/>
);
});

it('should display the value formatted', () => {
render(
<Card
label="Test card"
value={5000}
icon={<RefreshIcon width={24} height={24} />}
/>
);
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:

Expand All @@ -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)
7 changes: 6 additions & 1 deletion dashboard/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,12 @@
"@environments/*": ["environments/*"],
"@utils/*": ["utils/*"],
"@styles/*": ["styles/*"]
}
},
"plugins": [
{
"name": "next"
}
]
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
"exclude": ["node_modules"]
Expand Down
2 changes: 1 addition & 1 deletion dashboard/utils/formatNumber.test.ts
Original file line number Diff line number Diff line change
@@ -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');
Expand Down
2 changes: 1 addition & 1 deletion dashboard/utils/regex.test.ts
Original file line number Diff line number Diff line change
@@ -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(/./);
Expand Down

0 comments on commit 06747b2

Please sign in to comment.