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 705bfb2d64
commit 633513d3e9
12 changed files with 132 additions and 50 deletions

View File

@ -178,14 +178,7 @@ class Attribute implements \Countable, \ArrayAccess, \Iterator
return $this->name;
}
public function addValue(string $tag,string $value): void
{
$this->_values->put(
$tag,
$this->_values
->get($tag,collect())
->push($value));
}
/* INTERFACE */
public function current(): mixed
{
@ -237,6 +230,24 @@ class Attribute implements \Countable, \ArrayAccess, \Iterator
// 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
*
@ -266,8 +277,10 @@ class Attribute implements \Countable, \ArrayAccess, \Iterator
*/
public function isDirty(): bool
{
return ($this->values_old->count() !== $this->values->count())
|| ($this->values->diff($this->values_old)->count() !== 0);
return (($a=$this->values_old->dot())->keys()->count() !== ($b=$this->values->dot())->keys()->count())
|| ($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()
: 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
->values
->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());
}

View File

@ -12,17 +12,19 @@ class Attribute extends Component
public bool $edit;
public bool $new;
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.
*/
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->edit = $edit;
$this->old = $old;
$this->new = $new;
$this->langtag = $langtag;
$this->na = $na;
}

View File

@ -13,14 +13,16 @@ class AttributeType extends Component
{
private LDAPAttribute $o;
private bool $new;
private string $langtag;
/**
* 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->new = $new;
$this->langtag = $langtag;
}
/**
@ -30,6 +32,7 @@ class AttributeType extends Component
{
return view('components.attribute-type')
->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 {
--bs-tooltip-bg: var(--bs-danger);
}
.custom-tooltip {
--bs-tooltip-bg: var(--bs-gray-900);
}
.tooltip {

View File

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

View File

@ -1,31 +1,22 @@
<!-- $o=Attribute::class -->
<x-attribute.layout :edit="$edit ?? FALSE" :new="$new ?? FALSE" :o="$o">
@foreach(old($o->name_lc,($new ?? FALSE) ? [NULL] : $o->values) as $tag=>$tagvalues)
<div class="row p-2 border rounded">
<div class="col-2">
{{ $tag }}
</div>
<div class="col-10">
<div class="row">
<div class="col-12">
@foreach($tagvalues as $value)
@if(($edit ?? FALSE) && ! $o->is_rdn)
<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))>
@foreach(old($o->name_lc,($new ?? FALSE) ? [NULL] : $o->tagValues($langtag)) as $values)
<div class="col-12">
@foreach($values as $value)
@if(($edit ?? FALSE) && ! $o->is_rdn)
<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))>
<div class="invalid-feedback pb-2">
@if($e)
{{ join('|',$e) }}
@endif
</div>
</div>
@else
{{ $value }}
<div class="invalid-feedback pb-2">
@if($e)
{{ join('|',$e) }}
@endif
@endforeach
</div>
</div>
</div>
</div>
@else
{{ $value }}
@endif
@endforeach
</div>
@endforeach
</x-attribute.layout>

View File

@ -1,8 +1,8 @@
<!-- $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)
@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
{{ $value }}
@if ($o->isStructural($value))

View File

@ -1,6 +1,6 @@
<!-- @todo We are not handling redirect backs yet with updated passwords -->
<!-- $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)
@if($edit)
<div class="input-group has-validation mb-3">

View File

@ -4,7 +4,7 @@
<span class="p-0 m-0">
@if($o->is_rdn)
<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)
@switch(get_class($o))
@case(JpegPhoto::class)

View File

@ -26,10 +26,10 @@
<x-attribute :o="$o->getObject('entryuuid')" :na="__('Unknown')"/>
</th>
</tr>
@if(($x=$o->getLangTags())->count())
@if($langtags->count())
<tr class="mt-1">
<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>
@endif
</table>

View File

@ -1,7 +1,13 @@
@extends('layouts.dn')
@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
@section('page_actions')
@ -71,7 +77,7 @@
<div class="main-card mb-3 card">
<div class="card-body">
<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="#internal" class="nav-link">@lang('Internal')</a></li>
@env(['local'])
@ -87,9 +93,57 @@
<input type="hidden" name="dn" value="">
@foreach ($o->getVisibleAttributes() as $ao)
<x-attribute-type :edit="true" :o="$ao"/>
@endforeach
<div class="card-header border-bottom-0">
<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
</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')
</form>