Display a DN entry with language tags - work for #16

This commit is contained in:
Deon George 2025-03-23 22:16:26 +11:00
parent 0e2a8705ea
commit 5ef021c381
12 changed files with 132 additions and 50 deletions

View File

@ -178,14 +178,7 @@ class Attribute implements \Countable, \ArrayAccess, \Iterator
return $this->name; return $this->name;
} }
public function addValue(string $tag,string $value): void /* INTERFACE */
{
$this->_values->put(
$tag,
$this->_values
->get($tag,collect())
->push($value));
}
public function current(): mixed public function current(): mixed
{ {
@ -237,6 +230,24 @@ class Attribute implements \Countable, \ArrayAccess, \Iterator
// We cannot clear values using array syntax // We cannot clear values using array syntax
} }
/* METHODS */
public function addValue(string $tag,array $values): void
{
$this->_values->put(
$tag,
array_unique(array_merge($this->_values
->get($tag,[]),$values)));
}
public function addValueOld(string $tag,array $values): void
{
$this->_values_old->put(
$tag,
array_unique(array_merge($this->_values_old
->get($tag,[]),$values)));
}
/** /**
* Return the hints about this attribute, ie: RDN, Required, etc * Return the hints about this attribute, ie: RDN, Required, etc
* *
@ -266,8 +277,10 @@ class Attribute implements \Countable, \ArrayAccess, \Iterator
*/ */
public function isDirty(): bool public function isDirty(): bool
{ {
return ($this->values_old->count() !== $this->values->count()) return (($a=$this->values_old->dot())->keys()->count() !== ($b=$this->values->dot())->keys()->count())
|| ($this->values->diff($this->values_old)->count() !== 0); || ($a->values()->count() !== $b->values()->count())
|| ($a->keys()->diff($b->keys())->count() !== 0)
|| ($a->values()->diff($b->values())->count() !== 0);
} }
/** /**
@ -329,4 +342,18 @@ class Attribute implements \Countable, \ArrayAccess, \Iterator
? $this->oc->intersect($this->required_by->keys())->sort() ? $this->oc->intersect($this->required_by->keys())->sort()
: collect(); : collect();
} }
public function tagValues(string $tag=''): Collection
{
return $this->_values
->filter(fn($item,$key)=>($key === $tag))
->values();
}
public function tagValuesOld(string $tag=''): Collection
{
return $this->_values_old
->filter(fn($item,$key)=>($key === $tag))
->values();
}
} }

View File

@ -309,7 +309,9 @@ class Entry extends Model
->map(fn($item)=>$item ->map(fn($item)=>$item
->values ->values
->keys() ->keys()
->filter(fn($item)=>preg_match(sprintf('/%s+;?/',self::TAG_CHARS_LANG),$item))) ->filter(fn($item)=>preg_match(sprintf('/%s+;?/',self::TAG_CHARS_LANG),$item))
->map(fn($item)=>preg_replace('/lang-/','',$item))
)
->filter(fn($item)=>$item->count()); ->filter(fn($item)=>$item->count());
} }

View File

@ -12,17 +12,19 @@ class Attribute extends Component
public bool $edit; public bool $edit;
public bool $new; public bool $new;
public bool $old; public bool $old;
public ?string $na; public string $langtag;
public ?string $na; // Text to render if the LDAPAttribute is null
/** /**
* Create a new component instance. * Create a new component instance.
*/ */
public function __construct(?LDAPAttribute $o,bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,?string $na=NULL) public function __construct(?LDAPAttribute $o,bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,string $langtag='',?string $na=NULL)
{ {
$this->o = $o; $this->o = $o;
$this->edit = $edit; $this->edit = $edit;
$this->old = $old; $this->old = $old;
$this->new = $new; $this->new = $new;
$this->langtag = $langtag;
$this->na = $na; $this->na = $na;
} }

View File

@ -13,14 +13,16 @@ class AttributeType extends Component
{ {
private LDAPAttribute $o; private LDAPAttribute $o;
private bool $new; private bool $new;
private string $langtag;
/** /**
* Create a new component instance. * Create a new component instance.
*/ */
public function __construct(LDAPAttribute $o,bool $new=FALSE) public function __construct(LDAPAttribute $o,bool $new=FALSE,string $langtag='')
{ {
$this->o = $o; $this->o = $o;
$this->new = $new; $this->new = $new;
$this->langtag = $langtag;
} }
/** /**
@ -30,6 +32,7 @@ class AttributeType extends Component
{ {
return view('components.attribute-type') return view('components.attribute-type')
->with('o',$this->o) ->with('o',$this->o)
->with('new',$this->new); ->with('new',$this->new)
->with('langtag',$this->langtag);
} }
} }

View File

@ -30,7 +30,10 @@ input.form-control.input-group-end {
.custom-tooltip-danger { .custom-tooltip-danger {
--bs-tooltip-bg: var(--bs-danger); --bs-tooltip-bg: var(--bs-danger);
}
.custom-tooltip {
--bs-tooltip-bg: var(--bs-gray-900);
} }
.tooltip { .tooltip {

View File

@ -15,7 +15,7 @@
</div> </div>
</div> </div>
<x-attribute :o="$o" :edit="true" :new="$new ?? FALSE"/> <x-attribute :o="$o" :edit="true" :new="$new ?? FALSE" :langtag="$langtag"/>
</div> </div>
</div> </div>

View File

@ -1,14 +1,8 @@
<!-- $o=Attribute::class --> <!-- $o=Attribute::class -->
<x-attribute.layout :edit="$edit ?? FALSE" :new="$new ?? FALSE" :o="$o"> <x-attribute.layout :edit="$edit ?? FALSE" :new="$new ?? FALSE" :o="$o">
@foreach(old($o->name_lc,($new ?? FALSE) ? [NULL] : $o->values) as $tag=>$tagvalues) @foreach(old($o->name_lc,($new ?? FALSE) ? [NULL] : $o->tagValues($langtag)) as $values)
<div class="row p-2 border rounded">
<div class="col-2">
{{ $tag }}
</div>
<div class="col-10">
<div class="row">
<div class="col-12"> <div class="col-12">
@foreach($tagvalues as $value) @foreach($values as $value)
@if(($edit ?? FALSE) && ! $o->is_rdn) @if(($edit ?? FALSE) && ! $o->is_rdn)
<div class="input-group has-validation"> <div class="input-group has-validation">
<input type="text" @class(['form-control','is-invalid'=>($e=$errors->get($o->name_lc.'.'.$loop->index)),'mb-1','border-focus'=>($o->values->contains($value))]) name="{{ $o->name_lc }}[]" value="{{ $value }}" placeholder="{{ ! is_null($x=Arr::get($o->values,$loop->index)) ? $x : '['.__('NEW').']' }}" @readonly(! ($new ?? FALSE))> <input type="text" @class(['form-control','is-invalid'=>($e=$errors->get($o->name_lc.'.'.$loop->index)),'mb-1','border-focus'=>($o->values->contains($value))]) name="{{ $o->name_lc }}[]" value="{{ $value }}" placeholder="{{ ! is_null($x=Arr::get($o->values,$loop->index)) ? $x : '['.__('NEW').']' }}" @readonly(! ($new ?? FALSE))>
@ -24,8 +18,5 @@
@endif @endif
@endforeach @endforeach
</div> </div>
</div>
</div>
</div>
@endforeach @endforeach
</x-attribute.layout> </x-attribute.layout>

View File

@ -1,8 +1,8 @@
<!-- $o=Attribute::class --> <!-- $o=Attribute::class -->
<x-attribute.layout :edit="$edit" :new="$new" :o="$o"> <x-attribute.layout :edit="$edit" :new="$new" :o="$o" :langtag="$langtag">
@foreach(old($o->name_lc,$o->values) as $value) @foreach(old($o->name_lc,$o->values) as $value)
@if($edit) @if($edit)
<x-attribute.widget.objectclass :o="$o" :edit="$edit" :new="$new" :loop="$loop" :value="$value"/> <x-attribute.widget.objectclass :o="$o" :edit="$edit" :new="$new" :loop="$loop" :value="$value" :langtag="$langtag"/>
@else @else
{{ $value }} {{ $value }}
@if ($o->isStructural($value)) @if ($o->isStructural($value))

View File

@ -1,6 +1,6 @@
<!-- @todo We are not handling redirect backs yet with updated passwords --> <!-- @todo We are not handling redirect backs yet with updated passwords -->
<!-- $o=Password::class --> <!-- $o=Password::class -->
<x-attribute.layout :edit="$edit ?? FALSE" :new="$new ?? FALSE" :o="$o"> <x-attribute.layout :edit="$edit ?? FALSE" :new="$new ?? FALSE" :o="$o" :langtag="$langtag">
@foreach($o->values_old as $value) @foreach($o->values_old as $value)
@if($edit) @if($edit)
<div class="input-group has-validation mb-3"> <div class="input-group has-validation mb-3">

View File

@ -4,7 +4,7 @@
<span class="p-0 m-0"> <span class="p-0 m-0">
@if($o->is_rdn) @if($o->is_rdn)
<br/> <br/>
<span class="btn btn-sm btn-outline-focus mt-3" disabled><i class="fas fa-fw fa-exchange"></i> @lang('Rename')</span> <button class="btn btn-sm btn-outline-focus mt-3" disabled><i class="fas fa-fw fa-exchange"></i> @lang('Rename')</button>
@elseif($edit && $o->can_addvalues) @elseif($edit && $o->can_addvalues)
@switch(get_class($o)) @switch(get_class($o))
@case(JpegPhoto::class) @case(JpegPhoto::class)

View File

@ -26,10 +26,10 @@
<x-attribute :o="$o->getObject('entryuuid')" :na="__('Unknown')"/> <x-attribute :o="$o->getObject('entryuuid')" :na="__('Unknown')"/>
</th> </th>
</tr> </tr>
@if(($x=$o->getLangTags())->count()) @if($langtags->count())
<tr class="mt-1"> <tr class="mt-1">
<td class="p-0 pe-2">Tags</td> <td class="p-0 pe-2">Tags</td>
<th class="p-0">{{ $x->flatMap(fn($item)=>$item->values())->unique()->join(', ') }}</th> <th class="p-0">{{ $langtags->join(', ') }}</th>
</tr> </tr>
@endif @endif
</table> </table>

View File

@ -1,7 +1,13 @@
@extends('layouts.dn') @extends('layouts.dn')
@section('page_title') @section('page_title')
@include('fragment.dn.header',['o'=>($o ?? $o=$server->fetch($dn))]) @include('fragment.dn.header',[
'o'=>($o ?? $o=$server->fetch($dn)),
'langtags'=>($langtags=$o->getLangTags()
->flatMap(fn($item)=>$item->values())
->unique()
->sort())
])
@endsection @endsection
@section('page_actions') @section('page_actions')
@ -71,7 +77,7 @@
<div class="main-card mb-3 card"> <div class="main-card mb-3 card">
<div class="card-body"> <div class="card-body">
<div class="card-header-tabs"> <div class="card-header-tabs">
<ul class="nav nav-tabs"> <ul class="nav nav-tabs mb-0">
<li class="nav-item"><a data-bs-toggle="tab" href="#attributes" class="nav-link active">@lang('Attributes')</a></li> <li class="nav-item"><a data-bs-toggle="tab" href="#attributes" class="nav-link active">@lang('Attributes')</a></li>
<li class="nav-item"><a data-bs-toggle="tab" href="#internal" class="nav-link">@lang('Internal')</a></li> <li class="nav-item"><a data-bs-toggle="tab" href="#internal" class="nav-link">@lang('Internal')</a></li>
@env(['local']) @env(['local'])
@ -87,9 +93,57 @@
<input type="hidden" name="dn" value=""> <input type="hidden" name="dn" value="">
@foreach ($o->getVisibleAttributes() as $ao) <div class="card-header border-bottom-0">
<x-attribute-type :edit="true" :o="$ao"/> <div class="btn-actions-pane-right">
<div role="group" class="btn-group-sm nav btn-group">
@foreach($langtags->prepend('')->push('+') as $tag)
<a data-bs-toggle="tab" href="#tab-lang-{{ $tag ?: '_default' }}" class="btn btn-outline-light border-dark-subtle @if(! $loop->index) active @endif @if($loop->last)ndisabled @endif">
@switch($tag)
@case('')
<i class="fas fa-fw fa-border-none" data-bs-toggle="tooltip" data-bs-custom-class="custom-tooltip" title="@lang('No Lang Tag')"></i>
@break
@case('+')
<!-- @todo To implement -->
<i class="fas fa-fw fa-plus text-dark" data-bs-toggle="tooltip" data-bs-custom-class="custom-tooltip" title="@lang('Add Lang Tag')"></i>
@break
@default
<span class="f16" data-bs-toggle="tooltip" data-bs-custom-class="custom-tooltip" title="{{ strtoupper($tag) }}"><i class="flag {{ $tag }}"></i></span>
@endswitch
</a>
@endforeach @endforeach
</div>
</div>
</div>
<div class="card-body">
<div class="tab-content">
@foreach($langtags as $tag)
<div class="tab-pane @if(! $loop->index) active @endif" id="tab-lang-{{ $tag ?: '_default' }}" role="tabpanel">
@switch($tag)
@case('')
@foreach ($o->getVisibleAttributes($tag) as $ao)
<x-attribute-type :edit="true" :o="$ao" langtag=""/>
@endforeach
@break
@case('+')
<div class="ms-auto mt-4 alert alert-warning p-2" style="max-width: 30em; font-size: 0.80em;">
It is not possible to create new language tags at the moment. This functionality should come soon.<br>
You can create them with an LDIF import though.
</div>
@break
@default
@foreach ($o->getVisibleAttributes($langtag=sprintf('lang-%s',$tag)) as $ao)
<x-attribute-type :edit="true" :o="$ao" :langtag="$langtag"/>
@endforeach
@endswitch
</div>
@endforeach
</div>
</div>
@include('fragment.dn.add_attr') @include('fragment.dn.add_attr')
</form> </form>