76 - Lock feed language to channel language in onboarding wizard
This commit is contained in:
parent
2a0653981c
commit
35e4260c87
5 changed files with 199 additions and 61 deletions
|
|
@ -47,6 +47,7 @@ class Onboarding extends Component
|
||||||
// State
|
// State
|
||||||
public array $formErrors = [];
|
public array $formErrors = [];
|
||||||
public bool $isLoading = false;
|
public bool $isLoading = false;
|
||||||
|
private ?int $previousChannelLanguageId = null;
|
||||||
|
|
||||||
protected LemmyAuthService $lemmyAuthService;
|
protected LemmyAuthService $lemmyAuthService;
|
||||||
|
|
||||||
|
|
@ -104,6 +105,11 @@ public function nextStep(): void
|
||||||
{
|
{
|
||||||
$this->step++;
|
$this->step++;
|
||||||
$this->formErrors = [];
|
$this->formErrors = [];
|
||||||
|
|
||||||
|
// When entering feed step, inherit language from channel
|
||||||
|
if ($this->step === 4 && $this->channelLanguageId) {
|
||||||
|
$this->feedLanguageId = $this->channelLanguageId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function previousStep(): void
|
public function previousStep(): void
|
||||||
|
|
@ -210,24 +216,37 @@ public function createFeed(): void
|
||||||
$this->formErrors = [];
|
$this->formErrors = [];
|
||||||
$this->isLoading = true;
|
$this->isLoading = true;
|
||||||
|
|
||||||
|
// Get available provider codes for validation
|
||||||
|
$availableProviders = collect($this->getProvidersForLanguage())->pluck('code')->implode(',');
|
||||||
|
|
||||||
$this->validate([
|
$this->validate([
|
||||||
'feedName' => 'required|string|max:255',
|
'feedName' => 'required|string|max:255',
|
||||||
'feedProvider' => 'required|in:belga,vrt',
|
'feedProvider' => "required|in:{$availableProviders}",
|
||||||
'feedLanguageId' => 'required|exists:languages,id',
|
'feedLanguageId' => 'required|exists:languages,id',
|
||||||
'feedDescription' => 'nullable|string|max:1000',
|
'feedDescription' => 'nullable|string|max:1000',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Map provider to URL
|
// Get language short code
|
||||||
$url = $this->feedProvider === 'vrt'
|
$language = Language::find($this->feedLanguageId);
|
||||||
? 'https://www.vrt.be/vrtnws/en/'
|
$langCode = $language->short_code;
|
||||||
: 'https://www.belganewsagency.eu/';
|
|
||||||
|
// Look up URL from config
|
||||||
|
$url = config("feed.providers.{$this->feedProvider}.languages.{$langCode}.url");
|
||||||
|
|
||||||
|
if (!$url) {
|
||||||
|
$this->formErrors['general'] = 'Invalid provider and language combination.';
|
||||||
|
$this->isLoading = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$providerConfig = config("feed.providers.{$this->feedProvider}");
|
||||||
|
|
||||||
Feed::firstOrCreate(
|
Feed::firstOrCreate(
|
||||||
['url' => $url],
|
['url' => $url],
|
||||||
[
|
[
|
||||||
'name' => $this->feedName,
|
'name' => $this->feedName,
|
||||||
'type' => 'website',
|
'type' => $providerConfig['type'] ?? 'website',
|
||||||
'provider' => $this->feedProvider,
|
'provider' => $this->feedProvider,
|
||||||
'language_id' => $this->feedLanguageId,
|
'language_id' => $this->feedLanguageId,
|
||||||
'description' => $this->feedDescription ?: null,
|
'description' => $this->feedDescription ?: null,
|
||||||
|
|
@ -255,6 +274,16 @@ public function createChannel(): void
|
||||||
'channelDescription' => 'nullable|string|max:1000',
|
'channelDescription' => 'nullable|string|max:1000',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// If language changed, reset feed form
|
||||||
|
if ($this->previousChannelLanguageId !== null && $this->previousChannelLanguageId !== $this->channelLanguageId) {
|
||||||
|
$this->feedName = '';
|
||||||
|
$this->feedProvider = '';
|
||||||
|
$this->feedDescription = '';
|
||||||
|
$this->routeFeedId = null;
|
||||||
|
$this->routeChannelId = null;
|
||||||
|
}
|
||||||
|
$this->previousChannelLanguageId = $this->channelLanguageId;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$platformInstance = PlatformInstance::findOrFail($this->platformInstanceId);
|
$platformInstance = PlatformInstance::findOrFail($this->platformInstanceId);
|
||||||
|
|
||||||
|
|
@ -340,23 +369,97 @@ public function completeOnboarding(): void
|
||||||
$this->redirect(route('dashboard'));
|
$this->redirect(route('dashboard'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get language codes that have at least one active provider.
|
||||||
|
*/
|
||||||
|
public function getAvailableLanguageCodes(): array
|
||||||
|
{
|
||||||
|
$providers = config('feed.providers', []);
|
||||||
|
$languageCodes = [];
|
||||||
|
|
||||||
|
foreach ($providers as $provider) {
|
||||||
|
if (!($provider['is_active'] ?? false)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
foreach (array_keys($provider['languages'] ?? []) as $code) {
|
||||||
|
$languageCodes[$code] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_keys($languageCodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get providers available for the current channel language.
|
||||||
|
*/
|
||||||
|
public function getProvidersForLanguage(): array
|
||||||
|
{
|
||||||
|
if (!$this->channelLanguageId) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$language = Language::find($this->channelLanguageId);
|
||||||
|
if (!$language) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$langCode = $language->short_code;
|
||||||
|
$providers = config('feed.providers', []);
|
||||||
|
$available = [];
|
||||||
|
|
||||||
|
foreach ($providers as $key => $provider) {
|
||||||
|
if (!($provider['is_active'] ?? false)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (isset($provider['languages'][$langCode])) {
|
||||||
|
$available[] = [
|
||||||
|
'code' => $provider['code'],
|
||||||
|
'name' => $provider['name'],
|
||||||
|
'description' => $provider['description'] ?? '',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $available;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current channel language model.
|
||||||
|
*/
|
||||||
|
public function getChannelLanguage(): ?Language
|
||||||
|
{
|
||||||
|
if (!$this->channelLanguageId) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return Language::find($this->channelLanguageId);
|
||||||
|
}
|
||||||
|
|
||||||
public function render()
|
public function render()
|
||||||
{
|
{
|
||||||
$languages = Language::where('is_active', true)->orderBy('name')->get();
|
// For channel step: only show languages that have providers
|
||||||
$platformInstances = PlatformInstance::where('is_active', true)->orderBy('name')->get();
|
$availableCodes = $this->getAvailableLanguageCodes();
|
||||||
$feeds = Feed::where('is_active', true)->orderBy('name')->get();
|
$wizardLanguages = Language::where('is_active', true)
|
||||||
$channels = PlatformChannel::where('is_active', true)->orderBy('name')->get();
|
->whereIn('short_code', $availableCodes)
|
||||||
|
->orderBy('name')
|
||||||
|
->get();
|
||||||
|
|
||||||
$feedProviders = collect(config('feed.providers', []))
|
$platformInstances = PlatformInstance::where('is_active', true)->orderBy('name')->get();
|
||||||
->filter(fn($provider) => $provider['is_active'] ?? false)
|
$feeds = Feed::with('language')->where('is_active', true)->orderBy('name')->get();
|
||||||
->values();
|
$channels = PlatformChannel::with('language')->where('is_active', true)->orderBy('name')->get();
|
||||||
|
|
||||||
|
// For feed step: only show providers for the channel's language
|
||||||
|
$feedProviders = collect($this->getProvidersForLanguage());
|
||||||
|
|
||||||
|
// Get channel language for display
|
||||||
|
$channelLanguage = $this->getChannelLanguage();
|
||||||
|
|
||||||
return view('livewire.onboarding', [
|
return view('livewire.onboarding', [
|
||||||
'languages' => $languages,
|
'wizardLanguages' => $wizardLanguages,
|
||||||
'platformInstances' => $platformInstances,
|
'platformInstances' => $platformInstances,
|
||||||
'feeds' => $feeds,
|
'feeds' => $feeds,
|
||||||
'channels' => $channels,
|
'channels' => $channels,
|
||||||
'feedProviders' => $feedProviders,
|
'feedProviders' => $feedProviders,
|
||||||
|
'channelLanguage' => $channelLanguage,
|
||||||
])->layout('layouts.onboarding');
|
])->layout('layouts.onboarding');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,10 @@
|
||||||
'description' => 'Belgian public broadcaster news',
|
'description' => 'Belgian public broadcaster news',
|
||||||
'type' => 'website',
|
'type' => 'website',
|
||||||
'is_active' => true,
|
'is_active' => true,
|
||||||
|
'languages' => [
|
||||||
|
'en' => ['url' => 'https://www.vrt.be/vrtnws/en/'],
|
||||||
|
'nl' => ['url' => 'https://www.vrt.be/vrtnws/nl/'],
|
||||||
|
],
|
||||||
'parsers' => [
|
'parsers' => [
|
||||||
'homepage' => \App\Services\Parsers\VrtHomepageParserAdapter::class,
|
'homepage' => \App\Services\Parsers\VrtHomepageParserAdapter::class,
|
||||||
'article' => \App\Services\Parsers\VrtArticleParser::class,
|
'article' => \App\Services\Parsers\VrtArticleParser::class,
|
||||||
|
|
@ -27,10 +31,13 @@
|
||||||
],
|
],
|
||||||
'belga' => [
|
'belga' => [
|
||||||
'code' => 'belga',
|
'code' => 'belga',
|
||||||
'name' => 'Belga News Agency',
|
'name' => 'Belga News Agency',
|
||||||
'description' => 'Belgian national news agency',
|
'description' => 'Belgian national news agency',
|
||||||
'type' => 'rss',
|
'type' => 'rss',
|
||||||
'is_active' => true,
|
'is_active' => true,
|
||||||
|
'languages' => [
|
||||||
|
'en' => ['url' => 'https://www.belganewsagency.eu/'],
|
||||||
|
],
|
||||||
'parsers' => [
|
'parsers' => [
|
||||||
'homepage' => \App\Services\Parsers\BelgaHomepageParserAdapter::class,
|
'homepage' => \App\Services\Parsers\BelgaHomepageParserAdapter::class,
|
||||||
'article' => \App\Services\Parsers\BelgaArticleParser::class,
|
'article' => \App\Services\Parsers\BelgaArticleParser::class,
|
||||||
|
|
|
||||||
|
|
@ -12,30 +12,43 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'supported' => [
|
'supported' => [
|
||||||
'en' => [
|
'en' => ['short_code' => 'en', 'name' => 'English', 'native_name' => 'English', 'is_active' => true],
|
||||||
'short_code' => 'en',
|
'nl' => ['short_code' => 'nl', 'name' => 'Dutch', 'native_name' => 'Nederlands', 'is_active' => true],
|
||||||
'name' => 'English',
|
'fr' => ['short_code' => 'fr', 'name' => 'French', 'native_name' => 'Français', 'is_active' => true],
|
||||||
'native_name' => 'English',
|
'de' => ['short_code' => 'de', 'name' => 'German', 'native_name' => 'Deutsch', 'is_active' => true],
|
||||||
'is_active' => true,
|
'es' => ['short_code' => 'es', 'name' => 'Spanish', 'native_name' => 'Español', 'is_active' => true],
|
||||||
],
|
'it' => ['short_code' => 'it', 'name' => 'Italian', 'native_name' => 'Italiano', 'is_active' => true],
|
||||||
'nl' => [
|
'pt' => ['short_code' => 'pt', 'name' => 'Portuguese', 'native_name' => 'Português', 'is_active' => true],
|
||||||
'short_code' => 'nl',
|
'pl' => ['short_code' => 'pl', 'name' => 'Polish', 'native_name' => 'Polski', 'is_active' => true],
|
||||||
'name' => 'Dutch',
|
'ru' => ['short_code' => 'ru', 'name' => 'Russian', 'native_name' => 'Русский', 'is_active' => true],
|
||||||
'native_name' => 'Nederlands',
|
'uk' => ['short_code' => 'uk', 'name' => 'Ukrainian', 'native_name' => 'Українська', 'is_active' => true],
|
||||||
'is_active' => true,
|
'cs' => ['short_code' => 'cs', 'name' => 'Czech', 'native_name' => 'Čeština', 'is_active' => true],
|
||||||
],
|
'sk' => ['short_code' => 'sk', 'name' => 'Slovak', 'native_name' => 'Slovenčina', 'is_active' => true],
|
||||||
'fr' => [
|
'hu' => ['short_code' => 'hu', 'name' => 'Hungarian', 'native_name' => 'Magyar', 'is_active' => true],
|
||||||
'short_code' => 'fr',
|
'ro' => ['short_code' => 'ro', 'name' => 'Romanian', 'native_name' => 'Română', 'is_active' => true],
|
||||||
'name' => 'French',
|
'bg' => ['short_code' => 'bg', 'name' => 'Bulgarian', 'native_name' => 'Български', 'is_active' => true],
|
||||||
'native_name' => 'Français',
|
'hr' => ['short_code' => 'hr', 'name' => 'Croatian', 'native_name' => 'Hrvatski', 'is_active' => true],
|
||||||
'is_active' => true,
|
'sl' => ['short_code' => 'sl', 'name' => 'Slovenian', 'native_name' => 'Slovenščina', 'is_active' => true],
|
||||||
],
|
'sr' => ['short_code' => 'sr', 'name' => 'Serbian', 'native_name' => 'Српски', 'is_active' => true],
|
||||||
'de' => [
|
'el' => ['short_code' => 'el', 'name' => 'Greek', 'native_name' => 'Ελληνικά', 'is_active' => true],
|
||||||
'short_code' => 'de',
|
'tr' => ['short_code' => 'tr', 'name' => 'Turkish', 'native_name' => 'Türkçe', 'is_active' => true],
|
||||||
'name' => 'German',
|
'da' => ['short_code' => 'da', 'name' => 'Danish', 'native_name' => 'Dansk', 'is_active' => true],
|
||||||
'native_name' => 'Deutsch',
|
'sv' => ['short_code' => 'sv', 'name' => 'Swedish', 'native_name' => 'Svenska', 'is_active' => true],
|
||||||
'is_active' => true,
|
'no' => ['short_code' => 'no', 'name' => 'Norwegian', 'native_name' => 'Norsk', 'is_active' => true],
|
||||||
],
|
'fi' => ['short_code' => 'fi', 'name' => 'Finnish', 'native_name' => 'Suomi', 'is_active' => true],
|
||||||
|
'et' => ['short_code' => 'et', 'name' => 'Estonian', 'native_name' => 'Eesti', 'is_active' => true],
|
||||||
|
'lv' => ['short_code' => 'lv', 'name' => 'Latvian', 'native_name' => 'Latviešu', 'is_active' => true],
|
||||||
|
'lt' => ['short_code' => 'lt', 'name' => 'Lithuanian', 'native_name' => 'Lietuvių', 'is_active' => true],
|
||||||
|
'ja' => ['short_code' => 'ja', 'name' => 'Japanese', 'native_name' => '日本語', 'is_active' => true],
|
||||||
|
'zh' => ['short_code' => 'zh', 'name' => 'Chinese', 'native_name' => '中文', 'is_active' => true],
|
||||||
|
'ko' => ['short_code' => 'ko', 'name' => 'Korean', 'native_name' => '한국어', 'is_active' => true],
|
||||||
|
'ar' => ['short_code' => 'ar', 'name' => 'Arabic', 'native_name' => 'العربية', 'is_active' => true],
|
||||||
|
'he' => ['short_code' => 'he', 'name' => 'Hebrew', 'native_name' => 'עברית', 'is_active' => true],
|
||||||
|
'hi' => ['short_code' => 'hi', 'name' => 'Hindi', 'native_name' => 'हिन्दी', 'is_active' => true],
|
||||||
|
'th' => ['short_code' => 'th', 'name' => 'Thai', 'native_name' => 'ไทย', 'is_active' => true],
|
||||||
|
'vi' => ['short_code' => 'vi', 'name' => 'Vietnamese', 'native_name' => 'Tiếng Việt', 'is_active' => true],
|
||||||
|
'id' => ['short_code' => 'id', 'name' => 'Indonesian', 'native_name' => 'Bahasa Indonesia', 'is_active' => true],
|
||||||
|
'ms' => ['short_code' => 'ms', 'name' => 'Malay', 'native_name' => 'Bahasa Melayu', 'is_active' => true],
|
||||||
],
|
],
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -241,7 +241,7 @@ class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none foc
|
||||||
required
|
required
|
||||||
>
|
>
|
||||||
<option value="">Select language</option>
|
<option value="">Select language</option>
|
||||||
@foreach ($languages as $language)
|
@foreach ($wizardLanguages as $language)
|
||||||
<option value="{{ $language->id }}">{{ $language->name }}</option>
|
<option value="{{ $language->id }}">{{ $language->name }}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
|
|
@ -316,6 +316,25 @@ class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none foc
|
||||||
@error('feedName') <p class="text-red-600 text-sm mt-1">{{ $message }}</p> @enderror
|
@error('feedName') <p class="text-red-600 text-sm mt-1">{{ $message }}</p> @enderror
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label for="feedLanguageId" class="block text-sm font-medium text-gray-700 mb-2 flex items-center">
|
||||||
|
Language
|
||||||
|
<span class="ml-2 text-gray-400 cursor-help" title="Language matches your channel. Additional languages can be configured from the dashboard after setup.">
|
||||||
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
<select
|
||||||
|
id="feedLanguageId"
|
||||||
|
disabled
|
||||||
|
class="w-full px-3 py-2 border border-gray-300 rounded-md bg-gray-100 text-gray-600 cursor-not-allowed"
|
||||||
|
>
|
||||||
|
<option>{{ $channelLanguage?->name ?? 'Unknown' }}</option>
|
||||||
|
</select>
|
||||||
|
<p class="text-sm text-gray-500 mt-1">Inherited from your channel</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label for="feedProvider" class="block text-sm font-medium text-gray-700 mb-2">
|
<label for="feedProvider" class="block text-sm font-medium text-gray-700 mb-2">
|
||||||
News Provider
|
News Provider
|
||||||
|
|
@ -331,27 +350,12 @@ class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none foc
|
||||||
<option value="{{ $provider['code'] }}">{{ $provider['name'] }}</option>
|
<option value="{{ $provider['code'] }}">{{ $provider['name'] }}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
|
@if ($feedProviders->isEmpty())
|
||||||
|
<p class="text-sm text-amber-600 mt-1">No providers available for this language.</p>
|
||||||
|
@endif
|
||||||
@error('feedProvider') <p class="text-red-600 text-sm mt-1">{{ $message }}</p> @enderror
|
@error('feedProvider') <p class="text-red-600 text-sm mt-1">{{ $message }}</p> @enderror
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
|
||||||
<label for="feedLanguageId" class="block text-sm font-medium text-gray-700 mb-2">
|
|
||||||
Language
|
|
||||||
</label>
|
|
||||||
<select
|
|
||||||
id="feedLanguageId"
|
|
||||||
wire:model="feedLanguageId"
|
|
||||||
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
||||||
required
|
|
||||||
>
|
|
||||||
<option value="">Select language</option>
|
|
||||||
@foreach ($languages as $language)
|
|
||||||
<option value="{{ $language->id }}">{{ $language->name }}</option>
|
|
||||||
@endforeach
|
|
||||||
</select>
|
|
||||||
@error('feedLanguageId') <p class="text-red-600 text-sm mt-1">{{ $message }}</p> @enderror
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label for="feedDescription" class="block text-sm font-medium text-gray-700 mb-2">
|
<label for="feedDescription" class="block text-sm font-medium text-gray-700 mb-2">
|
||||||
Description (Optional)
|
Description (Optional)
|
||||||
|
|
@ -372,7 +376,7 @@ class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none foc
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
@disabled($isLoading)
|
@disabled($isLoading || $feedProviders->isEmpty())
|
||||||
class="bg-blue-600 text-white py-2 px-6 rounded-md hover:bg-blue-700 transition duration-200 disabled:opacity-50"
|
class="bg-blue-600 text-white py-2 px-6 rounded-md hover:bg-blue-700 transition duration-200 disabled:opacity-50"
|
||||||
>
|
>
|
||||||
{{ $isLoading ? 'Creating...' : 'Continue' }}
|
{{ $isLoading ? 'Creating...' : 'Continue' }}
|
||||||
|
|
@ -418,7 +422,7 @@ class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none foc
|
||||||
>
|
>
|
||||||
<option value="">Select a feed</option>
|
<option value="">Select a feed</option>
|
||||||
@foreach ($feeds as $feed)
|
@foreach ($feeds as $feed)
|
||||||
<option value="{{ $feed->id }}">{{ $feed->name }}</option>
|
<option value="{{ $feed->id }}">{{ $feed->name }} ({{ $feed->language?->short_code ?? '?' }})</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
@error('routeFeedId') <p class="text-red-600 text-sm mt-1">{{ $message }}</p> @enderror
|
@error('routeFeedId') <p class="text-red-600 text-sm mt-1">{{ $message }}</p> @enderror
|
||||||
|
|
@ -436,7 +440,7 @@ class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none foc
|
||||||
>
|
>
|
||||||
<option value="">Select a channel</option>
|
<option value="">Select a channel</option>
|
||||||
@foreach ($channels as $channel)
|
@foreach ($channels as $channel)
|
||||||
<option value="{{ $channel->id }}">{{ $channel->display_name ?? $channel->name }}</option>
|
<option value="{{ $channel->id }}">{{ $channel->display_name ?? $channel->name }} ({{ $channel->language?->short_code ?? '?' }})</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
@if ($channels->isEmpty())
|
@if ($channels->isEmpty())
|
||||||
|
|
|
||||||
11
shell.nix
11
shell.nix
|
|
@ -65,6 +65,16 @@ pkgs.mkShell {
|
||||||
podman-compose -f $COMPOSE_FILE restart "$@"
|
podman-compose -f $COMPOSE_FILE restart "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dev-rebuild() {
|
||||||
|
echo "Rebuilding services (down -v + up)..."
|
||||||
|
podman-compose -f $COMPOSE_FILE down -v
|
||||||
|
PODMAN_USERNS=keep-id podman-compose -f $COMPOSE_FILE up -d "$@"
|
||||||
|
echo ""
|
||||||
|
podman-compose -f $COMPOSE_FILE ps
|
||||||
|
echo ""
|
||||||
|
echo "App available at: http://localhost:8000"
|
||||||
|
}
|
||||||
|
|
||||||
dev-logs() {
|
dev-logs() {
|
||||||
podman-compose -f $COMPOSE_FILE logs -f app "$@"
|
podman-compose -f $COMPOSE_FILE logs -f app "$@"
|
||||||
}
|
}
|
||||||
|
|
@ -123,6 +133,7 @@ pkgs.mkShell {
|
||||||
echo "Commands:"
|
echo "Commands:"
|
||||||
echo " dev-up [services] Start all or specific services"
|
echo " dev-up [services] Start all or specific services"
|
||||||
echo " dev-down [-v] Stop services (-v removes volumes)"
|
echo " dev-down [-v] Stop services (-v removes volumes)"
|
||||||
|
echo " dev-rebuild Fresh start (down -v + up)"
|
||||||
echo " dev-restart Restart services"
|
echo " dev-restart Restart services"
|
||||||
echo " dev-logs Tail app logs"
|
echo " dev-logs Tail app logs"
|
||||||
echo " dev-logs-db Tail database logs"
|
echo " dev-logs-db Tail database logs"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue