feat: remove easy admin bundle, adopt admin theme
This commit is contained in:
@@ -0,0 +1,16 @@
|
|||||||
|
import { Controller } from '@hotwired/stimulus'
|
||||||
|
|
||||||
|
export default class extends Controller {
|
||||||
|
static outlets = [ 'mobilenav' ]
|
||||||
|
static classes = [ 'closed' ]
|
||||||
|
|
||||||
|
trigger({ params: { mode } }) {
|
||||||
|
this.mobilenavOutlet.toggle(mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
toggle(mode) {
|
||||||
|
// Add animation classes only now to avoid fouc
|
||||||
|
this.element.classList.add('transition-transform', 'duration-300')
|
||||||
|
this.element.classList.toggle(this.closedClass, 'close' === mode)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { Controller } from '@hotwired/stimulus'
|
||||||
|
|
||||||
|
export default class extends Controller {
|
||||||
|
|
||||||
|
static classes = ['closed', 'iconClosed', 'iconExpanded']
|
||||||
|
static targets = ['submenu', 'button', 'icon']
|
||||||
|
static values = { expanded: Boolean }
|
||||||
|
|
||||||
|
toggleSubmenu() {
|
||||||
|
this.expandedValue = !this.expandedValue
|
||||||
|
}
|
||||||
|
|
||||||
|
expandedValueChanged(expanded) {
|
||||||
|
this.submenuTarget.classList.toggle(this.closedClass, false === expanded)
|
||||||
|
if (false === this.hasButtonTarget) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.buttonTarget.setAttribute('aria-expanded', expanded)
|
||||||
|
if (false === this.hasIconTarget) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (true === expanded) {
|
||||||
|
this.iconTarget.classList.add(...this.iconExpandedClasses)
|
||||||
|
this.iconTarget.classList.remove(...this.iconClosedClasses)
|
||||||
|
} else {
|
||||||
|
this.iconTarget.classList.add(...this.iconClosedClasses)
|
||||||
|
this.iconTarget.classList.remove(...this.iconExpandedClasses)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,244 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<symbol id="icon-table" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M3.375 19.5h17.25m-17.25 0a1.125 1.125 0 0 1-1.125-1.125M3.375 19.5h7.5c.621 0 1.125-.504 1.125-1.125m-9.75 0V5.625m0 12.75v-1.5c0-.621.504-1.125 1.125-1.125m18.375 2.625V5.625m0 12.75c0 .621-.504 1.125-1.125 1.125m1.125-1.125v-1.5c0-.621-.504-1.125-1.125-1.125m0 3.75h-7.5A1.125 1.125 0 0 1 12 18.375m9.75-12.75c0-.621-.504-1.125-1.125-1.125H3.375c-.621 0-1.125.504-1.125 1.125m19.5 0v1.5c0 .621-.504 1.125-1.125 1.125M2.25 5.625v1.5c0 .621.504 1.125 1.125 1.125m0 0h17.25m-17.25 0h7.5c.621 0 1.125.504 1.125 1.125M3.375 8.25c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125m17.25-3.75h-7.5c-.621 0-1.125.504-1.125 1.125m8.625-1.125c.621 0 1.125.504 1.125 1.125v1.5c0 .621-.504 1.125-1.125 1.125m-17.25 0h7.5m-7.5 0c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125M12 10.875v-1.5m0 1.5c0 .621-.504 1.125-1.125 1.125M12 10.875c0 .621.504 1.125 1.125 1.125m-2.25 0c.621 0 1.125.504 1.125 1.125M13.125 12h7.5m-7.5 0c-.621 0-1.125.504-1.125 1.125M20.625 12c.621 0 1.125.504 1.125 1.125v1.5c0 .621-.504 1.125-1.125 1.125m-17.25 0h7.5M12 14.625v-1.5m0 1.5c0 .621-.504 1.125-1.125 1.125M12 14.625c0 .621.504 1.125 1.125 1.125m-2.25 0c.621 0 1.125.504 1.125 1.125m0 1.5v-1.5m0 0c0-.621.504-1.125 1.125-1.125m0 0h7.5" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-dots" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M12 6.75a.75.75 0 1 1 0-1.5.75.75 0 0 1 0 1.5ZM12 12.75a.75.75 0 1 1 0-1.5.75.75 0 0 1 0 1.5ZM12 18.75a.75.75 0 1 1 0-1.5.75.75 0 0 1 0 1.5Z" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-feedback" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M7.5 8.25h9m-9 3H12m-9.75 1.51c0 1.6 1.123 2.994 2.707 3.227 1.129.166 2.27.293 3.423.379.35.026.67.21.865.501L12 21l2.755-4.133a1.14 1.14 0 01.865-.501 48.172 48.172 0 003.423-.379c1.584-.233 2.707-1.626 2.707-3.228V6.741c0-1.602-1.123-2.995-2.707-3.228A48.394 48.394 0 0012 3c-2.392 0-4.744.175-7.043.513C3.373 3.746 2.25 5.14 2.25 6.741v6.018z" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-login" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 9V5.25A2.25 2.25 0 0013.5 3h-6a2.25 2.25 0 00-2.25 2.25v13.5A2.25 2.25 0 007.5 21h6a2.25 2.25 0 002.25-2.25V15m3 0l3-3m0 0l-3-3m3 3H9" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-logout" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 9V5.25A2.25 2.25 0 0013.5 3h-6a2.25 2.25 0 00-2.25 2.25v13.5A2.25 2.25 0 007.5 21h6a2.25 2.25 0 002.25-2.25V15M12 9l-3 3m0 0l3 3m-3-3h12.75" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-alert" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m9-.75a9 9 0 11-18 0 9 9 0 0118 0zm-9 3.75h.008v.008H12v-.008z" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-close" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-back" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M9 15L3 9m0 0l6-6M3 9h12a6 6 0 010 12h-3" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-list" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M8.25 6.75h12M8.25 12h12m-12 5.25h12M3.75 6.75h.007v.008H3.75V6.75zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0zM3.75 12h.007v.008H3.75V12zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0zm-.375 5.25h.007v.008H3.75v-.008zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0z" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-menu" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-edit" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L10.582 16.07a4.5 4.5 0 01-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 011.13-1.897l8.932-8.931zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0115.75 21H5.25A2.25 2.25 0 013 18.75V8.25A2.25 2.25 0 015.25 6H10" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-plus" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-minus" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 12h-15" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-search" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607z" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-user" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 6a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0zM4.501 20.118a7.5 7.5 0 0114.998 0A17.933 17.933 0 0112 21.75c-2.676 0-5.216-.584-7.499-1.632z" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-users" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M15 19.128a9.38 9.38 0 002.625.372 9.337 9.337 0 004.121-.952 4.125 4.125 0 00-7.533-2.493M15 19.128v-.003c0-1.113-.285-2.16-.786-3.07M15 19.128v.106A12.318 12.318 0 018.624 21c-2.331 0-4.512-.645-6.374-1.766l-.001-.109a6.375 6.375 0 0111.964-3.07M12 6.375a3.375 3.375 0 11-6.75 0 3.375 3.375 0 016.75 0zm8.25 2.25a2.625 2.625 0 11-5.25 0 2.625 2.625 0 015.25 0z" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-delete" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-check" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-upload" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12"/>
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-download" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5M16.5 12L12 16.5m0 0L7.5 12m4.5 4.5V3" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-sort" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M8.25 15L12 18.75 15.75 15m-7.5-6L12 5.25 15.75 9" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-arrow-left" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 12h-15m0 0l6.75 6.75M4.5 12l6.75-6.75" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-arrow-right" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M4.5 12h15m0 0l-6.75-6.75M19.5 12l-6.75 6.75" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-document" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 00-3.375-3.375h-1.5A1.125 1.125 0 0113.5 7.125v-1.5a3.375 3.375 0 00-3.375-3.375H8.25m0 12.75h7.5m-7.5 3H12M10.5 2.25H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 00-9-9z" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-filter" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M12 3c2.755 0 5.455.232 8.083.678.533.09.917.556.917 1.096v1.044a2.25 2.25 0 01-.659 1.591l-5.432 5.432a2.25 2.25 0 00-.659 1.591v2.927a2.25 2.25 0 01-1.244 2.013L9.75 21v-6.568a2.25 2.25 0 00-.659-1.591L3.659 7.409A2.25 2.25 0 013 5.818V4.774c0-.54.384-1.006.917-1.096A48.32 48.32 0 0112 3z" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-refresh" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0l3.181 3.183a8.25 8.25 0 0013.803-3.7M4.031 9.865a8.25 8.25 0 0113.803-3.7l3.181 3.182m0-4.991v4.99" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-settings" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M10.343 3.94c.09-.542.56-.94 1.11-.94h1.093c.55 0 1.02.398 1.11.94l.149.894c.07.424.384.764.78.93.398.164.855.142 1.205-.108l.737-.527a1.125 1.125 0 011.45.12l.773.774c.39.389.44 1.002.12 1.45l-.527.737c-.25.35-.272.806-.107 1.204.165.397.505.71.93.78l.893.15c.543.09.94.56.94 1.109v1.094c0 .55-.397 1.02-.94 1.11l-.893.149c-.425.07-.765.383-.93.78-.165.398-.143.854.107 1.204l.527.738c.32.447.269 1.06-.12 1.45l-.774.773a1.125 1.125 0 01-1.449.12l-.738-.527c-.35-.25-.806-.272-1.203-.107-.397.165-.71.505-.781.929l-.149.894c-.09.542-.56.94-1.11.94h-1.094c-.55 0-1.019-.398-1.11-.94l-.148-.894c-.071-.424-.384-.764-.781-.93-.398-.164-.854-.142-1.204.108l-.738.527c-.447.32-1.06.269-1.45-.12l-.773-.774a1.125 1.125 0 01-.12-1.45l.527-.737c.25-.35.273-.806.108-1.204-.165-.397-.505-.71-.93-.78l-.894-.15c-.542-.09-.94-.56-.94-1.109v-1.094c0-.55.398-1.02.94-1.11l.894-.149c.424-.07.765-.383.93-.78.165-.398.143-.854-.107-1.204l-.527-.738a1.125 1.125 0 01.12-1.45l.773-.773a1.125 1.125 0 011.45-.12l.737.527c.35.25.807.272 1.204.107.397-.165.71-.505.78-.929l.15-.894z" />
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-at" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" d="M16.5 12a4.5 4.5 0 11-9 0 4.5 4.5 0 019 0zm0 0c0 1.657 1.007 3 2.25 3S21 13.657 21 12a9 9 0 10-2.636 6.364M16.5 12V8.25" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-mail" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M21.75 6.75v10.5a2.25 2.25 0 01-2.25 2.25h-15a2.25 2.25 0 01-2.25-2.25V6.75m19.5 0A2.25 2.25 0 0019.5 4.5h-15a2.25 2.25 0 00-2.25 2.25m19.5 0v.243a2.25 2.25 0 01-1.07 1.916l-7.5 4.615a2.25 2.25 0 01-2.36 0L3.32 8.91a2.25 2.25 0 01-1.07-1.916V6.75" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-house" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M8.25 21v-4.875c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125V21m0 0h4.5V3.545M12.75 21h7.5V10.75M2.25 21h1.5m18 0h-18M2.25 9l4.5-1.636M18.75 3l-1.5.545m0 6.205l3 1m1.5.5l-1.5-.5M6.75 7.364V3h-3v18m3-13.636l10.5-3.819" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-phone" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M2.25 6.75c0 8.284 6.716 15 15 15h2.25a2.25 2.25 0 002.25-2.25v-1.372c0-.516-.351-.966-.852-1.091l-4.423-1.106c-.44-.11-.902.055-1.173.417l-.97 1.293c-.282.376-.769.542-1.21.38a12.035 12.035 0 01-7.143-7.143c-.162-.441.004-.928.38-1.21l1.293-.97c.363-.271.527-.734.417-1.173L6.963 3.102a1.125 1.125 0 00-1.091-.852H4.5A2.25 2.25 0 002.25 4.5v2.25z" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-mobile" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M10.5 1.5H8.25A2.25 2.25 0 0 0 6 3.75v16.5a2.25 2.25 0 0 0 2.25 2.25h7.5A2.25 2.25 0 0 0 18 20.25V3.75a2.25 2.25 0 0 0-2.25-2.25H13.5m-3 0V3h3V1.5m-3 0h3m-3 18.75h3" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-calendar" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M6.75 3v2.25M17.25 3v2.25M3 18.75V7.5a2.25 2.25 0 012.25-2.25h13.5A2.25 2.25 0 0121 7.5v11.25m-18 0A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75m-18 0v-7.5A2.25 2.25 0 015.25 9h13.5A2.25 2.25 0 0121 11.25v7.5m-9-6h.008v.008H12v-.008zM12 15h.008v.008H12V15zm0 2.25h.008v.008H12v-.008zM9.75 15h.008v.008H9.75V15zm0 2.25h.008v.008H9.75v-.008zM7.5 15h.008v.008H7.5V15zm0 2.25h.008v.008H7.5v-.008zm6.75-4.5h.008v.008h-.008v-.008zm0 2.25h.008v.008h-.008V15zm0 2.25h.008v.008h-.008v-.008zm2.25-4.5h.008v.008H16.5v-.008zm0 2.25h.008v.008H16.5V15z" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-hand" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M10.05 4.575a1.575 1.575 0 10-3.15 0v3m3.15-3v-1.5a1.575 1.575 0 013.15 0v1.5m-3.15 0l.075 5.925m3.075.75V4.575m0 0a1.575 1.575 0 013.15 0V15M6.9 7.575a1.575 1.575 0 10-3.15 0v8.175a6.75 6.75 0 006.75 6.75h2.018a5.25 5.25 0 003.712-1.538l1.732-1.732a5.25 5.25 0 001.538-3.712l.003-2.024a.668.668 0 01.198-.471 1.575 1.575 0 10-2.228-2.228 3.818 3.818 0 00-1.12 2.687M6.9 7.575V12m6.27 4.318A4.49 4.49 0 0116.35 15m.002 0h-.002" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-copy" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-photo" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M2.25 15.75l5.159-5.159a2.25 2.25 0 013.182 0l5.159 5.159m-1.5-1.5l1.409-1.409a2.25 2.25 0 013.182 0l2.909 2.909m-18 3.75h16.5a1.5 1.5 0 001.5-1.5V6a1.5 1.5 0 00-1.5-1.5H3.75A1.5 1.5 0 002.25 6v12a1.5 1.5 0 001.5 1.5zm10.5-11.25h.008v.008h-.008V8.25zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0z" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-print" fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24">
|
||||||
|
<path d="M6.72 13.829c-.24.03-.48.062-.72.096m.72-.096a42.415 42.415 0 0110.56 0m-10.56 0L6.34 18m10.94-4.171c.24.03.48.062.72.096m-.72-.096L17.66 18m0 0l.229 2.523a1.125 1.125 0 01-1.12 1.227H7.231c-.662 0-1.18-.568-1.12-1.227L6.34 18m11.318 0h1.091A2.25 2.25 0 0021 15.75V9.456c0-1.081-.768-2.015-1.837-2.175a48.055 48.055 0 00-1.913-.247M6.34 18H5.25A2.25 2.25 0 013 15.75V9.456c0-1.081.768-2.015 1.837-2.175a48.041 48.041 0 011.913-.247m10.5 0a48.536 48.536 0 00-10.5 0m10.5 0V3.375c0-.621-.504-1.125-1.125-1.125h-8.25c-.621 0-1.125.504-1.125 1.125v3.659M18 10.5h.008v.008H18V10.5zm-3 0h.008v.008H15V10.5z" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-locked" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M16.5 10.5V6.75a4.5 4.5 0 10-9 0v3.75m-.75 11.25h10.5a2.25 2.25 0 002.25-2.25v-6.75a2.25 2.25 0 00-2.25-2.25H6.75a2.25 2.25 0 00-2.25 2.25v6.75a2.25 2.25 0 002.25 2.25z" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-unlocked" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M13.5 10.5V6.75a4.5 4.5 0 119 0v3.75M3.75 21.75h10.5a2.25 2.25 0 002.25-2.25v-6.75a2.25 2.25 0 00-2.25-2.25H3.75a2.25 2.25 0 00-2.25 2.25v6.75a2.25 2.25 0 002.25 2.25z" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-mask" fill="currentColor" stroke="none" viewBox="0 0 576 512">
|
||||||
|
<!--! Font Awesome Pro 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. -->
|
||||||
|
<path d="M288 64C39.52 64 0 182.1 0 273.5C0 379.5 78.8 448 176 448c27.33 0 51.21-6.516 66.11-36.79l19.93-40.5C268.3 358.6 278.1 352.4 288 352.1c9.9 .3711 19.7 6.501 25.97 18.63l19.93 40.5C348.8 441.5 372.7 448 400 448c97.2 0 176-68.51 176-174.5C576 182.1 536.5 64 288 64zM400 400c-18.12 0-19.56-2.924-23.04-9.986l-20.35-41.33c-13.87-26.86-38.85-43.53-66.82-44.57L288 304L286.2 304.1c-27.96 1.049-52.94 17.71-67.24 45.41l-19.93 40.49C195.6 397.1 194.1 400 176 400c-75.36 0-128-52.04-128-126.5C48 229.3 48 112 288 112s240 117.3 240 161.5C528 347.1 475.4 400 400 400zM160 192C124.7 192 96 220.7 96 256s28.65 64 64 64c35.35 0 64-28.65 64-64S195.3 192 160 192zM416 192c-35.35 0-64 28.65-64 64s28.65 64 64 64c35.35 0 64-28.65 64-64S451.3 192 416 192z"/>
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-excel" fill="currentColor" stroke="none" viewBox="0 0 384 512">
|
||||||
|
<!--! Font Awesome Pro 6.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. -->
|
||||||
|
<path d="M365.3 93.38l-74.63-74.64C278.6 6.742 262.3 0 245.4 0H64C28.65 0 0 28.65 0 64l.0065 384c0 35.34 28.65 64 64 64H320c35.2 0 64-28.8 64-64V138.6C384 121.7 377.3 105.4 365.3 93.38zM336 448c0 8.836-7.164 16-16 16H64.02c-8.838 0-16-7.164-16-16L48 64.13c0-8.836 7.164-16 16-16h160L224 128c0 17.67 14.33 32 32 32h79.1V448zM229.1 233.3L192 280.9L154.9 233.3C146.8 222.8 131.8 220.9 121.3 229.1C110.8 237.2 108.9 252.3 117.1 262.8L161.6 320l-44.53 57.25c-8.156 10.47-6.25 25.56 4.188 33.69C125.7 414.3 130.8 416 135.1 416c7.156 0 14.25-3.188 18.97-9.25L192 359.1l37.06 47.65C233.8 412.8 240.9 416 248 416c5.125 0 10.31-1.656 14.72-5.062c10.44-8.125 12.34-23.22 4.188-33.69L222.4 320l44.53-57.25c8.156-10.47 6.25-25.56-4.188-33.69C252.2 220.9 237.2 222.8 229.1 233.3z"/>
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-pdf" fill="currentColor" stroke="none" viewBox="0 0 384 512">
|
||||||
|
<!--! Font Awesome Pro 6.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. -->
|
||||||
|
<path d="M365.3 93.38l-74.63-74.64C278.6 6.742 262.3 0 245.4 0H64C28.65 0 0 28.65 0 64l.0065 384c0 35.34 28.65 64 64 64H320c35.2 0 64-28.8 64-64V138.6C384 121.7 377.3 105.4 365.3 93.38zM336 448c0 8.836-7.164 16-16 16H64.02c-8.838 0-16-7.164-16-16L48 64.13c0-8.836 7.164-16 16-16h160L224 128c0 17.67 14.33 32 32 32h79.1V448zM202 286.1c.877-2.688 1.74-5.398 2.582-8.145c1.434-5.762 7.488-31.54 7.488-52.47C212.1 207 197.1 192 178.6 192C160.1 192 145.1 207 145.1 225.5c0 .2969 .1641 28.81 13.85 62.3c-7.035 19.36-15.57 38.8-25.41 57.93c-21.49 10.11-39.24 22.23-52.8 36.07c-6.234 6.438-9.367 14.74-9.367 24.72c0 18.45 15.01 33.46 33.46 33.46c10.8 0 20.98-5.227 27.22-13.98c7.322-10.28 18.38-26.9 30.47-48.95c15.8-6.352 33.88-11.72 53.88-16c13.55 9.578 28.9 17.29 45.71 22.95c4.527 1.551 9.402 2.348 14.43 2.348c20.26 0 36.13-16.19 36.13-36.86c0-20.33-16.54-36.87-36.87-36.87h-3.705c-2.727 .125-20.51 1.141-45.37 5.367C216.9 308.9 208.6 298.3 202 286.1zM110.2 410.4c-3.273 4.688-12.03 2.777-12.03-5.312c0-1.754 .6289-3.43 1.729-4.555c9.02-9.219 19.94-17.05 31.85-23.72C122.3 393.1 114.3 404.7 110.2 410.4zM178.6 218.8c3.693 0 6.703 3.008 6.703 6.703c0 15.21-4.109 34.84-5.746 42.1C172.1 245 171.9 227.2 171.9 225.5C171.9 221.8 174.9 218.8 178.6 218.8zM162.3 348.3c6.611-13.48 13.22-28.46 19.38-44.7c6.389 10.92 14.56 21.86 24.96 31.97C192.6 338.8 177.4 342.9 162.3 348.3zM272.4 339.5h3.352c5.539 0 10.05 4.5 10.05 10.79c0 5.129-4.176 9.32-9.32 9.32c-2.029 0-4.059-.3164-5.852-.9414c-12.33-4.137-23.11-9.32-32.54-15.19C258.3 340.3 272.1 339.5 272.4 339.5z"/>
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-file" fill="currentColor" stroke="none" viewBox="0 0 384 512">
|
||||||
|
<!--! Font Awesome Pro 6.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. -->
|
||||||
|
<path d="M365.3 93.38l-74.63-74.64C278.6 6.743 262.3 0 245.4 0L64-.0001c-35.35 0-64 28.65-64 64l.0065 384c0 35.35 28.65 64 64 64H320c35.2 0 64-28.8 64-64V138.6C384 121.7 377.3 105.4 365.3 93.38zM320 464H64.02c-8.836 0-15.1-7.163-16-15.1L48 64.13c-.0004-8.837 7.163-16 16-16h160L224 128c0 17.67 14.33 32 32 32h79.1v288C336 456.8 328.8 464 320 464z"/>
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-sigma" fill="currentColor" stroke="none" viewBox="0 0 384 512">
|
||||||
|
<!--! Font Awesome Pro 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. -->
|
||||||
|
<path d="M335.1 136l.0005-56H83.59l165 158.7C253.3 243.2 255.1 249.5 255.1 256s-2.656 12.78-7.375 17.31L83.59 432h252.4l-.0005-56c0-13.25 10.75-24 24-24C373.2 352 384 362.8 384 376v80c0 13.25-10.75 24-24 24H23.99c-9.782 0-18.59-5.938-22.25-15.03s-1.438-19.47 5.625-26.28L197.4 256L7.364 73.31C.3015 66.5-1.917 56.13 1.739 47.03S14.21 32 23.99 32h336C373.2 32 384 42.75 384 56v80C384 149.3 373.2 160 359.1 160C346.7 160 335.1 149.3 335.1 136z"/>
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-percent" fill="currentColor" stroke="none" viewBox="0 0 384 512">
|
||||||
|
<!--! Font Awesome Pro 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. -->
|
||||||
|
<path d="M376.1 71.03c-9.375-9.375-24.56-9.375-33.94 0l-336 336c-9.375 9.375-9.375 24.56 0 33.94C11.72 445.7 17.84 448 24 448s12.28-2.344 16.97-7.031l336-336C386.3 95.59 386.3 80.41 376.1 71.03zM64 176c26.51 0 48-21.49 48-48S90.51 80 64 80C37.49 80 16 101.5 16 128S37.49 176 64 176zM320 336c-26.51 0-48 21.49-48 48s21.49 48 48 48c26.51 0 48-21.49 48-48S346.5 336 320 336z"/>
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-chair" fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
|
||||||
|
<!--! Font Awesome Pro 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M288 16c26.5 0 48 21.5 48 48V256h16V64c0-35.3-28.7-64-64-64H160C124.7 0 96 28.7 96 64V256h16V64c0-26.5 21.5-48 48-48H288zM48 168c0-4.4-3.6-8-8-8s-8 3.6-8 8v80c0 4.4 3.6 8 8 8s8-3.6 8-8V168zm368 0c0-4.4-3.6-8-8-8s-8 3.6-8 8v80c0 4.4 3.6 8 8 8s8-3.6 8-8V168zM80 304H368c6.1 0 11.6 3.4 14.3 8.8l16 32c2.5 5 2.2 10.9-.7 15.6s-8.1 7.6-13.6 7.6H224 64c-5.5 0-10.7-2.9-13.6-7.6s-3.2-10.6-.7-15.6l16-32c2.7-5.4 8.3-8.8 14.3-8.8zm152 80H384c11.1 0 21.4-5.7 27.2-15.2s6.4-21.2 1.4-31.1l-16-32C391.2 294.8 380.1 288 368 288H80c-12.1 0-23.2 6.8-28.6 17.7l-16 32c-5 9.9-4.4 21.7 1.4 31.1S52.9 384 64 384H216v64H184c-30.9 0-56 25.1-56 56c0 4.4 3.6 8 8 8s8-3.6 8-8c0-22.1 17.9-40 40-40h32v40c0 4.4 3.6 8 8 8s8-3.6 8-8V464h32c22.1 0 40 17.9 40 40c0 4.4 3.6 8 8 8s8-3.6 8-8c0-30.9-25.1-56-56-56H232V384z"/>
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-eye" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 010-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178z" />
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-profile" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M7.864 4.243A7.5 7.5 0 0119.5 10.5c0 2.92-.556 5.709-1.568 8.268M5.742 6.364A7.465 7.465 0 004.5 10.5a7.464 7.464 0 01-1.15 3.993m1.989 3.559A11.209 11.209 0 008.25 10.5a3.75 3.75 0 117.5 0c0 .527-.021 1.049-.064 1.565M12 10.5a14.94 14.94 0 01-3.6 9.75m6.633-4.596a18.666 18.666 0 01-2.485 5.33" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-chart" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 3v11.25A2.25 2.25 0 006 16.5h2.25M3.75 3h-1.5m1.5 0h16.5m0 0h1.5m-1.5 0v11.25A2.25 2.25 0 0118 16.5h-2.25m-7.5 0h7.5m-7.5 0l-1 3m8.5-3l1 3m0 0l.5 1.5m-.5-1.5h-9.5m0 0l-.5 1.5M9 11.25v1.5M12 9v3.75m3-6v6" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-info" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-star" fill="currentColor" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M11.48 3.499a.562.562 0 011.04 0l2.125 5.111a.563.563 0 00.475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 00-.182.557l1.285 5.385a.562.562 0 01-.84.61l-4.725-2.885a.563.563 0 00-.586 0L6.982 20.54a.562.562 0 01-.84-.61l1.285-5.386a.562.562 0 00-.182-.557l-4.204-3.602a.563.563 0 01.321-.988l5.518-.442a.563.563 0 00.475-.345L11.48 3.5z" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-cancel" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M9.75 9.75l4.5 4.5m0-4.5l-4.5 4.5M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-bell" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-folder" fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24">
|
||||||
|
<path d="M2.25 12.75V12A2.25 2.25 0 014.5 9.75h15A2.25 2.25 0 0121.75 12v.75m-8.69-6.44l-2.12-2.12a1.5 1.5 0 00-1.061-.44H4.5A2.25 2.25 0 002.25 6v12a2.25 2.25 0 002.25 2.25h15A2.25 2.25 0 0021.75 18V9a2.25 2.25 0 00-2.25-2.25h-5.379a1.5 1.5 0 01-1.06-.44z" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-power" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M5.636 5.636a9 9 0 1 0 12.728 0M12 3v9" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-no-symbol" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M18.364 18.364A9 9 0 0 0 5.636 5.636m12.728 12.728A9 9 0 0 1 5.636 5.636m12.728 12.728L5.636 5.636" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-bus" xmlns="http://www.w3.org/2000/svg" stroke-width="1.5" viewBox="0 0 24 24" stroke="currentColor" fill="none">
|
||||||
|
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||||
|
<path d="M6 17m-2 0a2 2 0 1 0 4 0a2 2 0 1 0 -4 0" />
|
||||||
|
<path d="M18 17m-2 0a2 2 0 1 0 4 0a2 2 0 1 0 -4 0" />
|
||||||
|
<path d="M4 17h-2v-11a1 1 0 0 1 1 -1h14a5 7 0 0 1 5 7v5h-2m-4 0h-8" />
|
||||||
|
<path d="M16 5l1.5 7l4.5 0" />
|
||||||
|
<path d="M2 10l15 0" />
|
||||||
|
<path d="M7 5l0 5" />
|
||||||
|
<path d="M12 5l0 5" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-ski" fill="currentColor" stroke="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
||||||
|
<!--! Font Awesome Pro 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. -->
|
||||||
|
<path d="M380.7 48a48 48 0 1 1 96 0 48 48 0 1 1 -96 0zM2.7 268.9c6.1-11.8 20.6-16.3 32.4-10.2L239.8 365l49.6-74.5-82.7-87.9c-9.5-10.1-14.4-22.4-15.1-34.9l87.7 42 49.4 52.5c12.8 13.6 14.5 34.1 4.2 49.6l-50.2 75.4 135.8 70.5c13.6 7.1 29.8 7.2 43.6 .3l15.2-7.6c11.9-5.9 26.3-1.1 32.2 10.7s1.1 26.3-10.7 32.2l-15.2 7.6c-27.5 13.7-59.9 13.5-87.2-.7L12.9 301.3C1.2 295.2-3.4 280.7 2.7 268.9zM118.9 65.6L137 74.2l8.7-17.4c4-7.9 13.6-11.1 21.5-7.2s11.1 13.6 7.2 21.5l-8.5 16.9 55.5 26.6c1.7-.9 3.5-1.7 5.4-2.5l80.9-32.4c32.4-13 68.6 6.5 75.6 40.7l12.3 59.7 62.9 30.1c12 5.7 17 20 11.3 32s-20 17-32 11.3l-54.2-25.9c-1-.3-1.9-.6-2.8-1l-229.1-110-9.2 18.4c-4 7.9-13.6 11.1-21.5 7.2s-11.1-13.6-7.2-21.5l9-18-17.6-8.4c-8-3.8-11.3-13.4-7.5-21.3s13.4-11.3 21.3-7.5zm217.3 64.7c-1-4.9-6.2-7.7-10.8-5.8l-45.7 18.3 65.5 31.5-9-43.9z"/>
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-snowboard" fill="currentColor" stroke="nonw" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
||||||
|
<!--! Font Awesome Pro 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. -->
|
||||||
|
<path d="M204.3 3c11.6-6.4 26.2-2.3 32.6 9.3l31.9 57.4c1.3 2.3 3.6 3.8 6.2 4.1l33.8 3.4c24.1 2.4 46.9 12 65.4 27.6L503.5 213.6c10.1 8.5 11.4 23.7 2.9 33.8s-23.7 11.4-33.8 2.9l-68.2-57.5-82.3 43.9 24.7 18.9c24.9 19 34.6 51.9 24.1 81.4l-28.2 79c-1.4 3.8-3.6 7-6.3 9.6l93.3 35.7c4.6 1.8 9.4 2.6 14.3 2.6H472c13.3 0 24 10.7 24 24s-10.7 24-24 24H443.8c-10.8 0-21.4-2-31.5-5.8L60.1 371.3c-11.5-4.4-22-11.2-30.8-20L7 329c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0l22.4 22.4c4 4 8.7 7.1 14 9.1l19.4 7.4c-2.9-11.4 2.9-23.4 14-28.1L192 272l0-68.2c0-21.2 12-40.6 31-50.1L284.4 123l-14.1-1.4c-18.3-1.8-34.5-12.5-43.4-28.5L195 35.7c-6.4-11.6-2.3-26.2 9.3-32.6zm91.8 407.2c-.3-3.4 .1-6.9 1.3-10.3l28.2-79c3.5-9.8 .3-20.8-8-27.1L240 234.4l0 42.9c0 16.1-9.7 30.7-24.6 36.9L134 348.2l162.1 62.1zM259.6 189l20.5 15.7 84.6-45.1-17.2-14.5L259.6 189zM384 48a48 48 0 1 1 96 0 48 48 0 1 1 -96 0z"/>
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-hourglass" fill="currentColor" stroke="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512">
|
||||||
|
<!--! Font Awesome Pro 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. -->
|
||||||
|
<path d="M24 0C10.7 0 0 10.7 0 24S10.7 48 24 48h8V67c0 40.3 16 79 44.5 107.5L158.1 256 76.5 337.5C48 366 32 404.7 32 445v19H24c-13.3 0-24 10.7-24 24s10.7 24 24 24H360c13.3 0 24-10.7 24-24s-10.7-24-24-24h-8V445c0-40.3-16-79-44.5-107.5L225.9 256l81.5-81.5C336 146 352 107.3 352 67V48h8c13.3 0 24-10.7 24-24s-10.7-24-24-24H24zM192 289.9l81.5 81.5C293 391 304 417.4 304 445v19H80V445c0-27.6 11-54 30.5-73.5L192 289.9zm0-67.9l-81.5-81.5C91 121 80 94.6 80 67V48H304V67c0 27.6-11 54-30.5 73.5L192 222.1z"/>
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-car" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"><rect width="256" height="256" fill="none"/><circle cx="64" cy="176" r="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><circle cx="192" cy="176" r="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><line x1="88" y1="176" x2="168" y2="176" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><path d="M216,176h24a8,8,0,0,0,8-8V128a8,8,0,0,0-8-8H208L162.34,74.34A8,8,0,0,0,156.69,72H44.28a8,8,0,0,0-6.65,3.56L8,120v48a8,8,0,0,0,8,8H40" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><line x1="208" y1="120" x2="8" y2="120" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/></symbol>
|
||||||
|
<symbol id="icon-flag-a" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 480"><g fill-rule="evenodd"><path fill="#fff" d="M640 480H0V0h640z"/><path fill="#ed2939" d="M640 480H0V320h640zm0-319.9H0V.1h640z"/></g></symbol>
|
||||||
|
<symbol id="icon-flag-ch" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 480"><g fill-rule="evenodd" stroke-width="1pt"><path fill="#d52b1e" d="M0 0h640v480H0z"/><g fill="#fff"><path d="M170 195h300v90H170z"/><path d="M275 90h90v300h-90z"/></g></g></symbol>
|
||||||
|
<symbol id="icon-flag-d" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 480"><path fill="#ffce00" d="M0 320h640v160H0z"/><path d="M0 0h640v160H0z"/><path fill="#d00" d="M0 160h640v160H0z"/></symbol>
|
||||||
|
<symbol id="icon-flag-f" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 480"><g fill-rule="evenodd" stroke-width="1pt"><path fill="#fff" d="M0 0h640v480H0z"/><path fill="#00267f" d="M0 0h213.3v480H0z"/><path fill="#f31830" d="M426.7 0H640v480H426.7z"/></g></symbol>
|
||||||
|
<symbol id="icon-flag-i" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 480"><g fill-rule="evenodd" stroke-width="1pt"><path fill="#fff" d="M0 0h640v480H0z"/><path fill="#009246" d="M0 0h213.3v480H0z"/><path fill="#ce2b37" d="M426.7 0H640v480H426.7z"/></g></symbol>
|
||||||
|
<symbol id="icon-flag-nl" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 480"><g fill-rule="evenodd"><path fill="#21468b" d="M0 320h640v160H0z"/><path fill="#fff" d="M0 160h640v160H0z"/><path fill="#ae1c28" d="M0 0h640v160H0z"/></g></symbol>
|
||||||
|
<!-- By Sam Herbert (@sherb), for everyone. More @ http://goo.gl/7AJzbL -->
|
||||||
|
<symbol id="icon-spinner" viewBox="0 0 44 44" xmlns="http://www.w3.org/2000/svg" stroke="currentColor">
|
||||||
|
<g fill="none" fill-rule="evenodd" stroke-width="2">
|
||||||
|
<circle cx="22" cy="22" r="1">
|
||||||
|
<animate attributeName="r"
|
||||||
|
begin="0s" dur="1.8s"
|
||||||
|
values="1; 20"
|
||||||
|
calcMode="spline"
|
||||||
|
keyTimes="0; 1"
|
||||||
|
keySplines="0.165, 0.84, 0.44, 1"
|
||||||
|
repeatCount="indefinite" />
|
||||||
|
<animate attributeName="stroke-opacity"
|
||||||
|
begin="0s" dur="1.8s"
|
||||||
|
values="1; 0"
|
||||||
|
calcMode="spline"
|
||||||
|
keyTimes="0; 1"
|
||||||
|
keySplines="0.3, 0.61, 0.355, 1"
|
||||||
|
repeatCount="indefinite" />
|
||||||
|
</circle>
|
||||||
|
<circle cx="22" cy="22" r="1">
|
||||||
|
<animate attributeName="r"
|
||||||
|
begin="-0.9s" dur="1.8s"
|
||||||
|
values="1; 20"
|
||||||
|
calcMode="spline"
|
||||||
|
keyTimes="0; 1"
|
||||||
|
keySplines="0.165, 0.84, 0.44, 1"
|
||||||
|
repeatCount="indefinite" />
|
||||||
|
<animate attributeName="stroke-opacity"
|
||||||
|
begin="-0.9s" dur="1.8s"
|
||||||
|
values="1; 0"
|
||||||
|
calcMode="spline"
|
||||||
|
keyTimes="0; 1"
|
||||||
|
keySplines="0.3, 0.61, 0.355, 1"
|
||||||
|
repeatCount="indefinite" />
|
||||||
|
</circle>
|
||||||
|
</g>
|
||||||
|
</symbol>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 35 KiB |
@@ -1,6 +1,7 @@
|
|||||||
@import "components/typography.css";
|
|
||||||
@import "components/forms.css";
|
|
||||||
@import "components/button.css";
|
@import "components/button.css";
|
||||||
@import "components/tooltip.css";
|
@import "components/datatable.css";
|
||||||
@import "components/toast.css";
|
@import "components/forms.css";
|
||||||
@import "components/pagination.css";
|
@import "components/pagination.css";
|
||||||
|
@import "components/toast.css";
|
||||||
|
@import "components/tooltip.css";
|
||||||
|
@import "components/typography.css";
|
||||||
|
|||||||
@@ -29,6 +29,11 @@
|
|||||||
@apply hover:bg-gray-200/50;
|
@apply hover:bg-gray-200/50;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.button--warning {
|
||||||
|
@apply bg-none bg-red-500 text-white;
|
||||||
|
@apply hover:bg-red-500/50;
|
||||||
|
}
|
||||||
|
|
||||||
.sbw {
|
.sbw {
|
||||||
.button--primary {
|
.button--primary {
|
||||||
@apply bg-none bg-sbw-secondary text-white;
|
@apply bg-none bg-sbw-secondary text-white;
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
.data-table-wrapper {
|
||||||
|
@apply overflow-x-auto lg:overflow-x-visible mb-8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-table-wrapper__inner {
|
||||||
|
@apply align-middle inline-block min-w-full overflow-hidden lg:overflow-visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
@apply min-w-full;
|
||||||
|
}
|
||||||
|
|
||||||
|
tbody {
|
||||||
|
@apply bg-white;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr {
|
||||||
|
@apply border border-gray-300;
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
@apply px-4 py-2 bg-gray-200 text-left leading-4 font-bold text-primary align-top;
|
||||||
|
}
|
||||||
|
|
||||||
|
td {
|
||||||
|
@apply px-4 py-2 leading-5 align-top;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
table.horizontal td {
|
||||||
|
@apply py-4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-table tbody tr {
|
||||||
|
@apply hover:bg-gray-100;
|
||||||
|
}
|
||||||
+3
-1
@@ -14,9 +14,10 @@
|
|||||||
"doctrine/doctrine-bundle": "^2.13",
|
"doctrine/doctrine-bundle": "^2.13",
|
||||||
"doctrine/doctrine-migrations-bundle": "^3.3",
|
"doctrine/doctrine-migrations-bundle": "^3.3",
|
||||||
"doctrine/orm": "^3.3",
|
"doctrine/orm": "^3.3",
|
||||||
"easycorp/easyadmin-bundle": "^4.27",
|
|
||||||
"fakerphp/faker": "^1.24",
|
"fakerphp/faker": "^1.24",
|
||||||
"flagception/flagception-bundle": "^6.1",
|
"flagception/flagception-bundle": "^6.1",
|
||||||
|
"knplabs/knp-menu-bundle": "^3.7",
|
||||||
|
"knplabs/knp-paginator-bundle": "^6.10",
|
||||||
"league/flysystem-bundle": "^3.4",
|
"league/flysystem-bundle": "^3.4",
|
||||||
"league/flysystem-sftp-v3": "^3.29",
|
"league/flysystem-sftp-v3": "^3.29",
|
||||||
"league/oauth2-server-bundle": "^1.0",
|
"league/oauth2-server-bundle": "^1.0",
|
||||||
@@ -62,6 +63,7 @@
|
|||||||
"twig/extra-bundle": "^2.12|^3.0",
|
"twig/extra-bundle": "^2.12|^3.0",
|
||||||
"twig/html-extra": "^3.15",
|
"twig/html-extra": "^3.15",
|
||||||
"twig/intl-extra": "*",
|
"twig/intl-extra": "*",
|
||||||
|
"twig/string-extra": "^3.24",
|
||||||
"twig/twig": "^2.12|^3.0",
|
"twig/twig": "^2.12|^3.0",
|
||||||
"zenstruck/schedule-bundle": "^1.8"
|
"zenstruck/schedule-bundle": "^1.8"
|
||||||
},
|
},
|
||||||
|
|||||||
Generated
+373
-195
@@ -4,7 +4,7 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "2fd76853483361829d0bdb4d8d68c7ef",
|
"content-hash": "aa69dee5968ec6f7c3f152b8a8a6100d",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "carbonphp/carbon-doctrine-types",
|
"name": "carbonphp/carbon-doctrine-types",
|
||||||
@@ -1405,111 +1405,6 @@
|
|||||||
],
|
],
|
||||||
"time": "2025-10-31T18:51:33+00:00"
|
"time": "2025-10-31T18:51:33+00:00"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "easycorp/easyadmin-bundle",
|
|
||||||
"version": "v4.29.12",
|
|
||||||
"source": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/EasyCorp/EasyAdminBundle.git",
|
|
||||||
"reference": "c6e8111f8215d5ba5ae7c7ec23462d1a56ff41b2"
|
|
||||||
},
|
|
||||||
"dist": {
|
|
||||||
"type": "zip",
|
|
||||||
"url": "https://api.github.com/repos/EasyCorp/EasyAdminBundle/zipball/c6e8111f8215d5ba5ae7c7ec23462d1a56ff41b2",
|
|
||||||
"reference": "c6e8111f8215d5ba5ae7c7ec23462d1a56ff41b2",
|
|
||||||
"shasum": ""
|
|
||||||
},
|
|
||||||
"require": {
|
|
||||||
"doctrine/doctrine-bundle": "^2.5|^3.0",
|
|
||||||
"doctrine/orm": "^2.12|^3.0",
|
|
||||||
"php": ">=8.1",
|
|
||||||
"symfony/asset": "^5.4|^6.0|^7.0|^8.0",
|
|
||||||
"symfony/cache": "^5.4|^6.0|^7.0|^8.0",
|
|
||||||
"symfony/config": "^5.4|^6.0|^7.0|^8.0",
|
|
||||||
"symfony/dependency-injection": "^5.4|^6.0|^7.0|^8.0",
|
|
||||||
"symfony/deprecation-contracts": "^3.0",
|
|
||||||
"symfony/doctrine-bridge": "^5.4|^6.0|^7.0|^8.0",
|
|
||||||
"symfony/event-dispatcher": "^5.4|^6.0|^7.0|^8.0",
|
|
||||||
"symfony/filesystem": "^5.4|^6.0|^7.0|^8.0",
|
|
||||||
"symfony/form": "^5.4|^6.0|^7.0|^8.0",
|
|
||||||
"symfony/framework-bundle": "^5.4|^6.0|^7.0|^8.0",
|
|
||||||
"symfony/http-foundation": "^5.4|^6.0|^7.0|^8.0",
|
|
||||||
"symfony/http-kernel": "^5.4|^6.0|^7.0|^8.0",
|
|
||||||
"symfony/intl": "^5.4|^6.0|^7.0|^8.0",
|
|
||||||
"symfony/property-access": "^5.4|^6.0|^7.0|^8.0",
|
|
||||||
"symfony/security-bundle": "^5.4|^6.0|^7.0|^8.0",
|
|
||||||
"symfony/string": "^5.4|^6.0|^7.0|^8.0",
|
|
||||||
"symfony/translation": "^5.4|^6.0|^7.0|^8.0",
|
|
||||||
"symfony/twig-bridge": "^5.4.48|^6.4.16|^7.1.9|^8.0",
|
|
||||||
"symfony/twig-bundle": "^5.4|^6.0|^7.0|^8.0",
|
|
||||||
"symfony/uid": "^5.4|^6.0|^7.0|^8.0",
|
|
||||||
"symfony/ux-twig-component": "^2.21",
|
|
||||||
"symfony/validator": "^5.4|^6.0|^7.0|^8.0",
|
|
||||||
"twig/extra-bundle": "^3.17",
|
|
||||||
"twig/html-extra": "^3.17",
|
|
||||||
"twig/twig": "^3.20"
|
|
||||||
},
|
|
||||||
"conflict": {
|
|
||||||
"symfony/error-handler": "<5.4.35"
|
|
||||||
},
|
|
||||||
"require-dev": {
|
|
||||||
"doctrine/doctrine-fixtures-bundle": "^3.4|3.5.x-dev|^4.0",
|
|
||||||
"phpstan/extension-installer": "^1.4",
|
|
||||||
"phpstan/phpstan": "^2.0",
|
|
||||||
"phpstan/phpstan-phpunit": "^2.0",
|
|
||||||
"phpstan/phpstan-strict-rules": "^2.0",
|
|
||||||
"phpstan/phpstan-symfony": "^2.0",
|
|
||||||
"psr/log": "^1.0|^2.0|^3.0",
|
|
||||||
"symfony/browser-kit": "^5.4|^6.0|^7.0|^8.0",
|
|
||||||
"symfony/css-selector": "^5.4|^6.0|^7.0|^8.0",
|
|
||||||
"symfony/debug-bundle": "^5.4|^6.0|^7.0|^8.0",
|
|
||||||
"symfony/dom-crawler": "^5.4|^6.0|^7.0|^8.0",
|
|
||||||
"symfony/expression-language": "^5.4|^6.0|^7.0|^8.0",
|
|
||||||
"symfony/phpunit-bridge": "^6.1|^7.0|^8.0",
|
|
||||||
"symfony/process": "^5.4|^6.0|^7.0|^8.0",
|
|
||||||
"symfony/web-link": "^5.4|^6.0|^7.0|^8.0",
|
|
||||||
"vincentlanglet/twig-cs-fixer": "^3.10"
|
|
||||||
},
|
|
||||||
"type": "symfony-bundle",
|
|
||||||
"extra": {
|
|
||||||
"branch-alias": {
|
|
||||||
"dev-master": "4.0.x-dev"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"autoload": {
|
|
||||||
"psr-4": {
|
|
||||||
"EasyCorp\\Bundle\\EasyAdminBundle\\": "src/"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
|
||||||
"license": [
|
|
||||||
"MIT"
|
|
||||||
],
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "Project Contributors",
|
|
||||||
"homepage": "https://github.com/EasyCorp/EasyAdminBundle/graphs/contributors"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "Admin generator for Symfony applications",
|
|
||||||
"homepage": "https://github.com/EasyCorp/EasyAdminBundle",
|
|
||||||
"keywords": [
|
|
||||||
"admin",
|
|
||||||
"backend",
|
|
||||||
"generator"
|
|
||||||
],
|
|
||||||
"support": {
|
|
||||||
"issues": "https://github.com/EasyCorp/EasyAdminBundle/issues",
|
|
||||||
"source": "https://github.com/EasyCorp/EasyAdminBundle/tree/v4.29.12"
|
|
||||||
},
|
|
||||||
"funding": [
|
|
||||||
{
|
|
||||||
"url": "https://github.com/javiereguiluz",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"time": "2026-06-03T19:31:07+00:00"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "egulias/email-validator",
|
"name": "egulias/email-validator",
|
||||||
"version": "4.0.4",
|
"version": "4.0.4",
|
||||||
@@ -1773,6 +1668,311 @@
|
|||||||
},
|
},
|
||||||
"time": "2026-06-01T10:02:14+00:00"
|
"time": "2026-06-01T10:02:14+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "knplabs/knp-components",
|
||||||
|
"version": "v5.2.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/KnpLabs/knp-components.git",
|
||||||
|
"reference": "eabf39263fff305c0024820c3736e5b03e7edf50"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/KnpLabs/knp-components/zipball/eabf39263fff305c0024820c3736e5b03e7edf50",
|
||||||
|
"reference": "eabf39263fff305c0024820c3736e5b03e7edf50",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^8.1",
|
||||||
|
"symfony/event-dispatcher-contracts": "^3.0"
|
||||||
|
},
|
||||||
|
"conflict": {
|
||||||
|
"doctrine/dbal": "<3.8"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"doctrine/dbal": "^3.8 || ^4.0",
|
||||||
|
"doctrine/mongodb-odm": "^2.5.5",
|
||||||
|
"doctrine/orm": "^2.13 || ^3.0",
|
||||||
|
"doctrine/phpcr-odm": "^1.8 || ^2.0",
|
||||||
|
"ext-pdo_sqlite": "*",
|
||||||
|
"jackalope/jackalope-doctrine-dbal": "^1.12 || ^2.0",
|
||||||
|
"phpunit/phpunit": "^10.5 || ^11.3",
|
||||||
|
"propel/propel1": "^1.7",
|
||||||
|
"ruflin/elastica": "^7.0",
|
||||||
|
"solarium/solarium": "^6.0",
|
||||||
|
"symfony/http-foundation": "^5.4.38 || ^6.4.4 || ^7.0",
|
||||||
|
"symfony/http-kernel": "^5.4.38 || ^6.4.4 || ^7.0",
|
||||||
|
"symfony/property-access": "^5.4.38 || ^6.4.4 || ^7.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"doctrine/common": "to allow usage pagination with Doctrine ArrayCollection",
|
||||||
|
"doctrine/mongodb-odm": "to allow usage pagination with Doctrine ODM MongoDB",
|
||||||
|
"doctrine/orm": "to allow usage pagination with Doctrine ORM",
|
||||||
|
"doctrine/phpcr-odm": "to allow usage pagination with Doctrine ODM PHPCR",
|
||||||
|
"propel/propel1": "to allow usage pagination with Propel ORM",
|
||||||
|
"ruflin/elastica": "to allow usage pagination with ElasticSearch Client",
|
||||||
|
"solarium/solarium": "to allow usage pagination with Solarium Client",
|
||||||
|
"symfony/http-foundation": "to retrieve arguments from Request",
|
||||||
|
"symfony/property-access": "to allow sorting arrays"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "5.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Knp\\Component\\": "src/Knp/Component"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "KnpLabs Team",
|
||||||
|
"homepage": "https://knplabs.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://github.com/KnpLabs/knp-components/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Knplabs component library",
|
||||||
|
"homepage": "https://github.com/KnpLabs/knp-components",
|
||||||
|
"keywords": [
|
||||||
|
"components",
|
||||||
|
"knp",
|
||||||
|
"knplabs",
|
||||||
|
"pager",
|
||||||
|
"paginator"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/KnpLabs/knp-components/issues",
|
||||||
|
"source": "https://github.com/KnpLabs/knp-components/tree/v5.2.0"
|
||||||
|
},
|
||||||
|
"time": "2025-03-20T07:35:37+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "knplabs/knp-menu",
|
||||||
|
"version": "v3.8.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/KnpLabs/KnpMenu.git",
|
||||||
|
"reference": "79d325909a1d428a93f1a0f55e90177830e283bb"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/KnpLabs/KnpMenu/zipball/79d325909a1d428a93f1a0f55e90177830e283bb",
|
||||||
|
"reference": "79d325909a1d428a93f1a0f55e90177830e283bb",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^8.1"
|
||||||
|
},
|
||||||
|
"conflict": {
|
||||||
|
"symfony/http-foundation": "<5.4",
|
||||||
|
"twig/twig": "<2.16"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpstan/phpstan": "^2.1",
|
||||||
|
"phpunit/phpunit": "^9.6",
|
||||||
|
"psr/container": "^1.0 || ^2.0",
|
||||||
|
"symfony/http-foundation": "^5.4 || ^6.0 || ^7.0",
|
||||||
|
"symfony/phpunit-bridge": "^7.0",
|
||||||
|
"symfony/routing": "^5.4 || ^6.0 || ^7.0",
|
||||||
|
"twig/twig": "^2.16 || ^3.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"twig/twig": "for the TwigRenderer and the integration with your templates"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "3.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Knp\\Menu\\": "src/Knp/Menu"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "KnpLabs",
|
||||||
|
"homepage": "https://knplabs.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Christophe Coevoet",
|
||||||
|
"email": "[email protected]"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "The Community",
|
||||||
|
"homepage": "https://github.com/KnpLabs/KnpMenu/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "An object oriented menu library",
|
||||||
|
"homepage": "https://knplabs.com",
|
||||||
|
"keywords": [
|
||||||
|
"menu",
|
||||||
|
"tree"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/KnpLabs/KnpMenu/issues",
|
||||||
|
"source": "https://github.com/KnpLabs/KnpMenu/tree/v3.8.0"
|
||||||
|
},
|
||||||
|
"time": "2025-06-13T15:03:33+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "knplabs/knp-menu-bundle",
|
||||||
|
"version": "v3.7.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/KnpLabs/KnpMenuBundle.git",
|
||||||
|
"reference": "aa22e57f8f41c34ad5e382aae4d0c12998c0eb5a"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/KnpLabs/KnpMenuBundle/zipball/aa22e57f8f41c34ad5e382aae4d0c12998c0eb5a",
|
||||||
|
"reference": "aa22e57f8f41c34ad5e382aae4d0c12998c0eb5a",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"knplabs/knp-menu": "^3.8",
|
||||||
|
"php": "^8.1",
|
||||||
|
"symfony/config": "^6.4 | ^7.0 | ^8.0",
|
||||||
|
"symfony/dependency-injection": "^6.4 | ^7.0 | ^8.0",
|
||||||
|
"symfony/deprecation-contracts": "^2.5 | ^3.3",
|
||||||
|
"symfony/http-kernel": "^6.4 | ^7.0 | ^8.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^10.5 | ^11.5 | ^12.4",
|
||||||
|
"symfony/expression-language": "^6.4 | ^7.0 | ^8.0",
|
||||||
|
"symfony/phpunit-bridge": "^7.0 | ^8.0",
|
||||||
|
"symfony/templating": "^6.4 | ^7.0 | ^8.0"
|
||||||
|
},
|
||||||
|
"type": "symfony-bundle",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "3.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Knp\\Bundle\\MenuBundle\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Knplabs",
|
||||||
|
"homepage": "http://knplabs.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Christophe Coevoet",
|
||||||
|
"email": "[email protected]"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://github.com/KnpLabs/KnpMenuBundle/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "This bundle provides an integration of the KnpMenu library",
|
||||||
|
"keywords": [
|
||||||
|
"menu"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/KnpLabs/KnpMenuBundle/issues",
|
||||||
|
"source": "https://github.com/KnpLabs/KnpMenuBundle/tree/v3.7.0"
|
||||||
|
},
|
||||||
|
"time": "2025-11-30T08:30:04+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "knplabs/knp-paginator-bundle",
|
||||||
|
"version": "v6.10.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/KnpLabs/KnpPaginatorBundle.git",
|
||||||
|
"reference": "8d41f8ed47d880f8fa569389ffa4fecfbc5b8d41"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/KnpLabs/KnpPaginatorBundle/zipball/8d41f8ed47d880f8fa569389ffa4fecfbc5b8d41",
|
||||||
|
"reference": "8d41f8ed47d880f8fa569389ffa4fecfbc5b8d41",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"knplabs/knp-components": "^4.4 || ^5.0",
|
||||||
|
"php": "^8.1",
|
||||||
|
"symfony/config": "^6.4 || ^7.0 || ^8.0",
|
||||||
|
"symfony/dependency-injection": "^6.4 || ^7.0 || ^8.0",
|
||||||
|
"symfony/event-dispatcher": "^6.4 || ^7.0 || ^8.0",
|
||||||
|
"symfony/http-foundation": "^6.4 || ^7.0 || ^8.0",
|
||||||
|
"symfony/http-kernel": "^6.4 || ^7.0 || ^8.0",
|
||||||
|
"symfony/routing": "^6.4 || ^7.0 || ^8.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpstan/phpstan": "^1.12",
|
||||||
|
"phpunit/phpunit": "^10.5 || ^11.5 || ^12.2",
|
||||||
|
"symfony/templating": "^6.4 || ^7.0 || ^8.0",
|
||||||
|
"symfony/translation": "^6.4 || ^7.0 || ^8.0",
|
||||||
|
"twig/twig": "^3.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"symfony/translation": "To use the templates",
|
||||||
|
"twig/twig": "To use the templates"
|
||||||
|
},
|
||||||
|
"type": "symfony-bundle",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "6.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Knp\\Bundle\\PaginatorBundle\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "KnpLabs Team",
|
||||||
|
"homepage": "https://knplabs.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://github.com/KnpLabs/KnpPaginatorBundle/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Paginator bundle for Symfony to automate pagination and simplify sorting and other features",
|
||||||
|
"homepage": "https://github.com/KnpLabs/KnpPaginatorBundle",
|
||||||
|
"keywords": [
|
||||||
|
"bundle",
|
||||||
|
"knp",
|
||||||
|
"knplabs",
|
||||||
|
"pager",
|
||||||
|
"pagination",
|
||||||
|
"paginator",
|
||||||
|
"symfony"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/KnpLabs/KnpPaginatorBundle/issues",
|
||||||
|
"source": "https://github.com/KnpLabs/KnpPaginatorBundle/tree/v6.10.0"
|
||||||
|
},
|
||||||
|
"time": "2025-11-29T09:14:09+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "lcobucci/clock",
|
"name": "lcobucci/clock",
|
||||||
"version": "3.5.0",
|
"version": "3.5.0",
|
||||||
@@ -9944,95 +10144,6 @@
|
|||||||
],
|
],
|
||||||
"time": "2025-12-23T15:07:59+00:00"
|
"time": "2025-12-23T15:07:59+00:00"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "symfony/ux-twig-component",
|
|
||||||
"version": "v2.36.0",
|
|
||||||
"source": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/symfony/ux-twig-component.git",
|
|
||||||
"reference": "d64b068d8339e905cd48974bdd6e9ba54dc8f247"
|
|
||||||
},
|
|
||||||
"dist": {
|
|
||||||
"type": "zip",
|
|
||||||
"url": "https://api.github.com/repos/symfony/ux-twig-component/zipball/d64b068d8339e905cd48974bdd6e9ba54dc8f247",
|
|
||||||
"reference": "d64b068d8339e905cd48974bdd6e9ba54dc8f247",
|
|
||||||
"shasum": ""
|
|
||||||
},
|
|
||||||
"require": {
|
|
||||||
"php": ">=8.1",
|
|
||||||
"symfony/dependency-injection": "^5.4|^6.0|^7.0|^8.0",
|
|
||||||
"symfony/deprecation-contracts": "^2.2|^3.0",
|
|
||||||
"symfony/event-dispatcher": "^5.4|^6.0|^7.0|^8.0",
|
|
||||||
"symfony/property-access": "^5.4|^6.0|^7.0|^8.0",
|
|
||||||
"twig/twig": "^3.10.3"
|
|
||||||
},
|
|
||||||
"conflict": {
|
|
||||||
"symfony/config": "<5.4.0"
|
|
||||||
},
|
|
||||||
"require-dev": {
|
|
||||||
"symfony/console": "^5.4|^6.0|^7.0|^8.0",
|
|
||||||
"symfony/css-selector": "^5.4|^6.0|^7.0|^8.0",
|
|
||||||
"symfony/dom-crawler": "^5.4|^6.0|^7.0|^8.0",
|
|
||||||
"symfony/framework-bundle": "^5.4|^6.0|^7.0|^8.0",
|
|
||||||
"symfony/phpunit-bridge": "^6.0|^7.0|^8.0",
|
|
||||||
"symfony/stimulus-bundle": "^2.9.1|^3.0",
|
|
||||||
"symfony/twig-bundle": "^5.4|^6.0|^7.0|^8.0",
|
|
||||||
"symfony/webpack-encore-bundle": "^1.15|^2.3.0",
|
|
||||||
"twig/extra-bundle": "^3.10.3",
|
|
||||||
"twig/html-extra": "^3.10.3"
|
|
||||||
},
|
|
||||||
"type": "symfony-bundle",
|
|
||||||
"extra": {
|
|
||||||
"thanks": {
|
|
||||||
"url": "https://github.com/symfony/ux",
|
|
||||||
"name": "symfony/ux"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"autoload": {
|
|
||||||
"psr-4": {
|
|
||||||
"Symfony\\UX\\TwigComponent\\": "src/"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
|
||||||
"license": [
|
|
||||||
"MIT"
|
|
||||||
],
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "Symfony Community",
|
|
||||||
"homepage": "https://symfony.com/contributors"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "Twig components for Symfony",
|
|
||||||
"homepage": "https://symfony.com",
|
|
||||||
"keywords": [
|
|
||||||
"components",
|
|
||||||
"symfony-ux",
|
|
||||||
"twig"
|
|
||||||
],
|
|
||||||
"support": {
|
|
||||||
"source": "https://github.com/symfony/ux-twig-component/tree/v2.36.0"
|
|
||||||
},
|
|
||||||
"funding": [
|
|
||||||
{
|
|
||||||
"url": "https://symfony.com/sponsor",
|
|
||||||
"type": "custom"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://github.com/fabpot",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://github.com/nicolas-grekas",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
|
||||||
"type": "tidelift"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"time": "2026-04-03T05:13:59+00:00"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "symfony/validator",
|
"name": "symfony/validator",
|
||||||
"version": "v6.4.37",
|
"version": "v6.4.37",
|
||||||
@@ -10748,6 +10859,73 @@
|
|||||||
],
|
],
|
||||||
"time": "2026-05-19T20:44:48+00:00"
|
"time": "2026-05-19T20:44:48+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "twig/string-extra",
|
||||||
|
"version": "v3.24.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/twigphp/string-extra.git",
|
||||||
|
"reference": "6ec8f2e8ca9b2193221a02cb599dc92c36384368"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/twigphp/string-extra/zipball/6ec8f2e8ca9b2193221a02cb599dc92c36384368",
|
||||||
|
"reference": "6ec8f2e8ca9b2193221a02cb599dc92c36384368",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=8.1.0",
|
||||||
|
"symfony/string": "^5.4|^6.4|^7.0|^8.0",
|
||||||
|
"symfony/translation-contracts": "^1.1|^2|^3",
|
||||||
|
"twig/twig": "^3.13|^4.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"symfony/phpunit-bridge": "^6.4|^7.0"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Twig\\Extra\\String\\": ""
|
||||||
|
},
|
||||||
|
"exclude-from-classmap": [
|
||||||
|
"/Tests/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Fabien Potencier",
|
||||||
|
"email": "[email protected]",
|
||||||
|
"homepage": "http://fabien.potencier.org",
|
||||||
|
"role": "Lead Developer"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "A Twig extension for Symfony String",
|
||||||
|
"homepage": "https://twig.symfony.com",
|
||||||
|
"keywords": [
|
||||||
|
"html",
|
||||||
|
"string",
|
||||||
|
"twig",
|
||||||
|
"unicode"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/twigphp/string-extra/tree/v3.24.0"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/twig/twig",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2025-12-02T14:45:16+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "twig/twig",
|
"name": "twig/twig",
|
||||||
"version": "v3.27.1",
|
"version": "v3.27.1",
|
||||||
|
|||||||
+2
-2
@@ -16,7 +16,7 @@ return [
|
|||||||
League\FlysystemBundle\FlysystemBundle::class => ['all' => true],
|
League\FlysystemBundle\FlysystemBundle::class => ['all' => true],
|
||||||
League\Bundle\OAuth2ServerBundle\LeagueOAuth2ServerBundle::class => ['all' => true],
|
League\Bundle\OAuth2ServerBundle\LeagueOAuth2ServerBundle::class => ['all' => true],
|
||||||
Zenstruck\ScheduleBundle\ZenstruckScheduleBundle::class => ['all' => true],
|
Zenstruck\ScheduleBundle\ZenstruckScheduleBundle::class => ['all' => true],
|
||||||
Symfony\UX\TwigComponent\TwigComponentBundle::class => ['all' => true],
|
|
||||||
EasyCorp\Bundle\EasyAdminBundle\EasyAdminBundle::class => ['all' => true],
|
|
||||||
Flagception\Bundle\FlagceptionBundle\FlagceptionBundle::class => ['all' => true],
|
Flagception\Bundle\FlagceptionBundle\FlagceptionBundle::class => ['all' => true],
|
||||||
|
Knp\Bundle\MenuBundle\KnpMenuBundle::class => ['all' => true],
|
||||||
|
Knp\Bundle\PaginatorBundle\KnpPaginatorBundle::class => ['all' => true],
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
knp_menu:
|
||||||
|
twig:
|
||||||
|
template: _partials/_menu.html.twig
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
knp_paginator:
|
||||||
|
default_options:
|
||||||
|
page_name: page
|
||||||
|
sort_field_name: sort
|
||||||
|
sort_direction_name: direction
|
||||||
|
distinct: true
|
||||||
|
filter_field_name: filterField
|
||||||
|
filter_value_name: filterValue
|
||||||
|
template:
|
||||||
|
pagination: '_partials/_paginator_sliding.html.twig'
|
||||||
|
sortable: '_partials/_paginator_sortable_link.html.twig'
|
||||||
@@ -4,6 +4,7 @@ monolog:
|
|||||||
- bpn
|
- bpn
|
||||||
- core
|
- core
|
||||||
- auth
|
- auth
|
||||||
|
- admin
|
||||||
|
|
||||||
when@dev:
|
when@dev:
|
||||||
monolog:
|
monolog:
|
||||||
@@ -27,11 +28,16 @@ when@dev:
|
|||||||
path: "%kernel.logs_dir%/%kernel.environment%.core.log"
|
path: "%kernel.logs_dir%/%kernel.environment%.core.log"
|
||||||
level: debug
|
level: debug
|
||||||
channels: ["core"]
|
channels: ["core"]
|
||||||
|
admin:
|
||||||
|
type: stream
|
||||||
|
path: "%kernel.logs_dir%/%kernel.environment%.admin.log"
|
||||||
|
level: debug
|
||||||
|
channels: ["admin"]
|
||||||
main:
|
main:
|
||||||
type: stream
|
type: stream
|
||||||
path: "%kernel.logs_dir%/%kernel.environment%.log"
|
path: "%kernel.logs_dir%/%kernel.environment%.log"
|
||||||
level: debug
|
level: debug
|
||||||
channels: ["!event", "!bpn", "!core", "!auth"]
|
channels: ["!event", "!bpn", "!core", "!auth", "!admin"]
|
||||||
# uncomment to get logging in your browser
|
# uncomment to get logging in your browser
|
||||||
# you may have to allow bigger header sizes in your Web server configuration
|
# you may have to allow bigger header sizes in your Web server configuration
|
||||||
#firephp:
|
#firephp:
|
||||||
@@ -84,13 +90,19 @@ when@prod: &prod_config
|
|||||||
path: "%kernel.logs_dir%/%kernel.environment%.core.log"
|
path: "%kernel.logs_dir%/%kernel.environment%.core.log"
|
||||||
level: info
|
level: info
|
||||||
channels: ["core"]
|
channels: ["core"]
|
||||||
|
admin:
|
||||||
|
type: rotating_file
|
||||||
|
max_files: 7
|
||||||
|
path: "%kernel.logs_dir%/%kernel.environment%.admin.log"
|
||||||
|
level: info
|
||||||
|
channels: ["admin"]
|
||||||
main:
|
main:
|
||||||
type: fingers_crossed
|
type: fingers_crossed
|
||||||
action_level: error
|
action_level: error
|
||||||
handler: nested
|
handler: nested
|
||||||
excluded_http_codes: [404, 405]
|
excluded_http_codes: [404, 405]
|
||||||
buffer_size: 50 # How many messages should be saved? Prevent memory leaks
|
buffer_size: 50 # How many messages should be saved? Prevent memory leaks
|
||||||
channels: ["!bpn", "!core", "!auth"]
|
channels: ["!bpn", "!core", "!auth", "!admin"]
|
||||||
nested:
|
nested:
|
||||||
type: rotating_file
|
type: rotating_file
|
||||||
path: "%kernel.logs_dir%/%kernel.environment%.framework.log"
|
path: "%kernel.logs_dir%/%kernel.environment%.framework.log"
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
twig_component:
|
|
||||||
anonymous_template_directory: 'components/'
|
|
||||||
defaults:
|
|
||||||
# Namespace & directory for components
|
|
||||||
App\Twig\Components\: 'components/'
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
easyadmin:
|
|
||||||
resource: .
|
|
||||||
type: easyadmin.routes
|
|
||||||
@@ -108,6 +108,14 @@ services:
|
|||||||
arguments:
|
arguments:
|
||||||
$path: '%path_to_keys%'
|
$path: '%path_to_keys%'
|
||||||
|
|
||||||
|
App\Menu\AdminMenuBuilder:
|
||||||
|
arguments:
|
||||||
|
$factory: '@knp_menu.factory'
|
||||||
|
tags:
|
||||||
|
- name: knp_menu.menu_builder
|
||||||
|
method: createMainMenu
|
||||||
|
alias: admin_main
|
||||||
|
|
||||||
App\Service\BpnXmlSyncManager:
|
App\Service\BpnXmlSyncManager:
|
||||||
arguments:
|
arguments:
|
||||||
$xmlSource: '@xml_source.storage'
|
$xmlSource: '@xml_source.storage'
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Admin\Field;
|
|
||||||
|
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Contracts\Field\FieldInterface;
|
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Field\FieldTrait;
|
|
||||||
|
|
||||||
class JsonDataField implements FieldInterface
|
|
||||||
{
|
|
||||||
use FieldTrait;
|
|
||||||
|
|
||||||
public static function new(string $propertyName, ?string $label = null): self
|
|
||||||
{
|
|
||||||
return (new self())
|
|
||||||
->setProperty($propertyName)
|
|
||||||
->setLabel($label)
|
|
||||||
->setTemplatePath('admin/field/json.html.twig');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Controller\Admin;
|
||||||
|
|
||||||
|
use App\Controller\Traits\ReturnUrlTrait;
|
||||||
|
use App\Entity\BookingEditDraft;
|
||||||
|
use App\Htmx\HxRedirectResponse;
|
||||||
|
use App\Repository\BookingEditDraftRepository;
|
||||||
|
use App\Service\BookingExporter;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Knp\Component\Pager\PaginatorInterface;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
|
|
||||||
|
class BookingEditDraftController extends AbstractController
|
||||||
|
{
|
||||||
|
use ReturnUrlTrait;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
private readonly EntityManagerInterface $entityManager,
|
||||||
|
private readonly BookingEditDraftRepository $bookingEditDraftRepository,
|
||||||
|
private readonly PaginatorInterface $paginator,
|
||||||
|
private readonly BookingExporter $bookingExporter,
|
||||||
|
private readonly LoggerInterface $adminLogger,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Route('/admin/booking-edit-draft', name: 'app_admin_bookingeditdraft')]
|
||||||
|
public function index(Request $request): Response
|
||||||
|
{
|
||||||
|
$qb = $this
|
||||||
|
->bookingEditDraftRepository
|
||||||
|
->createQueryBuilder('booking_edit_draft')
|
||||||
|
->leftJoin('booking_edit_draft.user', 'user')
|
||||||
|
;
|
||||||
|
|
||||||
|
$pagination = $this->paginator->paginate(
|
||||||
|
$qb,
|
||||||
|
$request->query->getInt('page', 1),
|
||||||
|
$request->query->getInt('limit', 20),
|
||||||
|
[
|
||||||
|
'defaultSortFieldName' => 'booking_edit_draft.createdAt',
|
||||||
|
'defaultSortDirection' => 'DESC',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this->render('admin/booking_edit_draft/index.html.twig', [
|
||||||
|
'pagination' => $pagination,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Route('/admin/booking-edit-draft/{id}/show', name: 'app_admin_bookingeditdraft_show')]
|
||||||
|
public function show(BookingEditDraft $draft, Request $request): Response
|
||||||
|
{
|
||||||
|
$returnUrl = $this->getReturnUrl($request, 'app_admin_bookingeditdraft');
|
||||||
|
|
||||||
|
return $this->render('admin/booking_edit_draft/show.html.twig', [
|
||||||
|
'draft' => $draft,
|
||||||
|
'returnUrl' => $returnUrl,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Route('/admin/booking-edit-draft/{id}/delete', name: 'app_admin_bookingeditdraft_delete')]
|
||||||
|
public function delete(BookingEditDraft $draft, Request $request): Response
|
||||||
|
{
|
||||||
|
if (true === $request->isMethod(Request::METHOD_POST)) {
|
||||||
|
$this->entityManager->remove($draft);
|
||||||
|
$this->entityManager->flush();
|
||||||
|
|
||||||
|
$this->adminLogger->info('Delete booking edit draft', [
|
||||||
|
'booking_number' => $draft->getBookingNumber(),
|
||||||
|
]);
|
||||||
|
$this->addFlash('success', 'Der Buchungsentwurf wurde gelöscht');
|
||||||
|
|
||||||
|
$returnUrl = $this->getReturnUrl($request, 'app_admin_bookingeditdraft');
|
||||||
|
|
||||||
|
return new HxRedirectResponse($returnUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->render('admin/booking_edit_draft/modal_delete.html.twig', [
|
||||||
|
'draft' => $draft,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Route('/admin/booking-edit-draft/{id}/export', name: 'app_admin_bookingeditdraft_export')]
|
||||||
|
public function export(BookingEditDraft $draft): Response
|
||||||
|
{
|
||||||
|
if (false === $draft->hasExportData()) {
|
||||||
|
$this->addFlash('warning', 'Der Export ist fehlgeschlagen');
|
||||||
|
|
||||||
|
return $this->redirectToRoute('app_admin_bookingeditdraft');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return $this->bookingExporter->createExportResponse($draft);
|
||||||
|
} catch (\RuntimeException $e) {
|
||||||
|
$this->addFlash('warning', 'Der Export ist fehlgeschlagen: '.$e->getMessage());
|
||||||
|
|
||||||
|
return $this->redirectToRoute('app_admin_bookingeditdraft');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,101 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace App\Controller\Admin;
|
|
||||||
|
|
||||||
use App\Admin\Field\JsonDataField;
|
|
||||||
use App\Entity\BookingEditDraft;
|
|
||||||
use App\Entity\User;
|
|
||||||
use App\Service\BookingExporter;
|
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Config\Action;
|
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Config\Actions;
|
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
|
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
|
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Field\AssociationField;
|
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Field\DateTimeField;
|
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Field\IntegerField;
|
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Router\AdminUrlGenerator;
|
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
|
||||||
use Symfony\Component\Routing\Attribute\Route;
|
|
||||||
|
|
||||||
/** @extends AbstractCrudController<BookingEditDraft> */
|
|
||||||
class BookingEditDraftCrudController extends AbstractCrudController
|
|
||||||
{
|
|
||||||
public function __construct(
|
|
||||||
private readonly BookingExporter $exportService,
|
|
||||||
private readonly AdminUrlGenerator $adminUrlGenerator,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getEntityFqcn(): string
|
|
||||||
{
|
|
||||||
return BookingEditDraft::class;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function configureActions(Actions $actions): Actions
|
|
||||||
{
|
|
||||||
$exportAction = Action::new('exportExcel', 'Excel Export', 'fa fa-file-excel')
|
|
||||||
->linkToRoute(
|
|
||||||
'admin_booking_draft_export',
|
|
||||||
static fn (BookingEditDraft $entity): array => ['id' => $entity->getId()]
|
|
||||||
)
|
|
||||||
->displayIf(static fn (BookingEditDraft $entity): bool => $entity->hasExportData());
|
|
||||||
|
|
||||||
return $actions
|
|
||||||
->add(Crud::PAGE_INDEX, Action::DETAIL)
|
|
||||||
->add(Crud::PAGE_INDEX, $exportAction)
|
|
||||||
->add(Crud::PAGE_DETAIL, $exportAction)
|
|
||||||
->remove(Crud::PAGE_INDEX, Action::NEW)
|
|
||||||
->remove(Crud::PAGE_INDEX, Action::EDIT)
|
|
||||||
->remove(Crud::PAGE_DETAIL, Action::EDIT)
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[Route('/admin/booking-draft/{id}/export', name: 'admin_booking_draft_export', requirements: ['id' => '\d+'])]
|
|
||||||
public function export(BookingEditDraft $draft): Response
|
|
||||||
{
|
|
||||||
if (false === $draft->hasExportData()) {
|
|
||||||
$this->addFlash('danger', 'Export nicht möglich: Reisedaten fehlen');
|
|
||||||
|
|
||||||
$url = $this->adminUrlGenerator
|
|
||||||
->setController(self::class)
|
|
||||||
->setAction(Action::INDEX)
|
|
||||||
->generateUrl();
|
|
||||||
|
|
||||||
return $this->redirect($url);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
return $this->exportService->createExportResponse($draft);
|
|
||||||
} catch (\RuntimeException $e) {
|
|
||||||
$this->addFlash('danger', 'Export fehlgeschlagen: '.$e->getMessage());
|
|
||||||
|
|
||||||
$url = $this->adminUrlGenerator
|
|
||||||
->setController(self::class)
|
|
||||||
->setAction(Action::INDEX)
|
|
||||||
->generateUrl();
|
|
||||||
|
|
||||||
return $this->redirect($url);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function configureCrud(Crud $crud): Crud
|
|
||||||
{
|
|
||||||
return $crud
|
|
||||||
->setEntityLabelInSingular('Buchungsentwurf')
|
|
||||||
->setEntityLabelInPlural('Buchungsentwürfe')
|
|
||||||
->setDefaultSort(['createdAt' => 'DESC']);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function configureFields(string $pageName): iterable
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
IntegerField::new('bookingNumber', 'Vorgang'),
|
|
||||||
AssociationField::new('user', 'Kundenaccount')->formatValue(fn (User $user) => $user->getEmail()),
|
|
||||||
DateTimeField::new('createdAt', 'erstellt am'),
|
|
||||||
DateTimeField::new('updatedAt', 'aktualisiert am'),
|
|
||||||
JsonDataField::new('formData', 'Daten')->onlyOnDetail(),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,48 +1,18 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Controller\Admin;
|
namespace App\Controller\Admin;
|
||||||
|
|
||||||
use App\Entity\BookingEditDraft;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use App\Entity\LogEntry;
|
|
||||||
use App\Entity\User;
|
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Attribute\AdminDashboard;
|
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Config\Dashboard;
|
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Config\MenuItem;
|
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Config\UserMenu;
|
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractDashboardController;
|
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Security\Core\User\UserInterface;
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
|
|
||||||
#[AdminDashboard(routePath: '/admin', routeName: 'admin')]
|
class DashboardController extends AbstractController
|
||||||
class DashboardController extends AbstractDashboardController
|
|
||||||
{
|
{
|
||||||
|
#[Route('/admin/dashboard', name: 'app_admin_dashboard')]
|
||||||
public function index(): Response
|
public function index(): Response
|
||||||
{
|
{
|
||||||
return $this->render('admin/dashboard/index.html.twig');
|
return $this->render('admin/dashboard.html.twig');
|
||||||
}
|
|
||||||
|
|
||||||
public function configureDashboard(): Dashboard
|
|
||||||
{
|
|
||||||
return Dashboard::new()
|
|
||||||
->setTitle('MyE&P')
|
|
||||||
->setLocales(['de'])
|
|
||||||
->setFaviconPath('build/favicon/icon.svg')
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function configureUserMenu(UserInterface $user): UserMenu
|
|
||||||
{
|
|
||||||
return parent::configureUserMenu($user)
|
|
||||||
->addMenuItems([
|
|
||||||
MenuItem::linkToRoute('MyE&P', 'fa fa-user', 'app_account'),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function configureMenuItems(): iterable
|
|
||||||
{
|
|
||||||
yield MenuItem::linkToDashboard('Dashboard', 'fa fa-home');
|
|
||||||
yield MenuItem::linkToCrud('Log', 'fa fa-list', LogEntry::class);
|
|
||||||
yield MenuItem::linkToCrud('Buchungsentwürfe', 'fa fa-pen-to-square', BookingEditDraft::class);
|
|
||||||
yield MenuItem::linkToCrud('Benutzeraccounts', 'fa fa-users', User::class);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Controller\Admin;
|
||||||
|
|
||||||
|
use App\Entity\Log;
|
||||||
|
use App\Entity\LogEntry;
|
||||||
|
use App\Repository\LogEntryRepository;
|
||||||
|
use App\Service\XmlDumpReader;
|
||||||
|
use Knp\Component\Pager\PaginatorInterface;
|
||||||
|
use League\Flysystem\FilesystemException;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
|
||||||
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
|
|
||||||
|
class LogController extends AbstractController
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private readonly LogEntryRepository $logEntryRepository,
|
||||||
|
private readonly PaginatorInterface $paginator,
|
||||||
|
private readonly XmlDumpReader $xmlDumpReader,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Route('/admin/log', name: 'app_admin_log')]
|
||||||
|
public function index(Request $request): Response
|
||||||
|
{
|
||||||
|
$qb = $this
|
||||||
|
->logEntryRepository
|
||||||
|
->createQueryBuilder('log_entry')
|
||||||
|
;
|
||||||
|
|
||||||
|
$pagination = $this->paginator->paginate(
|
||||||
|
$qb,
|
||||||
|
$request->query->getInt('page', 1),
|
||||||
|
$request->query->getInt('limit', 50),
|
||||||
|
[
|
||||||
|
'defaultSortFieldName' => 'log_entry.createdAt',
|
||||||
|
'defaultSortDirection' => 'DESC',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this->render('admin/log/index.html.twig', [
|
||||||
|
'pagination' => $pagination,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Route('/admin/log/{id}/xml-dumps', name: 'app_admin_log_xmldumps')]
|
||||||
|
public function xmlDumps(LogEntry $logEntry): Response
|
||||||
|
{
|
||||||
|
$dumps = [];
|
||||||
|
try {
|
||||||
|
$dumps = $this->xmlDumpReader->findDumpsForRequestId($logEntry->getRequestId());
|
||||||
|
} catch (FilesystemException) {
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->render('admin/log/xml_dumps.html.twig', [
|
||||||
|
'logEntry' => $logEntry,
|
||||||
|
'dumps' => $dumps,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Route('/admin/log/download/{filename}', name: 'app_admin_log_xmldump_download', requirements: ['filename' => '.+'])]
|
||||||
|
public function downloadXmlDump(string $filename): Response
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if (false === $this->xmlDumpReader->fileExists($filename)) {
|
||||||
|
throw $this->createNotFoundException('Dump file not found. It may have been cleaned up.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$content = $this->xmlDumpReader->getContent($filename);
|
||||||
|
} catch (FilesystemException $e) {
|
||||||
|
throw $this->createNotFoundException('Failed to read dump file: '.$e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = new Response($content);
|
||||||
|
$response->headers->set('Content-Type', 'application/xml');
|
||||||
|
|
||||||
|
$disposition = $response->headers->makeDisposition(
|
||||||
|
ResponseHeaderBag::DISPOSITION_ATTACHMENT,
|
||||||
|
basename($filename)
|
||||||
|
);
|
||||||
|
$response->headers->set('Content-Disposition', $disposition);
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace App\Controller\Admin;
|
|
||||||
|
|
||||||
use App\Admin\Field\JsonDataField;
|
|
||||||
use App\Entity\LogEntry;
|
|
||||||
use App\Repository\LogEntryRepository;
|
|
||||||
use App\Service\XmlDumpReader;
|
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Config\Action;
|
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Config\Actions;
|
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
|
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
|
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Field\DateTimeField;
|
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
|
|
||||||
use League\Flysystem\FilesystemException;
|
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
|
||||||
|
|
||||||
/** @extends AbstractCrudController<LogEntry> */
|
|
||||||
class LogEntryCrudController extends AbstractCrudController
|
|
||||||
{
|
|
||||||
public function __construct(
|
|
||||||
private readonly LogEntryRepository $logEntryRepository,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getEntityFqcn(): string
|
|
||||||
{
|
|
||||||
return LogEntry::class;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function configureActions(Actions $actions): Actions
|
|
||||||
{
|
|
||||||
$viewDumps = Action::new('viewDumps', 'XML Dumps', 'fa fa-file-code')
|
|
||||||
->linkToCrudAction('xmlDumps')
|
|
||||||
->displayIf(static fn (LogEntry $entity): bool => 'bpn' === $entity->getChannel());
|
|
||||||
|
|
||||||
return $actions
|
|
||||||
->add(Crud::PAGE_INDEX, Action::DETAIL)
|
|
||||||
->add(Crud::PAGE_INDEX, $viewDumps)
|
|
||||||
->add(Crud::PAGE_DETAIL, $viewDumps)
|
|
||||||
->remove(Crud::PAGE_INDEX, Action::NEW)
|
|
||||||
->remove(Crud::PAGE_INDEX, Action::EDIT)
|
|
||||||
->remove(Crud::PAGE_INDEX, Action::DELETE)
|
|
||||||
->remove(Crud::PAGE_DETAIL, Action::EDIT)
|
|
||||||
->remove(Crud::PAGE_DETAIL, Action::DELETE)
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function configureCrud(Crud $crud): Crud
|
|
||||||
{
|
|
||||||
return $crud
|
|
||||||
->setEntityLabelInSingular('Logeintrag')
|
|
||||||
->setEntityLabelInPlural('Logeinträge')
|
|
||||||
->setDefaultSort(['createdAt' => 'DESC'])
|
|
||||||
->setSearchFields(['errorCode', 'message', 'channel', 'extra']);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function configureFields(string $pageName): iterable
|
|
||||||
{
|
|
||||||
yield DateTimeField::new('createdAt', 'Zeitstempel');
|
|
||||||
yield TextField::new('errorCode', 'Fehlercode')
|
|
||||||
->formatValue(static fn (?string $value): string => $value ?? '-');
|
|
||||||
yield TextField::new('username', 'Benutzer');
|
|
||||||
yield TextField::new('message', 'Aktion');
|
|
||||||
yield TextField::new('requestId', 'Request ID');
|
|
||||||
yield TextField::new('uri', 'URI');
|
|
||||||
yield JsonDataField::new('context', 'Kontext')->onlyOnDetail();
|
|
||||||
yield JsonDataField::new('extra', 'Extra')->onlyOnDetail();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function xmlDumps(Request $request, XmlDumpReader $xmlDumpService): Response
|
|
||||||
{
|
|
||||||
$entityId = $request->query->getInt('entityId');
|
|
||||||
if ($entityId <= 0) {
|
|
||||||
throw $this->createNotFoundException('Log entry not found.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$entity = $this->logEntryRepository->find($entityId);
|
|
||||||
if (!$entity instanceof LogEntry) {
|
|
||||||
throw $this->createNotFoundException('Log entry not found.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$dumps = [];
|
|
||||||
try {
|
|
||||||
$dumps = $xmlDumpService->findDumpsForRequestId($entity->getRequestId());
|
|
||||||
} catch (FilesystemException) {
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->render('admin/xml_dump/list.html.twig', [
|
|
||||||
'logEntry' => $entity,
|
|
||||||
'requestId' => $entity->getRequestId(),
|
|
||||||
'dumps' => $dumps,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Controller\Admin;
|
||||||
|
|
||||||
|
use App\Repository\UserRepository;
|
||||||
|
use Knp\Component\Pager\PaginatorInterface;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
|
|
||||||
|
class UserController extends AbstractController
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private readonly UserRepository $userRepository,
|
||||||
|
private readonly PaginatorInterface $paginator,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Route('/admin/user', name: 'app_admin_user')]
|
||||||
|
public function index(Request $request): Response
|
||||||
|
{
|
||||||
|
$qb = $this
|
||||||
|
->userRepository
|
||||||
|
->createQueryBuilder('user')
|
||||||
|
;
|
||||||
|
|
||||||
|
$pagination = $this->paginator->paginate(
|
||||||
|
$qb,
|
||||||
|
$request->query->getInt('page', 1),
|
||||||
|
$request->query->getInt('limit', 50),
|
||||||
|
[
|
||||||
|
'defaultSortFieldName' => 'user.lastLoginAt',
|
||||||
|
'defaultSortDirection' => 'DESC',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this->render('admin/user/index.html.twig', [
|
||||||
|
'pagination' => $pagination,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Controller\Admin;
|
|
||||||
|
|
||||||
use App\Entity\User;
|
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Config\Action;
|
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Config\Actions;
|
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
|
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
|
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Field\DateTimeField;
|
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
|
|
||||||
|
|
||||||
/** @extends AbstractCrudController<User> */
|
|
||||||
class UserCrudController extends AbstractCrudController
|
|
||||||
{
|
|
||||||
public static function getEntityFqcn(): string
|
|
||||||
{
|
|
||||||
return User::class;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function configureActions(Actions $actions): Actions
|
|
||||||
{
|
|
||||||
return $actions
|
|
||||||
->remove(Crud::PAGE_INDEX, Action::NEW)
|
|
||||||
->remove(Crud::PAGE_INDEX, Action::EDIT)
|
|
||||||
->remove(Crud::PAGE_INDEX, Action::DELETE)
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function configureCrud(Crud $crud): Crud
|
|
||||||
{
|
|
||||||
return $crud
|
|
||||||
->setEntityLabelInSingular('Benutzeraccount')
|
|
||||||
->setEntityLabelInPlural('Benutzeraccounts')
|
|
||||||
->setDefaultSort(['lastLoginAt' => 'DESC']);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function configureFields(string $pageName): iterable
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
TextField::new('email', 'E-Mail'),
|
|
||||||
DateTimeField::new('lastLoginAt', 'letzter Login'),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace App\Controller\Admin;
|
|
||||||
|
|
||||||
use App\Repository\LogEntryRepository;
|
|
||||||
use App\Service\XmlDumpReader;
|
|
||||||
use League\Flysystem\FilesystemException;
|
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
|
||||||
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
|
|
||||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
|
||||||
use Symfony\Component\Routing\Attribute\Route;
|
|
||||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
|
||||||
|
|
||||||
#[Route('/admin/xml-dump')]
|
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
|
||||||
class XmlDumpController extends AbstractController
|
|
||||||
{
|
|
||||||
public function __construct(
|
|
||||||
private readonly XmlDumpReader $xmlDumpService,
|
|
||||||
private readonly LogEntryRepository $logEntryRepository,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
|
|
||||||
#[Route('/{id}', name: 'admin_xml_dump_list', methods: ['GET'])]
|
|
||||||
public function list(int $id): Response
|
|
||||||
{
|
|
||||||
$logEntry = $this->logEntryRepository->find($id);
|
|
||||||
|
|
||||||
if (null === $logEntry) {
|
|
||||||
throw new NotFoundHttpException('Log entry not found.');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('bpn' !== $logEntry->getChannel()) {
|
|
||||||
throw new NotFoundHttpException('XML dumps are only available for BPN channel entries.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$requestId = $logEntry->getRequestId();
|
|
||||||
$dumps = [];
|
|
||||||
|
|
||||||
try {
|
|
||||||
$dumps = $this->xmlDumpService->findDumpsForRequestId($requestId);
|
|
||||||
} catch (FilesystemException) {
|
|
||||||
// Dumps directory may not exist or be inaccessible
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->render('admin/xml_dump/list.html.twig', [
|
|
||||||
'logEntry' => $logEntry,
|
|
||||||
'requestId' => $requestId,
|
|
||||||
'dumps' => $dumps,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[Route('/download/{filename}', name: 'admin_xml_dump_download', methods: ['GET'], requirements: ['filename' => '.+'])]
|
|
||||||
public function download(string $filename): Response
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
if (false === $this->xmlDumpService->fileExists($filename)) {
|
|
||||||
throw new NotFoundHttpException('Dump file not found. It may have been cleaned up.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$content = $this->xmlDumpService->getContent($filename);
|
|
||||||
} catch (FilesystemException $e) {
|
|
||||||
throw new NotFoundHttpException('Failed to read dump file: '.$e->getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
$response = new Response($content);
|
|
||||||
$response->headers->set('Content-Type', 'application/xml');
|
|
||||||
|
|
||||||
$disposition = $response->headers->makeDisposition(
|
|
||||||
ResponseHeaderBag::DISPOSITION_ATTACHMENT,
|
|
||||||
basename($filename)
|
|
||||||
);
|
|
||||||
$response->headers->set('Content-Disposition', $disposition);
|
|
||||||
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Controller\Traits;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
|
||||||
|
trait ReturnUrlTrait
|
||||||
|
{
|
||||||
|
public function getReturnUrl(Request $request, string $defaultRoute, array $parameters = []): string
|
||||||
|
{
|
||||||
|
$defaultUrl = $this->generateUrl($defaultRoute, $parameters);
|
||||||
|
|
||||||
|
return rawurldecode($request->query->get('r', $defaultUrl));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove specified query parameters from a URL.
|
||||||
|
*
|
||||||
|
* @param string $url The URL to process
|
||||||
|
* @param string[] $parametersKeys Array of query parameter keys to remove
|
||||||
|
*
|
||||||
|
* @return string The URL without the specified query parameters
|
||||||
|
*/
|
||||||
|
public function removeQueryParameters(string $url, array $parametersKeys): string
|
||||||
|
{
|
||||||
|
if ([] === $parametersKeys) {
|
||||||
|
return $url;
|
||||||
|
}
|
||||||
|
|
||||||
|
$urlParts = parse_url($url);
|
||||||
|
|
||||||
|
if (false === isset($urlParts['query'])) {
|
||||||
|
return $url;
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_str($urlParts['query'], $queryParams);
|
||||||
|
|
||||||
|
foreach ($parametersKeys as $key) {
|
||||||
|
unset($queryParams[$key]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$urlParts['query'] = http_build_query($queryParams);
|
||||||
|
|
||||||
|
if ('' === $urlParts['query']) {
|
||||||
|
unset($urlParts['query']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rebuild URL
|
||||||
|
$result = '';
|
||||||
|
if (isset($urlParts['scheme'])) {
|
||||||
|
$result .= $urlParts['scheme'].'://';
|
||||||
|
}
|
||||||
|
if (isset($urlParts['host'])) {
|
||||||
|
$result .= $urlParts['host'];
|
||||||
|
}
|
||||||
|
if (isset($urlParts['port'])) {
|
||||||
|
$result .= ':'.$urlParts['port'];
|
||||||
|
}
|
||||||
|
if (isset($urlParts['path'])) {
|
||||||
|
$result .= $urlParts['path'];
|
||||||
|
}
|
||||||
|
if (isset($urlParts['query'])) {
|
||||||
|
$result .= '?'.$urlParts['query'];
|
||||||
|
}
|
||||||
|
if (isset($urlParts['fragment'])) {
|
||||||
|
$result .= '#'.$urlParts['fragment'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-1
@@ -2,11 +2,12 @@
|
|||||||
|
|
||||||
namespace App\Entity;
|
namespace App\Entity;
|
||||||
|
|
||||||
|
use App\Repository\UserRepository;
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
|
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
|
||||||
use Symfony\Component\Security\Core\User\UserInterface;
|
use Symfony\Component\Security\Core\User\UserInterface;
|
||||||
|
|
||||||
#[ORM\Entity]
|
#[ORM\Entity(repositoryClass: UserRepository::class)]
|
||||||
class User implements UserInterface, PasswordAuthenticatedUserInterface
|
class User implements UserInterface, PasswordAuthenticatedUserInterface
|
||||||
{
|
{
|
||||||
#[ORM\Id]
|
#[ORM\Id]
|
||||||
|
|||||||
@@ -0,0 +1,133 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Menu;
|
||||||
|
|
||||||
|
use Knp\Menu\FactoryInterface;
|
||||||
|
use Knp\Menu\ItemInterface;
|
||||||
|
use Symfony\Bundle\SecurityBundle\Security;
|
||||||
|
use Symfony\Component\HttpFoundation\RequestStack;
|
||||||
|
use Symfony\Component\Uid\Uuid;
|
||||||
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
|
|
||||||
|
abstract class AbstractMenuBuilder
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
protected FactoryInterface $factory,
|
||||||
|
protected Security $security,
|
||||||
|
protected RequestStack $requestStack,
|
||||||
|
protected TranslatorInterface $translator,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function createRootElement(): ItemInterface
|
||||||
|
{
|
||||||
|
return $this->factory->createItem('root');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getDefaultRouteParameters(string $parameter = 'id', string $default = '0'): array
|
||||||
|
{
|
||||||
|
$request = $this->requestStack->getMainRequest();
|
||||||
|
|
||||||
|
return [
|
||||||
|
$parameter => $request->get($parameter, $default),
|
||||||
|
'r' => $request->get('r'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function addAdminItem(ItemInterface $menu): void
|
||||||
|
{
|
||||||
|
if ($this->security->isGranted('ROLE_ADMIN')) {
|
||||||
|
$this->addDivider($menu);
|
||||||
|
$menu->addChild('zum Adminbereich', [
|
||||||
|
'route' => 'app_admin_index',
|
||||||
|
'linkAttributes' => [
|
||||||
|
'title' => 'zum Adminbereich',
|
||||||
|
],
|
||||||
|
'extras' => [
|
||||||
|
'icon' => 'user',
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function addManagerItem(ItemInterface $menu): void
|
||||||
|
{
|
||||||
|
if ($this->security->isGranted('ROLE_MANAGER')) {
|
||||||
|
$this->addDivider($menu);
|
||||||
|
$menu->addChild('zum Managementbereich', [
|
||||||
|
'route' => 'app_manager_index',
|
||||||
|
'linkAttributes' => [
|
||||||
|
'title' => 'zum Managementbereich',
|
||||||
|
],
|
||||||
|
'extras' => [
|
||||||
|
'icon' => 'user',
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function addTeamerItem(ItemInterface $menu): void
|
||||||
|
{
|
||||||
|
if ($this->security->isGranted('ROLE_TEAMER')) {
|
||||||
|
$this->addDivider($menu);
|
||||||
|
$menu->addChild('zum Teambereich', [
|
||||||
|
'route' => 'app_teamer_index',
|
||||||
|
'linkAttributes' => [
|
||||||
|
'title' => 'zum Teambereich',
|
||||||
|
],
|
||||||
|
'extras' => [
|
||||||
|
'icon' => 'user',
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function addHouseManagerItem(ItemInterface $menu): void
|
||||||
|
{
|
||||||
|
if ($this->security->isGranted('ROLE_HOUSE_MANAGER')) {
|
||||||
|
$this->addDivider($menu);
|
||||||
|
$menu->addChild('zum Hausleitungsbereich', [
|
||||||
|
'route' => 'app_house_manager_index',
|
||||||
|
'linkAttributes' => [
|
||||||
|
'title' => 'zum Hausleitungsbereich',
|
||||||
|
],
|
||||||
|
'extras' => [
|
||||||
|
'icon' => 'user',
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function addLogoutItem(ItemInterface $menu): void
|
||||||
|
{
|
||||||
|
$this->addDivider($menu);
|
||||||
|
|
||||||
|
$menu->addChild('MyE&P', [
|
||||||
|
'route' => 'app_account',
|
||||||
|
'linkAttributes' => [
|
||||||
|
'title' => 'zu MyE&P',
|
||||||
|
],
|
||||||
|
'extras' => [
|
||||||
|
'icon' => 'logout',
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
$menu->addChild('Logout', [
|
||||||
|
'route' => 'app_logout',
|
||||||
|
'linkAttributes' => [
|
||||||
|
'title' => 'Logout',
|
||||||
|
],
|
||||||
|
'extras' => [
|
||||||
|
'icon' => 'logout',
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function addDivider(ItemInterface $menu): void
|
||||||
|
{
|
||||||
|
$menu->addChild(Uuid::v4(), [
|
||||||
|
'extras' => [
|
||||||
|
'divider' => true,
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Menu;
|
||||||
|
|
||||||
|
use Knp\Menu\ItemInterface;
|
||||||
|
|
||||||
|
class AdminMenuBuilder extends AbstractMenuBuilder
|
||||||
|
{
|
||||||
|
public function createMainMenu(array $options): ItemInterface
|
||||||
|
{
|
||||||
|
$menu = $this->createRootElement();
|
||||||
|
|
||||||
|
$menu->addChild('Dashboard', [
|
||||||
|
'route' => 'app_admin_dashboard',
|
||||||
|
'linkAttributes' => [
|
||||||
|
'title' => 'Dashboard',
|
||||||
|
],
|
||||||
|
'extras' => [
|
||||||
|
'icon' => 'chart',
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
$menu->addChild('Buchungsentwürfe', [
|
||||||
|
'route' => 'app_admin_bookingeditdraft',
|
||||||
|
'linkAttributes' => [
|
||||||
|
'title' => 'Buchungsentwürfe',
|
||||||
|
],
|
||||||
|
'extras' => [
|
||||||
|
'icon' => 'edit',
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
$menu->addChild('Benutzer', [
|
||||||
|
'route' => 'app_admin_user',
|
||||||
|
'linkAttributes' => [
|
||||||
|
'title' => 'Benutzer',
|
||||||
|
],
|
||||||
|
'extras' => [
|
||||||
|
'icon' => 'users',
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
$menu->addChild('Logs', [
|
||||||
|
'route' => 'app_admin_log',
|
||||||
|
'linkAttributes' => [
|
||||||
|
'title' => 'Logs',
|
||||||
|
],
|
||||||
|
'extras' => [
|
||||||
|
'icon' => 'list',
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->addLogoutItem($menu);
|
||||||
|
|
||||||
|
return $menu;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Repository;
|
||||||
|
|
||||||
|
use App\Entity\User;
|
||||||
|
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||||
|
use Doctrine\Persistence\ManagerRegistry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @extends ServiceEntityRepository<User>
|
||||||
|
*/
|
||||||
|
class UserRepository extends ServiceEntityRepository
|
||||||
|
{
|
||||||
|
public function __construct(ManagerRegistry $registry)
|
||||||
|
{
|
||||||
|
parent::__construct($registry, User::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -33,6 +33,7 @@ class AppExtension extends AbstractExtension
|
|||||||
public function getFunctions(): array
|
public function getFunctions(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
|
new TwigFunction('icon', [AppRuntime::class, 'renderIcon'], ['needs_environment' => true, 'is_safe' => ['html']]),
|
||||||
new TwigFunction('is_participant_eligible', [AppRuntime::class, 'isParticipantEligible']),
|
new TwigFunction('is_participant_eligible', [AppRuntime::class, 'isParticipantEligible']),
|
||||||
new TwigFunction('qa_attribute', [AppRuntime::class, 'renderQaAttribute'], ['is_safe' => ['html']]),
|
new TwigFunction('qa_attribute', [AppRuntime::class, 'renderQaAttribute'], ['is_safe' => ['html']]),
|
||||||
new TwigFunction('is_static_text', [AppRuntime::class, 'isStaticText']),
|
new TwigFunction('is_static_text', [AppRuntime::class, 'isStaticText']),
|
||||||
@@ -42,6 +43,7 @@ class AppExtension extends AbstractExtension
|
|||||||
new TwigFunction('booking_theme', [AppRuntime::class, 'getBookingTheme']),
|
new TwigFunction('booking_theme', [AppRuntime::class, 'getBookingTheme']),
|
||||||
new TwigFunction('gtm_id', [AppRuntime::class, 'getGtmId']),
|
new TwigFunction('gtm_id', [AppRuntime::class, 'getGtmId']),
|
||||||
new TwigFunction('cmp_url', [AppRuntime::class, 'getCmpUrl']),
|
new TwigFunction('cmp_url', [AppRuntime::class, 'getCmpUrl']),
|
||||||
|
new TwigFunction('return_url', [AppRuntime::class, 'getEncodedReturnUrl']),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ use App\Model\DomainConfig;
|
|||||||
use App\Service\ParticipantEligibilityChecker;
|
use App\Service\ParticipantEligibilityChecker;
|
||||||
use Symfony\Component\Form\FormView;
|
use Symfony\Component\Form\FormView;
|
||||||
use Symfony\Component\HttpFoundation\RequestStack;
|
use Symfony\Component\HttpFoundation\RequestStack;
|
||||||
|
use Twig\Environment;
|
||||||
use Twig\Extension\RuntimeExtensionInterface;
|
use Twig\Extension\RuntimeExtensionInterface;
|
||||||
use Twig\Extra\Intl\IntlExtension;
|
use Twig\Extra\Intl\IntlExtension;
|
||||||
|
|
||||||
@@ -148,6 +149,14 @@ class AppRuntime implements RuntimeExtensionInterface
|
|||||||
return sprintf(' data-qa-%s="%s"', strtolower($label), $value);
|
return sprintf(' data-qa-%s="%s"', strtolower($label), $value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function renderIcon(Environment $environment, string $icon, string $classes = 'w-5 h-5'): string
|
||||||
|
{
|
||||||
|
return $environment->render('_partials/_icon.html.twig', [
|
||||||
|
'icon' => $icon,
|
||||||
|
'class' => $classes,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if a form field should be rendered as static text.
|
* Checks if a form field should be rendered as static text.
|
||||||
*
|
*
|
||||||
@@ -268,6 +277,17 @@ class AppRuntime implements RuntimeExtensionInterface
|
|||||||
return $this->getDomainConfig()->cmpUrl;
|
return $this->getDomainConfig()->cmpUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getEncodedReturnUrl(): string
|
||||||
|
{
|
||||||
|
$masterRequest = $this->requestStack->getMainRequest();
|
||||||
|
|
||||||
|
if (null === $masterRequest) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return rawurlencode($masterRequest->getRequestUri());
|
||||||
|
}
|
||||||
|
|
||||||
private function getDomainConfig(): DomainConfig
|
private function getDomainConfig(): DomainConfig
|
||||||
{
|
{
|
||||||
$request = $this->requestStack->getCurrentRequest();
|
$request = $this->requestStack->getCurrentRequest();
|
||||||
|
|||||||
+6
-24
@@ -35,18 +35,6 @@
|
|||||||
"migrations/.gitignore"
|
"migrations/.gitignore"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"easycorp/easyadmin-bundle": {
|
|
||||||
"version": "4.27",
|
|
||||||
"recipe": {
|
|
||||||
"repo": "github.com/symfony/recipes",
|
|
||||||
"branch": "main",
|
|
||||||
"version": "4.14",
|
|
||||||
"ref": "13b3e524d1038a6861ad6c7fc64e31b644ba0c54"
|
|
||||||
},
|
|
||||||
"files": [
|
|
||||||
"config/routes/easyadmin.yaml"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"flagception/flagception-bundle": {
|
"flagception/flagception-bundle": {
|
||||||
"version": "6.1",
|
"version": "6.1",
|
||||||
"recipe": {
|
"recipe": {
|
||||||
@@ -71,6 +59,12 @@
|
|||||||
".php-cs-fixer.dist.php"
|
".php-cs-fixer.dist.php"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"knplabs/knp-menu-bundle": {
|
||||||
|
"version": "v3.7.0"
|
||||||
|
},
|
||||||
|
"knplabs/knp-paginator-bundle": {
|
||||||
|
"version": "v6.10.0"
|
||||||
|
},
|
||||||
"league/flysystem-bundle": {
|
"league/flysystem-bundle": {
|
||||||
"version": "3.4",
|
"version": "3.4",
|
||||||
"recipe": {
|
"recipe": {
|
||||||
@@ -364,18 +358,6 @@
|
|||||||
"config/packages/uid.yaml"
|
"config/packages/uid.yaml"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"symfony/ux-twig-component": {
|
|
||||||
"version": "2.32",
|
|
||||||
"recipe": {
|
|
||||||
"repo": "github.com/symfony/recipes",
|
|
||||||
"branch": "main",
|
|
||||||
"version": "2.13",
|
|
||||||
"ref": "f367ae2a1faf01c503de2171f1ec22567febeead"
|
|
||||||
},
|
|
||||||
"files": [
|
|
||||||
"config/packages/twig_component.yaml"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"symfony/validator": {
|
"symfony/validator": {
|
||||||
"version": "6.4",
|
"version": "6.4",
|
||||||
"recipe": {
|
"recipe": {
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<div class="relative inline-block text-left group">
|
||||||
|
<button type="button" class="flex items-center text-gray-400 hover:text-gray-600 focus:outline-none focus:ring-0" aria-expanded="true" aria-haspopup="true">
|
||||||
|
<span class="sr-only">Funktionen</span>
|
||||||
|
{{ icon('dots', 'w-6 h-6') }}
|
||||||
|
</button>
|
||||||
|
<div class="hidden group-hover:block absolute right-0 top-0 z-10 w-56 origin-top-right pt-4" role="menu" aria-orientation="vertical" aria-labelledby="menu-button" tabindex="-1">
|
||||||
|
<div class="rounded-md bg-white shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none">
|
||||||
|
<div class="py-1 menu menu--pulldown" role="none">
|
||||||
|
{% block content %}{% endblock %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
|
{% import _self as self %}
|
||||||
|
|
||||||
{% macro render_value(value) %}
|
{% macro render_value(value) %}
|
||||||
{% import _self as self %}
|
|
||||||
{% if value is iterable %}
|
{% if value is iterable %}
|
||||||
<ul class="list-disc list-inside ml-4">
|
<ul class="list-disc list-inside ml-4">
|
||||||
{% for key, item in value %}
|
{% for key, item in value %}
|
||||||
@@ -18,5 +19,4 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
{% import _self as self %}
|
{{ self.render_value(value) }}
|
||||||
{{ self.render_value(field.value) }}
|
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
{% extends 'knp_menu.html.twig' %}
|
||||||
|
|
||||||
|
{% block list %}
|
||||||
|
{% if item.hasChildren and options.depth is not same as(0) and item.displayChildren %}
|
||||||
|
{% if item.level == 0 %}
|
||||||
|
<div class="min-h-full flex grow flex-col gap-y-5 lg:border-r border-gray-200 bg-white md:pr-6">
|
||||||
|
<nav class="flex flex-1 flex-col">
|
||||||
|
<ul role="list" class="space-y-1">
|
||||||
|
{{ block('children') }}
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<ul class="{{ html_classes('mt-1 px-2', { 'hidden': not matcher.isCurrent(item) }) }}" {{ stimulus_target('sidebar-menu', 'submenu') }}>
|
||||||
|
{{ block('children') }}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block item %}
|
||||||
|
{% if item.displayed %}
|
||||||
|
<li>
|
||||||
|
{%- if item.hasChildren and item.displayChildren %}
|
||||||
|
<div {{ stimulus_controller('sidebar-menu', {'expanded': matcher.isAncestor(item)}, {'closed': 'hidden', 'iconClosed': 'text-gray-400', 'iconExpanded': 'text-gray-500'}) }}>
|
||||||
|
{%- endif %}
|
||||||
|
{%- if item.uri is not empty %}
|
||||||
|
{{ block('linkElement') }}
|
||||||
|
{%- else %}
|
||||||
|
{{ block('spanElement') }}
|
||||||
|
{%- endif %}
|
||||||
|
{{ block('list') }}
|
||||||
|
{%- if item.hasChildren and item.displayChildren %}
|
||||||
|
</div>
|
||||||
|
{%- endif %}
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block linkElement %}
|
||||||
|
{% import _self as knp_menu %}
|
||||||
|
<a href="{{ item.uri }}"
|
||||||
|
class="{{ html_classes('', {
|
||||||
|
'group flex gap-x-3 rounded-md p-2 text-sm leading-6 font-semibold text-gray-700 hover:bg-gray-50': item.level == 1,
|
||||||
|
'block rounded-md py-2 pr-2 pl-9 text-sm leading-6 text-gray-700 hover:bg-gray-50': item.level > 1,
|
||||||
|
'bg-gray-50': matcher.isCurrent(item) or matcher.isAncestor(item)
|
||||||
|
}) }}"
|
||||||
|
{{ knp_menu.attributes(item.linkAttributes) }}>
|
||||||
|
{{ block('label') }}
|
||||||
|
</a>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block spanElement %}
|
||||||
|
{% import _self as knp_menu %}
|
||||||
|
{% if item.hasChildren %}
|
||||||
|
<button type="button"
|
||||||
|
{{ stimulus_action('sidebar-menu', 'toggleSubmenu') }}
|
||||||
|
{{ stimulus_target('sidebar-menu', 'button') }}
|
||||||
|
{{ knp_menu.attributes(item.linkAttributes) }}
|
||||||
|
class="{{ html_classes('hover:bg-gray-50 flex items-center w-full text-left rounded-md p-2 gap-x-3 text-sm leading-6 font-semibold text-gray-700', { 'bg-gray-50': matcher.isAncestor(item) }) }}"
|
||||||
|
aria-expanded="false">
|
||||||
|
{{ block('label') }}
|
||||||
|
</button>
|
||||||
|
{% elseif item.extras.divider is defined %}
|
||||||
|
<hr class="my-4 h-px bg-gray-200">
|
||||||
|
{% else %}
|
||||||
|
<div class="hover:bg-gray-50 group flex gap-x-3 rounded-md p-2 text-sm leading-5 font-semibold text-gray-700"
|
||||||
|
role="button">
|
||||||
|
{{ block('label') }}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block label %}
|
||||||
|
{% if item.extras.icon is defined %}
|
||||||
|
{{ icon(item.extras.icon, 'h-5 w-5 shrink-0 text-gray-400') }}
|
||||||
|
<span class="flex-1">{{ item.label|raw }}</span>
|
||||||
|
{% else %}
|
||||||
|
{{ item.label|raw }}
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
{% if pageCount > 0 %}
|
||||||
|
<div class="bg-gray-100 border border-gray-300 border-t-0 px-4 py-3 flex items-center justify-between sm:px-4">
|
||||||
|
<div class="flex-1 flex items-center justify-between">
|
||||||
|
<div class="flex items-center space-x-4">
|
||||||
|
<div class="text-sm leading-5 text-gray-700">
|
||||||
|
{{ 'paginator.info'|trans({ '{from}': firstItemNumber, '{to}': lastItemNumber, '{total}': totalCount })|raw }}
|
||||||
|
</div>
|
||||||
|
<select name="limit"
|
||||||
|
class="text-sm py-1 border-gray-300"
|
||||||
|
hx-get="{{ path(route, query|merge({(pageParameterName): 1})) }}"
|
||||||
|
hx-replace-url="{{ path(route, query|merge({(pageParameterName): 1})) }}"
|
||||||
|
hx-target="body">
|
||||||
|
<option value="10"{% if numItemsPerPage == 10 %} selected{% endif %}>10 pro Seite</option>
|
||||||
|
<option value="20"{% if numItemsPerPage == 20 %} selected{% endif %}>20 pro Seite</option>
|
||||||
|
<option value="50"{% if numItemsPerPage == 50 %} selected{% endif %}>50 pro Seite</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<nav class="relative z-0 inline-flex">
|
||||||
|
{% if pageCount > 1 %}
|
||||||
|
{% if first is defined and current != first %}
|
||||||
|
<a href="{{ path(route, query|merge({(pageParameterName): first})) }}" class="relative inline-flex items-center px-2 py-2 border border-gray-300 bg-white text-sm leading-5 font-medium hover:bg-secondary hover:text-white">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="m18.75 4.5-7.5 7.5 7.5 7.5m-6-15L5.25 12l7.5 7.5" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
{% if previous is defined %}
|
||||||
|
<a href="{{ path(route, query|merge({(pageParameterName): previous})) }}" class="-ml-px relative inline-flex items-center px-2 py-2 border border-gray-300 bg-white text-sm leading-5 font-medium hover:bg-secondary hover:text-white" aria-label="Previous">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 19.5 8.25 12l7.5-7.5" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
{% if current > 3 %}
|
||||||
|
<span class="-ml-px relative inline-flex items-center px-4 py-2 border border-gray-300 bg-white text-sm leading-5 font-medium text-gray-700">
|
||||||
|
...
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
{% for page in pagesInRange %}
|
||||||
|
<a href="{{ path(route, query|merge({(pageParameterName): page})) }}" class="-ml-px relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm leading-5 font-medium focus:z-10 hover:bg-secondary {% if page == current %}bg-primary text-white hover:text-white{% else %}bg-white text-gray-700 hover:text-white{% endif %}">
|
||||||
|
{{ page }}
|
||||||
|
</a>
|
||||||
|
{% endfor %}
|
||||||
|
{% if current < pageCount - 3 %}
|
||||||
|
<span class="-ml-px relative inline-flex items-center px-4 py-2 border border-gray-300 bg-white text-sm leading-5 font-medium text-gray-700">
|
||||||
|
...
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
{% if next is defined %}
|
||||||
|
<a href="{{ path(route, query|merge({(pageParameterName): next})) }}" class="-ml-px relative inline-flex items-center px-2 py-2 border border-gray-300 bg-white text-sm leading-5 font-medium hover:bg-secondary hover:text-white" aria-label="Next">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="m8.25 4.5 7.5 7.5-7.5 7.5" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
{% if last is defined and current != last %}
|
||||||
|
<a href="{{ path(route, query|merge({(pageParameterName): last})) }}" class="-ml-px relative inline-flex items-center px-2 py-2 border border-gray-300 bg-white text-sm leading-5 font-medium hover:bg-secondary hover:text-white">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="m5.25 4.5 7.5 7.5-7.5 7.5m6-15 7.5 7.5-7.5 7.5" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
{% if pageCount > 0 %}
|
||||||
|
<div class="bg-gray-100 border border-gray-200 rounded-md px-4 py-3 flex items-center justify-between sm:px-4">
|
||||||
|
<div class="flex-1 flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<p class="text-sm leading-5 text-gray-700">{{ 'paginator.info'|trans({ '{from}': firstItemNumber, '{to}': lastItemNumber, '{total}': totalCount })|raw }}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<nav class="relative z-0 inline-flex">
|
||||||
|
{% if pageCount > 1 %}
|
||||||
|
{% if previous is defined %}
|
||||||
|
<a href="{{ path(route, query|merge({(pageParameterName): previous})) }}" class="relative inline-flex items-center px-2 py-2 border border-gray-300 bg-white text-sm leading-5 font-medium hover:bg-secondary hover:text-white" aria-label="Previous">
|
||||||
|
<svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
|
||||||
|
<path fill-rule="evenodd" d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z" clip-rule="evenodd"/>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
{% if current > 3 %}
|
||||||
|
<span class="-ml-px relative inline-flex items-center px-4 py-2 border border-gray-300 bg-white text-sm leading-5 font-medium text-gray-700">
|
||||||
|
...
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
{% for page in pagesInRange %}
|
||||||
|
<a href="{{ path(route, query|merge({(pageParameterName): page})) }}" class="-ml-px relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm leading-5 font-medium focus:z-10 hover:bg-secondary {% if page == current %}bg-primary text-white hover:text-white{% else %}bg-white text-gray-700 hover:text-white{% endif %}">
|
||||||
|
{{ page }}
|
||||||
|
</a>
|
||||||
|
{% endfor %}
|
||||||
|
{% if current < pageCount - 3 %}
|
||||||
|
<span class="-ml-px relative inline-flex items-center px-4 py-2 border border-gray-300 bg-white text-sm leading-5 font-medium text-gray-700">
|
||||||
|
...
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
{% if next is defined %}
|
||||||
|
<a href="{{ path(route, query|merge({(pageParameterName): next})) }}" class="-ml-px relative inline-flex items-center px-2 py-2 border border-gray-300 bg-white text-sm leading-5 font-medium hover:bg-secondary hover:text-white" aria-label="Next">
|
||||||
|
<svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
|
||||||
|
<path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"/>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
<a href="{{ options.href }}" class="flex items-center space-x-2">
|
||||||
|
<span>{{ title|raw }}</span>
|
||||||
|
{%- if sorted -%}
|
||||||
|
{%- if direction == 'desc' -%}
|
||||||
|
<svg class="w-4 h-4 shrink-0" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path d="M3 4h13M3 8h9m-9 4h6m4 0l4-4m0 0l4 4m-4-4v12"></path>
|
||||||
|
</svg>
|
||||||
|
{%- else -%}
|
||||||
|
<svg class="w-4 h-4 shrink-0" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path d="M3 4h13M3 8h9m-9 4h9m5-4v12m0 0l-4-4m4 4l4-4"></path>
|
||||||
|
</svg>
|
||||||
|
{%- endif -%}
|
||||||
|
{%- endif -%}
|
||||||
|
</a>
|
||||||
|
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
</li>
|
</li>
|
||||||
{% if is_granted('ROLE_ADMIN') %}
|
{% if is_granted('ROLE_ADMIN') %}
|
||||||
<li class="py-4">
|
<li class="py-4">
|
||||||
<a href="{{ path('admin') }}" class="flex items-center space-x-2 group" hx-boost="false">
|
<a href="{{ path('app_admin_dashboard') }}" class="flex items-center space-x-2 group" hx-boost="false">
|
||||||
<svg class="w-8 h-8 text-white group-hover:text-primary-light" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"><rect width="256" height="256" fill="none"/><circle cx="128" cy="128" r="40" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><path d="M41.43,178.09A99.14,99.14,0,0,1,31.36,153.8l16.78-21a81.59,81.59,0,0,1,0-9.64l-16.77-21a99.43,99.43,0,0,1,10.05-24.3l26.71-3a81,81,0,0,1,6.81-6.81l3-26.7A99.14,99.14,0,0,1,102.2,31.36l21,16.78a81.59,81.59,0,0,1,9.64,0l21-16.77a99.43,99.43,0,0,1,24.3,10.05l3,26.71a81,81,0,0,1,6.81,6.81l26.7,3a99.14,99.14,0,0,1,10.07,24.29l-16.78,21a81.59,81.59,0,0,1,0,9.64l16.77,21a99.43,99.43,0,0,1-10,24.3l-26.71,3a81,81,0,0,1-6.81,6.81l-3,26.7a99.14,99.14,0,0,1-24.29,10.07l-21-16.78a81.59,81.59,0,0,1-9.64,0l-21,16.77a99.43,99.43,0,0,1-24.3-10l-3-26.71a81,81,0,0,1-6.81-6.81Z" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/></svg>
|
<svg class="w-8 h-8 text-white group-hover:text-primary-light" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"><rect width="256" height="256" fill="none"/><circle cx="128" cy="128" r="40" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><path d="M41.43,178.09A99.14,99.14,0,0,1,31.36,153.8l16.78-21a81.59,81.59,0,0,1,0-9.64l-16.77-21a99.43,99.43,0,0,1,10.05-24.3l26.71-3a81,81,0,0,1,6.81-6.81l3-26.7A99.14,99.14,0,0,1,102.2,31.36l21,16.78a81.59,81.59,0,0,1,9.64,0l21-16.77a99.43,99.43,0,0,1,24.3,10.05l3,26.71a81,81,0,0,1,6.81,6.81l26.7,3a99.14,99.14,0,0,1,10.07,24.29l-16.78,21a81.59,81.59,0,0,1,0,9.64l16.77,21a99.43,99.43,0,0,1-10,24.3l-26.71,3a81,81,0,0,1-6.81,6.81l-3,26.7a99.14,99.14,0,0,1-24.29,10.07l-21-16.78a81.59,81.59,0,0,1-9.64,0l-21,16.77a99.43,99.43,0,0,1-24.3-10l-3-26.71a81,81,0,0,1-6.81-6.81Z" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/></svg>
|
||||||
<span class="text-xl uppercase text-white group-hover:text-primary-light">Admin</span>
|
<span class="text-xl uppercase text-white group-hover:text-primary-light">Admin</span>
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
{% extends 'layout_admin.html.twig' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1 class="text-2xl font-bold pb-8">
|
||||||
|
Buchungsentwürfe
|
||||||
|
</h1>
|
||||||
|
<div class="data-table-wrapper">
|
||||||
|
<div class="data-table-wrapper__inner text-sm">
|
||||||
|
<table class="data-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
{{ knp_pagination_sortable(pagination, 'erstellt am', 'booking_edit_draft.createdAt') }}
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
{{ knp_pagination_sortable(pagination, 'Vorgang', 'booking_edit_draft.bookingNumber') }}
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
{{ knp_pagination_sortable(pagination, 'Kundenaccount', 'user.email') }}
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
{{ knp_pagination_sortable(pagination, 'aktualisiert am', 'booking_edit_draft.updatedAt') }}
|
||||||
|
</th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for draft in pagination %}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
{{ draft.createdAt | date('d.m.Y, H:i') }}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ draft.bookingNumber | default('-') }}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ draft.user.email | default('-') }}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{% if draft.updatedAt is not null and draft.updatedAt != draft.createdAt %}
|
||||||
|
{{ draft.updatedAt | date('d.m.Y, H:i') }}
|
||||||
|
{% else %}
|
||||||
|
-
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{% embed '_partials/_dropdown.html.twig' %}
|
||||||
|
{% block content %}
|
||||||
|
<a href="{{ path('app_admin_bookingeditdraft_show', { 'id': draft.id, 'r': return_url() }) }}"
|
||||||
|
class="text-gray-700 hover:text-primary block px-4 py-2 text-sm"
|
||||||
|
role="menuitem"
|
||||||
|
tabindex="-1">
|
||||||
|
Details
|
||||||
|
</a>
|
||||||
|
<a href="{{ path('app_admin_bookingeditdraft_export', { 'id': draft.id }) }}"
|
||||||
|
class="text-gray-700 hover:text-primary block px-4 py-2 text-sm"
|
||||||
|
role="menuitem"
|
||||||
|
tabindex="-1">
|
||||||
|
XLS-Export
|
||||||
|
</a>
|
||||||
|
<button type="button"
|
||||||
|
class="text-red-500 hover:text-primary block px-4 py-2 text-sm w-full text-left"
|
||||||
|
role="menuitem"
|
||||||
|
tabindex="-1"
|
||||||
|
hx-get="{{ path('app_admin_bookingeditdraft_delete', { 'id': draft.id, 'r': return_url() }) }}"
|
||||||
|
hx-target="body"
|
||||||
|
hx-swap="beforeend">
|
||||||
|
löschen
|
||||||
|
</button>
|
||||||
|
{% endblock %}
|
||||||
|
{% endembed %}
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% else %}
|
||||||
|
<tr>
|
||||||
|
<td colspan="5">
|
||||||
|
Keine Daten...
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{{ knp_pagination_render(pagination) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{% extends 'htmx_confirmation_modal.html.twig' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div>
|
||||||
|
Möchtest du den Buchungsentwurf zum Vorgang <em>{{ draft.bookingNumber }}</em> wirklich löschen?
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
{% extends 'layout_admin.html.twig' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1 class="text-2xl font-bold pb-8">
|
||||||
|
Buchungsentwurf
|
||||||
|
</h1>
|
||||||
|
<h2 class="text-xl font-bold pb-4">
|
||||||
|
Vorgang {{ draft.bookingNumber }}
|
||||||
|
</h2>
|
||||||
|
{% include('_partials/_json.html.twig') with { 'value': draft.formData } %}
|
||||||
|
<div class="flex justify-end pt-8">
|
||||||
|
<a href="{{ returnUrl }}" class="button button--secondary button--small">
|
||||||
|
zurück
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{% extends 'layout_admin.html.twig' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1>
|
||||||
|
MyE&P Admin
|
||||||
|
</h1>
|
||||||
|
<p>
|
||||||
|
Noch nicht wirklich was zu sehen hier...
|
||||||
|
</p>
|
||||||
|
{% endblock %}
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{% extends '@EasyAdmin/layout.html.twig' %}
|
|
||||||
|
|
||||||
{% block main %}
|
|
||||||
|
|
||||||
{% endblock main %}
|
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
{% extends 'layout_admin.html.twig' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1 class="text-2xl font-bold pb-8">
|
||||||
|
Logs
|
||||||
|
</h1>
|
||||||
|
<div class="data-table-wrapper">
|
||||||
|
<div class="data-table-wrapper__inner text-sm">
|
||||||
|
<table class="data-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
{{ knp_pagination_sortable(pagination, 'Datum', 'log.timestamp') }}
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
Fehlercode
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
Benutzer
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
Aktion
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
<span class="whitespace-nowrap">Request ID</span>
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
URI
|
||||||
|
</th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for entry in pagination %}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
{{ entry.createdAt | date('d.m.Y H:i') }}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ entry.errorCode | default('-') }}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ entry.userName }}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ entry.message }}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ entry.requestId | default('-') }}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="text-xs">{{ entry.uri | default('-') | u.truncate(48, '...') }}</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{% if entry.channel == 'bpn' %}
|
||||||
|
{% embed '_partials/_dropdown.html.twig' %}
|
||||||
|
{% block content %}
|
||||||
|
<a href="{{ path('app_admin_log_xmldumps', { 'id': entry.id }) }}"
|
||||||
|
class="text-gray-700 hover:text-primary block px-4 py-2 text-sm"
|
||||||
|
role="menuitem"
|
||||||
|
tabindex="-1">
|
||||||
|
XML-Dumps
|
||||||
|
</a>
|
||||||
|
{% endblock %}
|
||||||
|
{% endembed %}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% else %}
|
||||||
|
<tr>
|
||||||
|
<td colspan="7">
|
||||||
|
Keine Daten...
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{{ knp_pagination_render(pagination) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
{% extends 'layout_admin.html.twig' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1 class="text-2xl font-bold pb-8">
|
||||||
|
XML-Dumps für Request ID {{ logEntry.requestId }}
|
||||||
|
</h1>
|
||||||
|
{% if dumps is empty %}
|
||||||
|
<div class="alert alert-warning">
|
||||||
|
<i class="fa fa-exclamation-triangle"></i>
|
||||||
|
Keine XML-Dumps gefunden. Die Dateien wurden vermutlich bereits bereinigt.
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<div class="data-table-wrapper">
|
||||||
|
<div class="data-table-wrapper__inner text-sm">
|
||||||
|
<table class="data-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
Dateiname
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
Typ
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
Dateigröße
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
Aktion
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for dump in dumps %}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<code>{{ dump.filename }}</code>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{% if dump.type == 'request' %}
|
||||||
|
<span class="badge bg-primary">Request</span>
|
||||||
|
{% else %}
|
||||||
|
<span class="badge bg-success">Response</span>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ (dump.size / 1024)|number_format(1) }} KB
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a href="{{ path('app_admin_log_xmldump_download', { filename: dump.filename }) }}"
|
||||||
|
class="">
|
||||||
|
{{ icon('download', 'w-4 h-4')}} Download
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
{% extends 'layout_admin.html.twig' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1 class="text-2xl font-bold pb-8">
|
||||||
|
Benutzeraccounts
|
||||||
|
</h1>
|
||||||
|
<div class="data-table-wrapper">
|
||||||
|
<div class="data-table-wrapper__inner text-sm">
|
||||||
|
<table class="data-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
{{ knp_pagination_sortable(pagination, 'E-Mail', 'user.email') }}
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
{{ knp_pagination_sortable(pagination, 'BusPro Adress Id', 'user.addressId') }}
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
{{ knp_pagination_sortable(pagination, 'BusPro Personen Id', 'user.personId') }}
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
{{ knp_pagination_sortable(pagination, 'Letzter Login', 'user.lastLoginAt') }}
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for user in pagination %}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
{{ user.email }}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ user.addressId | default('-') }}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ user.personId | default('-') }}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ user.lastLoginAt | date('d.m.Y, H:i') }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% else %}
|
||||||
|
<tr>
|
||||||
|
<td colspan="2">
|
||||||
|
Keine Daten...
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{{ knp_pagination_render(pagination) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
{% extends '@EasyAdmin/layout.html.twig' %}
|
|
||||||
|
|
||||||
{% block content_title %}
|
|
||||||
XML Dumps
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block main %}
|
|
||||||
<div class="content-panel">
|
|
||||||
<div class="content-panel-header">
|
|
||||||
<h2>XML Dumps for Request ID</h2>
|
|
||||||
<code>{{ requestId }}</code>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="content-panel-body">
|
|
||||||
{% if dumps is empty %}
|
|
||||||
<div class="alert alert-warning">
|
|
||||||
<i class="fa fa-exclamation-triangle"></i>
|
|
||||||
Keine XML-Dumps gefunden. Die Dateien wurden vermutlich bereits bereinigt.
|
|
||||||
</div>
|
|
||||||
{% else %}
|
|
||||||
<table class="table table-striped">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Dateiname</th>
|
|
||||||
<th>Typ</th>
|
|
||||||
<th class="text-end">Dateigröße</th>
|
|
||||||
<th class="text-end">Aktion</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for dump in dumps %}
|
|
||||||
<tr>
|
|
||||||
<td><code>{{ dump.filename }}</code></td>
|
|
||||||
<td>
|
|
||||||
{% if dump.type == 'request' %}
|
|
||||||
<span class="badge bg-primary">Request</span>
|
|
||||||
{% else %}
|
|
||||||
<span class="badge bg-success">Response</span>
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
<td class="text-end">{{ (dump.size / 1024)|number_format(1) }} KB</td>
|
|
||||||
<td class="text-end">
|
|
||||||
<a href="{{ path('admin_xml_dump_download', {filename: dump.filename}) }}"
|
|
||||||
class="btn btn-sm btn-outline-primary">
|
|
||||||
<i class="fa fa-download"></i> Download
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="content-panel-footer">
|
|
||||||
<a href="{{ ea_url().setController('App\\Controller\\Admin\\LogEntryCrudController').setAction('index') }}"
|
|
||||||
class="btn btn-secondary">
|
|
||||||
<i class="fa fa-arrow-left"></i> Zurück zur Liste
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="de">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta name="robots" content="noindex,nofollow">
|
||||||
|
<title>{% block title %}MyE&P{% endblock %}</title>
|
||||||
|
<link rel="icon" href="{{ asset('build/favicon/favicon.ico') }}" sizes="32x32">
|
||||||
|
<link rel="icon" href="{{ asset('build/favicon/icon.svg') }}" type="image/svg+xml">
|
||||||
|
<link rel="apple-touch-icon" href="{{ asset('build/favicon/apple-touch-icon.png') }}">
|
||||||
|
{% block stylesheets %}
|
||||||
|
{{ encore_entry_link_tags('app') }}
|
||||||
|
{% endblock %}
|
||||||
|
{% block javascripts %}
|
||||||
|
{{ encore_entry_script_tags('app') }}
|
||||||
|
{% endblock %}
|
||||||
|
</head>
|
||||||
|
<body class="bg-white text-gray-700 font-sans antialiased {{ booking_theme() }}">
|
||||||
|
{% block body %}{% endblock %}
|
||||||
|
{% block data_layer %}{% endblock %}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
<div id="htmx-confirmation-modal" class="fixed top-0 left-0 z-50 inset-0" {{ stimulus_controller('modal') }}>
|
||||||
|
<div class="absolute top-0 left-0 inset-0 bg-black/80" {{ stimulus_action('modal', 'close', 'click') }}></div>
|
||||||
|
<div class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 bg-white p-8 w-full max-w-3xl rounded-md">
|
||||||
|
<div class="flex justify-between border-b border-gray-200 pb-2 mb-4">
|
||||||
|
<div class="flex items-center space-x-2">
|
||||||
|
{{ icon('alert', 'w-8 h-8') }}
|
||||||
|
<div class="text-xl font-bold">
|
||||||
|
{% block title %}Bist du sicher?{% endblock %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button type="button" class="inline-block" {{ stimulus_action('modal', 'close') }}>
|
||||||
|
{{ icon('close', 'w-8 h-8') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{% block content %}{% endblock %}
|
||||||
|
<div class="mt-6 flex items-center justify-between">
|
||||||
|
<button type="button" class="button button--warning" {% block button_attribute %}hx-post="{{ app.request.uri }}"{% endblock %}>
|
||||||
|
{% block button_confirm %}Ja{% endblock %}
|
||||||
|
</button>
|
||||||
|
<button type="button" class="button button--neutral" {{ stimulus_action('modal', 'close') }}>
|
||||||
|
{% block button_cancel %}Abbrechen{% endblock %}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
{% extends 'base_admin.html.twig' %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
<div class="max-w-screen-2xl mx-auto px-4 lg:px-8 lg:grid lg:grid-cols-4 gap-8 py-8">
|
||||||
|
<div class="lg:col-span-4 flex items-center justify-between pb-4 lg:pb-0">
|
||||||
|
<a href="{{ path(app.user ? 'app_admin_dashboard' : 'app_security_login') }}">
|
||||||
|
<img class="h-8 w-auto" src="{{ asset('build/images/logo_ep.svg') }}" alt="My E&P Admin">
|
||||||
|
</a>
|
||||||
|
{% if app.user %}
|
||||||
|
<div class="flex items-center space-x-4">
|
||||||
|
<button type="button"
|
||||||
|
class="lg:hidden"
|
||||||
|
{{ stimulus_controller('mobilenav', [], [], { 'mobilenav': '#mobilenav' }) }}
|
||||||
|
{{ stimulus_action('mobilenav', 'trigger', null, { 'mode': 'open' }) }}>
|
||||||
|
{{ icon('menu', 'w-8 h-8 text-gray-700') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="hidden lg:block">
|
||||||
|
{{ knp_menu_render(knp_menu_get('admin_main')) }}
|
||||||
|
</div>
|
||||||
|
<div class="lg:col-span-3">
|
||||||
|
{% block content %}{% endblock %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="mobilenav"
|
||||||
|
class="fixed z-50 top-0 left-0 inset-0 pr-16 bg-black/70 -translate-x-full"
|
||||||
|
{{ stimulus_controller('mobilenav', [], { 'closed': '-translate-x-full' }, { 'mobilenav': '#mobilenav' }) }}
|
||||||
|
>
|
||||||
|
<div class="h-screen w-full bg-white">
|
||||||
|
<div class="flex justify-between p-8">
|
||||||
|
<img src="{{ asset('build/images/logo_ep.svg') }}" alt="" class="block w-auto h-8">
|
||||||
|
<button type="button"
|
||||||
|
{{ stimulus_action('mobilenav', 'trigger', null, { 'mode': 'close' }) }}>
|
||||||
|
{{ icon('close', 'w-8 h-8') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="w-full h-full p-8 pt-0 overflow-y-scroll">
|
||||||
|
{{ knp_menu_render(knp_menu_get('admin_main')) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
@@ -12,3 +12,8 @@ service:
|
|||||||
max: 'Jahrgang bis %yearTo%'
|
max: 'Jahrgang bis %yearTo%'
|
||||||
mixed:
|
mixed:
|
||||||
separator: ' und '
|
separator: ' und '
|
||||||
|
|
||||||
|
paginator:
|
||||||
|
previous: vorherige
|
||||||
|
next: nächste
|
||||||
|
info: 'Einträge <span class="font-medium">{from}</span> bis <span class="font-medium">{to}</span> von {total}'
|
||||||
|
|||||||
Reference in New Issue
Block a user