OneBot: Leantime 改造版源码(BOM/Univer 表格/AI 接管/品牌替换等)

This commit is contained in:
wangruiguo
2026-09-03 18:49:20 +08:00
commit d647428529
3501 changed files with 1988906 additions and 0 deletions

View File

@@ -0,0 +1,16 @@
@props([
'user' => null
])
<div class="profileBox">
<div class="commentImage">
@if (isset($user['userId']) || isset($user->userId))
<x-users::profile-image :user="$user" />
@else
<i class="fa fa-user"></i>
@endif
</div>
<div class="userName">
{{ $slot }}
</div>
</div>

View File

@@ -0,0 +1,7 @@
@props([
'user' => null
])
<img {{ $attributes->merge([
'src' => BASE_URL . '/api/users?profileImage=' . $user['id'] .'&v='.format($user['modified'])->timestamp(),
]) }} />

View File

@@ -0,0 +1,32 @@
@extends($layout)
@section('content')
<div class="pageheader">
<div class="pageicon"><span class="fa {{ $tpl->getModulePicture() }}"></span></div>
<div class="pagetitle">
<h5>{!! __('label.administration') !!}</h5>
<h1><h1>{!! __('headlines.delete_user') !!}</h1></h1>
</div>
</div><!--pageheader-->
<div class="maincontent">
<div class="maincontentinner">
{!! $tpl->displayNotification() !!}
<h4 class="widget widgettitle">{!! __('subtitles.delete') !!}</h4>
<div class="widgetcontent">
<form method="post">
<input type="hidden" name="{{ session('formTokenName') }}" value="{{ session('formTokenValue') }}" />
<p>{!! __('text.confirm_user_deletion') !!}</p><br />
<x-global::forms.button tag="input" inputType="submit" contentRole="primary" :labelText="__('buttons.yes_delete')" name="del" />
<x-global::forms.button tag="a" contentRole="tertiary" link="{{ BASE_URL }}/users/showAll">{!! __('buttons.back') !!}</x-global::forms.button>
</form>
</div>
</div>
</div>
@endsection

View File

@@ -0,0 +1,508 @@
@extends($layout)
@section('content')
<x-global::pageheader :icon="'fa fa-user'">
<h5>{{ __('label.overview') }}</h5>
<h1>{!! __('headlines.accountSettings') !!}</h1>
</x-global::pageheader>
<div class="maincontent">
{!! $tpl->displayNotification() !!}
<div class="row">
<div class="col-md-12">
<div class="maincontentinner">
<div class="tabbedwidget tab-primary accountTabs">
<ul>
<li><a href="#myProfile">{!! __('tabs.myProfile') !!}</a></li>
<li><a href="#security">{!! __('tabs.security') !!}</a></li>
<li><a href="#settings">{!! __('tabs.settings') !!}</a></li>
<li><a href="#notifications">{!! __('tabs.notifications') !!}</a></li>
<li><a href="#theme">{!! __('tabs.theme') !!}</a></li>
@dispatchEvent('tabs')
</ul>
<div id="myProfile">
<div class="row">
<div class="col-md-8">
<form action="" method="post">
<h4 class="widgettitle title-light"><?php echo $tpl->__('label.profile_information'); ?></h4>
<input type="hidden" name="{{ session("formTokenName") }}" value="{{ session("formTokenValue") }}" />
<div class="row-fluid">
<div class="form-group">
<label for="firstname" >{{ __('label.firstname') }}</label>
<span>
<input type="text" class="input" name="firstname" id="firstname" {{ session("userdata.isExternalAuth") ? "disabled='disabled'" : '' }}
value="{{ $values['firstname'] }}"/><br/>
</span>
</div>
<div class="form-group">
<label for="lastname" >{{ __('label.lastname') }}</label>
<span>
<input type="text" name="lastname" class="input" id="lastname" {{ session("userdata.isExternalAuth") ? "disabled='disabled'" : '' }}
value="{{ $values['lastname'] }}"/><br/>
</span>
</div>
<div class="form-group">
<label for="user" >{{ __('label.email') }}</label>
<span>
<input type="text" name="user" class="input" id="user" {{ session("userdata.isExternalAuth") ? "disabled='disabled'" : '' }}
value="{{ $values['user'] }}"/><br/>
</span>
</div>
<div class="form-group">
<label for="phone" >{{ __('label.phone') }}</label>
<span>
<input type="text" name="phone" class="input" id="phone" {{ session("userdata.isExternalAuth") ? "disabled='disabled'" : '' }}
value="{{ $values['phone'] }}"/><br/>
</span>
</div>
<p class='stdformbutton'>
<input type="hidden" name="profileInfo" value="1" />
<x-global::forms.button tag="input" inputType="submit" contentRole="primary" :labelText="__('buttons.save')" name="save" id="save" />
</p>
<br />
<h4 class="widgettitle title-light">{{ __('label.employee_information') }}</h4>
<em>{{ __('text.only_admins_can_change_user_info') }}</em><br /><br />
<div class="form-group">
<label for="phone" >{{ __('label.jobTitle') }}</label>
<span>
<input type="text" name="jobTitle" readonly class="input" id="jobTitle"}}
value="{{ $values['jobTitle'] }}"/><br/>
</span>
</div>
<div class="form-group">
<label for="phone" >{{ __('label.jobLevel') }}</label>
<span>
<input type="text" name="jobLevel" readonly class="input" id="jobLevel"}}
value="{{ $values['jobLevel'] }}"/><br/>
</span>
</div>
<div class="form-group">
<label for="phone" >{{ __('label.department') }}</label>
<span>
<input type="text" name="department" readonly class="input" id="department"}}
value="{{ $values['department'] }}"/><br/>
</span>
</div>
</div>
</form>
</div>
<div class="col-md-4">
<div class="center">
<img src='{{ BASE_URL }}/api/users?profileImage={{ $user['id'] }}&v={{ format($user['modified'])->timestamp() }}' class='profileImg tw-rounded-full' alt='Profile Picture' id="previousImage"/>
<div id="profileImg">
</div>
<div class="par">
<label>{{ __('label.upload') }}</label>
<div class='fileupload fileupload-new' data-provides='fileupload'>
<input type="hidden"/>
<div class="input-append">
<div class="uneditable-input span3">
<i class="fa-file fileupload-exists"></i>
<span class="fileupload-preview"></span>
</div>
<span class="btn btn-file">
<span class="fileupload-new">{{ __('buttons.select_file') }}</span>
<span class='fileupload-exists'>{{ __('buttons.change') }}</span>
<input type='file' name='file' onchange="leantime.usersController.readURL(this)" accept=".jpg,.png,.gif,.webp"/>
</span>
<a href='#' class='btn fileupload-exists' data-dismiss='fileupload' onclick="leantime.usersController.clearCroppie()">{{ __('buttons.remove') }}</a>
</div>
<p class='stdformbutton'>
<span id="save-picture" class="btn btn-primary fileupload-exists ld-ext-right">
<span onclick="leantime.usersController.saveCroppie()">{{ __('buttons.save') }}</span>
<span class="ld ld-ring ld-spin"></span>
</span>
<input type="hidden" name="profileImage" value="1" />
<input id="picSubmit" type="submit" name="savePic" class="hidden"
value="{{ __('buttons.upload') }}"/>
</p>
</div>
</div>
</div>
</div>
</div>
</div>
<div id="security">
<h4 class="widgettitle title-light">
{!! __('headlines.change_password') !!}
</h4>
@if (session("userdata.isExternalAuth") )
<strong> {{ __("text.account_managed_external_auth") }}</strong><br /><br />
@endif
<form method="post">
<input type="hidden" name="{{ session("formTokenName") }}" value="{{ session("formTokenValue") }}" />
<div class="row-fluid">
<div class="form-group">
<label for="currentPassword" >{{ __('label.old_password') }}</label>
<span>
<input type='password' value="" name="currentPassword" class="input" {{ session("userdata.isExternalAuth") ? "disabled='disabled'" : '' }}
id="currentPassword"/><br/>
</span>
</div>
<div class="form-group">
<label for="newPassword" >{{ __('label.new_password') }}</label>
<span>
<input type='password' value="" name="newPassword" class="input" {{ session("userdata.isExternalAuth") ? "disabled='disabled'" : '' }}
id="newPassword"/>
<span id="pwStrength"></span>
</span>
</div>
<div class="form-group">
<label for="confirmPassword" >{{ __('label.password_repeat') }}</label>
<span>
<input type="password" value="" name="confirmPassword" class="input" {{ session("userdata.isExternalAuth") ? "disabled='disabled'" : '' }}
id="confirmPassword"/><br/>
@if (!session("userdata.isExternalAuth") )
<small>{{ __('label.passwordRequirements') }}</small>
@endif
</span>
</div>
</div>
@if (!session("userdata.isExternalAuth") )
<input type="hidden" name="savepw" value="1" />
<x-global::forms.button tag="input" inputType="submit" contentRole="primary" :labelText="__('buttons.save')" name="save" id="savePw" />
@endif
</form>
<br /><br />
<h4 class="widgettitle title-light">
<i class="fa-solid fa-shield-halved"></i> {{ __('headlines.twoFA') }}
</h4>
@if ($values['twoFAEnabled'] )
<p>{!! __('text.twoFA_enabled') !!}</p>
@else
<p>{!! __('text.twoFA_disabled') !!}</p>
@endif
<p><a href="{{ BASE_URL }}/twoFA/edit">{!! __('text.twoFA_manage') !!}</a></p>
</div>
<div id="settings">
<form action="" method="post">
<input type="hidden" name="{{ session("formTokenName") }}" value="{{ session("formTokenValue") }}" />
<div class="row-fluid">
<div class="form-group">
<label for="language" >{{ __('label.language') }}</label>
<span class='field'>
<select name="language" id="language" style="width: 220px">
@foreach ($languageList as $languagKey => $languageValue )
<option value="{{ $languagKey }}"
@if ($userLang == $languagKey )
selected='selected'
@endif >{{ $languageValue }}</option>
@endforeach
</select>
</span>
</div>
<div class="form-group">
<label for="date_format" >{{ __('label.date_format') }}</label>
<span>
<select name="date_format" id="date_format" style="width: 220px">
@php
$dateFormats = $dateTimeValues['dates'];
$dateTimeNow = date_create();
@endphp
@foreach ($dateFormats as $format)
<option value="{{ $format }}"
@if ($dateFormat == $format)
selected='selected'
@endif >{{ date_format($dateTimeNow, $format) }}</option>
@endforeach
</select>
</span>
</div>
<div class="form-group">
<label for="time_format" >{{ __('label.time_format') }}</label>
<span>
<select name="time_format" id="time_format" style="width: 220px">
@php
$timeFormats = $dateTimeValues['times'];
$dateTimeNow = date_create();
@endphp
@foreach ($timeFormats as $format)
<option value="{{ $format }}"
@if ($timeFormat == $format)
selected='selected'
@endif>{{ date_format($dateTimeNow, $format) }}</option>
@endforeach
</select>
</span>
</div>
<div class="form-group">
<label for="timezone" >{{ __('label.timezone') }}</label>
<span>
<select name="timezone" id="timezone" style="width: 220px">
@foreach ($timezoneOptions as $tz)
<option value="{{ $tz }}"
@if ($timezone === $tz )
selected='selected'
@endif
>{{ $tz }}</option>
@endforeach
</select>
</span>
</div>
</div>
<input type="hidden" name="saveSettings" value="1" />
<x-global::forms.button tag="input" inputType="submit" contentRole="primary" :labelText="__('buttons.save')" name="save" id="saveSettings" />
</form>
</div>
<div id="theme">
<form action="" method="post">
<input type="hidden" name="{{ session("formTokenName") }}" value="{{ session("formTokenValue") }}" />
<div class="row-fluid">
<div class="form-group">
<label for="themeSelect">Optimal Stimulation</label>
<span class='field tw-flex tw-w-80'>
<?php
foreach ($availableThemes as $key => $theme) { ?>
<x-global::selectable selected="{{ ($userTheme == $key ? 'true' : 'false') }}" :id="''" :name="'theme'" :value="$key" :label="''" class="tw-w-1/2" onclick="leantime.snippets.toggleBg('{{ $key }}')">
<img src="{{ BASE_URL }}/dist/images/background-{{$key}}.png" style="margin:0; border-radius:10px;" />
<br /><?= $tpl->__($theme['name']) ?>
</x-global::selectable>
<?php } ?>
</span>
</div>
<div class="row">
<div class="col-md-12">
<hr />
<label for="colormode" >{{ __('label.colormode') }}</label>
<x-global::selectable :selected="($userColorMode == 'light') ? 'true' : ''" :id="'light'" :name="'colormode'" :value="'light'" :label="'Light'" onclick="leantime.snippets.toggleTheme('light')">
<label for="colormode-light" class="tw-w-[100px]">
<i class="fa-solid fa-sun tw-font-xxl"></i>
</label>
</x-global::selectable>
<x-global::selectable :selected="($userColorMode == 'dark') ? 'true' : ''" :id="'dark'" :name="'colormode'" :value="'dark'" :label="'Dark'" onclick="leantime.snippets.toggleTheme('dark')">
<label for="colormode-light" class="tw-w-[100px]">
<i class="fa-solid fa-moon tw-font-xxl"></i>
</label>
</x-global::selectable>
</div>
</div>
<div class="row">
<div class="col-md-12">
<hr />
<label>Font</label>
@foreach($availableFonts as $key => $font)
<x-global::selectable :selected="($themeFont == $font) ? 'true' : ''" :id="$key" :name="'themeFont'" :value="$font" :label="$font" onclick="leantime.snippets.toggleFont('{{ $font }}')">
<label for="selectable-{{ $key }}" class="font tw-w-[200px]"
style="font-family:'{{ $font }}'; font-size:16px;">
The quick brown fox jumps over the lazy dog
</label>
</x-global::selectable>
@endforeach
</div>
</div>
<div class="row">
<div class="col-md-12">
<hr />
<label>Color Scheme</label>
@foreach($availableColorSchemes as $key => $scheme )
<x-global::selectable class="circle" :selected="($userColorScheme == $key) ? 'true' : ''" :id="$key" :name="'colorscheme'" :value="$key" :label="__($scheme['name'])" onclick="leantime.snippets.toggleColors('{{ $scheme['primaryColor'] }}','{{ $scheme['secondaryColor'] }}');">
<label for="color-{{ $key }}" class="colorCircle"
style="background:linear-gradient(135deg, {{ $scheme["primaryColor"] }} 20%, {{ $scheme["secondaryColor"] }} 100%);">
</label>
</x-global::selectable>
@endforeach
</div>
</div>
</div>
<br /><br />
<input type="hidden" name="saveTheme" value="1" />
<x-global::forms.button tag="input" inputType="submit" contentRole="primary" :labelText="__('buttons.save')" name="save" id="saveTheme" />
</form>
@dispatchEvent('themecontent')
</div>
<div id="notifications">
<form action="" method="post">
<input type="hidden" name="{{ session("formTokenName") }}" value="{{ session("formTokenValue") }}" />
<div class="row-fluid">
<div class="form-group">
<label for="notifications" style="display: inline-flex; align-items: center; gap: 8px; cursor: pointer;">
<input type="checkbox" value="on" name="notifications" class="input"
id="notifications"
@if ($values['notifications'] == "1" )
checked='checked'
@endif/>
{{ __('label.receive_notifications') }}
</label>
</div>
<div class="form-group">
<label for="messagesfrequency" >{{ __('label.messages_frequency') }}</label>
<span>
<select name="messagesfrequency" class="input" id="messagesfrequency" style="width: 220px">
<option value="">--{{ __('label.choose_option') }}--</option>
<option value="60"
@if ($values['messagesfrequency'] == "60" )
selected="selected"
@endif>{{ __('label.1min') }}</option>
<option value="300" @if ($values['messagesfrequency'] == "300" )
selected="selected"
@endif>{{ __('label.5min') }}</option>
<option value="900" @if ($values['messagesfrequency'] == "900" )
selected="selected"
@endif>{{ __('label.15min') }}</option>
<option value="1800" @if ($values['messagesfrequency'] == "1800" )
selected="selected"
@endif>{{ __('label.30min') }}</option>
<option value="3600" @if ($values['messagesfrequency'] == "3600" )
selected="selected"
@endif>{{ __('label.1h') }}</option>
<option value="10800" @if ($values['messagesfrequency'] == "10800" )
selected="selected"
@endif>{{ __('label.3h') }}</option>
<option value="36000" @if ($values['messagesfrequency'] == "36000" )
selected="selected"
@endif>{{ __('label.6h') }}</option>
<option value="43200" @if ($values['messagesfrequency'] == "43200" )
selected="selected"
@endif>{{ __('label.12h') }}</option>
<option value="86400" @if ($values['messagesfrequency'] == "86400" )
selected="selected"
@endif>{{ __('label.24h') }}</option>
<option value="172800" @if ($values['messagesfrequency'] == "172800" )
selected="selected"
@endif>{{ __('label.48h') }}</option>
<option value="604800" @if ($values['messagesfrequency'] == "604800" )
selected="selected"
@endif>{{ __('label.1w') }}</option>
</select> <br/>
</span>
</div>
</div>
<hr />
<h4 class="widgettitle title-light">{{ __('label.notification_event_types') }}</h4>
<p><small>{{ __('label.notification_event_types_description') }}</small></p>
<div class="tw-mb-4">
@php
$categoryLabels = [
'tasks' => 'label.notification_category_tasks',
'comments' => 'label.notification_category_comments',
'goals' => 'label.notification_category_goals',
'ideas' => 'label.notification_category_ideas',
'projects' => 'label.notification_category_projects',
'boards' => 'label.notification_category_boards',
];
@endphp
@foreach ($notificationCategories as $categoryKey => $config)
<label class="tw-flex tw-items-start tw-gap-2 tw-cursor-pointer tw-m-0 tw-py-1.5">
<input type="checkbox"
name="enabledEventTypes[]"
value="{{ $categoryKey }}"
class="input tw-mt-0.5"
@if (in_array($categoryKey, $enabledEventTypes))
checked="checked"
@endif
/>
<span>
<strong>{{ __($categoryLabels[$categoryKey] ?? $categoryKey) }}</strong><br />
<small class="tw-text-gray-500">{{ __($config['description'] ?? '') }}</small>
</span>
</label>
@endforeach
</div>
<hr />
<h4 class="widgettitle title-light">{{ __('label.project_notifications') }}</h4>
<p><small>{{ __('label.project_notifications_description') }}</small></p>
<div class="tw-max-w-lg tw-max-h-[350px] tw-overflow-y-auto tw-mb-5">
@if (count($userProjects) > 0)
@foreach ($userProjects as $project)
@php
$currentLevel = $projectNotificationLevels[$project['id']] ?? $companyDefaultRelevance;
@endphp
<div class="tw-flex tw-items-center tw-justify-between tw-py-1.5 tw-border-b tw-border-gray-100">
<span class="tw-truncate tw-mr-3">
{{ $project['name'] }}
@if (!empty($project['clientName']))
<span class="tw-text-gray-400 tw-text-xs">({{ $project['clientName'] }})</span>
@endif
</span>
<select name="projectNotificationLevel[{{ $project['id'] }}]"
class="tw-text-sm tw-border tw-border-gray-300 tw-rounded tw-px-2 tw-py-1 tw-min-w-[140px]">
@foreach ($relevanceLevels as $level => $labelKey)
<option value="{{ $level }}"
@if ($currentLevel === $level) selected @endif
>{{ __($labelKey) }}</option>
@endforeach
</select>
</div>
@endforeach
@else
<p class="tw-text-gray-400 tw-p-2">{{ __('label.no_projects') }}</p>
@endif
</div>
<input type="hidden" name="savenotifications" value="1" />
<x-global::forms.button tag="input" inputType="submit" contentRole="primary" :labelText="__('buttons.save')" name="save" />
</form>
</div>
@dispatchEvent('tabsContent')
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript">
jQuery(document).ready(function(){
leantime.usersController.checkPWStrength('newPassword');
jQuery('.accountTabs').tabs();
jQuery("#messagesfrequency").chosen();
jQuery("#language").chosen();
jQuery("#themeSelect").chosen();
});
</script>
@endsection

View File

@@ -0,0 +1,243 @@
@extends($layout)
@section('content')
@php
$projects = $relations;
@endphp
{!! $tpl->displayNotification() !!}
<div class="pageheader">
<div class="pageicon"><span class="fa {{ $tpl->getModulePicture() }}"></span></div>
<div class="pagetitle">
<h5>{!! __('label.administration') !!}</h5>
<h1>{!! __('headlines.edit_user') !!}</h1>
</div>
</div><!--pageheader-->
<form action="" method="post" class="stdform userEditModal">
<input type="hidden" name="{{ session('formTokenName') }}" value="{{ session('formTokenValue') }}" />
<div class="maincontent">
<div class="row">
<div class="col-md-7">
<div class="maincontentinner">
<h4 class="widgettitle title-light">{!! __('label.profile_information') !!}</h4>
<label for="firstname">{!! __('label.firstname') !!}</label> <x-global::forms.text-input
name="firstname" id="firstname"
value="{{ $values['firstname'] }}" /><br />
<label for="lastname">{!! __('label.lastname') !!}</label> <x-global::forms.text-input
name="lastname" id="lastname"
value="{{ $values['lastname'] }}" /><br />
<label for="role">{!! __('label.role') !!}</label>
<select name="role" id="role">
@foreach ($roles as $key => $role)
{{-- Privilege ceiling (parity with newUser): a manager may never
assign the admin(40)/owner(50) roles. Editing users is admin+
today, so this is defense-in-depth against any future widening
of who can reach this screen a lower role must never be able
to escalate an account above its own authority. --}}
@if ($login::userHasRole(\Leantime\Domain\Auth\Models\Roles::$manager) && $key > 30)
@continue
@endif
<option value="{{ $key }}"
@if ($key == $values['role']) selected="selected" @endif>
{!! __('label.roles.' . $role) !!}
</option>
@endforeach
</select> <br />
<label for="status">{!! __('label.status') !!}</label>
<select name="status" id="status" class="pull-left">
<option value="a"
@if (strtolower($values['status']) == 'a') selected="selected" @endif>
{!! __('label.active') !!}
</option>
<option value="i"
@if (strtolower($values['status']) == 'i') selected="selected" @endif>
{!! __('label.invited') !!}
</option>
<option value="0"
@if (strtolower($values['status']) === '' || $values['status'] === 0 || $values['status'] === '0') selected="selected" @endif>
{!! __('label.deactivated') !!}
</option>
</select>
@if ($values['status'] == 'i')
<div class="pull-left dropdownWrapper" style="padding-left:5px; line-height: 29px;">
<a class="dropdown-toggle btn btn-default" data-toggle="dropdown" href="{{ BASE_URL }}/auth/userInvite/{{ $values['pwReset'] }}"><i class="fa fa-link"></i> {!! __('label.copyinviteLink') !!}</a>
<div class="dropdown-menu padding-md noClickProp">
<x-global::forms.text-input id="inviteURL" value="{{ BASE_URL }}/auth/userInvite/{{ $values['pwReset'] }}" />
<x-global::forms.button contentRole="primary" onclick="leantime.snippets.copyUrl('inviteURL');">{!! __('links.copy_url') !!}</x-global::forms.button>
</div>
<x-global::forms.button tag="a" link="{{ BASE_URL }}/users/editUser/{{ $values['id'] }}?resendInvite=1" contentRole="default" style="margin-left:5px;"><i class="fa fa-envelope"></i> {!! __('buttons.resend_invite') !!}</x-global::forms.button>
</div>
@endif
<div class="clearfix"></div>
<label for="client">{!! __('label.client') !!}</label>
<select name='client' id="client">
@if ($login::userIsAtLeast('manager'))
<option value="0" selected="selected">{!! __('label.no_clients') !!}</option>
@endif
@foreach ($clients as $clientItem)
<option value="{{ $clientItem['id'] }}" @if ($clientItem['id'] == $values['clientId']) selected="selected" @endif>{{ $clientItem['name'] }}</option>
@endforeach
</select><br/>
<br/>
<h4 class="widgettitle title-light">{!! __('label.contact_information') !!}</h4>
<label for="user">{!! __('label.email') !!}</label> <x-global::forms.text-input
name="user" id="user" value="{{ $values['user'] }}" /><br />
<label for="phone">{!! __('label.phone') !!}</label> <x-global::forms.text-input
name="phone" id="phone"
value="{{ $values['phone'] }}" /><br /><br />
<h4 class="widgettitle title-light">{!! __('label.employee_information') !!}</h4>
<label for="jobTitle">{!! __('label.jobTitle') !!}</label> <x-global::forms.text-input
name="jobTitle" id="jobTitle" value="{{ $values['jobTitle'] }}" /><br />
<label for="jobLevel">{!! __('label.jobLevel') !!}</label> <x-global::forms.text-input
name="jobLevel" id="jobLevel" value="{{ $values['jobLevel'] }}" /><br />
<label for="department">{!! __('label.department') !!}</label> <x-global::forms.text-input
name="department" id="department" value="{{ $values['department'] }}" /><br />
@if ($login::userIsAtLeast(\Leantime\Domain\Auth\Models\Roles::$admin))
{{-- Capacity attributes admin-only. Weekly hours is what
downstream resource-planning surfaces (Resource
Allocation, cross-program warnings, portfolio
rollups) use to answer "how much of this person
is available to plan against?". Employment type
sets the semantic (target vs ceiling vs cap vs
best-effort). Both nullable until an admin
sets them, capacity math treats this user as
unconfigured and skips warnings. --}}
<h4 class="widgettitle title-light">{!! __('label.capacity') !!}</h4>
<label for="weekly_hours">{!! __('label.weekly_hours') !!}</label>
<x-global::forms.text-input
name="weekly_hours"
id="weekly_hours"
type="number"
min="0"
max="168"
:value="$values['weekly_hours'] ?? ''"
placeholder="{{ __('label.weekly_hours_placeholder') }}" /><br />
<span class="hint">{!! __('label.weekly_hours_hint') !!}</span><br /><br />
<label for="employment_type">{!! __('label.employment_type') !!}</label>
<select name="employment_type" id="employment_type">
<option value="">{!! __('label.employment_type.unset') !!}</option>
@foreach (\Leantime\Domain\Users\Enums\EmploymentType::cases() as $type)
<option value="{{ $type->value }}"
@if (($values['employment_type'] ?? '') === $type->value) selected="selected" @endif>
{!! __($type->langKey()) !!}
</option>
@endforeach
</select><br />
<span class="hint">{!! __('label.employment_type_hint') !!}</span><br /><br />
@endif
<p class="stdformbutton">
<x-global::forms.button tag="input" inputType="submit" contentRole="primary" :labelText="__('buttons.save')" name="save" id="save" />
</p>
</div>
</div>
<div class="col-md-5">
<div class="maincontentinner">
<h4 class="widgettitle title-light">{!! __('label.project_assignment') !!}</h4>
<div class="scrollableItemList">
@php
$currentClient = '';
$i = 0;
@endphp
@foreach ($allProjects as $row)
@php
if ($row['clientName'] == null) {
$row['clientName'] = 'Not assigned to client';
}
@endphp
@if ($currentClient != $row['clientName'])
@if ($i > 0)
</div>
@endif
<h3 id='accordion_link_{{ $i }}'>
<a href='#' onclick='accordionToggle({{ $i }});' id='accordion_toggle_{{ $i }}'><i class='fa fa-angle-down'></i> {{ $row['clientName'] }}</a>
</h3>
<div id='accordion_{{ $i }}' class='simpleAccordionContainer'>
@php $currentClient = $row['clientName']; @endphp
@endif
<div class="item" style="padding:10px 0px;">
<input type="checkbox" name="projects[]" id='project_{{ $row['id'] }}' value="{{ $row['id'] }}"
@if (is_array($projects) === true && in_array($row['id'], $projects) === true)
checked='checked'
@endif
/>
<span class="projectAvatar" style="width:30px; float:left; margin-right:10px;">
<img src='{{ BASE_URL }}/api/projects?projectAvatar={{ $row['id'] }}&v={{ format($row['modified'])->timestamp() }}' />
</span>
<label for="project_{{ $row['id'] }}" style="margin-top:-11px">
<small>{{ $row['type'] }}</small><br />
{{ $row['name'] }}</label>
<div class="clearall"></div>
</div>
@php $i++; @endphp
@endforeach
</div>
</div>
</div>
</div>
</div>
</form>
@once
@push('scripts')
<script>
jQuery(".noClickProp.dropdown-menu").on("click", function(e) {
e.stopPropagation();
});
function accordionToggle(id) {
let currentLink = jQuery("#accordion_toggle_"+id).find("i.fa");
if(currentLink.hasClass("fa-angle-right")){
currentLink.removeClass("fa-angle-right");
currentLink.addClass("fa-angle-down");
jQuery('#accordion_'+id).slideDown("fast");
}else{
currentLink.removeClass("fa-angle-down");
currentLink.addClass("fa-angle-right");
jQuery('#accordion_'+id).slideUp("fast");
}
}
</script>
@endpush
@endonce
@endsection

View File

@@ -0,0 +1,35 @@
@extends($layout)
@section('content')
<div class="showDialogOnLoad" style="display:none;">
<h4 class="widgettitle title-light"><i class="fa fa-arrow-circle-o-right"></i>
{!! __('headlines.import_ldap_users') !!}
</h4>
{!! $tpl->displayNotification() !!}
@if ($confirmUsers)
<form class="importModal userImportModal" method="post" action="{{ BASE_URL }}/users/import">
@foreach ($allLdapUsers as $user)
<input type="checkbox" value="{{ $user['user'] }}" id="{{ $user['user'] }}" name="users[]" checked="checked"/>
<label for="{{ $user['user'] }}" style="display:inline;">{{ $user['user'] }} - {{ $user['firstname'] }}, {{ $user['lastname'] }}<br />
@endforeach
<br />
<input type="hidden" name="importSubmit" value="1"/>
<x-global::forms.button tag="input" inputType="submit" contentRole="primary" :labelText="__('buttons.import')" />
</form>
@else
<form class="importModal userImportModal" method="post" action="{{ BASE_URL }}/users/import">
<label>{!! __('label.please_enter_password') !!} </label>
<x-global::forms.text-input type="password" name="password" />
<input type="hidden" name="pwSubmit" value="1"/>
<x-global::forms.button tag="input" inputType="submit" contentRole="primary" :labelText="__('buttons.find_users')" />
</form>
@endif
</div>
@endsection

View File

@@ -0,0 +1,219 @@
@extends($layout)
@section('content')
@php
$projects = $relations;
@endphp
<h4 class="widgettitle title-light"><i class="fa fa-people-group"></i> {!! __('headlines.new_user') !!}</h4>
{!! $tpl->displayNotification() !!}
<form action="{{ BASE_URL }}/users/newUser" method="post" class="stdform userEditModal formModal">
<div class="row" style="width:800px;">
<div class="col-md-7">
<h4 class="widgettitle title-light">{!! __('label.profile_information') !!}</h4>
<label for="firstname">{!! __('label.firstname') !!}</label> <x-global::forms.text-input
name="firstname" id="firstname"
value="{{ $values['firstname'] }}" /><br />
<label for="lastname">{!! __('label.lastname') !!}</label> <x-global::forms.text-input
name="lastname" id="lastname"
value="{{ $values['lastname'] }}" /><br />
<label for="role">{!! __('label.role') !!}</label>
<select name="role" id="role">
@foreach ($roles as $key => $role)
@if ($login::userHasRole(\Leantime\Domain\Auth\Models\Roles::$manager) && $key > 30)
@continue
@endif
<option value="{{ $key }}"
@if ($key == $values['role']) selected="selected" @endif>
{!! __('label.roles.' . $role) !!}
</option>
@endforeach
</select> <br />
<label for="client">{!! __('label.client') !!}</label>
<select name='client' id="client">
@if ($login::userIsAtLeast('admin'))
<option value="0" selected="selected">{!! __('label.no_clients') !!}</option>
@endif
@foreach ($clients as $clientItem)
@if ($login::userHasRole(\Leantime\Domain\Auth\Models\Roles::$manager) && $clientItem['id'] !== session('userdata.clientId'))
@continue
@endif
<option value="{{ $clientItem['id'] }}"
@if ($clientItem['id'] == $values['clientId'] || $preSelectedClient == $clientItem['id']) selected="selected" @endif>{{ $clientItem['name'] }}</option>
@endforeach
</select><br/>
<br/>
<h4 class="widgettitle title-light">{!! __('label.contact_information') !!}</h4>
<label for="user">{!! __('label.email') !!}</label> <x-global::forms.text-input
name="user" id="user" value="{{ $values['user'] }}" /><br />
<label for="phone">{!! __('label.phone') !!}</label> <x-global::forms.text-input
name="phone" id="phone"
value="{{ $values['phone'] }}" /><br />
<br/>
<h4 class="widgettitle title-light">{!! __('label.employee_information') !!}</h4>
<label for="jobTitle">{!! __('label.jobTitle') !!}</label> <x-global::forms.text-input
name="jobTitle" id="jobTitle" value="{{ $values['jobTitle'] }}" /><br />
<label for="jobLevel">{!! __('label.jobLevel') !!}</label> <x-global::forms.text-input
name="jobLevel" id="jobLevel" value="{{ $values['jobLevel'] }}" /><br />
<label for="department">{!! __('label.department') !!}</label> <x-global::forms.text-input
name="department" id="department" value="{{ $values['department'] }}" /><br />
<p class="stdformbutton">
<input type="hidden" name="save" value="1" />
<x-global::forms.button tag="input" inputType="submit" contentRole="primary" :labelText="__('buttons.invite_user')" name="save" id="save" />
</p>
</div>
<div class="col-md-5">
<h4 class="widgettitle title-light">{!! __('label.project_assignment') !!}</h4>
<div class="scrollableItemList">
@php
$currentClient = '';
$i = 0;
@endphp
@foreach ($allProjects as $row)
@if ($login::userHasRole(\Leantime\Domain\Auth\Models\Roles::$manager) && $row['clientId'] !== session('userdata.clientId'))
@continue
@endif
@php
if ($row['clientName'] == '') {
$row['clientName'] = 'Not assigned to client';
}
@endphp
@if ($currentClient != $row['clientName'])
@if ($i > 0)
</div>
@endif
<h3 id='accordion_link_{{ $i }}'>
<a href='#' onclick='accordionToggle({{ $i }});' id='accordion_toggle_{{ $i }}'><i class='fa fa-angle-down'></i> {{ $row['clientName'] }}</a>
</h3>
<div id='accordion_{{ $i }}' class='simpleAccordionContainer'>
@php $currentClient = $row['clientName']; @endphp
@endif
<div class="item" style="padding:10px 0px;">
<input type="checkbox" name="projects[]" id='project_{{ $row['id'] }}' value="{{ $row['id'] }}"
@if (is_array($projects) === true && in_array($row['id'], $projects) === true)
checked='checked'
@endif
/>
<span class="projectAvatar" style="width:30px; float:left; margin-right:10px;">
<img src='{{ BASE_URL }}/api/projects?projectAvatar={{ $row['id'] }}&v={{ format($row['modified'])->timestamp() }}' />
</span>
<label for="project_{{ $row['id'] }}" style="margin-top:-11px">
<small>{{ $row['type'] }}</small><br />
{{ $row['name'] }}</label>
<div class="clearall"></div>
</div>
@php $i++; @endphp
@endforeach
</div>
</div>
</div>
</form>
@once
@push('scripts')
<script type="text/javascript">
jQuery(document).ready(function(){
// Dual Box Select
var db = jQuery('#dualselect').find('.ds_arrow button'); //get arrows of dual select
var sel1 = jQuery('#dualselect select#selectOrigin'); //get first select element
var sel2 = jQuery('#dualselect select#selectDest'); //get second select element
var projects = jQuery('#projects');
//sel2.empty(); //empty it first from dom.
db.click(function(){
var t = (jQuery(this).hasClass('ds_prev'))? 0 : 1; // 0 if arrow prev otherwise arrow next
if(t) {
sel1.find('option').each(function(){
if(jQuery(this).is(':selected')) {
jQuery(this).attr('selected',false);
sel2.append(jQuery(this).clone());
jQuery('#projects').append(jQuery(this));
jQuery('#projects option').attr("selected", "selected");
}
});
} else {
sel2.find('option').each(function(){
if(jQuery(this).is(':selected')) {
jQuery(this).attr('selected',false);
index = jQuery(this).index();
sel1.append(jQuery(this));
jQuery('#projects option:eq('+index+')').remove();
jQuery('#projects option').attr("selected", "selected");
}
});
}
return false;
});
});
</script>
<script>
function accordionToggle(id) {
let currentLink = jQuery("#accordion_toggle_"+id).find("i.fa");
if(currentLink.hasClass("fa-angle-right")){
currentLink.removeClass("fa-angle-right");
currentLink.addClass("fa-angle-down");
jQuery('#accordion_'+id).slideDown("fast");
}else{
currentLink.removeClass("fa-angle-down");
currentLink.addClass("fa-angle-right");
jQuery('#accordion_'+id).slideUp("fast");
}
}
</script>
@endpush
@endonce
@endsection

View File

@@ -0,0 +1,94 @@
@extends($layout)
@section('content')
<div class="pageheader">
<div class="pageicon"><span class="fa {{ $tpl->getModulePicture() }}"></span></div>
<div class="pagetitle">
<h5>{!! __('label.administration') !!}</h5>
<h1>{!! __('headlines.users') !!}</h1>
</div>
</div><!--pageheader-->
<div class="maincontent">
<div class="maincontentinner">
{!! $tpl->displayNotification() !!}
<div class="row">
<div class="col-md-6">
@can('users.create')
<x-global::forms.button tag="a" link="{{ BASE_URL }}/users/newUser" contentRole="primary" class="userEditModal"><i class='fa fa-plus'></i> {!! __('buttons.add_user') !!} </x-global::forms.button>
@endcan
</div>
<div class="col-md-6 align-right">
</div>
</div>
<table class="table table-bordered" id="allUsersTable">
<colgroup>
<col class="con1">
<col class="con0">
<col class="con1">
<col class="con0">
<col class="con1">
<col class="con0">
<col class="con1">
</colgroup>
<thead>
<tr>
<th class='head1'>{!! __('label.name') !!}</th>
<th class='head0'>{!! __('label.email') !!}</th>
<th class='head1'>{!! __('label.client') !!}</th>
<th class='head1'>{!! __('label.role') !!}</th>
<th class='head1'>{!! __('label.status') !!}</th>
<th class='head1'>{!! __('headlines.twoFA') !!}</th>
<th class='head0 no-sort'></th>
</tr>
</thead>
<tbody>
@foreach ($allUsers as $row)
<tr>
<td style="padding:6px 10px;">
<a href="{{ BASE_URL }}/users/editUser/{{ $row['id'] }}">{!! sprintf(__('text.full_name'), e($row['firstname']), e($row['lastname'])) !!}</a>
</td>
<td><a href="{{ BASE_URL }}/users/editUser/{{ $row['id'] }}">{{ $row['username'] }}</a></td>
<td>{{ $row['clientName'] }}</td>
<td>{!! __('label.roles.' . $roles[$row['role']]) !!}</td>
<td>@if (strtolower($row['status']) == 'a')
{!! __('label.active') !!}
@elseif (strtolower($row['status']) == 'i')
{!! __('label.invited') !!}
@else
{!! __('label.deactivated') !!}
@endif</td>
<td>@if ($row['twoFAEnabled'])
{!! __('label.yes') !!}
@else
{!! __('label.no') !!}
@endif</td>
<td>@can('users.delete')<a href="{{ BASE_URL }}/users/delUser/{{ $row['id'] }}" class="delete"><i class="fa fa-trash"></i> {!! __('links.delete') !!}</a>@endcan</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
@once
@push('scripts')
<script type="text/javascript">
jQuery(document).ready(function() {
leantime.usersController.initUserTable();
leantime.usersController._initModals();
leantime.usersController.initUserEditModal();
}
);
</script>
@endpush
@endonce
@endsection