Skip to content

Commit

Permalink
Merge pull request #6 from solidtime-io/feature/add_frontend_dashboard
Browse files Browse the repository at this point in the history
add dashboard frontend
  • Loading branch information
Onatcer authored Mar 13, 2024
2 parents 161da5b + b36894a commit 9b3e243
Show file tree
Hide file tree
Showing 201 changed files with 9,464 additions and 1,667 deletions.
17 changes: 10 additions & 7 deletions .env.ci
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
APP_NAME=Laravel
APP_NAME=solidtime
APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost
APP_FORCE_HTTPS=false
SESSION_SECURE_COOKIE=false

LOG_CHANNEL=stack
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug

DB_CONNECTION=sqlite
DB_HOST=127.0.0.1
DB_PORT=5432
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=root
DB_CONNECTION=pgsql_test

DB_TEST_HOST=127.0.0.1
DB_TEST_PORT=5432
DB_TEST_DATABASE=laravel
DB_TEST_USERNAME=root
DB_TEST_PASSWORD=root

BROADCAST_DRIVER=log
CACHE_DRIVER=file
Expand Down
10 changes: 9 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ APP_KEY=base64:UNQNf1SXeASNkWux01Rj8EnHYx8FO0kAxWNDwktclkk=
APP_DEBUG=true
APP_URL=https://solidtime.test
APP_FORCE_HTTPS=true
SESSION_SECURE_COOKIE=true

SUPER_ADMINS=[email protected]

Expand All @@ -12,12 +13,19 @@ LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug

DB_CONNECTION=pgsql

DB_HOST=pgsql
DB_PORT=5432
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=root

DB_TEST_HOST=pgsql_test
DB_TEST_PORT=5432
DB_TEST_DATABASE=laravel
DB_TEST_USERNAME=root
DB_TEST_PASSWORD=root

BROADCAST_DRIVER=log
CACHE_DRIVER=file
FILESYSTEM_DISK=local
Expand All @@ -37,7 +45,7 @@ MAIL_PORT=1025
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS="[email protected]"
MAIL_FROM_ADDRESS="[email protected]"
MAIL_FROM_NAME="${APP_NAME}"

AWS_ACCESS_KEY_ID=
Expand Down
6 changes: 1 addition & 5 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,7 @@
require("@rushstack/eslint-patch/modern-module-resolution")

module.exports = {
extends: [
'plugin:vue/vue3-essential',
'@vue/eslint-config-typescript/recommended',
'@vue/eslint-config-prettier'
],
extends: ['plugin:vue/vue3-essential', '@vue/eslint-config-typescript/recommended', '@vue/eslint-config-prettier'],
rules: {
'vue/multi-word-component-names': 'off',
}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/phpunit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ jobs:
runs-on: ubuntu-latest

services:
pgsql:
pgsql_test:
image: postgres:15
env:
PGPASSWORD: 'root'
Expand Down
24 changes: 18 additions & 6 deletions .github/workflows/playwright.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,20 @@ jobs:
services:
mailpit:
image: 'axllent/mailpit:latest'
pgsql_test:
image: postgres:15
env:
PGPASSWORD: 'root'
POSTGRES_DB: 'laravel'
POSTGRES_USER: 'root'
POSTGRES_PASSWORD: 'root'
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- name: "Checkout code"
Expand All @@ -24,20 +38,18 @@ jobs:
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv
extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv
coverage: none

- name: Run composer install
run: composer install -n --prefer-dist

- name: Create SQLite database
run: touch database/database.sqlite

- name: Prepare Laravel Application
run: |
cp .env.ci .env
php artisan key:generate
php artisan migrate --seed
php artisan passport:keys
- name: Install dependencies
run: npm ci
Expand All @@ -59,7 +71,7 @@ jobs:
- uses: actions/upload-artifact@v3
if: always()
with:
name: playwright-report
path: playwright-report/
name: test-results
path: test-results/
retention-days: 30

1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@ yarn-error.log
/blob-report/
/playwright/.cache/
/coverage
/extensions/*
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ cp .env.example .env

./vendor/bin/sail artisan migrate:fresh --seed

./vendor/bin/sail php artisan passport:install

./vendor/bin/sail npm install

./vendor/bin/sail npm run build
Expand All @@ -36,6 +38,7 @@ Add the following entry to your `/etc/hosts`
```
127.0.0.1 solidtime.test
127.0.0.1 playwright.solidtime.test
127.0.0.1 mail.solidtime.test
```

## Running E2E Tests
Expand All @@ -52,6 +55,19 @@ npx playwright install
npx playwright codegen solidtime.test
```

## E2E Troubleshooting

If the E2E tests are not working consistently and fail with a timeout during the authentication, you might want to delete the `test-results/.auth` directory to force new test accounts to be created.

## Generate ZOD Client

The Zodius HTTP client is generated using the following command:

```bash

npm run generate:zod
```

## Contributing

This project is in a very early stage. The structure and APIs are still subject to change and not stable.
Expand Down
22 changes: 20 additions & 2 deletions app/Actions/Fortify/CreateNewUser.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@

use App\Models\Organization;
use App\Models\User;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\ValidationException;
use Korridor\LaravelModelValidationRules\Rules\UniqueEloquent;
use Laravel\Fortify\Contracts\CreatesNewUsers;
use Laravel\Jetstream\Jetstream;

Expand All @@ -20,12 +23,27 @@ class CreateNewUser implements CreatesNewUsers
* Create a newly registered user.
*
* @param array<string, string> $input
*
* @throws ValidationException
*/
public function create(array $input): User
{
Validator::make($input, [
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
'name' => [
'required',
'string',
'max:255',
],
'email' => [
'required',
'string',
'email',
'max:255',
new UniqueEloquent(User::class, 'email', function (Builder $builder): Builder {
/** @var Builder<User> $builder */
return $builder->where('is_placeholder', '=', false);
}),
],
'password' => $this->passwordRules(),
'terms' => Jetstream::hasTermsAndPrivacyPolicyFeature() ? ['accepted', 'required'] : '',
])->validate();
Expand Down
34 changes: 22 additions & 12 deletions app/Actions/Jetstream/AddOrganizationMember.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@
use App\Models\User;
use Closure;
use Illuminate\Contracts\Validation\Rule;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Validator;
use Korridor\LaravelModelValidationRules\Rules\ExistsEloquent;
use Laravel\Jetstream\Contracts\AddsTeamMembers;
use Laravel\Jetstream\Events\AddingTeamMember;
use Laravel\Jetstream\Events\TeamMemberAdded;
Expand All @@ -21,21 +24,24 @@ class AddOrganizationMember implements AddsTeamMembers
/**
* Add a new team member to the given team.
*/
public function add(User $user, Organization $organization, string $email, ?string $role = null): void
public function add(User $owner, Organization $organization, string $email, ?string $role = null): void
{
Gate::forUser($user)->authorize('addTeamMember', $organization);
Gate::forUser($owner)->authorize('addTeamMember', $organization);

$this->validate($organization, $email, $role);

$newTeamMember = Jetstream::findUserByEmailOrFail($email);
$newOrganizationMember = User::query()
->where('email', $email)
->where('is_placeholder', '=', false)
->firstOrFail();

AddingTeamMember::dispatch($organization, $newTeamMember);
AddingTeamMember::dispatch($organization, $newOrganizationMember);

$organization->users()->attach(
$newTeamMember, ['role' => $role]
$newOrganizationMember, ['role' => $role]
);

TeamMemberAdded::dispatch($organization, $newTeamMember);
TeamMemberAdded::dispatch($organization, $newOrganizationMember);
}

/**
Expand All @@ -46,22 +52,26 @@ protected function validate(Organization $organization, string $email, ?string $
Validator::make([
'email' => $email,
'role' => $role,
], $this->rules(), [
'email.exists' => __('We were unable to find a registered user with this email address.'),
])->after(
], $this->rules())->after(
$this->ensureUserIsNotAlreadyOnTeam($organization, $email)
)->validateWithBag('addTeamMember');
}

/**
* Get the validation rules for adding a team member.
*
* @return array<string, array<Rule|string>>
* @return array<string, array<ValidationRule|Rule|string>>
*/
protected function rules(): array
{
return array_filter([
'email' => ['required', 'email', 'exists:users'],
'email' => [
'required',
'email',
(new ExistsEloquent(User::class, 'email', function (Builder $builder) {
return $builder->where('is_placeholder', '=', false);
}))->withMessage(__('We were unable to find a registered user with this email address.')),
],
'role' => Jetstream::hasRoles()
? ['required', 'string', new Role]
: null,
Expand All @@ -75,7 +85,7 @@ protected function ensureUserIsNotAlreadyOnTeam(Organization $team, string $emai
{
return function ($validator) use ($team, $email) {
$validator->errors()->addIf(
$team->hasUserWithEmail($email),
$team->hasRealUserWithEmail($email),
'email',
__('This user already belongs to the team.')
);
Expand Down
11 changes: 5 additions & 6 deletions app/Actions/Jetstream/InviteOrganizationMember.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public function invite(User $user, Organization $organization, string $email, ?s

InvitingTeamMember::dispatch($organization, $email, $role);

/** @var OrganizationInvitation $invitation */
$invitation = $organization->teamInvitations()->create([
'email' => $email,
'role' => $role,
Expand All @@ -50,9 +51,7 @@ protected function validate(Organization $organization, string $email, ?string $
Validator::make([
'email' => $email,
'role' => $role,
], $this->rules($organization), [
'email.unique' => __('This user has already been invited to the team.'),
])->after(
], $this->rules($organization))->after(
$this->ensureUserIsNotAlreadyOnTeam($organization, $email)
)->validateWithBag('addTeamMember');
}
Expand All @@ -68,10 +67,10 @@ protected function rules(Organization $organization): array
'email' => [
'required',
'email',
new UniqueEloquent(OrganizationInvitation::class, 'email', function (Builder $builder) use ($organization) {
(new UniqueEloquent(OrganizationInvitation::class, 'email', function (Builder $builder) use ($organization) {
/** @var Builder<OrganizationInvitation> $builder */
return $builder->whereBelongsTo($organization, 'organization');
}),
}))->withMessage(__('This user has already been invited to the team.')),
],
'role' => Jetstream::hasRoles()
? ['required', 'string', new Role]
Expand All @@ -86,7 +85,7 @@ protected function ensureUserIsNotAlreadyOnTeam(Organization $organization, stri
{
return function ($validator) use ($organization, $email) {
$validator->errors()->addIf(
$organization->hasUserWithEmail($email),
$organization->hasRealUserWithEmail($email),
'email',
__('This user already belongs to the team.')
);
Expand Down
Loading

0 comments on commit 9b3e243

Please sign in to comment.