mirror of
https://github.com/LinkStackOrg/LinkStack.git
synced 2025-02-02 20:27:05 +01:00
Added built in Config Editor
LittleLink Custom now includes an .env config editor. This editor can be accessed via the Admin Panel under Admin>Config. This editor allows admins to edit, backup, download and upload the .env configuration file. All in all, the new feature, allows users to more easily edit the configuration file, contributing to my goal of making LittleLink Custom easier to use. Read more about this topic on the Blog https://blog.littlelink-custom.com/built-in-config-editor
This commit is contained in:
parent
9bdf937e4b
commit
fef2e09aa9
71
.env
71
.env
@ -1,44 +1,45 @@
|
||||
APP_NAME="LittleLink Custom"
|
||||
APP_ENV=local
|
||||
APP_KEY=
|
||||
APP_DEBUG=true
|
||||
APP_URL=
|
||||
#App Settings=Changes settings regarding your LittleLink Custom installation. You probably only want to change the App Name setting.
|
||||
#=App_Name changes the displayed name for the App in the title, for example.
|
||||
App_Name="LittleLink Custom"
|
||||
App_Key=base64:khLI7djHyA97qfrA+rfz1YUFukELiN6Bk9gQ19+9zwk=
|
||||
App_URL=
|
||||
|
||||
LOG_CHANNEL=stack
|
||||
LOG_LEVEL=debug
|
||||
|
||||
DB_CONNECTION=sqlite
|
||||
#Debug Settings=Changes if your page should display a full error description instead of a generic error 500
|
||||
#=App_debug either true or false. You might want to change this to false after you're done installing, but it's very useful for troubleshooting.
|
||||
App_debug=true
|
||||
#=App_env either local or production. Change this to production if you set the value above to false
|
||||
App_env=local
|
||||
Log_channel=stack
|
||||
Log_level=debug
|
||||
|
||||
BROADCAST_DRIVER=log
|
||||
CACHE_DRIVER=file
|
||||
QUEUE_CONNECTION=sync
|
||||
SESSION_DRIVER=file
|
||||
SESSION_LIFETIME=120
|
||||
|
||||
MEMCACHED_HOST=127.0.0.1
|
||||
#Database Settings=Should be left alone. If you wish to use mysql you'd have to seed the database again.
|
||||
DB_connection=sqlite
|
||||
|
||||
REDIS_HOST=127.0.0.1
|
||||
REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
|
||||
MAIL_MAILER=smtp
|
||||
MAIL_HOST=mailhog
|
||||
MAIL_PORT=1025
|
||||
MAIL_USERNAME=null
|
||||
MAIL_PASSWORD=null
|
||||
MAIL_ENCRYPTION=null
|
||||
MAIL_FROM_ADDRESS=null
|
||||
MAIL_FROM_NAME="${APP_NAME}"
|
||||
#Mail Settings=LittleLink Custom comes with a free to use built-in SMTP server for sending mail. You can leave this setting as is, if you wish to use this service please read our terms and conditions at llc-mail.tru.io. If you do not wish to use the built-in SMTP server, change the setting below
|
||||
#=Mail_mailer either smtp or built-in. Make sure to change this setting if you want to add a custom SMTP server.
|
||||
Mail_mailer=built-in
|
||||
Mail_host=
|
||||
Mail_port=
|
||||
Mail_username=
|
||||
Mail_password=
|
||||
Mail_encryption=
|
||||
Mail_from_address=
|
||||
Mail_from_name="${app_name}"
|
||||
|
||||
AWS_ACCESS_KEY_ID=
|
||||
AWS_SECRET_ACCESS_KEY=
|
||||
AWS_DEFAULT_REGION=us-east-1
|
||||
AWS_BUCKET=
|
||||
|
||||
PUSHER_APP_ID=
|
||||
PUSHER_APP_KEY=
|
||||
PUSHER_APP_SECRET=
|
||||
PUSHER_APP_CLUSTER=mt1
|
||||
#Cache Settings=Completely optional
|
||||
Memcached_host=127.0.0.1
|
||||
Redis_host=127.0.0.1
|
||||
Redis_password=null
|
||||
Redis_port=6379
|
||||
|
||||
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
|
||||
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
|
||||
|
||||
#Miscellaneous Settings=Should be left alone if you don't know what you're doing.
|
||||
Broadcast_driver=log
|
||||
Cache_driver=file
|
||||
Queue_connection=sync
|
||||
Session_driver=file
|
||||
Session_lifetime=120
|
@ -8,6 +8,7 @@
|
||||
"php": "^7.3|^8.0",
|
||||
"fideloper/proxy": "^4.4",
|
||||
"fruitcake/laravel-cors": "^2.0",
|
||||
"geo-sot/laravel-env-editor": "^1.1",
|
||||
"guzzlehttp/guzzle": "^7.0.1",
|
||||
"laravel/framework": "^8.12",
|
||||
"laravel/tinker": "^2.5"
|
||||
@ -58,4 +59,3 @@
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true
|
||||
}
|
||||
|
||||
|
66
composer.lock
generated
66
composer.lock
generated
@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "0ad35353a22e3d26fcc6897fcc5dc893",
|
||||
"content-hash": "90a7893b152b65a22c6ed40595cd35c0",
|
||||
"packages": [
|
||||
{
|
||||
"name": "asm89/stack-cors",
|
||||
@ -557,6 +557,68 @@
|
||||
],
|
||||
"time": "2021-04-26T11:24:25+00:00"
|
||||
},
|
||||
{
|
||||
"name": "geo-sot/laravel-env-editor",
|
||||
"version": "v1.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/GeoSot/Laravel-EnvEditor.git",
|
||||
"reference": "d519594fcbc5dd9d35d47d56a96aae17f12c685f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/GeoSot/Laravel-EnvEditor/zipball/d519594fcbc5dd9d35d47d56a96aae17f12c685f",
|
||||
"reference": "d519594fcbc5dd9d35d47d56a96aae17f12c685f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"laravel/framework": ">=8",
|
||||
"php": ">=7.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "^3.4",
|
||||
"nunomaduro/larastan": "^1.0",
|
||||
"orchestra/testbench": "^6"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"GeoSot\\EnvEditor\\ServiceProvider"
|
||||
],
|
||||
"aliases": {
|
||||
"EnvEditor": "GeoSot\\EnvEditor\\Facades\\EnvEditor"
|
||||
}
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"GeoSot\\EnvEditor\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Geo Sot",
|
||||
"email": "geo.sotis@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "A laravel Package that supports .Env File, editing and backup ",
|
||||
"keywords": [
|
||||
"EnvEditor",
|
||||
"geo-sot",
|
||||
"laravel",
|
||||
"laravel-env-editor"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/GeoSot/Laravel-EnvEditor/issues",
|
||||
"source": "https://github.com/GeoSot/Laravel-EnvEditor/tree/v1.1.0"
|
||||
},
|
||||
"time": "2022-01-25T17:13:30+00:00"
|
||||
},
|
||||
{
|
||||
"name": "graham-campbell/result-type",
|
||||
"version": "v1.0.1",
|
||||
@ -7457,5 +7519,5 @@
|
||||
"php": "^7.3|^8.0"
|
||||
},
|
||||
"platform-dev": [],
|
||||
"plugin-api-version": "2.0.0"
|
||||
"plugin-api-version": "2.2.0"
|
||||
}
|
||||
|
46
config/env-editor.php
Normal file
46
config/env-editor.php
Normal file
@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Files Config
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
'paths' => [
|
||||
// .env file directory
|
||||
'env' => base_path(),
|
||||
//backup files directory
|
||||
'backupDirectory' => 'backups',
|
||||
],
|
||||
// .env file name
|
||||
'envFileName' => '.env',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Routes group config
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
*/
|
||||
'route' => [
|
||||
// Prefix url for route Group
|
||||
'prefix' => 'env-editor',
|
||||
// Routes base name
|
||||
'name' => 'env-editor',
|
||||
// Middleware(s) applied on route Group
|
||||
'middleware' => ['web', 'admin'],
|
||||
],
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
| Time Format for Views and parsed backups
|
||||
| ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
'timeFormat' => 'd/m/Y H:i:s',
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
| Set Views options
|
||||
| ------------------------------------------------------------------------------------------------
|
||||
| Here you can set The "extends" blade of index.blade.php
|
||||
*/
|
||||
'layout' => 'env-editor::layout',
|
||||
|
||||
];
|
89
resources/lang/vendor/env-editor/en/env-editor.php
vendored
Normal file
89
resources/lang/vendor/env-editor/en/env-editor.php
vendored
Normal file
@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'menuTitle' => '.env Editor',
|
||||
'controllerMessages' => [
|
||||
'backupWasCreated' => 'A new backup was created',
|
||||
'fileWasRestored' => 'The backup file ":name", was restored as default .env',
|
||||
'fileWasDeleted' => 'The backup file ":name", was deleted',
|
||||
'currentEnvWasReplacedByTheUploadedFile' => 'File was uploaded and become the new .env file',
|
||||
'uploadedFileSavedAsBackup' => 'File was uploaded as backup with the name ":name"',
|
||||
'keyWasAdded' => 'Key ":name" was added',
|
||||
'keyWasEdited' => 'Key ":name" has ben updated',
|
||||
'keyWasDeleted' => 'Key ":name" was Deleted',
|
||||
],
|
||||
'views' => [
|
||||
'tabTitles' => [
|
||||
'upload' => 'Upload',
|
||||
'backup' => 'Backups',
|
||||
'currentEnv' => 'Current .env',
|
||||
],
|
||||
'currentEnv' => [
|
||||
'title' => 'Current .env file Content',
|
||||
'tableTitles' => [
|
||||
'key' => 'Key',
|
||||
'value' => 'Value',
|
||||
'actions' => 'Actions',
|
||||
],
|
||||
'btn' => [
|
||||
'edit' => 'Edit File',
|
||||
'delete' => 'Delete Key',
|
||||
'addAfterKey' => 'Add new key after this key',
|
||||
'addNewKey' => 'Add New key',
|
||||
'deleteConfigCache' => 'Clear config cache',
|
||||
'deleteConfigCacheDesc' => 'On production environments changed values may not applied immediately cause of cached config. So you may try to un-cache it',
|
||||
],
|
||||
'modal' => [
|
||||
'title' => [
|
||||
'new' => 'New Key',
|
||||
'edit' => 'Edit Key',
|
||||
'delete' => 'Delete Key',
|
||||
],
|
||||
'input' => [
|
||||
'key' => 'Key',
|
||||
'value' => 'Value',
|
||||
],
|
||||
'btn' => [
|
||||
'close' => 'Close',
|
||||
'new' => 'Add Key',
|
||||
'edit' => 'Update Key',
|
||||
'delete' => 'Delete Key',
|
||||
],
|
||||
],
|
||||
|
||||
],
|
||||
'upload' => [
|
||||
'title' => 'Here You can upload a new ".env" file as a backup or to replace the current ".env"',
|
||||
'selectFilePrompt' => 'Select File',
|
||||
'btn' => [
|
||||
'clearFile' => 'Cancel',
|
||||
'uploadAsBackup' => 'Upload as backup',
|
||||
'uploadAndReplace' => 'Upload and replace current .env',
|
||||
],
|
||||
],
|
||||
'backup' => [
|
||||
'title' => 'Here you can see a list of saved backup files (if you have), you can create a new one, or download the .env file',
|
||||
'tableTitles' => [
|
||||
'filename' => 'File Name',
|
||||
'created_at' => 'Creation Date',
|
||||
'actions' => 'Actions',
|
||||
],
|
||||
'noBackUpItems' => 'There are no backups on your chosen directory. <br> You can make your first backup by pressing the "Get a new BackUp" button',
|
||||
'btn' => [
|
||||
'backUpCurrentEnv' => 'Get a new BackUp',
|
||||
'downloadCurrentEnv' => 'Download current .env',
|
||||
'download' => 'Download File',
|
||||
'delete' => 'Delete File',
|
||||
'restore' => 'Restore File',
|
||||
'viewContent' => 'View file Contents',
|
||||
],
|
||||
],
|
||||
],
|
||||
'exceptions' => [
|
||||
'fileNotExists' => 'File ":name" does not Exists !!!',
|
||||
'keyAlreadyExists' => 'Key ":name" already Exists !!!',
|
||||
'keyNotExists' => 'Key ":name" does not Exists !!!',
|
||||
'provideFileName' => 'You have to provide a FileName !!!',
|
||||
],
|
||||
|
||||
];
|
@ -74,6 +74,9 @@
|
||||
<li class="active">
|
||||
<a href="#adminSubmenu" data-toggle="collapse" aria-expanded="false" class="dropdown-toggle">Admin</a>
|
||||
<ul class="collapse list-unstyled" id="adminSubmenu">
|
||||
<li>
|
||||
<a href="{{ url('env-editor') }}">Config</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ url('panel/users/all') }}">Users</a>
|
||||
</li>
|
||||
|
118
resources/views/vendor/env-editor/components/_backup.blade.php
vendored
Normal file
118
resources/views/vendor/env-editor/components/_backup.blade.php
vendored
Normal file
@ -0,0 +1,118 @@
|
||||
@php($translatePrefix='env-editor::env-editor.views.backup.')
|
||||
<template id="env-editor-backups">
|
||||
<div>
|
||||
<div class="h5 my-4">{{__($translatePrefix.'title')}}</div>
|
||||
<div>
|
||||
<button class="btn-info btn " @click="createBackUp">{{__($translatePrefix.'btn.backUpCurrentEnv')}}</button>
|
||||
<a class="btn-info btn" href="{{route(config($package.'.route.name').'.download')}}">{{__($translatePrefix.'btn.downloadCurrentEnv')}}</a>
|
||||
</div>
|
||||
<div class=" my-3">
|
||||
|
||||
<div v-if="items.length" class="table-responsive">
|
||||
<table id="env-editor-table-accordion" class="table">
|
||||
<thead>
|
||||
<tr class="table-secondary">
|
||||
<th scope="col">{{__($translatePrefix.'tableTitles.filename')}}</th>
|
||||
<th scope="col">{{__($translatePrefix.'tableTitles.created_at')}}</th>
|
||||
<th scope="col">{{__($translatePrefix.'tableTitles.actions')}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<template v-for="(item, index) in items">
|
||||
<tr :key="item.real_name" :bind="item">
|
||||
<th scope="row" class="font-weight-bold ">@{{ item.name }}</th>
|
||||
<td>@{{ item.created_at_formatted }}</td>
|
||||
<td>
|
||||
<div class="btn-group" role="group">
|
||||
<button class="btn btn-info" data-toggle="collapse" aria-expanded="false"
|
||||
:data-target="'#collapse_'+item.real_name"
|
||||
:aria-controls="'#collaps_'+item.real_name" title="{{__($translatePrefix.'btn.viewContent')}}"><span class="fas fa-eye"></span></button>
|
||||
<a class="btn btn-info" :href="getDownLoadLink(item)" title="{{__($translatePrefix.'btn.download')}}"><span
|
||||
class="fas fa-download"></span></a>
|
||||
<button class="btn btn-secondary" @click="restore(item)" title="{{__($translatePrefix.'btn.restore')}}"><span class="fas fa-redo"></span>
|
||||
</button>
|
||||
<button class="btn btn-danger" @click="destroy(item)" title="{{__($translatePrefix.'btn.delete')}}"><span class="fas fa-trash"></span></button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="100%" class="p-0">
|
||||
<div class="collapse" :id="'collapse_'+item.real_name" data-parent="#env-editor-table-accordion">
|
||||
<div class="table-responsive table-sm px-3 pb-3">
|
||||
<table class="w-100 bg-light">
|
||||
<tr v-for="(dt, index) in item.parsed_data">
|
||||
<td class="pl-3"><code>@{{ dt.key||' ' }}</code></td>
|
||||
<td><code>@{{ dt.value }}</code></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="text-primary font-italic" v-else>{!! __($translatePrefix.'noBackUpItems') !!}</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@push('scripts')
|
||||
|
||||
<script>
|
||||
const backUps = {
|
||||
template: '#env-editor-backups',
|
||||
data: () => {
|
||||
return {
|
||||
modalItem: '',
|
||||
items: []
|
||||
}
|
||||
},
|
||||
computed: {},
|
||||
mounted() {
|
||||
this.getItemsWithAjax();
|
||||
envEventBus.$on('env:backupsChanged', () => {
|
||||
this.getItemsWithAjax();
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
|
||||
getDownLoadLink(item) {
|
||||
let downloadUrl = '{{route(config($package.'.route.name').'.download')}}/';
|
||||
return downloadUrl + item.real_name;
|
||||
},
|
||||
createBackUp() {
|
||||
let url = '{{route(config($package.'.route.name').'.createBackup')}}';
|
||||
this.sendBasicAjaxRequest('post', url, 'backupsChanged');
|
||||
},
|
||||
restore(item) {
|
||||
let url = '{{route(config($package.'.route.name').'.restoreBackup')}}/';
|
||||
this.sendBasicAjaxRequest('post', url + item.real_name, 'changed');
|
||||
},
|
||||
destroy(item) {
|
||||
let url = '{{route(config($package.'.route.name').'.destroyBackup')}}/';
|
||||
this.sendBasicAjaxRequest('delete', url + item.real_name, 'backupsChanged');
|
||||
|
||||
},
|
||||
sendBasicAjaxRequest($method, $url, $eventToTrigger) {
|
||||
envClient($url, { method: $method }).then((data) => {
|
||||
if (data.message) {
|
||||
envAlert('info', data.message);
|
||||
}
|
||||
envEventBus.$emit('env:' + $eventToTrigger);
|
||||
})
|
||||
},
|
||||
getItemsWithAjax() {
|
||||
envClient('{{route(config($package.'.route.name').'.getBackups')}}')
|
||||
.then(data => this.items = Object.values(data.items))
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
@endpush
|
33
resources/views/vendor/env-editor/components/_configActions.blade.php
vendored
Normal file
33
resources/views/vendor/env-editor/components/_configActions.blade.php
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
@php($translatePrefix='env-editor::env-editor.views.currentEnv.')
|
||||
<template id="env-editor-config-actions">
|
||||
<div>
|
||||
<button class="btn-outline-dark btn btn-sm" title="{{__($translatePrefix.'btn.deleteConfigCacheDesc')}}"
|
||||
@click="deleteConfigCache">{{__($translatePrefix.'btn.deleteConfigCache')}}</button>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@push('scripts')
|
||||
|
||||
<script>
|
||||
|
||||
let configActions = {
|
||||
template: '#env-editor-config-actions',
|
||||
methods: {
|
||||
deleteConfigCache() {
|
||||
this.submit('delete', '{{route(config($package.'.route.name').'.clearConfigCache')}}');
|
||||
},
|
||||
submit(method, url) {
|
||||
envClient(url,{
|
||||
method: method
|
||||
}).then(data => {
|
||||
if (data.message) {
|
||||
envAlert('info', data.message);
|
||||
}
|
||||
})
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
</script>
|
||||
@endpush
|
87
resources/views/vendor/env-editor/components/_currentEnv.blade.php
vendored
Normal file
87
resources/views/vendor/env-editor/components/_currentEnv.blade.php
vendored
Normal file
@ -0,0 +1,87 @@
|
||||
@php($translatePrefix='env-editor::env-editor.views.currentEnv.')
|
||||
<template id="env-editor-main-tab">
|
||||
<div>
|
||||
<div class="h5 my-4">{{__($translatePrefix.'title')}}</div>
|
||||
<div class="py-3 text-right">
|
||||
<button class="btn btn-info" @click="addNew()">{{__($translatePrefix.'btn.addNewKey')}}</button>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-sm">
|
||||
<thead>
|
||||
<tr class="table-secondary ">
|
||||
<th class="py-2" scope="col">{{__($translatePrefix.'tableTitles.key')}}</th>
|
||||
<th class="py-2" scope="col">{{__($translatePrefix.'tableTitles.value')}}</th>
|
||||
<th class="py-2" scope="col">{{__($translatePrefix.'tableTitles.actions')}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(item, index) in items" :key="item.key" v-bind="item" v-if="!item.separator">
|
||||
<th scope="row" class="font-weight-bold ">@{{ item.key }}</th>
|
||||
<td>@{{ item.value }}</td>
|
||||
<td>
|
||||
<div class="btn-group" role="group">
|
||||
<button class="btn btn-info" @click="edit(item)" title="{{__($translatePrefix.'btn.edit')}}"><span class="fas fa-edit"></span></button>
|
||||
<button class="btn btn-secondary" @click="addAfter(item)" title="{{__($translatePrefix.'btn.addAfterKey')}}"><span class="fas fa-share"></span></button>
|
||||
<button class="btn btn-danger" @click="remove(item)" title="{{__($translatePrefix.'btn.delete')}}"><span class="fas fa-trash"></span></button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-else>
|
||||
<td colspan="100%"> </td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@push('scripts')
|
||||
|
||||
|
||||
<script>
|
||||
const itemsWrapper = {
|
||||
template: '#env-editor-main-tab',
|
||||
data: () => {
|
||||
return {
|
||||
items: [],
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
envEventBus.$on('env:changed', () => {
|
||||
this.getItemsWithAjax();
|
||||
});
|
||||
this.getItemsWithAjax()
|
||||
},
|
||||
methods: {
|
||||
edit: function (item) {
|
||||
envEventBus.$emit('env:item:edit', item);
|
||||
},
|
||||
addNew() {
|
||||
envEventBus.$emit('env:item:new');
|
||||
},
|
||||
addAfter(item) {
|
||||
let oldItem = {
|
||||
key: null,
|
||||
value: null,
|
||||
group: item.group,
|
||||
index: item.index + 0.1,
|
||||
}
|
||||
|
||||
envEventBus.$emit('env:item:new', oldItem);
|
||||
},
|
||||
remove(item) {
|
||||
envEventBus.$emit('env:item:delete', item);
|
||||
},
|
||||
getItemsWithAjax() {
|
||||
envClient('{{route(config($package.'.route.name').'.index')}}')
|
||||
.then(data => this.items = data.items)
|
||||
}
|
||||
},
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
</script>
|
||||
@endpush
|
152
resources/views/vendor/env-editor/components/_itemModal.blade.php
vendored
Normal file
152
resources/views/vendor/env-editor/components/_itemModal.blade.php
vendored
Normal file
@ -0,0 +1,152 @@
|
||||
@php($translatePrefix='env-editor::env-editor.views.currentEnv.')
|
||||
<template id="env-editor-modal">
|
||||
<div id="env-editor-keys-modal" class=" modal fade " tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" :class="'text-'+actionClass">@{{ title }}</h5>
|
||||
<button type="button" class="close" @click="hideModal()" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form>
|
||||
<input type="hidden" name="group" v-model.trim="modalItem.group">
|
||||
<div class="form-group">
|
||||
<label for="env_key" class="col-form-label">{{__($translatePrefix.'modal.input.key')}}:</label>
|
||||
<input type="text" class="form-control" id="env_key" :readonly="readonly.key" v-model.trim="modalItem.key"/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="env_value" class="col-form-label">{{__($translatePrefix.'modal.input.value')}}:</label>
|
||||
<input type="text" class="form-control" id="env_value" :readonly="readonly.value" v-model.trim="modalItem.value"/>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal" @click="hideModal()">{{__($translatePrefix.'modal.btn.close')}}</button>
|
||||
<button id="save_evnVariable" type="button" class="btn " :class="'btn-'+actionClass" @click="submit()"> @{{ submitBtn }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@push('scripts')
|
||||
|
||||
<script>
|
||||
|
||||
let itemsModal = {
|
||||
template: '#env-editor-modal',
|
||||
data: () => {
|
||||
return {
|
||||
modal: '#env-editor-keys-modal',
|
||||
type: '',
|
||||
modalItem: {},
|
||||
readonly: {
|
||||
key: false,
|
||||
value: false,
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.modalItem = this.newModalItem();
|
||||
|
||||
envEventBus.$on('env:item:edit', (item) => {
|
||||
this.makeReadOnly('key');
|
||||
this.show('edit', item);
|
||||
}).$on('env:item:delete', (item) => {
|
||||
this.makeReadOnly('key');
|
||||
this.makeReadOnly('value');
|
||||
this.show('delete', item);
|
||||
}).$on('env:item:new', (item) => {
|
||||
this.show('new', item);
|
||||
});
|
||||
},
|
||||
computed: {
|
||||
submitBtn() {
|
||||
let values = {
|
||||
'new': '{{__($translatePrefix."modal.btn.new")}}',
|
||||
'edit': '{{__($translatePrefix."modal.btn.edit")}}',
|
||||
'delete': '{{__($translatePrefix."modal.btn.delete")}}',
|
||||
};
|
||||
|
||||
return values[this.type.toLowerCase()];
|
||||
},
|
||||
title() {
|
||||
let values = {
|
||||
'new': '{{__($translatePrefix."modal.title.new")}}',
|
||||
'edit': '{{__($translatePrefix."modal.title.edit")}}',
|
||||
'delete': '{{__($translatePrefix."modal.title.delete")}}',
|
||||
};
|
||||
|
||||
return values[this.type.toLowerCase()] + ': ' + this.modalItem.key;
|
||||
},
|
||||
actionClass() {
|
||||
switch (this.type) {
|
||||
case 'delete':
|
||||
return 'danger';
|
||||
case 'edit':
|
||||
return 'info';
|
||||
default:
|
||||
return 'success';
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
newModalItem: () => {
|
||||
return {
|
||||
key: '',
|
||||
value:'',
|
||||
group: null,
|
||||
}
|
||||
},
|
||||
hideModal() {
|
||||
this.modalItem = this.newModalItem();
|
||||
this.readonly.key = false;
|
||||
this.readonly.value = false;
|
||||
$(this.modal).modal('hide');
|
||||
},
|
||||
getAjaxMethod() {
|
||||
switch (this.type) {
|
||||
case 'delete':
|
||||
return 'delete';
|
||||
case 'edit':
|
||||
return 'patch';
|
||||
default:
|
||||
return 'post'
|
||||
}
|
||||
},
|
||||
makeReadOnly(arg = null) {
|
||||
let $vm = this;
|
||||
if (arg) {
|
||||
$vm.readonly[arg] = true;
|
||||
return;
|
||||
}
|
||||
Object.keys($vm.readonly).forEach(function (el) {
|
||||
$vm.readonly[el] = true;
|
||||
});
|
||||
},
|
||||
show(type = '', item) {
|
||||
(item) ? this.modalItem = item : '';
|
||||
this.type = type;
|
||||
$(this.modal).modal('show')
|
||||
},
|
||||
submit() {
|
||||
envClient('{{route(config($package.'.route.name').'.key')}}',{
|
||||
method: this.getAjaxMethod(),
|
||||
data: this.modalItem
|
||||
}).then(data => {
|
||||
if (data.message) {
|
||||
envAlert('info', data.message);
|
||||
}
|
||||
envEventBus.$emit('env:changed')
|
||||
|
||||
}).then(() => {
|
||||
this.hideModal();
|
||||
});
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
</script>
|
||||
@endpush
|
92
resources/views/vendor/env-editor/components/_upload.blade.php
vendored
Normal file
92
resources/views/vendor/env-editor/components/_upload.blade.php
vendored
Normal file
@ -0,0 +1,92 @@
|
||||
@php($translatePrefix='env-editor::env-editor.views.upload.')
|
||||
<template id="env-editor-uploadFile">
|
||||
<div>
|
||||
<div class="h5 my-4">{{__($translatePrefix.'title')}}</div>
|
||||
<div id="uploadEnvForm">
|
||||
<div class="input-group mb-4">
|
||||
<div class="custom-file ">
|
||||
<input type="file" class="custom-file-input" :class="formInputNotValidClass" @change="fileInputChanged" lang="en">
|
||||
<label class="custom-file-label" for="customFileLang">@{{ promptMsg }}</label>
|
||||
</div>
|
||||
<div class="invalid-feedback d-block" v-if="formIsInvalid">
|
||||
@{{ errors }}
|
||||
</div>
|
||||
<div class="input-group-append" v-if="hasFile">
|
||||
<button class="btn btn-outline-secondary" @click="clearFileInput" type="button">{{__($translatePrefix.'btn.clearFile')}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="my-4">
|
||||
<button class="btn-info btn " :disabled="!hasFile" @click="uploadAsBackUp">{{__($translatePrefix.'btn.uploadAsBackup')}}</button>
|
||||
<button class="btn-warning btn " :disabled="!hasFile" @click="uploadAndReplaceCurrent">{{__($translatePrefix.'btn.uploadAndReplace')}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@push('scripts')
|
||||
|
||||
<script>
|
||||
const fileUpload = {
|
||||
template: '#env-editor-uploadFile',
|
||||
data: () => {
|
||||
return {
|
||||
file: null,
|
||||
fileName: null,
|
||||
formIsInvalid: false,
|
||||
errors: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
promptMsg() {
|
||||
return this.hasFile ? this.fileName : "{{__($translatePrefix.'selectFilePrompt')}}"
|
||||
},
|
||||
hasFile() {
|
||||
return (this.file !== null)
|
||||
},
|
||||
formInputNotValidClass() {
|
||||
return this.formIsInvalid ? 'is-invalid ' : ''
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
clearFileInput: function () {
|
||||
this.file = null;
|
||||
this.fileName = null;
|
||||
},
|
||||
uploadAsBackUp: function (e) {
|
||||
return this.submitForm(e);
|
||||
},
|
||||
uploadAndReplaceCurrent: function (e) {
|
||||
return this.submitForm(e, true);
|
||||
},
|
||||
fileInputChanged({ type, target }) {
|
||||
this.fileName = target.files[0].name;
|
||||
this.file = target.files[0]
|
||||
},
|
||||
submitForm(event, replaceCurrentEnv = false) {
|
||||
this.formIsInvalid = false;
|
||||
const formData = new FormData();
|
||||
formData.append('file', this.file);
|
||||
formData.append('replace_current', replaceCurrentEnv.toString());
|
||||
|
||||
envClient('{{route(config($package.'.route.name').'.upload')}}', {
|
||||
body: formData,
|
||||
method: 'post',
|
||||
}).then(data => {
|
||||
if (data.message) {
|
||||
envAlert('info', data.message);
|
||||
}
|
||||
(replaceCurrentEnv) ? envEventBus.$emit('env:changed') : envEventBus.$emit('env:backupsChanged');
|
||||
this.fileName = null;
|
||||
this.file = null;
|
||||
}).catch((error) => {
|
||||
this.errors = error.errors.file[0];
|
||||
this.formIsInvalid = true;
|
||||
});
|
||||
}
|
||||
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
@endpush
|
114
resources/views/vendor/env-editor/index.blade.php
vendored
Normal file
114
resources/views/vendor/env-editor/index.blade.php
vendored
Normal file
@ -0,0 +1,114 @@
|
||||
@php($package='env-editor')
|
||||
@php($translatePrefix='env-editor::env-editor.')
|
||||
|
||||
@extends(config("$package.layout"))
|
||||
@push('documentTitle')
|
||||
<i class="fas fa-cog" aria-hidden="true"></i>
|
||||
{{trans('env-editor::env-editor.menuTitle')}}
|
||||
@endpush
|
||||
|
||||
|
||||
@section('content')
|
||||
<div id="env-editor">
|
||||
<div id="env-alerts"></div>
|
||||
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" data-toggle="tab" href="#current-env" role="tab">{{__($translatePrefix.'views.tabTitles.currentEnv')}}</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" data-toggle="tab" href="#backup-env" role="tab">{{__($translatePrefix.'views.tabTitles.backup')}}</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" data-toggle="tab" href="#upload-env" role="tab">{{__($translatePrefix.'views.tabTitles.upload')}}</a>
|
||||
</li>
|
||||
<li class="nav-item ml-auto">
|
||||
<env-editor-config-actions></env-editor-config-actions>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="tab-content" id="nav-tabContent">
|
||||
<div class="tab-pane fade show active p-3" id="current-env" role="tabpanel" aria-labelledby="nav-home-tab">
|
||||
<env-main-tab></env-main-tab>
|
||||
</div>
|
||||
<div class="tab-pane fade p-3" id="backup-env" role="tabpanel" aria-labelledby="nav-profile-tab">
|
||||
<env-editor-backups></env-editor-backups>
|
||||
</div>
|
||||
<div class="tab-pane fade p-3" id="upload-env" role="tabpanel" aria-labelledby="nav-contact-tab">
|
||||
<env-file-upload></env-file-upload>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<env-keys-modal ref="keysModal"></env-keys-modal>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
@stop
|
||||
@include('env-editor::components._itemModal')
|
||||
@include('env-editor::components._currentEnv')
|
||||
@include('env-editor::components._upload')
|
||||
@include('env-editor::components._backup')
|
||||
@include('env-editor::components._configActions')
|
||||
@push('scripts')
|
||||
<script>
|
||||
window.envEventBus = new Vue();
|
||||
const envAlert = ($type, $text) => {
|
||||
let alert =
|
||||
'<div id="__id__" class="alert alert-__type__ alert-dismissible fade show" role="alert">' +
|
||||
' <div>__text__</div>' +
|
||||
' <button type="button" class="close" data-dismiss="alert" aria-label="Close">' +
|
||||
' <span aria-hidden="true">×</span>' +
|
||||
' </button>' +
|
||||
'</div>';
|
||||
let $id = 'env-alert_' + Date.now();
|
||||
let $html = alert.replace('__type__', $type).replace('__text__', $text).replace('__id__', $id);
|
||||
$('#env-alerts').append($html);
|
||||
setTimeout(() => {
|
||||
$('#' + $id).alert('close')
|
||||
}, 3000)
|
||||
};
|
||||
|
||||
window.envClient = (endpoint, customConfig) => {
|
||||
const data= customConfig && customConfig.data
|
||||
let headers = {
|
||||
'Accept': 'application/json',
|
||||
"X-CSRF-Token": '{{csrf_token()}}'
|
||||
}
|
||||
if (data) {
|
||||
headers['Content-Type'] = 'application/json'
|
||||
customConfig.body = JSON.stringify(customConfig.data)
|
||||
}
|
||||
|
||||
const config = {
|
||||
...customConfig,
|
||||
headers: headers,
|
||||
}
|
||||
|
||||
return window
|
||||
.fetch(endpoint, config)
|
||||
.then(async response => {
|
||||
const data = await response.json()
|
||||
if (response.ok) {
|
||||
return data
|
||||
}
|
||||
envAlert('danger', data.message);
|
||||
return Promise.reject(data)
|
||||
})
|
||||
};
|
||||
|
||||
const dotEnv = new Vue({
|
||||
el: '#env-editor',
|
||||
components: {
|
||||
'env-main-tab': itemsWrapper,
|
||||
'env-keys-modal': itemsModal,
|
||||
'env-file-upload': fileUpload,
|
||||
'env-editor-backups': backUps,
|
||||
'env-editor-config-actions': configActions
|
||||
}
|
||||
})
|
||||
</script>
|
||||
@endpush
|
||||
|
||||
@extends('layouts.sidebar')
|
37
resources/views/vendor/env-editor/layout.blade.php
vendored
Normal file
37
resources/views/vendor/env-editor/layout.blade.php
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="{{app()->getLocale()}}" xml:lang="{{config('app.locale')}}" itemscope itemtype="http://schema.org/WebSite">
|
||||
<head>
|
||||
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>@lang('env-editor::env-editor.menuTitle')</title>
|
||||
|
||||
<!-- CSRF Token -->
|
||||
<meta name="csrf-token" content="{{ csrf_token() }}"/>
|
||||
|
||||
<link rel="stylesheet"
|
||||
href="https://pro.fontawesome.com/releases/v5.10.0/css/all.css"
|
||||
integrity="sha384-AYmEC3Yw5cVb3ZcuHtOA93w35dYTsvhLPVnYs9eStHfGJvOvKxVfELGroGkvsg+p"
|
||||
crossorigin="anonymous"/>
|
||||
|
||||
@stack('styles')
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<span class="javascripts">
|
||||
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"
|
||||
integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj"
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js"
|
||||
integrity="sha384-fQybjgWLrvvRgtW6bFlB7jaZrFsaBXjsOMm/tB9LTS58ONXgqbR9W8oWht/amnpF"
|
||||
crossorigin="anonymous"></script>
|
||||
|
||||
|
||||
@stack('scripts')
|
||||
|
||||
</span>
|
||||
</body>
|
||||
</html>
|
46
storage/backups/default_settings
Normal file
46
storage/backups/default_settings
Normal file
@ -0,0 +1,46 @@
|
||||
#App Settings=Changes settings regarding your LittleLink Custom installation. You probably only want to change the App Name setting.
|
||||
#=App_Name changes the displayed name for the App in the title, for example.
|
||||
App_Name="LittleLink Custom"
|
||||
# You can get a new App Key from https://littlelink-custom.com/key.php
|
||||
App_Key=base64:YOU+MUST+CHANGE+THIS+YUFukELiN6Bk9gQ19+9zwk=
|
||||
App_URL=
|
||||
|
||||
|
||||
#Debug Settings=Changes if your page should display a full error description instead of a generic error 500
|
||||
#=App_debug either true or false. You might want to change this to false after you're done installing, but it's very useful for troubleshooting.
|
||||
App_debug=true
|
||||
#=App_env either local or production. Change this to production if you set the value above to false
|
||||
App_env=local
|
||||
Log_channel=stack
|
||||
Log_level=debug
|
||||
|
||||
|
||||
#Database Settings=Should be left alone. If you wish to use mysql you'd have to seed the database again.
|
||||
DB_connection=sqlite
|
||||
|
||||
|
||||
#Mail Settings=LittleLink Custom comes with a free to use built-in SMTP server for sending mail. You can leave this setting as is, if you wish to use this service please read our terms and conditions at llc-mail.tru.io. If you do not wish to use the built-in SMTP server, change the setting below
|
||||
#=Mail_mailer either smtp or built-in. Make sure to change this setting if you want to add a custom SMTP server.
|
||||
Mail_mailer=built-in
|
||||
Mail_host=
|
||||
Mail_port=
|
||||
Mail_username=
|
||||
Mail_password=
|
||||
Mail_encryption=
|
||||
Mail_from_address=
|
||||
Mail_from_name="${app_name}"
|
||||
|
||||
|
||||
#Cache Settings=Completely optional
|
||||
Memcached_host=127.0.0.1
|
||||
Redis_host=127.0.0.1
|
||||
Redis_password=null
|
||||
Redis_port=6379
|
||||
|
||||
|
||||
#Miscellaneous Settings=Should be left alone if you don't know what you're doing.
|
||||
Broadcast_driver=log
|
||||
Cache_driver=file
|
||||
Queue_connection=sync
|
||||
Session_driver=file
|
||||
Session_lifetime=120
|
Loading…
x
Reference in New Issue
Block a user