mirror of
https://github.com/solidtime-io/solidtime.git
synced 2026-10-07 21:33:18 +01:00
Compare commits
3 Commits
main
...
feature/ex
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6ff77f6027 | ||
|
|
a40327298c | ||
|
|
fffb438963 |
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_repository=$(jq -r '.Invoicing.repository' extensions/manifest.json)"
|
||||||
echo "invoicing_ref=$(jq -r '.Invoicing.ref' 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"
|
} >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
- name: "Checkout invoicing extension"
|
- name: "Checkout invoicing extension"
|
||||||
@@ -119,9 +121,26 @@ jobs:
|
|||||||
- name: "Install npm dependencies in invoicing extension"
|
- name: "Install npm dependencies in invoicing extension"
|
||||||
run: cd extensions/Invoicing && npm ci
|
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"
|
- name: "Activate invoicing extension"
|
||||||
run: php artisan module:enable Invoicing
|
run: php artisan module:enable Invoicing
|
||||||
|
|
||||||
|
- name: "Activate auditing extension"
|
||||||
|
run: php artisan module:enable Auditing
|
||||||
|
|
||||||
- name: "Install npm dependencies"
|
- name: "Install npm dependencies"
|
||||||
run: npm ci
|
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 "services_ref=$(jq -r '.Services.ref' extensions/manifest.json)"
|
||||||
echo "invoicing_repository=$(jq -r '.Invoicing.repository' extensions/manifest.json)"
|
echo "invoicing_repository=$(jq -r '.Invoicing.repository' extensions/manifest.json)"
|
||||||
echo "invoicing_ref=$(jq -r '.Invoicing.ref' 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"
|
} >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
- name: "Checkout billing extension"
|
- name: "Checkout billing extension"
|
||||||
@@ -145,6 +147,25 @@ jobs:
|
|||||||
- name: "Install npm dependencies in invoicing extension"
|
- name: "Install npm dependencies in invoicing extension"
|
||||||
run: cd extensions/Invoicing && npm ci
|
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"
|
- name: "Setup PHP with PECL extension"
|
||||||
uses: shivammathur/setup-php@v2
|
uses: shivammathur/setup-php@v2
|
||||||
with:
|
with:
|
||||||
@@ -168,6 +189,9 @@ jobs:
|
|||||||
- name: "Activate invoicing extension"
|
- name: "Activate invoicing extension"
|
||||||
run: php artisan module:enable Invoicing
|
run: php artisan module:enable Invoicing
|
||||||
|
|
||||||
|
- name: "Activate auditing extension"
|
||||||
|
run: php artisan module:enable Auditing
|
||||||
|
|
||||||
- name: "Install npm dependencies"
|
- name: "Install npm dependencies"
|
||||||
run: npm ci
|
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
|
name: NPM Format Check
|
||||||
|
|
||||||
on: [push]
|
on: [push]
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
format-check:
|
format-check:
|
||||||
|
|||||||
@@ -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/project-members', heading: 'Project Members' },
|
||||||
{ path: '/admin/tokens', heading: 'Tokens' },
|
{ path: '/admin/tokens', heading: 'Tokens' },
|
||||||
{ path: '/admin/failed-jobs', heading: 'Failed Jobs' },
|
{ path: '/admin/failed-jobs', heading: 'Failed Jobs' },
|
||||||
{ path: '/admin/audits', heading: 'Audits' },
|
|
||||||
];
|
];
|
||||||
|
|
||||||
test.describe('Admin Panel Access', () => {
|
test.describe('Admin Panel Access', () => {
|
||||||
|
|||||||
@@ -10,5 +10,9 @@
|
|||||||
"Invoicing": {
|
"Invoicing": {
|
||||||
"repository": "solidtime-io/extension-invoicing",
|
"repository": "solidtime-io/extension-invoicing",
|
||||||
"ref": "v0.0.7"
|
"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);
|
const showActionBlockedModal = ref(false);
|
||||||
|
|
||||||
function addNotification(type: NotificationType, title: string, message?: string) {
|
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 });
|
notifications.value.push({ title, message, type, uuid });
|
||||||
|
|
||||||
setTimeout(() => {
|
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