mirror of
https://github.com/solidtime-io/solidtime.git
synced 2026-10-08 05:43:18 +01:00
Compare commits
4 Commits
feature/ex
...
feature/po
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b5c0da4c6a | ||
|
|
fa0bbc8cfd | ||
|
|
fff3502e53 | ||
|
|
e801c4311c |
19
.github/workflows/build-onpremise.yml
vendored
19
.github/workflows/build-onpremise.yml
vendored
@@ -103,6 +103,8 @@ jobs:
|
||||
{
|
||||
echo "invoicing_repository=$(jq -r '.Invoicing.repository' extensions/manifest.json)"
|
||||
echo "invoicing_ref=$(jq -r '.Invoicing.ref' extensions/manifest.json)"
|
||||
echo "auditing_repository=$(jq -r '.Auditing.repository' extensions/manifest.json)"
|
||||
echo "auditing_ref=$(jq -r '.Auditing.ref' extensions/manifest.json)"
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: "Checkout invoicing extension"
|
||||
@@ -119,9 +121,26 @@ jobs:
|
||||
- name: "Install npm dependencies in invoicing extension"
|
||||
run: cd extensions/Invoicing && npm ci
|
||||
|
||||
- name: "Checkout auditing extension"
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
repository: ${{ steps.extension-manifest.outputs.auditing_repository }}
|
||||
ref: ${{ steps.extension-manifest.outputs.auditing_ref }}
|
||||
path: extensions/Auditing
|
||||
ssh-key: ${{ secrets.SSH_PRIVATE_KEY_AUDITING_EXTENSION }}
|
||||
|
||||
- name: "Install composer dependencies in auditing extension"
|
||||
run: cd extensions/Auditing && composer install --no-dev --no-ansi --no-interaction --prefer-dist --ignore-platform-reqs --classmap-authoritative
|
||||
|
||||
- name: "Install npm dependencies in auditing extension"
|
||||
run: cd extensions/Auditing && npm ci
|
||||
|
||||
- name: "Activate invoicing extension"
|
||||
run: php artisan module:enable Invoicing
|
||||
|
||||
- name: "Activate auditing extension"
|
||||
run: php artisan module:enable Auditing
|
||||
|
||||
- name: "Install npm dependencies"
|
||||
run: npm ci
|
||||
|
||||
|
||||
24
.github/workflows/build-private.yml
vendored
24
.github/workflows/build-private.yml
vendored
@@ -84,6 +84,8 @@ jobs:
|
||||
echo "services_ref=$(jq -r '.Services.ref' extensions/manifest.json)"
|
||||
echo "invoicing_repository=$(jq -r '.Invoicing.repository' extensions/manifest.json)"
|
||||
echo "invoicing_ref=$(jq -r '.Invoicing.ref' extensions/manifest.json)"
|
||||
echo "auditing_repository=$(jq -r '.Auditing.repository' extensions/manifest.json)"
|
||||
echo "auditing_ref=$(jq -r '.Auditing.ref' extensions/manifest.json)"
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: "Checkout billing extension"
|
||||
@@ -145,6 +147,25 @@ jobs:
|
||||
- name: "Install npm dependencies in invoicing extension"
|
||||
run: cd extensions/Invoicing && npm ci
|
||||
|
||||
- name: "Checkout auditing extension"
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
repository: ${{ steps.extension-manifest.outputs.auditing_repository }}
|
||||
ref: ${{ steps.extension-manifest.outputs.auditing_ref }}
|
||||
path: extensions/Auditing
|
||||
ssh-key: ${{ secrets.SSH_PRIVATE_KEY_AUDITING_EXTENSION }}
|
||||
|
||||
- name: "Install composer dependencies in auditing extension"
|
||||
uses: php-actions/composer@v6
|
||||
with:
|
||||
working_dir: "extensions/Auditing"
|
||||
command: install
|
||||
only_args: --no-dev --no-ansi --no-interaction --prefer-dist --ignore-platform-reqs --classmap-authoritative
|
||||
php_version: 8.3
|
||||
|
||||
- name: "Install npm dependencies in auditing extension"
|
||||
run: cd extensions/Auditing && npm ci
|
||||
|
||||
- name: "Setup PHP with PECL extension"
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
@@ -168,6 +189,9 @@ jobs:
|
||||
- name: "Activate invoicing extension"
|
||||
run: php artisan module:enable Invoicing
|
||||
|
||||
- name: "Activate auditing extension"
|
||||
run: php artisan module:enable Auditing
|
||||
|
||||
- name: "Install npm dependencies"
|
||||
run: npm ci
|
||||
|
||||
|
||||
2
.github/workflows/npm-format-check.yml
vendored
2
.github/workflows/npm-format-check.yml
vendored
@@ -1,6 +1,8 @@
|
||||
name: NPM Format Check
|
||||
|
||||
on: [push]
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
format-check:
|
||||
|
||||
2
.github/workflows/phpunit-extensions.yml
vendored
2
.github/workflows/phpunit-extensions.yml
vendored
@@ -8,7 +8,7 @@ jobs:
|
||||
timeout-minutes: 15
|
||||
strategy:
|
||||
matrix:
|
||||
postgres_version: [ 15, 16, 17 ]
|
||||
postgres_version: [ 15, 16, 17, 18 ]
|
||||
|
||||
services:
|
||||
pgsql_test:
|
||||
|
||||
2
.github/workflows/phpunit.yml
vendored
2
.github/workflows/phpunit.yml
vendored
@@ -8,7 +8,7 @@ jobs:
|
||||
timeout-minutes: 10
|
||||
strategy:
|
||||
matrix:
|
||||
postgres_version: [ 15, 16, 17 ]
|
||||
postgres_version: [ 15, 16, 17, 18 ]
|
||||
|
||||
services:
|
||||
pgsql_test:
|
||||
|
||||
@@ -1,99 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\Resources;
|
||||
|
||||
use App\Filament\Resources\AuditResource\Pages\CreateAudit;
|
||||
use App\Filament\Resources\AuditResource\Pages\ListAudits;
|
||||
use App\Filament\Resources\AuditResource\Pages\ViewAudit;
|
||||
use App\Models\Audit;
|
||||
use Filament\Actions\ViewAction;
|
||||
use Filament\Forms\Components\Textarea;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Filament\Resources\Resource;
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Tables\Columns\IconColumn;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Support\Str;
|
||||
use Novadaemon\FilamentPrettyJson\Form\PrettyJsonField;
|
||||
|
||||
class AuditResource extends Resource
|
||||
{
|
||||
protected static ?string $model = Audit::class;
|
||||
|
||||
protected static string|\BackedEnum|null $navigationIcon = 'heroicon-o-archive-box';
|
||||
|
||||
protected static string|\UnitEnum|null $navigationGroup = 'System';
|
||||
|
||||
public static function form(Schema $schema): Schema
|
||||
{
|
||||
return $schema
|
||||
->components([
|
||||
TextInput::make('user_type')
|
||||
->maxLength(255),
|
||||
TextInput::make('user_id'),
|
||||
TextInput::make('event')
|
||||
->required()
|
||||
->maxLength(255),
|
||||
TextInput::make('auditable_type')
|
||||
->required()
|
||||
->maxLength(255),
|
||||
TextInput::make('auditable_id')
|
||||
->required(),
|
||||
PrettyJsonField::make('old_values'),
|
||||
PrettyJsonField::make('new_values'),
|
||||
Textarea::make('url'),
|
||||
TextInput::make('ip_address'),
|
||||
TextInput::make('user_agent')
|
||||
->maxLength(1023),
|
||||
TextInput::make('tags')
|
||||
->maxLength(255),
|
||||
]);
|
||||
}
|
||||
|
||||
public static function table(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->columns([
|
||||
TextColumn::make('user.name'),
|
||||
TextColumn::make('event'),
|
||||
TextColumn::make('auditable_type'),
|
||||
TextColumn::make('auditable_id'),
|
||||
IconColumn::make('was_command')
|
||||
->getStateUsing(fn (Audit $record) => Str::startsWith($record->url, 'artisan '))
|
||||
->boolean(),
|
||||
TextColumn::make('created_at')
|
||||
->sortable()
|
||||
->dateTime(),
|
||||
TextColumn::make('updated_at')
|
||||
->sortable()
|
||||
->dateTime(),
|
||||
])
|
||||
->filters([
|
||||
//
|
||||
])
|
||||
->recordActions([
|
||||
ViewAction::make(),
|
||||
])
|
||||
->toolbarActions([
|
||||
])
|
||||
->defaultSort('created_at', 'desc');
|
||||
}
|
||||
|
||||
public static function getRelations(): array
|
||||
{
|
||||
return [
|
||||
];
|
||||
}
|
||||
|
||||
public static function getPages(): array
|
||||
{
|
||||
return [
|
||||
'index' => ListAudits::route('/'),
|
||||
'create' => CreateAudit::route('/create'),
|
||||
'view' => ViewAudit::route('/{record}'),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\Resources\AuditResource\Pages;
|
||||
|
||||
use App\Filament\Resources\AuditResource;
|
||||
use Filament\Resources\Pages\CreateRecord;
|
||||
|
||||
class CreateAudit extends CreateRecord
|
||||
{
|
||||
protected static string $resource = AuditResource::class;
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\Resources\AuditResource\Pages;
|
||||
|
||||
use App\Filament\Resources\AuditResource;
|
||||
use Filament\Resources\Pages\ListRecords;
|
||||
|
||||
class ListAudits extends ListRecords
|
||||
{
|
||||
protected static string $resource = AuditResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\Resources\AuditResource\Pages;
|
||||
|
||||
use App\Filament\Resources\AuditResource;
|
||||
use Filament\Resources\Pages\ViewRecord;
|
||||
|
||||
class ViewAudit extends ViewRecord
|
||||
{
|
||||
protected static string $resource = AuditResource::class;
|
||||
}
|
||||
@@ -19,7 +19,6 @@ const resourcePages = [
|
||||
{ path: '/admin/project-members', heading: 'Project Members' },
|
||||
{ path: '/admin/tokens', heading: 'Tokens' },
|
||||
{ path: '/admin/failed-jobs', heading: 'Failed Jobs' },
|
||||
{ path: '/admin/audits', heading: 'Audits' },
|
||||
];
|
||||
|
||||
test.describe('Admin Panel Access', () => {
|
||||
|
||||
@@ -10,5 +10,9 @@
|
||||
"Invoicing": {
|
||||
"repository": "solidtime-io/extension-invoicing",
|
||||
"ref": "v0.0.7"
|
||||
},
|
||||
"Auditing": {
|
||||
"repository": "solidtime-io/extension-auditing",
|
||||
"ref": "v0.0.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ export const useNotificationsStore = defineStore('notifications', () => {
|
||||
const showActionBlockedModal = ref(false);
|
||||
|
||||
function addNotification(type: NotificationType, title: string, message?: string) {
|
||||
const uuid = Math.random().toString(36).substring(7);
|
||||
const uuid = crypto.randomUUID();
|
||||
notifications.value.push({ title, message, type, uuid });
|
||||
|
||||
setTimeout(() => {
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Unit\Filament\Resources;
|
||||
|
||||
use App\Filament\Resources\AuditResource;
|
||||
use App\Models\Audit;
|
||||
use App\Models\TimeEntry;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Livewire\Livewire;
|
||||
use PHPUnit\Framework\Attributes\UsesClass;
|
||||
use Tests\Unit\Filament\FilamentTestCase;
|
||||
|
||||
#[UsesClass(AuditResource::class)]
|
||||
class AuditResourceTest extends FilamentTestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
Config::set('auth.super_admins', ['admin@example.com']);
|
||||
$user = User::factory()->withPersonalOrganization()->create([
|
||||
'email' => 'admin@example.com',
|
||||
]);
|
||||
|
||||
$this->actingAs($user);
|
||||
}
|
||||
|
||||
public function test_can_list_audits(): void
|
||||
{
|
||||
// Arrange
|
||||
$user = $this->createUserWithPermission();
|
||||
$timeEntry = TimeEntry::factory()->forMember($user->member)->create();
|
||||
DB::table((new Audit)->getTable())->delete();
|
||||
$audits = Audit::factory()->auditFor($timeEntry)->auditUser($user->user)->createMany(5);
|
||||
|
||||
// Act
|
||||
$response = Livewire::test(AuditResource\Pages\ListAudits::class);
|
||||
|
||||
// Assert
|
||||
$response->assertSuccessful();
|
||||
$response->assertCanSeeTableRecords($audits);
|
||||
}
|
||||
|
||||
public function test_can_see_view_page_of_audit(): void
|
||||
{
|
||||
// Arrange
|
||||
DB::table((new Audit)->getTable())->delete();
|
||||
$audit = Audit::factory()->create();
|
||||
|
||||
// Act
|
||||
$response = Livewire::test(AuditResource\Pages\ViewAudit::class, ['record' => $audit->getKey()]);
|
||||
|
||||
// Assert
|
||||
$response->assertSuccessful();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user