diff --git a/app/Filament/Resources/AppResource.php b/app/Filament/Resources/AppResource.php
index fc1c07d9..22e57d83 100644
--- a/app/Filament/Resources/AppResource.php
+++ b/app/Filament/Resources/AppResource.php
@@ -3,11 +3,13 @@
namespace App\Filament\Resources;
use App\Filament\Resources\AppResource\Pages;
+use App\Filament\Resources\AppResource\RelationManagers\GroupsRelationManager;
use App\Models\App;
use App\Services\Hydra\Client;
use Filament\Forms\Components\Card;
use Filament\Forms\Components\Checkbox;
use Filament\Forms\Components\CheckboxList;
+use Filament\Forms\Components\DateTimePicker;
use Filament\Forms\Components\Group;
use Filament\Forms\Components\Placeholder;
use Filament\Forms\Components\Section;
@@ -43,17 +45,17 @@ public static function form(Form $form): Form
Tabs::make('Tabs')->tabs([
Tabs\Tab::make('Information')->icon('heroicon-o-paper-clip')->schema([
TextInput::make('data.client_uri')
- ->url()
- ->helperText('A URL string of a web page providing information about the client'),
+ ->url()
+ ->helperText('A URL string of a web page providing information about the client'),
TextInput::make('data.logo_uri')
- ->url()
- ->helperText('A URL string that references a logo for the client'),
+ ->url()
+ ->helperText('A URL string that references a logo for the client'),
TextInput::make('data.policy_uri')
- ->url()
- ->helperText('A URL string that references the privacy policy for the client'),
+ ->url()
+ ->helperText('A URL string that references the privacy policy for the client'),
TextInput::make('data.tos_uri')
- ->url()
- ->helperText('A URL string that references the terms of service for the client'),
+ ->url()
+ ->helperText('A URL string that references the terms of service for the client'),
]),
Tabs\Tab::make('Login')->icon('heroicon-o-login')->schema([
TagsInput::make('data.redirect_uris')->columnSpan(2),
@@ -81,8 +83,8 @@ public static function form(Form $form): Form
"none" => "none",
]),
TextInput::make('data.jwks_uri')
- ->helperText('When authenticating with a signed jwks key against the token endpoint, you may enter a path to a keys.json containing the public keys of your app here.')
- ->url(),
+ ->helperText('When authenticating with a signed jwks key against the token endpoint, you may enter a path to a keys.json containing the public keys of your app here.')
+ ->url(),
CheckboxList::make('data.scope')->options(static function () {
return collect((new Client())->getScopes())->mapWithKeys(fn($v) => [$v => $v]);
@@ -97,24 +99,24 @@ public static function form(Form $form): Form
Tabs\Tab::make('Logout')->icon('heroicon-o-logout')->schema([
TagsInput::make('data.post_logout_redirect_uris')->columnSpan(2),
Section::make('Frontchannel Logout')
- ->description('Configure frontchannel logout.')
- ->schema([
- TextInput::make('data.frontchannel_logout_uri')
- ->helperText('Client URL that will cause the client to log itself out when rendered in an iframe by Identity')
- ->url(),
- Checkbox::make('data.frontchannel_logout_session_required')
- ->helperText('Specifying whether the client requires that a sid (session ID) Claim be included in the Logout Token to identify the client session with the OP when the frontchannel logout is used.'),
- ]),
+ ->description('Configure frontchannel logout.')
+ ->schema([
+ TextInput::make('data.frontchannel_logout_uri')
+ ->helperText('Client URL that will cause the client to log itself out when rendered in an iframe by Identity')
+ ->url(),
+ Checkbox::make('data.frontchannel_logout_session_required')
+ ->helperText('Specifying whether the client requires that a sid (session ID) Claim be included in the Logout Token to identify the client session with the OP when the frontchannel logout is used.'),
+ ]),
Section::make('Backchannel Logout')
- ->description('Configure backchannel logout.')
- ->schema([
- TextInput::make('data.backchannel_logout_uri')
- ->helperText('Client URL that will cause the client to log itself out when sent a Logout Token by Identity.')
- ->url(),
- Checkbox::make('data.backchannel_logout_session_required')
- ->helperText('Specifying whether the client requires that a sid (session ID) Claim be included in the Logout Token to identify the client session with the OP when the backchannel logout is used.')
-
- ]),
+ ->description('Configure backchannel logout.')
+ ->schema([
+ TextInput::make('data.backchannel_logout_uri')
+ ->helperText('Client URL that will cause the client to log itself out when sent a Logout Token by Identity.')
+ ->url(),
+ Checkbox::make('data.backchannel_logout_session_required')
+ ->helperText('Specifying whether the client requires that a sid (session ID) Claim be included in the Logout Token to identify the client session with the OP when the backchannel logout is used.'),
+
+ ]),
]),
Tabs\Tab::make('Request')->icon('heroicon-o-status-online')->schema([
@@ -138,21 +140,37 @@ public static function form(Form $form): Form
Group::make()->columnSpan(1)->schema([
Section::make('Owner')
- ->columns(1)
- ->schema([
- Select::make('user_id')
- ->label('Owner')
- ->relationship('owner', 'name')->required(),
- ]),
+ ->columns(1)
+ ->schema([
+ Select::make('user_id')
+ ->label('Owner')
+ ->relationship('owner', 'name')->required(),
+ ]),
+ Section::make('Dashboard Settings')
+ ->description('These settings control the visibility of the app on the dashboard. This is NOT access control in any way.')
+ ->columns(1)
+ ->schema([
+ DateTimePicker::make('starts_at')->hint('UTC')->nullable(),
+ DateTimePicker::make('ends_at')->hint('UTC')->nullable(),
+ TextInput::make('priority')->numeric()->minValue('1')->maxValue('10000')->hint('Sets order of dashboard apps'),
+ Checkbox::make('public')->hint('App is publicly visible (ignoring group selection)'),
+ TextInput::make('name')->required(),
+ TextInput::make('description')->required(),
+ Select::make('icon')->options([
+ "TicketDuotone" => "TicketDuotone",
+ "CogsDuotone" => "CogsDuotone",
+ ])->hint('Request new Icons @ Thiritin')->required(),
+ TextInput::make('url')->url(),
+ ]),
Card::make()->schema([
Placeholder::make('created_at')
- ->label("Created At")
- ->content(fn(?App $record): string => $record?->created_at?->diffForHumans() ?? '-'),
+ ->label("Created At")
+ ->content(fn(?App $record): string => $record?->created_at?->diffForHumans() ?? '-'),
Placeholder::make('updated_at')
- ->label("Updated At")
- ->content(fn(?App $record): string => $record?->updated_at?->diffForHumans() ?? '-'),
- ])
+ ->label("Updated At")
+ ->content(fn(?App $record): string => $record?->updated_at?->diffForHumans() ?? '-'),
+ ]),
]),
])->columns(3);
@@ -164,7 +182,7 @@ public static function table(Table $table): Table
->columns([
TextColumn::make('client_id'),
TextColumn::make('data.client_name')->label('Name'),
- TextColumn::make('owner.name')
+ TextColumn::make('owner.name'),
]);
}
@@ -177,10 +195,17 @@ public static function getPages(): array
];
}
+ public static function getRelations(): array
+ {
+ return [
+ GroupsRelationManager::class,
+ ];
+ }
+
public static function getGloballySearchableAttributes(): array
{
return [
- "data.client_name"
+ "data.client_name",
];
}
}
diff --git a/app/Filament/Resources/AppResource/RelationManagers/GroupsRelationManager.php b/app/Filament/Resources/AppResource/RelationManagers/GroupsRelationManager.php
new file mode 100644
index 00000000..d97ff793
--- /dev/null
+++ b/app/Filament/Resources/AppResource/RelationManagers/GroupsRelationManager.php
@@ -0,0 +1,46 @@
+schema([
+ Forms\Components\TextInput::make('name')
+ ->required()
+ ->maxLength(255),
+ ]);
+ }
+
+ public static function table(Table $table): Table
+ {
+ return $table
+ ->columns([
+ Tables\Columns\TextColumn::make('name'),
+ ])
+ ->filters([
+ //
+ ])
+ ->headerActions([
+ Tables\Actions\AttachAction::make(),
+ ])
+ ->actions([
+ Tables\Actions\DetachAction::make(),
+ ])
+ ->bulkActions([
+ Tables\Actions\DetachBulkAction::make(),
+ ]);
+ }
+}
diff --git a/app/Http/Controllers/DashboardController.php b/app/Http/Controllers/DashboardController.php
new file mode 100644
index 00000000..b833811d
--- /dev/null
+++ b/app/Http/Controllers/DashboardController.php
@@ -0,0 +1,31 @@
+where('public', '=', true)->orWhereHas('groups', function (Builder $q) {
+ $q->whereIn('id', Auth::user()->groups->pluck('id'));
+ });
+ })->where(function (Builder $q) {
+ $q->where(function (Builder $q) {
+ $q->whereDate('starts_at', '<=', now())->orWhereNull('starts_at');
+ })->where(function (Builder $q) {
+ $q->whereDate('ends_at', '>=', now())->orWhereNull('ends_at');
+ });
+ })->get();
+
+ return Inertia::render('Dashboard', [
+ 'apps' => $apps,
+ ]);
+ }
+}
diff --git a/app/Models/App.php b/app/Models/App.php
index 613f71bb..7e6f267f 100644
--- a/app/Models/App.php
+++ b/app/Models/App.php
@@ -9,11 +9,16 @@ class App extends Model
{
protected $guarded = [];
protected $casts = [
- "data" => "array"
+ "data" => "array",
];
public function owner(): BelongsTo
{
return $this->belongsTo(User::class, 'user_id', 'id');
}
+
+ public function groups()
+ {
+ return $this->belongsToMany(Group::class);
+ }
}
diff --git a/app/Models/Group.php b/app/Models/Group.php
index a474595b..514eb468 100644
--- a/app/Models/Group.php
+++ b/app/Models/Group.php
@@ -55,6 +55,11 @@ public function users()
);
}
+ public function apps()
+ {
+ return $this->belongsToMany(App::class);
+ }
+
public function getHashidsConnection()
{
return 'group';
diff --git a/database/migrations/2023_02_12_103409_create_app_group_pivot_table.php b/database/migrations/2023_02_12_103409_create_app_group_pivot_table.php
new file mode 100644
index 00000000..fbb10d0a
--- /dev/null
+++ b/database/migrations/2023_02_12_103409_create_app_group_pivot_table.php
@@ -0,0 +1,33 @@
+unsignedBigInteger('app_id')->index();
+ $table->foreign('app_id')->references('id')->on('apps')->onDelete('cascade');
+ $table->unsignedBigInteger('group_id')->index();
+ $table->foreign('group_id')->references('id')->on('groups')->onDelete('cascade');
+ $table->primary(['app_id', 'group_id']);
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::dropIfExists('app_group');
+ }
+}
diff --git a/database/migrations/2023_02_12_114846_add_fields_to_apps_table.php b/database/migrations/2023_02_12_114846_add_fields_to_apps_table.php
new file mode 100644
index 00000000..d0beecc1
--- /dev/null
+++ b/database/migrations/2023_02_12_114846_add_fields_to_apps_table.php
@@ -0,0 +1,39 @@
+timestamp("starts_at")->nullable()->after('client_id');
+ $table->timestamp("ends_at")->nullable()->after('starts_at');
+ $table->boolean('public')->default(false)->after('ends_at');
+ $table->boolean('featured')->default(false)->after('ends_at');
+ $table->integer('priority')->unsigned()->default(1000)->after('public');
+ $table->string('name')->nullable()->after('client_id');
+ $table->string('description')->nullable()->after('name');
+ $table->string('icon')->nullable()->after('description');
+ $table->string('url')->nullable()->after('icon');
+ });
+ }
+
+ public function down()
+ {
+ Schema::table('apps', function (Blueprint $table) {
+ $table->dropColumn([
+ "starts_at",
+ "ends_at",
+ "public",
+ "featured",
+ "priority",
+ "name",
+ "description",
+ "icon",
+ "url",
+ ]);
+ });
+ }
+};
diff --git a/resources/js/Pages/Dashboard.vue b/resources/js/Pages/Dashboard.vue
index 4dc4ba7e..4a12b383 100644
--- a/resources/js/Pages/Dashboard.vue
+++ b/resources/js/Pages/Dashboard.vue
@@ -15,31 +15,28 @@
items-start
lg:grid-cols-3 lg:gap-8
'>
-
-
-