Add ability to force the queried icons collection on the Advanced form

This commit is contained in:
Bubka 2025-06-05 13:06:03 +02:00
parent 9e3794a956
commit c693c840b2
5 changed files with 62 additions and 31 deletions

View File

@ -11,6 +11,7 @@ use App\Models\TwoFAccount;
use Exception; use Exception;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Http\UploadedFile; use Illuminate\Http\UploadedFile;
use Illuminate\Support\Arr;
class IconController extends Controller class IconController extends Controller
{ {
@ -52,7 +53,11 @@ class IconController extends Controller
{ {
$validated = $request->validated(); $validated = $request->validated();
$icon = LogoLib::driver('tfa')->getIcon($validated['service']); $iconCollection = Arr::has($validated, 'iconCollection') && $validated['iconCollection']
? $validated['iconCollection']
: $request->user()->preferences['iconCollection'];
$icon = LogoLib::driver($iconCollection)->getIcon($validated['service']);
return $icon return $icon
? response()->json(['filename' => $icon], 201) ? response()->json(['filename' => $icon], 201)

View File

@ -26,6 +26,7 @@ class IconFetchRequest extends FormRequest
{ {
return [ return [
'service' => 'string', 'service' => 'string',
'iconCollection' => 'nullable|string|in:tfa,selfh,dashboardicons',
]; ];
} }

View File

@ -23,8 +23,8 @@ export default {
return apiClient.post('/twofaccounts', { uri: uri }, { ...config }) return apiClient.post('/twofaccounts', { uri: uri }, { ...config })
}, },
getLogo(service, config = {}) { getLogo(service, iconCollection, config = {}) {
return apiClient.post('/icons/default', { service: service }, { ...config }) return apiClient.post('/icons/default', { service: service, iconCollection: iconCollection }, { ...config })
}, },
deleteIcon(icon, config = {}) { deleteIcon(icon, config = {}) {

View File

@ -37,6 +37,11 @@
const iconForm = reactive(new Form({ const iconForm = reactive(new Form({
icon: null icon: null
})) }))
const iconCollections = [
{ text: 'selfh.st', value: 'selfh' },
{ text: 'dashboardicons.com', value: 'dashboardicons' },
{ text: '2fa.directory', value: 'tfa' },
]
const otpDisplayProps = ref({ const otpDisplayProps = ref({
otp_type: '', otp_type: '',
account : '', account : '',
@ -69,6 +74,7 @@
const showAdvancedForm = ref(false) const showAdvancedForm = ref(false)
const ShowTwofaccountInModal = ref(false) const ShowTwofaccountInModal = ref(false)
const fetchingLogo = ref(false) const fetchingLogo = ref(false)
const iconCollection = ref(user.preferences.iconCollection)
// $refs // $refs
const iconInput = ref(null) const iconInput = ref(null)
@ -379,7 +385,7 @@
if (user.preferences.getOfficialIcons) { if (user.preferences.getOfficialIcons) {
fetchingLogo.value = true fetchingLogo.value = true
twofaccountService.getLogo(form.service, { returnError: true }) twofaccountService.getLogo(form.service, iconCollection.value, { returnError: true })
.then(response => { .then(response => {
if (response.status === 201) { if (response.status === 201) {
// clean possible already uploaded temp icon // clean possible already uploaded temp icon
@ -486,16 +492,31 @@
<FormField v-model="form.account" fieldName="account" :fieldError="form.errors.get('account')" label="twofaccounts.account" :placeholder="$t('twofaccounts.forms.account.placeholder')" /> <FormField v-model="form.account" fieldName="account" :fieldError="form.errors.get('account')" label="twofaccounts.account" :placeholder="$t('twofaccounts.forms.account.placeholder')" />
<!-- icon upload --> <!-- icon upload -->
<label for="filUploadIcon" class="label">{{ $t('twofaccounts.icon') }}</label> <label for="filUploadIcon" class="label">{{ $t('twofaccounts.icon') }}</label>
<div class="columns is-mobile mb-0">
<div class="column">
<!-- try my luck -->
<fieldset v-if="user.preferences.getOfficialIcons" :disabled="!form.service">
<div class="field is-grouped"> <div class="field is-grouped">
<!-- Try my luck button --> <div class="control">
<div class="control" v-if="user.preferences.getOfficialIcons"> <VueButton @click="fetchLogo" :color="mode == 'dark' ? 'is-dark' : ''" :nativeType="'button'" :is-loading="fetchingLogo" aria-describedby="lgdTryMyLuck">
<VueButton @click="fetchLogo" :color="mode == 'dark' ? 'is-dark' : ''" :nativeType="'button'" :is-loading="fetchingLogo" :isDisabled="!form.service" aria-describedby="lgdTryMyLuck">
<span class="icon is-small"> <span class="icon is-small">
<FontAwesomeIcon :icon="['fas', 'globe']" /> <FontAwesomeIcon :icon="['fas', 'globe']" />
</span> </span>
<span>{{ $t('twofaccounts.forms.i_m_lucky') }}</span> <span>{{ $t('twofaccounts.forms.i_m_lucky') }}</span>
</VueButton> </VueButton>
</div> </div>
<div class="control">
<div class="select">
<select name="icon-collection" v-model="iconCollection">
<option v-for="collection in iconCollections" :key="collection.text" :value="collection.value">
{{ collection.text }}
</option>
</select>
</div>
</div>
</div>
</fieldset>
<div class="field is-grouped">
<!-- upload icon button --> <!-- upload icon button -->
<div class="control is-flex"> <div class="control is-flex">
<div role="button" tabindex="0" class="file mr-3" :class="mode == 'dark' ? 'is-dark' : 'is-white'" @keyup.enter="iconInputLabel.click()"> <div role="button" tabindex="0" class="file mr-3" :class="mode == 'dark' ? 'is-dark' : 'is-white'" @keyup.enter="iconInputLabel.click()">
@ -515,6 +536,10 @@
</span> </span>
</div> </div>
</div> </div>
</div>
<div class="column is-narrow" style="width: 200px;">
</div>
</div>
<div class="field"> <div class="field">
<FieldError v-if="iconForm.errors.hasAny('icon')" :error="iconForm.errors.get('icon')" :field="'icon'" class="help-for-file" /> <FieldError v-if="iconForm.errors.hasAny('icon')" :error="iconForm.errors.get('icon')" :field="'icon'" class="help-for-file" />
<p id="lgdTryMyLuck" v-if="user.preferences.getOfficialIcons" class="help" v-html="$t('twofaccounts.forms.i_m_lucky_legend')"></p> <p id="lgdTryMyLuck" v-if="user.preferences.getOfficialIcons" class="help" v-html="$t('twofaccounts.forms.i_m_lucky_legend')"></p>

View File

@ -66,7 +66,7 @@ return [
], ],
'choose_image' => 'Upload', 'choose_image' => 'Upload',
'i_m_lucky' => 'Try my luck', 'i_m_lucky' => 'Try my luck',
'i_m_lucky_legend' => 'The "Try my luck" button try to get the official icon of the given service. Enter actual service name without ".xyz" extension and try to avoid typo. (beta feature)', 'i_m_lucky_legend' => 'The "Try my luck" button tries to get a standard icon from the selected icon collection. The simpler the service value, the more likely you are to get the correct icon: Do not append any extension (like ".com"), use the exact name of the service, avoid special chars.',
'test' => 'Test', 'test' => 'Test',
'group' => [ 'group' => [
'label' => 'Group', 'label' => 'Group',