CacheProxy.php
Component.php
select-repositories.blade.php
select-type.blade.php
SelectRepositories.php
SelectType.php
show-wizard.blade.php
ShowWizard.php
upload-files.blade.php
UploadFiles.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Http\Livewire; | |
class CacheProxy | |
{ | |
private $key; | |
public function __construct($key) | |
{ | |
$this->key = $key; | |
} | |
public function get($default = null, $assoc = false) | |
{ | |
return json_decode(cache()->get($this->key, json_encode($default)), $assoc); | |
} | |
public function getRaw($default = null) | |
{ | |
return cache()->get($this->key, $default); | |
} | |
public function set($value) | |
{ | |
cache()->forever($this->key, json_encode($value)); | |
} | |
public function setRaw($value) | |
{ | |
cache()->forever($this->key, $value); | |
} | |
public function forget() | |
{ | |
cache()->forget($this->key); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Http\Livewire; | |
use Illuminate\Support\Str; | |
use Livewire\Component as BaseComponent; | |
class Component extends BaseComponent | |
{ | |
public function uuid() | |
{ | |
return (string) Str::uuid(); | |
} | |
public function cache($key) | |
{ | |
static $cacheProxies; | |
if (!$cacheProxies) { | |
$cacheProxies = []; | |
} | |
if (!isset($cacheProxies[$key])) { | |
$cacheProxies[$key] = new CacheProxy($key); | |
} | |
return $cacheProxies[$key]; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div class="flex flex-col w-full h-screen"> | |
<h1 class="text-xl">Select repositories</h1> | |
@guest | |
<a href="{{ route('users.redirect-to-github', ['elevated' => 1]) }}" class="text-indigo-500 underline text-sm">Log in with Github</a> | |
<a href="{{ route('users.redirect-to-bitbucket', ['elevated' => 1]) }}" class="text-indigo-500 underline text-sm">Log in with BitBucket</a> | |
@endguest | |
@auth | |
<div class="my-2"> | |
<button wire:click="sync" class="bg-gray-900 text-white px-2 py-1">sync</button> | |
@unless(auth()->user() && auth()->user()->github_elevated_token) | |
<a href="{{ route('users.redirect-to-github', ['elevated' => 1]) }}" class="text-indigo-500 underline ml-2 text-sm">Connect Github</a> | |
@endunless | |
@unless(auth()->user() && auth()->user()->bitbucket_elevated_token) | |
<a href="{{ route('users.redirect-to-bitbucket', ['elevated' => 1]) }}" class="text-indigo-500 underline ml-2 text-sm">Connect BitBucket</a> | |
@endunless | |
</div> | |
@forelse($available as $repository) | |
<label class="flex flex-row items-center justify-start w-full px-2 py-1"> | |
<input | |
type="checkbox" | |
value="{{ json_encode($repository) }}" | |
wire:change="$emit('onSelectRepository', $event.target.value, $event.target.checked)" | |
class="mr-2" | |
@if(count($selected) > 0 and in_array($repository->name, array_keys($selected)) and $selected[$repository->name])) | |
checked | |
@endif | |
/> {{ $repository->name }} ({{ $repository->source }}) | |
</label> | |
@empty | |
No repositories. | |
@endforelse | |
@endauth | |
<div class="my-2"> | |
<button wire:click="$emit('onPrevious')" class="bg-gray-900 text-white px-2 py-1">previous</button> | |
@if($selected and count(array_keys($selected)) > 0) | |
<button wire:click="$emit('onNext')" class="bg-gray-900 text-white px-2 py-1">next</button> | |
@endif | |
</div> | |
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div class="flex flex-col w-full h-screen"> | |
<h1 class="text-xl">Select type</h1> | |
@foreach($available as $type) | |
<label class="flex flex-row items-center justify-start w-full px-2 py-1"> | |
<input | |
type="radio" | |
name="wizard-type" | |
value="{{ json_encode($type) }}" | |
wire:change="$emit('onSelectType', $event.target.value, $event.target.checked)" | |
class="mr-2" | |
@if($selected and $selected->id == $type->id) | |
checked | |
@endif | |
/> {{ $type->name }} | |
</label> | |
@endforeach | |
<div class="my-2"> | |
@if($selected) | |
<button wire:click="$emit('onNext')" class="bg-gray-900 text-white px-2 py-1">next</button> | |
@endif | |
</div> | |
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Http\Livewire; | |
class SelectRepositories extends Component | |
{ | |
public $availableCacheUuid; | |
public $selectedCacheUuid; | |
public function mount($selected = []) | |
{ | |
$this->availableCacheUuid = session()->get('SelectRepositories.availableCacheUuid', $this->uuid()); | |
$this->selectedCacheUuid = session()->get('SelectRepositories.selectedCacheUuid', $this->uuid()); | |
// remember these if we just created them... | |
session()->put('SelectRepositories.availableCacheUuid', $this->availableCacheUuid); | |
session()->put('SelectRepositories.selectedCacheUuid', $this->selectedCacheUuid); | |
$this->cache($this->selectedCacheUuid)->set($selected); | |
} | |
public function sync() | |
{ | |
$available = array_merge( | |
$this->syncGithub(), | |
$this->syncBitbucket(), | |
); | |
$this->cache($this->availableCacheUuid)->set($available); | |
} | |
private function syncGithub() | |
{ | |
$user = auth()->user(); | |
if (!$user || !$user->github_elevated_token) { | |
return []; | |
} | |
sleep(1); | |
return [ | |
(object) [ | |
'name' => 'assertchris/attempt-promise', | |
'source' => 'github', | |
], | |
]; | |
} | |
private function syncBitbucket() | |
{ | |
$user = auth()->user(); | |
if (!$user || !$user->bitbucket_elevated_token) { | |
return []; | |
} | |
sleep(1); | |
return [ | |
(object) [ | |
'name' => 'assertchris/solr-full-text-search', | |
'source' => 'bitbucket', | |
], | |
]; | |
} | |
public function render() | |
{ | |
$available = $this->cache($this->availableCacheUuid)->get([]); | |
$selected = $this->cache($this->selectedCacheUuid)->get([], true); | |
return view('livewire.select-repositories', compact('available', 'selected')); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Http\Livewire; | |
class SelectType extends Component | |
{ | |
protected $available; | |
protected $selected; | |
public function mount($selected = null) | |
{ | |
$this->available = [ | |
(object) [ | |
'id' => 'files-for-sale', | |
'name' => 'files for sale', | |
], | |
(object) [ | |
'id' => 'files-for-email', | |
'name' => 'files for email', | |
], | |
(object) [ | |
'id' => 'repositories-for-sale', | |
'name' => 'repositories for sale', | |
], | |
(object) [ | |
'id' => 'repositories-for-email', | |
'name' => 'repositories for email', | |
], | |
]; | |
$this->selected = $selected; | |
} | |
public function render() | |
{ | |
$available = $this->available; | |
$selected = $this->selected; | |
return view('livewire.select-type', compact('available', 'selected')); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div class="flex flex-row w-full h-screen"> | |
<div class="flex flex-col w-2/3 pr-8"> | |
@if($this->show === 'select-type') | |
@livewire('select-type', $type, key('select-type-' . json_encode($type))) | |
@endif | |
@if($this->show === 'select-repositories') | |
@livewire('select-repositories', $repositories, key('select-repositories-' . json_encode($repositories))) | |
@endif | |
@if($this->show === 'upload-files') | |
@livewire('upload-files') | |
@endif | |
@if($this->show === 'select-provider') | |
@livewire('select-provider') | |
@endif | |
@if($this->show === 'show-confirmation') | |
@livewire('show-confirmation') | |
@endif | |
</div> | |
<div class="flex flex-col items-start justify-start w-1/3 text-gray-500"> | |
<h1 class="text-lg">Debug info</h1> | |
@if($type) | |
<div> | |
Type: | |
<div> | |
{{ json_encode($type) }} | |
</div> | |
</div> | |
@endif | |
@if(count(array_filter($repositories)) > 0) | |
<div> | |
Repositories: | |
@foreach($repositories as $repository) | |
<div> | |
{{ json_encode($repository) }} | |
</div> | |
@endforeach | |
</div> | |
@endif | |
<button wire:click="flush" class="bg-gray-900 text-white px-2 py-1 mt-2">Flush</button> | |
</div> | |
</div> | |
@push('scripts') | |
<script type="text/javascript"> | |
var queue = [] | |
var current = undefined | |
function stop(e) { | |
e.preventDefault() | |
e.stopPropagation() | |
} | |
function show(element) { | |
element.classList.remove('hidden') | |
element.classList.add('flex') | |
} | |
function hide(element) { | |
element.classList.remove('flex') | |
element.classList.add('hidden') | |
} | |
function fileToBase64(file) { | |
return new Promise((resolve, reject) => { | |
var reader = new FileReader() | |
reader.onload = function() { | |
resolve(reader.result) | |
} | |
reader.onerror = function(error) { | |
reject(error) | |
} | |
reader.readAsDataURL(file) | |
}) | |
} | |
function uploadFile(file) { | |
queue.push({ | |
name: file.name, | |
isBusy: false, | |
isComplete: false, | |
error: undefined, | |
file: file | |
}) | |
updateStatus() | |
} | |
function updateStatus() { | |
// DEBUG | |
// console.log(queue) | |
document.querySelector('[data-uploader-status]').innerHTML = ` | |
${queue.map(upload => ` | |
<div class="flex flex-col w-full md:w-1/2 pr-2 pb-2"> | |
<div class="flex w-full">${upload.name}</div> | |
<div class="flex w-full"> | |
${upload.isBusy ? 'uploading' : ''} | |
${upload.isComplete ? 'uploaded' : ''} | |
${upload.error ? error.message : ''} | |
</div> | |
</div> | |
`).join('\n')} | |
` | |
} | |
setInterval(function() { | |
if (current) { | |
// DEBUG | |
// console.log('still busy') | |
return | |
} | |
var next = queue.find(next => !next.isBusy && !next.isComplete && !next.error) | |
if (!next) { | |
// DEBUG | |
// console.log('empty queue', queue) | |
return | |
} | |
// DEBUG | |
console.log('starting next', next) | |
current = next | |
current.isBusy = true | |
updateStatus() | |
fileToBase64(current.file) | |
.then(function(data) { | |
window.livewire.emit('onUploadFile', current.name, current.type, current.size, data) | |
}) | |
.catch(function(error) { | |
console.log('file had an error', current.name, error) | |
current.isBusy = false | |
current.error = error | |
current = undefined | |
updateStatus() | |
}) | |
}, 100) | |
document.addEventListener('DOMContentLoaded', function () { | |
console.log('attaching uploader events') | |
document.addEventListener('dragenter', function(e) { | |
if (e.target.matches('[data-uploader-drop]')) { | |
document.querySelectorAll('[data-uploader-overlay]').forEach(element => show(element)) | |
} | |
stop(e) | |
}, false) | |
document.addEventListener('dragleave', function(e) { | |
if (e.target.matches('[data-uploader-drop]')) { | |
document.querySelectorAll('[data-uploader-overlay]').forEach(element => hide(element)) | |
} | |
stop(e) | |
}, false) | |
document.addEventListener('dragover', function(e) { | |
// if we don't stop this, we don't get a drop event... | |
stop(e) | |
}, false) | |
document.addEventListener('drop', function(e) { | |
console.log('drop', e) | |
if (e.target.matches('[data-uploader-drop]')) { | |
document.querySelectorAll('[data-uploader-overlay]').forEach(element => hide(element)) | |
var files = Array.from(e.dataTransfer.files) | |
files.forEach(file => uploadFile(file)) | |
} | |
stop(e) | |
}, false) | |
window.livewire.on('onUploadedFile', function(name, uuid) { | |
console.log('file was uploaded', name, uuid) | |
current.isBusy = false | |
current.isComplete = true | |
current.uuid = uuid | |
current = undefined | |
updateStatus() | |
}) | |
}) | |
</script> | |
@endpush |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Http\Livewire; | |
class ShowWizard extends Component | |
{ | |
protected $listeners = [ | |
'onSelectType' => 'onSelectType', | |
'onSelectRepository' => 'onSelectRepository', | |
'onPrevious' => 'onPrevious', | |
'onNext' => 'onNext', | |
]; | |
public $show; | |
public $typeCacheUuid; | |
public $repositoriesCacheUuid; | |
public function mount() | |
{ | |
$this->show = session()->get('ShowWizard.step', 'select-type'); | |
$this->typeCacheUuid = session()->get('ShowWizard.typeCacheUuid', $this->uuid()); | |
$this->repositoriesCacheUuid = session()->get('ShowWizard.repositoriesCacheUuid', $this->uuid()); | |
// remember these if we just created them... | |
session()->put('ShowWizard.typeCacheUuid', $this->typeCacheUuid); | |
session()->put('ShowWizard.repositoriesCacheUuid', $this->repositoriesCacheUuid); | |
} | |
public function onSelectType($json, $checked) | |
{ | |
$data = json_decode($json); | |
$this->cache($this->typeCacheUuid)->set($data); | |
} | |
public function onSelectRepository($json, $checked) | |
{ | |
$data = json_decode($json); | |
$repositories = $this->cache($this->repositoriesCacheUuid)->get([], true); | |
if ($checked) { | |
$repositories[$data->name] = $data; | |
} else { | |
$repositories[$data->name] = null; | |
} | |
$this->cache($this->repositoriesCacheUuid)->set($repositories); | |
} | |
public function onPrevious() | |
{ | |
$type = $this->cache($this->typeCacheUuid)->get(); | |
if (in_array($this->show, ['select-repositories', 'upload-files'])) { | |
$this->show = 'select-type'; | |
} else if (in_array($this->show, ['select-provider']) and in_array($type->id, ['repositories-for-sale', 'repositories-for-email'])) { | |
$this->show = 'select-repositories'; | |
} else if (in_array($this->show, ['select-provider']) and in_array($type->id, ['files-for-sale', 'files-for-email'])) { | |
$this->show = 'upload-files'; | |
} else if (in_array($this->show, ['show-confirmation'])) { | |
$this->show = 'select-provider'; | |
} | |
session()->put('ShowWizard.step', $this->show); | |
} | |
public function onNext() | |
{ | |
$type = $this->cache($this->typeCacheUuid)->get(); | |
if (in_array($this->show, ['select-type']) and in_array($type->id, ['repositories-for-sale', 'repositories-for-email'])) { | |
$this->show = 'select-repositories'; | |
} else if (in_array($this->show, ['select-type']) and in_array($type->id, ['files-for-sale', 'files-for-email'])) { | |
$this->show = 'upload-files'; | |
} else if (in_array($this->show, ['select-repositories'])) { | |
$this->show = 'select-provider'; | |
} else if (in_array($this->show, ['select-provider'])) { | |
$this->show = 'show-confirmation'; | |
} | |
session()->put('ShowWizard.step', $this->show); | |
} | |
public function flush() | |
{ | |
cache()->flush(); | |
session()->flush(); | |
$this->redirect(route('show-wizard')); | |
} | |
public function render() | |
{ | |
$type = $this->cache($this->typeCacheUuid)->get(); | |
$repositories = $this->cache($this->repositoriesCacheUuid)->get([], true); | |
return view('livewire.show-wizard', compact('type', 'repositories')); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div data-uploader-drop class="flex flex-col w-full h-screen"> | |
<h1 class="text-xl">Upload files</h1> | |
<div data-uploader-status class="flex flex-row flex-wrap w-full"> </div> | |
<div class="my-2"> | |
<button wire:click="$emit('onPrevious')" class="bg-gray-900 text-white px-2 py-1">Previous</button> | |
@if(count($uploaded) > 0) | |
<button wire:click="$emit('onNext')" class="bg-gray-900 text-white px-2 py-1">Next</button> | |
@endif | |
</div> | |
<div data-uploader-overlay class="hidden absolute top-0 right-0 bottom-0 left-0 bg-white opacity-75 pointer-events-none"> </div> | |
<div data-uploader-overlay class="hidden items-center justify-center absolute top-0 right-0 bottom-0 left-0 pointer-events-none"> | |
<div class="flex text-3xl text-black text-semibold pointer-events-none">Drop files to upload</div> | |
</div> | |
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Http\Livewire; | |
class UploadFiles extends Component | |
{ | |
protected $listeners = [ | |
'onUploadFile' => 'onUploadFile', | |
]; | |
public $uploadedCacheUuid; | |
public function mount($uploaded = []) | |
{ | |
$this->uploadedCacheUuid = session()->get('UploadFiles.uploadedCacheUuid', $this->uuid()); | |
// remember these if we just created them... | |
session()->put('UploadFiles.uploadedCacheUuid', $this->uploadedCacheUuid); | |
$this->cache($this->uploadedCacheUuid)->set($uploaded); | |
} | |
public function onUploadFile($name, $type, $size, $data) | |
{ | |
$uuid = $this->uuid(); | |
sleep(5); | |
$this->emit('onUploadedFile', $name, $uuid); | |
} | |
public function render() | |
{ | |
$uploaded = $this->cache($this->uploadedCacheUuid)->get([], true); | |
return view('livewire.upload-files', compact('uploaded')); | |
} | |
} |