- 2.x - sites (wip)

- improved ssh error handling
- database soft deletes
This commit is contained in:
Saeed Vaziry
2024-10-04 21:34:07 +02:00
parent ecdba02bc9
commit d1f2add699
64 changed files with 1340 additions and 421 deletions

View File

@ -11,13 +11,18 @@ .choices__item--selectable {
}
.fi-sidebar {
@apply bg-gray-100/50 dark:bg-gray-900/50 !important;
@apply bg-gray-100 dark:bg-gray-900 !important;
}
.fi-sidebar-item a, .fi-tenant-menu-trigger {
@apply hover:bg-gray-200/50 hover:dark:bg-gray-800 !important;
}
.fi-sidebar-item-active a {
@apply bg-gray-100 dark:bg-gray-800/50 !important;
@apply bg-gray-200/50 dark:bg-gray-800 !important;
}
.fi-btn-color-primary {
background-image: linear-gradient(to bottom right, rgba(var(--primary-500), 1), rgba(var(--primary-900), 1));
box-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a;

View File

@ -1,40 +1,40 @@
import ace from 'brace';
import 'brace/mode/javascript';
import 'brace/mode/plain_text';
import 'brace/mode/sh';
import 'brace/mode/ini';
import 'brace/ext/searchbox'
import './theme-vito'
import './mode-env';
import './mode-nginx';
import ace from "brace";
import "brace/mode/javascript";
import "brace/mode/plain_text";
import "brace/mode/sh";
import "brace/mode/ini";
import "brace/ext/searchbox";
import "./theme-vito";
import "./mode-env";
import "./mode-nginx";
window.initAceEditor = function (options = {}) {
const editorValue = JSON.parse(options.value || '');
const editorValue = JSON.parse(options.value || "");
const editor = ace.edit(options.id);
editor.setTheme("ace/theme/vito");
editor.getSession().setMode(`ace/mode/${options.lang || 'plain_text'}`);
editor.setValue(editorValue, -1);
editor.clearSelection();
editor.focus();
editor.setOptions({
enableBasicAutocompletion: true,
enableSnippets: true,
enableLiveAutocompletion: true,
// enableBasicAutocompletion: true,
// enableSnippets: true,
// enableLiveAutocompletion: true,
printMargin: false,
});
editor.renderer.setScrollMargin(15, 15, 0, 0)
editor.renderer.setScrollMargin(15, 15, 0, 0);
editor.renderer.setPadding(15);
editor.getSession().on('change', function () {
document.getElementById(`textarea-${options.id}`).value = editor.getValue();
editor.getSession().on("change", function () {
document.getElementById(`textarea-${options.id}`).value =
editor.getValue();
});
window.addEventListener('resize', function () {
window.addEventListener("resize", function () {
editor.resize();
})
});
document.getElementById(`textarea-${options.id}`).innerHTML = editorValue;
return editor;
}
};

View File

@ -1,62 +1,7 @@
import 'flowbite';
import 'flowbite/dist/datepicker.js';
import './ace-editor/ace-editor';
import CodeEditorAlpinePlugin from "./components/editor";
import Alpine from 'alpinejs';
window.Alpine = Alpine;
Alpine.start();
import ApexCharts from 'apexcharts';
window.ApexCharts = ApexCharts;
import htmx from "htmx.org";
window.htmx = htmx;
window.htmx.defineExtension('disable-element', {
onEvent: function (name, evt) {
let elt = evt.detail.elt;
let target = elt.getAttribute("hx-disable-element");
let targetElements = (target === "self") ? [elt] : document.querySelectorAll(target);
for (let i = 0; i < targetElements.length; i++) {
if (name === "htmx:beforeRequest" && targetElements[i]) {
targetElements[i].disabled = true;
} else if (name === "htmx:afterRequest" && targetElements[i]) {
targetElements[i].disabled = false;
}
}
}
});
document.body.addEventListener('htmx:configRequest', (event) => {
event.detail.headers['X-CSRF-TOKEN'] = document.head.querySelector('meta[name="csrf-token"]').content;
// if (window.getSelection) { window.getSelection().removeAllRanges(); }
// else if (document.selection) { document.selection.empty(); }
});
document.body.addEventListener('htmx:beforeRequest', (event) => {
let targetElements = event.target.querySelectorAll('[hx-disable]');
for (let i = 0; i < targetElements.length; i++) {
targetElements[i].disabled = true;
}
});
document.body.addEventListener('htmx:afterRequest', (event) => {
let targetElements = event.target.querySelectorAll('[hx-disable]');
for (let i = 0; i < targetElements.length; i++) {
targetElements[i].disabled = false;
}
});
document.body.addEventListener('htmx:afterSwap', (event) => {
tippy('[data-tooltip]', {
content(reference) {
return reference.getAttribute('data-tooltip');
},
});
});
import tippy from 'tippy.js';
import 'tippy.js/dist/tippy.css';
tippy('[data-tooltip]', {
content(reference) {
return reference.getAttribute('data-tooltip');
},
document.addEventListener("alpine:init", () => {
window.Alpine.plugin(CodeEditorAlpinePlugin);
});
window.copyToClipboard = async function (text) {
@ -73,11 +18,11 @@ window.copyToClipboard = async function (text) {
textArea.select();
try {
document.execCommand('copy');
document.execCommand("copy");
} catch (error) {
//
} finally {
textArea.remove();
}
}
}
};

View File

@ -0,0 +1,48 @@
import ace from "brace";
import "brace/mode/ini";
import "brace/ext/searchbox";
import "../ace-editor/theme-vito";
import "../ace-editor/mode-env";
import "../ace-editor/mode-nginx";
export default (Alpine) => {
Alpine.data("codeEditorFormComponent", ({ state, options }) => {
return {
state,
options,
init: function () {
this.render();
},
render() {
this.editor = null;
const editorValue = JSON.parse(this.options.value || "");
this.editor = ace.edit(this.options.id);
this.editor.$blockScrolling = Infinity;
this.editor.setTheme("ace/theme/vito");
this.editor.setValue(editorValue, -1);
this.editor
.getSession()
.setMode(`ace/mode/${this.options.lang || "plain_text"}`);
this.editor.clearSelection();
this.editor.focus();
this.editor.setOptions({
printMargin: false,
});
this.editor.renderer.setScrollMargin(15, 15, 0, 0);
this.editor.renderer.setPadding(15);
this.editor.getSession().on("change", () => {
this.state = this.editor.getValue();
});
window.addEventListener("resize", () => {
this.editor.resize();
});
this.state = editorValue;
},
};
});
};

View File

@ -1,5 +1,5 @@
<div>
<form wire:submit="submit">
<form>
{{ $this->form }}
</form>
<x-filament-actions::modals />

View File

@ -1,13 +1,11 @@
<div {{ $this->getExtraAttributesBag() }}>
<x-filament-panels::page>
@if (method_exists($this, "getSecondSubNavigation"))
@if (method_exists($this, "getSecondSubNavigation") && count($this->getSecondSubNavigation()) > 0)
<x-filament-panels::page.sub-navigation.tabs class="!flex" :navigation="$this->getSecondSubNavigation()" />
@endif
@foreach ($this->getWidgets() as $key => $widget)
@livewire($widget[0], $widget[1] ?? [], key(class_basename($widget[0]) . "-" . $key))
@endforeach
<x-filament-actions::modals />
</x-filament-panels::page>
</div>

View File

@ -0,0 +1,18 @@
<x-dynamic-component :component="$getFieldWrapperView()" :field="$field" :label-sr-only="$isLabelHidden()">
<div
wire:ignore
x-data="codeEditorFormComponent({
state: $wire.{{ $applyStateBindingModifiers('entangle(\'' . $getStatePath() . '\')') }},
options: @js($getOptions()),
})"
>
<div>
<div
id="{{ $getId() }}"
{{ $attributes->merge(["class" => "mt-1 min-h-[400px] w-full border border-gray-100 dark:border-gray-700"]) }}
class="ace-vito ace_dark"
></div>
<textarea id="textarea-{{ $getId() }}" style="display: none" x-model="state"></textarea>
</div>
</div>
</x-dynamic-component>