Compare commits
4 commits
1b6a9956c5
...
dcdb3d87be
Author | SHA1 | Date | |
---|---|---|---|
dcdb3d87be | |||
d061110d88 | |||
fed63118d0 | |||
c12221dd9c |
7 changed files with 600 additions and 149 deletions
|
@ -3,6 +3,7 @@ from django.conf import settings
|
|||
|
||||
from .models import Think
|
||||
|
||||
|
||||
class CreateThinkForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Think
|
||||
|
@ -15,11 +16,13 @@ class CreateThinkForm(forms.ModelForm):
|
|||
instance.root.mkdir(exist_ok=True,parents=True)
|
||||
return instance
|
||||
|
||||
|
||||
class RemixThinkForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Think
|
||||
fields = []
|
||||
|
||||
|
||||
class RenameThinkForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Think
|
||||
|
@ -49,6 +52,7 @@ class RenameThinkForm(forms.ModelForm):
|
|||
instance = super().save(commit)
|
||||
return instance
|
||||
|
||||
|
||||
class SaveFileForm(forms.ModelForm):
|
||||
path = forms.CharField()
|
||||
content = forms.CharField(required=False, widget=forms.Textarea)
|
||||
|
@ -72,6 +76,7 @@ class SaveFileForm(forms.ModelForm):
|
|||
|
||||
return super().save(commit)
|
||||
|
||||
|
||||
class RenameFileForm(forms.ModelForm):
|
||||
path = forms.CharField()
|
||||
newpath = forms.CharField()
|
||||
|
@ -100,6 +105,7 @@ class RenameFileForm(forms.ModelForm):
|
|||
|
||||
return super().save(commit)
|
||||
|
||||
|
||||
class DeleteFileForm(forms.ModelForm):
|
||||
path = forms.CharField()
|
||||
|
||||
|
@ -121,6 +127,7 @@ class DeleteFileForm(forms.ModelForm):
|
|||
|
||||
return super().save(commit)
|
||||
|
||||
|
||||
class RunCommandForm(forms.ModelForm):
|
||||
command = forms.CharField()
|
||||
|
||||
|
@ -128,9 +135,51 @@ class RunCommandForm(forms.ModelForm):
|
|||
model = Think
|
||||
fields = []
|
||||
|
||||
|
||||
class GitCommitForm(forms.ModelForm):
|
||||
message = forms.CharField()
|
||||
|
||||
class Meta:
|
||||
model = Think
|
||||
fields = []
|
||||
|
||||
|
||||
class MultipleFileInput(forms.ClearableFileInput):
|
||||
allow_multiple_selected = True
|
||||
|
||||
|
||||
class MultipleFileField(forms.FileField):
|
||||
def __init__(self, *args, **kwargs):
|
||||
kwargs.setdefault("widget", MultipleFileInput())
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def clean(self, data, initial=None):
|
||||
single_file_clean = super().clean
|
||||
if isinstance(data, (list, tuple)):
|
||||
result = [single_file_clean(d, initial) for d in data]
|
||||
else:
|
||||
result = [single_file_clean(data, initial)]
|
||||
return result
|
||||
|
||||
|
||||
class UploadFileForm(forms.ModelForm):
|
||||
files = MultipleFileField()
|
||||
|
||||
class Meta:
|
||||
model = Think
|
||||
fields = []
|
||||
|
||||
|
||||
def save(self, commit=False):
|
||||
think = self.instance
|
||||
|
||||
files = self.cleaned_data['files']
|
||||
|
||||
for uf in files:
|
||||
path = think.file_path(uf.name)
|
||||
print(uf, path)
|
||||
with open(path, 'wb') as df:
|
||||
for chunk in uf.chunks():
|
||||
df.write(chunk)
|
||||
|
||||
return super().save(commit)
|
||||
|
|
|
@ -26,14 +26,19 @@ class JJController:
|
|||
)
|
||||
return res
|
||||
|
||||
def init_jj(self):
|
||||
def init_jj(self, force=False):
|
||||
print("Init jj")
|
||||
if not (self.root / '.jj').exists():
|
||||
res = self.run(['jj','git','remote','list'])
|
||||
if force or not (self.root / '.jj').exists():
|
||||
self.run(['jj','git','init'])
|
||||
self.ignore_paths(['.make.*'])
|
||||
git_url = settings.GIT_REPO_URL_TEMPLATE.format(name=self.think.slug)
|
||||
self.run(['jj','git','remote','add','origin', git_url])
|
||||
|
||||
def clean_paths(self, paths):
|
||||
paths = [self.root / p for p in paths]
|
||||
return [str(p.relative_to(self.root)) for p in paths if p.is_relative_to(self.root)]
|
||||
|
||||
@ensure_jj
|
||||
def ignore_paths(self, paths):
|
||||
paths = self.clean_paths(paths)
|
||||
|
|
|
@ -109,8 +109,12 @@ input:not([type="hidden"]) ~ button {
|
|||
|
||||
input {
|
||||
border: thin solid currentColor;
|
||||
height: 100%;
|
||||
background: var(--default-background);
|
||||
}
|
||||
input[type="file"] {
|
||||
font-size: 0.66rem;
|
||||
}
|
||||
|
||||
|
||||
.field {
|
||||
display: flex;
|
||||
|
@ -239,6 +243,12 @@ input {
|
|||
z-index: 1;
|
||||
}
|
||||
|
||||
& #file-form {
|
||||
& > :is(img,video) {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
& code-editor {
|
||||
background: var(--default-background);
|
||||
display: block;
|
||||
|
|
|
@ -5546,7 +5546,9 @@ var $author$project$App$Model = function (show_preview) {
|
|||
return function (file_content) {
|
||||
return function (is_dir) {
|
||||
return function (elm_packages) {
|
||||
return {command_to_run: command_to_run, commit_message: commit_message, content_changed: content_changed, csrf_token: csrf_token, editor_size: editor_size, elm_packages: elm_packages, file_content: file_content, file_path: file_path, files: files, is_dir: is_dir, jj_status: jj_status, log: log, preview_url: preview_url, selected_package: selected_package, show_log: show_log, show_preview: show_preview, slug: slug};
|
||||
return function (mime_type) {
|
||||
return {command_to_run: command_to_run, commit_message: commit_message, content_changed: content_changed, csrf_token: csrf_token, editor_size: editor_size, elm_packages: elm_packages, file_content: file_content, file_path: file_path, files: files, is_dir: is_dir, jj_status: jj_status, log: log, mime_type: mime_type, preview_url: preview_url, selected_package: selected_package, show_log: show_log, show_preview: show_preview, slug: slug};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -5564,6 +5566,10 @@ var $author$project$App$Model = function (show_preview) {
|
|||
};
|
||||
};
|
||||
};
|
||||
var $danyx23$elm_mimetype$MimeType$PlainText = {$: 'PlainText'};
|
||||
var $danyx23$elm_mimetype$MimeType$Text = function (a) {
|
||||
return {$: 'Text', a: a};
|
||||
};
|
||||
var $elm_community$json_extra$Json$Decode$Extra$andMap = $elm$json$Json$Decode$map2($elm$core$Basics$apR);
|
||||
var $elm$json$Json$Decode$bool = _Json_decodeBool;
|
||||
var $elm$core$Basics$composeR = F3(
|
||||
|
@ -5597,8 +5603,201 @@ var $author$project$App$decode_file_info = A4(
|
|||
A2($elm$json$Json$Decode$field, 'name', $elm$json$Json$Decode$string),
|
||||
A2($elm$json$Json$Decode$field, 'is_dir', $elm$json$Json$Decode$bool),
|
||||
A2($elm$json$Json$Decode$field, 'path', $elm$json$Json$Decode$string));
|
||||
var $danyx23$elm_mimetype$MimeType$App = function (a) {
|
||||
return {$: 'App', a: a};
|
||||
};
|
||||
var $danyx23$elm_mimetype$MimeType$Audio = function (a) {
|
||||
return {$: 'Audio', a: a};
|
||||
};
|
||||
var $danyx23$elm_mimetype$MimeType$Avi = {$: 'Avi'};
|
||||
var $danyx23$elm_mimetype$MimeType$Css = {$: 'Css'};
|
||||
var $danyx23$elm_mimetype$MimeType$Excel = {$: 'Excel'};
|
||||
var $danyx23$elm_mimetype$MimeType$ExcelXml = {$: 'ExcelXml'};
|
||||
var $danyx23$elm_mimetype$MimeType$Gif = {$: 'Gif'};
|
||||
var $danyx23$elm_mimetype$MimeType$Html = {$: 'Html'};
|
||||
var $danyx23$elm_mimetype$MimeType$Image = function (a) {
|
||||
return {$: 'Image', a: a};
|
||||
};
|
||||
var $danyx23$elm_mimetype$MimeType$Jpeg = {$: 'Jpeg'};
|
||||
var $danyx23$elm_mimetype$MimeType$Json = {$: 'Json'};
|
||||
var $danyx23$elm_mimetype$MimeType$Mp3 = {$: 'Mp3'};
|
||||
var $danyx23$elm_mimetype$MimeType$Mp4 = {$: 'Mp4'};
|
||||
var $danyx23$elm_mimetype$MimeType$Mpeg = {$: 'Mpeg'};
|
||||
var $danyx23$elm_mimetype$MimeType$Ogg = {$: 'Ogg'};
|
||||
var $danyx23$elm_mimetype$MimeType$OtherAudio = function (a) {
|
||||
return {$: 'OtherAudio', a: a};
|
||||
};
|
||||
var $danyx23$elm_mimetype$MimeType$OtherImage = function (a) {
|
||||
return {$: 'OtherImage', a: a};
|
||||
};
|
||||
var $danyx23$elm_mimetype$MimeType$OtherMimeType = function (a) {
|
||||
return {$: 'OtherMimeType', a: a};
|
||||
};
|
||||
var $danyx23$elm_mimetype$MimeType$OtherText = function (a) {
|
||||
return {$: 'OtherText', a: a};
|
||||
};
|
||||
var $danyx23$elm_mimetype$MimeType$OtherVideo = function (a) {
|
||||
return {$: 'OtherVideo', a: a};
|
||||
};
|
||||
var $danyx23$elm_mimetype$MimeType$Pdf = {$: 'Pdf'};
|
||||
var $danyx23$elm_mimetype$MimeType$Png = {$: 'Png'};
|
||||
var $danyx23$elm_mimetype$MimeType$PowerPoint = {$: 'PowerPoint'};
|
||||
var $danyx23$elm_mimetype$MimeType$PowerPointXml = {$: 'PowerPointXml'};
|
||||
var $danyx23$elm_mimetype$MimeType$Quicktime = {$: 'Quicktime'};
|
||||
var $danyx23$elm_mimetype$MimeType$Video = function (a) {
|
||||
return {$: 'Video', a: a};
|
||||
};
|
||||
var $danyx23$elm_mimetype$MimeType$Wav = {$: 'Wav'};
|
||||
var $danyx23$elm_mimetype$MimeType$Webm = {$: 'Webm'};
|
||||
var $danyx23$elm_mimetype$MimeType$Word = {$: 'Word'};
|
||||
var $danyx23$elm_mimetype$MimeType$WordXml = {$: 'WordXml'};
|
||||
var $danyx23$elm_mimetype$MimeType$Xml = {$: 'Xml'};
|
||||
var $elm$core$String$toLower = _String_toLower;
|
||||
var $danyx23$elm_mimetype$MimeType$parseMimeType = function (mimeString) {
|
||||
var _v0 = $elm$core$String$toLower(mimeString);
|
||||
switch (_v0) {
|
||||
case '':
|
||||
return $elm$core$Maybe$Nothing;
|
||||
case 'image/jpeg':
|
||||
return $elm$core$Maybe$Just(
|
||||
$danyx23$elm_mimetype$MimeType$Image($danyx23$elm_mimetype$MimeType$Jpeg));
|
||||
case 'image/png':
|
||||
return $elm$core$Maybe$Just(
|
||||
$danyx23$elm_mimetype$MimeType$Image($danyx23$elm_mimetype$MimeType$Png));
|
||||
case 'image/gif':
|
||||
return $elm$core$Maybe$Just(
|
||||
$danyx23$elm_mimetype$MimeType$Image($danyx23$elm_mimetype$MimeType$Gif));
|
||||
case 'audio/mp3':
|
||||
return $elm$core$Maybe$Just(
|
||||
$danyx23$elm_mimetype$MimeType$Audio($danyx23$elm_mimetype$MimeType$Mp3));
|
||||
case 'audio/mpeg':
|
||||
return $elm$core$Maybe$Just(
|
||||
$danyx23$elm_mimetype$MimeType$Audio($danyx23$elm_mimetype$MimeType$Mp3));
|
||||
case 'audio/wav':
|
||||
return $elm$core$Maybe$Just(
|
||||
$danyx23$elm_mimetype$MimeType$Audio($danyx23$elm_mimetype$MimeType$Wav));
|
||||
case 'audio/ogg':
|
||||
return $elm$core$Maybe$Just(
|
||||
$danyx23$elm_mimetype$MimeType$Audio($danyx23$elm_mimetype$MimeType$Ogg));
|
||||
case 'video/mp4':
|
||||
return $elm$core$Maybe$Just(
|
||||
$danyx23$elm_mimetype$MimeType$Video($danyx23$elm_mimetype$MimeType$Mp4));
|
||||
case 'video/mpeg':
|
||||
return $elm$core$Maybe$Just(
|
||||
$danyx23$elm_mimetype$MimeType$Video($danyx23$elm_mimetype$MimeType$Mpeg));
|
||||
case 'video/quicktime':
|
||||
return $elm$core$Maybe$Just(
|
||||
$danyx23$elm_mimetype$MimeType$Video($danyx23$elm_mimetype$MimeType$Quicktime));
|
||||
case 'video/avi':
|
||||
return $elm$core$Maybe$Just(
|
||||
$danyx23$elm_mimetype$MimeType$Video($danyx23$elm_mimetype$MimeType$Avi));
|
||||
case 'video/webm':
|
||||
return $elm$core$Maybe$Just(
|
||||
$danyx23$elm_mimetype$MimeType$Video($danyx23$elm_mimetype$MimeType$Webm));
|
||||
case 'text/plain':
|
||||
return $elm$core$Maybe$Just(
|
||||
$danyx23$elm_mimetype$MimeType$Text($danyx23$elm_mimetype$MimeType$PlainText));
|
||||
case 'text/html':
|
||||
return $elm$core$Maybe$Just(
|
||||
$danyx23$elm_mimetype$MimeType$Text($danyx23$elm_mimetype$MimeType$Html));
|
||||
case 'text/css':
|
||||
return $elm$core$Maybe$Just(
|
||||
$danyx23$elm_mimetype$MimeType$Text($danyx23$elm_mimetype$MimeType$Css));
|
||||
case 'text/xml':
|
||||
return $elm$core$Maybe$Just(
|
||||
$danyx23$elm_mimetype$MimeType$Text($danyx23$elm_mimetype$MimeType$Xml));
|
||||
case 'application/json':
|
||||
return $elm$core$Maybe$Just(
|
||||
$danyx23$elm_mimetype$MimeType$Text($danyx23$elm_mimetype$MimeType$Json));
|
||||
case 'application/msword':
|
||||
return $elm$core$Maybe$Just(
|
||||
$danyx23$elm_mimetype$MimeType$App($danyx23$elm_mimetype$MimeType$Word));
|
||||
case 'application/vnd.openxmlformats-officedocument.wordprocessingml.document':
|
||||
return $elm$core$Maybe$Just(
|
||||
$danyx23$elm_mimetype$MimeType$App($danyx23$elm_mimetype$MimeType$WordXml));
|
||||
case 'application/vnd.ms-excel':
|
||||
return $elm$core$Maybe$Just(
|
||||
$danyx23$elm_mimetype$MimeType$App($danyx23$elm_mimetype$MimeType$Excel));
|
||||
case 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet':
|
||||
return $elm$core$Maybe$Just(
|
||||
$danyx23$elm_mimetype$MimeType$App($danyx23$elm_mimetype$MimeType$ExcelXml));
|
||||
case 'application/vnd.ms-powerpoint':
|
||||
return $elm$core$Maybe$Just(
|
||||
$danyx23$elm_mimetype$MimeType$App($danyx23$elm_mimetype$MimeType$PowerPoint));
|
||||
case 'application/vnd.openxmlformats-officedocument.presentationml.presentation':
|
||||
return $elm$core$Maybe$Just(
|
||||
$danyx23$elm_mimetype$MimeType$App($danyx23$elm_mimetype$MimeType$PowerPointXml));
|
||||
case 'application/pdf':
|
||||
return $elm$core$Maybe$Just(
|
||||
$danyx23$elm_mimetype$MimeType$App($danyx23$elm_mimetype$MimeType$Pdf));
|
||||
default:
|
||||
var lowerCaseMimeString = _v0;
|
||||
return A2($elm$core$String$startsWith, 'image/', lowerCaseMimeString) ? $elm$core$Maybe$Just(
|
||||
$danyx23$elm_mimetype$MimeType$Image(
|
||||
$danyx23$elm_mimetype$MimeType$OtherImage(
|
||||
A2(
|
||||
$elm$core$String$dropLeft,
|
||||
$elm$core$String$length('image/'),
|
||||
lowerCaseMimeString)))) : (A2($elm$core$String$startsWith, 'audio/', lowerCaseMimeString) ? $elm$core$Maybe$Just(
|
||||
$danyx23$elm_mimetype$MimeType$Audio(
|
||||
$danyx23$elm_mimetype$MimeType$OtherAudio(
|
||||
A2(
|
||||
$elm$core$String$dropLeft,
|
||||
$elm$core$String$length('audio/'),
|
||||
lowerCaseMimeString)))) : (A2($elm$core$String$startsWith, 'video/', lowerCaseMimeString) ? $elm$core$Maybe$Just(
|
||||
$danyx23$elm_mimetype$MimeType$Video(
|
||||
$danyx23$elm_mimetype$MimeType$OtherVideo(
|
||||
A2(
|
||||
$elm$core$String$dropLeft,
|
||||
$elm$core$String$length('video/'),
|
||||
lowerCaseMimeString)))) : (A2($elm$core$String$startsWith, 'text/', lowerCaseMimeString) ? $elm$core$Maybe$Just(
|
||||
$danyx23$elm_mimetype$MimeType$Text(
|
||||
$danyx23$elm_mimetype$MimeType$OtherText(
|
||||
A2(
|
||||
$elm$core$String$dropLeft,
|
||||
$elm$core$String$length('text/'),
|
||||
lowerCaseMimeString)))) : $elm$core$Maybe$Just(
|
||||
$danyx23$elm_mimetype$MimeType$OtherMimeType(lowerCaseMimeString)))));
|
||||
}
|
||||
};
|
||||
var $elm$core$Maybe$withDefault = F2(
|
||||
function (_default, maybe) {
|
||||
if (maybe.$ === 'Just') {
|
||||
var value = maybe.a;
|
||||
return value;
|
||||
} else {
|
||||
return _default;
|
||||
}
|
||||
});
|
||||
var $author$project$App$decode_mime_type = A2(
|
||||
$elm$json$Json$Decode$map,
|
||||
A2(
|
||||
$elm$core$Basics$composeR,
|
||||
$danyx23$elm_mimetype$MimeType$parseMimeType,
|
||||
$elm$core$Maybe$withDefault(
|
||||
$danyx23$elm_mimetype$MimeType$Text($danyx23$elm_mimetype$MimeType$PlainText))),
|
||||
$elm$json$Json$Decode$string);
|
||||
var $author$project$App$NotLoaded = {$: 'NotLoaded'};
|
||||
var $author$project$App$init_model = {command_to_run: '', commit_message: '', content_changed: false, csrf_token: '', editor_size: 0.5, elm_packages: _List_Nil, file_content: 'The editor has not loaded successfully.', file_path: 'Oops!', files: _List_Nil, is_dir: false, jj_status: '', log: $author$project$App$NotLoaded, preview_url: '', selected_package: '', show_log: false, show_preview: true, slug: 'not-a-real-thing'};
|
||||
var $author$project$App$init_model = {
|
||||
command_to_run: '',
|
||||
commit_message: '',
|
||||
content_changed: false,
|
||||
csrf_token: '',
|
||||
editor_size: 0.5,
|
||||
elm_packages: _List_Nil,
|
||||
file_content: 'The editor has not loaded successfully.',
|
||||
file_path: 'Oops!',
|
||||
files: _List_Nil,
|
||||
is_dir: false,
|
||||
jj_status: '',
|
||||
log: $author$project$App$NotLoaded,
|
||||
mime_type: $danyx23$elm_mimetype$MimeType$Text($danyx23$elm_mimetype$MimeType$PlainText),
|
||||
preview_url: '',
|
||||
selected_package: '',
|
||||
show_log: false,
|
||||
show_preview: true,
|
||||
slug: 'not-a-real-thing'
|
||||
};
|
||||
var $elm$json$Json$Decode$list = _Json_decodeList;
|
||||
var $elm$json$Json$Decode$oneOf = _Json_oneOf;
|
||||
var $elm$core$Result$withDefault = F2(
|
||||
|
@ -5618,38 +5817,52 @@ var $author$project$App$load_flags = A2(
|
|||
$elm$json$Json$Decode$oneOf(
|
||||
_List_fromArray(
|
||||
[
|
||||
A2(
|
||||
$elm$json$Json$Decode$field,
|
||||
'elm_packages',
|
||||
$elm$json$Json$Decode$list($author$project$App$decode_elm_package)),
|
||||
$elm$json$Json$Decode$succeed(_List_Nil)
|
||||
A2($elm$json$Json$Decode$field, 'mime_type', $author$project$App$decode_mime_type),
|
||||
$elm$json$Json$Decode$succeed(
|
||||
$danyx23$elm_mimetype$MimeType$Text($danyx23$elm_mimetype$MimeType$PlainText))
|
||||
])),
|
||||
A2(
|
||||
$elm_community$json_extra$Json$Decode$Extra$andMap,
|
||||
A2($elm$json$Json$Decode$field, 'is_dir', $elm$json$Json$Decode$bool),
|
||||
$elm$json$Json$Decode$oneOf(
|
||||
_List_fromArray(
|
||||
[
|
||||
A2(
|
||||
$elm$json$Json$Decode$field,
|
||||
'elm_packages',
|
||||
$elm$json$Json$Decode$list($author$project$App$decode_elm_package)),
|
||||
$elm$json$Json$Decode$succeed(_List_Nil)
|
||||
])),
|
||||
A2(
|
||||
$elm_community$json_extra$Json$Decode$Extra$andMap,
|
||||
A2($elm$json$Json$Decode$field, 'file_content', $elm$json$Json$Decode$string),
|
||||
A2($elm$json$Json$Decode$field, 'is_dir', $elm$json$Json$Decode$bool),
|
||||
A2(
|
||||
$elm_community$json_extra$Json$Decode$Extra$andMap,
|
||||
A2($elm$json$Json$Decode$field, 'file_path', $elm$json$Json$Decode$string),
|
||||
$elm$json$Json$Decode$oneOf(
|
||||
_List_fromArray(
|
||||
[
|
||||
A2($elm$json$Json$Decode$field, 'file_content', $elm$json$Json$Decode$string),
|
||||
$elm$json$Json$Decode$succeed('')
|
||||
])),
|
||||
A2(
|
||||
$elm_community$json_extra$Json$Decode$Extra$andMap,
|
||||
A2(
|
||||
$elm$json$Json$Decode$field,
|
||||
'files',
|
||||
$elm$json$Json$Decode$list($author$project$App$decode_file_info)),
|
||||
A2($elm$json$Json$Decode$field, 'file_path', $elm$json$Json$Decode$string),
|
||||
A2(
|
||||
$elm_community$json_extra$Json$Decode$Extra$andMap,
|
||||
A2($elm$json$Json$Decode$field, 'slug', $elm$json$Json$Decode$string),
|
||||
A2(
|
||||
$elm$json$Json$Decode$field,
|
||||
'files',
|
||||
$elm$json$Json$Decode$list($author$project$App$decode_file_info)),
|
||||
A2(
|
||||
$elm_community$json_extra$Json$Decode$Extra$andMap,
|
||||
A2($elm$json$Json$Decode$field, 'preview_url', $elm$json$Json$Decode$string),
|
||||
A2($elm$json$Json$Decode$field, 'slug', $elm$json$Json$Decode$string),
|
||||
A2(
|
||||
$elm_community$json_extra$Json$Decode$Extra$andMap,
|
||||
A2($elm$json$Json$Decode$field, 'csrf_token', $elm$json$Json$Decode$string),
|
||||
$elm$json$Json$Decode$succeed(
|
||||
A9($author$project$App$Model, $author$project$App$init_model.show_preview, $author$project$App$init_model.show_log, $author$project$App$init_model.editor_size, $author$project$App$init_model.content_changed, $author$project$App$init_model.log, $author$project$App$init_model.command_to_run, $author$project$App$init_model.selected_package, $author$project$App$init_model.jj_status, $author$project$App$init_model.commit_message))))))))))),
|
||||
A2($elm$json$Json$Decode$field, 'preview_url', $elm$json$Json$Decode$string),
|
||||
A2(
|
||||
$elm_community$json_extra$Json$Decode$Extra$andMap,
|
||||
A2($elm$json$Json$Decode$field, 'csrf_token', $elm$json$Json$Decode$string),
|
||||
$elm$json$Json$Decode$succeed(
|
||||
A9($author$project$App$Model, $author$project$App$init_model.show_preview, $author$project$App$init_model.show_log, $author$project$App$init_model.editor_size, $author$project$App$init_model.content_changed, $author$project$App$init_model.log, $author$project$App$init_model.command_to_run, $author$project$App$init_model.selected_package, $author$project$App$init_model.jj_status, $author$project$App$init_model.commit_message)))))))))))),
|
||||
$elm$core$Result$withDefault($author$project$App$init_model));
|
||||
var $author$project$App$SetLog = function (a) {
|
||||
return {$: 'SetLog', a: a};
|
||||
|
@ -6447,8 +6660,8 @@ var $author$project$App$FileSaved = F2(
|
|||
function (a, b) {
|
||||
return {$: 'FileSaved', a: a, b: b};
|
||||
});
|
||||
var $author$project$App$FileUploaded = function (a) {
|
||||
return {$: 'FileUploaded', a: a};
|
||||
var $author$project$App$FilesUploaded = function (a) {
|
||||
return {$: 'FilesUploaded', a: a};
|
||||
};
|
||||
var $author$project$App$HttpError = function (a) {
|
||||
return {$: 'HttpError', a: a};
|
||||
|
@ -6480,10 +6693,6 @@ var $author$project$App$SaveContent = function (a) {
|
|||
var $author$project$App$SetFileContent = function (a) {
|
||||
return {$: 'SetFileContent', a: a};
|
||||
};
|
||||
var $author$project$App$UploadFile = F2(
|
||||
function (a, b) {
|
||||
return {$: 'UploadFile', a: a, b: b};
|
||||
});
|
||||
var $elm$core$Platform$Cmd$batch = _Platform_batch;
|
||||
var $author$project$App$decode_command_response = $elm$json$Json$Decode$oneOf(
|
||||
_List_fromArray(
|
||||
|
@ -6563,6 +6772,7 @@ var $author$project$App$fetch_jj_status = $elm$http$Http$get(
|
|||
A2($elm$json$Json$Decode$field, 'status', $elm$json$Json$Decode$string)),
|
||||
url: 'jj/status'
|
||||
});
|
||||
var $elm$http$Http$filePart = _Http_pair;
|
||||
var $elm$url$Url$Builder$toQueryPair = function (_v0) {
|
||||
var key = _v0.a;
|
||||
var value = _v0.b;
|
||||
|
@ -6764,10 +6974,10 @@ var $author$project$App$update = F2(
|
|||
case 'DropFiles':
|
||||
var action = msg.a;
|
||||
var files = msg.b;
|
||||
var _v3 = $elm$core$List$head(files);
|
||||
if (_v3.$ === 'Just') {
|
||||
var file = _v3.a;
|
||||
if (action.$ === 'Content') {
|
||||
if (action.$ === 'Content') {
|
||||
var _v4 = $elm$core$List$head(files);
|
||||
if (_v4.$ === 'Just') {
|
||||
var file = _v4.a;
|
||||
return _Utils_Tuple2(
|
||||
model,
|
||||
A2(
|
||||
|
@ -6775,51 +6985,47 @@ var $author$project$App$update = F2(
|
|||
$author$project$App$SetFileContent,
|
||||
$elm$file$File$toString(file)));
|
||||
} else {
|
||||
return _Utils_Tuple2(
|
||||
model,
|
||||
A2(
|
||||
$elm$core$Task$perform,
|
||||
$author$project$App$UploadFile(file),
|
||||
$elm$file$File$toString(file)));
|
||||
return _Utils_Tuple2(model, $elm$core$Platform$Cmd$none);
|
||||
}
|
||||
} else {
|
||||
return _Utils_Tuple2(model, $elm$core$Platform$Cmd$none);
|
||||
}
|
||||
case 'UploadFile':
|
||||
var file = msg.a;
|
||||
var contents = msg.b;
|
||||
return _Utils_Tuple2(
|
||||
model,
|
||||
$elm$http$Http$post(
|
||||
{
|
||||
body: $elm$http$Http$multipartBody(
|
||||
_List_fromArray(
|
||||
[
|
||||
return _Utils_Tuple2(
|
||||
model,
|
||||
$elm$http$Http$post(
|
||||
{
|
||||
body: $elm$http$Http$multipartBody(
|
||||
_Utils_ap(
|
||||
_List_fromArray(
|
||||
[
|
||||
A2($elm$http$Http$stringPart, 'csrfmiddlewaretoken', model.csrf_token)
|
||||
]),
|
||||
A2(
|
||||
$elm$http$Http$stringPart,
|
||||
'path',
|
||||
$elm$file$File$name(file)),
|
||||
A2($elm$http$Http$stringPart, 'content', contents),
|
||||
A2($elm$http$Http$stringPart, 'csrfmiddlewaretoken', model.csrf_token)
|
||||
])),
|
||||
expect: $elm$http$Http$expectWhatever(
|
||||
function (r) {
|
||||
if (r.$ === 'Ok') {
|
||||
return $author$project$App$FileUploaded(file);
|
||||
} else {
|
||||
return $author$project$App$NoOp;
|
||||
}
|
||||
}),
|
||||
url: 'save-file'
|
||||
}));
|
||||
case 'FileUploaded':
|
||||
var file = msg.a;
|
||||
var name = $elm$file$File$name(file);
|
||||
var url = $author$project$App$file_edit_url(
|
||||
{is_dir: false, name: name, path: name});
|
||||
return _Utils_Tuple2(
|
||||
model,
|
||||
$elm$browser$Browser$Navigation$load(url));
|
||||
$elm$core$List$map,
|
||||
$elm$http$Http$filePart('files'),
|
||||
files))),
|
||||
expect: $elm$http$Http$expectWhatever(
|
||||
function (r) {
|
||||
if (r.$ === 'Ok') {
|
||||
return $author$project$App$FilesUploaded(files);
|
||||
} else {
|
||||
return $author$project$App$NoOp;
|
||||
}
|
||||
}),
|
||||
url: 'upload-files'
|
||||
}));
|
||||
}
|
||||
case 'FilesUploaded':
|
||||
var files = msg.a;
|
||||
if (files.b) {
|
||||
var file = files.a;
|
||||
var name = $elm$file$File$name(file);
|
||||
var url = $author$project$App$file_edit_url(
|
||||
{is_dir: false, name: name, path: name});
|
||||
return _Utils_Tuple2(
|
||||
model,
|
||||
$elm$browser$Browser$Navigation$load(url));
|
||||
} else {
|
||||
return $author$project$App$nocmd(model);
|
||||
}
|
||||
case 'SetCommand':
|
||||
var cmd = msg.a;
|
||||
return $author$project$App$nocmd(
|
||||
|
@ -7184,12 +7390,14 @@ var $author$project$App$DropFiles = F2(
|
|||
function (a, b) {
|
||||
return {$: 'DropFiles', a: a, b: b};
|
||||
});
|
||||
var $elm$html$Html$a = _VirtualDom_node('a');
|
||||
var $elm$html$Html$Attributes$action = function (uri) {
|
||||
return A2(
|
||||
$elm$html$Html$Attributes$stringProperty,
|
||||
'action',
|
||||
_VirtualDom_noJavaScriptUri(uri));
|
||||
};
|
||||
var $elm$html$Html$audio = _VirtualDom_node('audio');
|
||||
var $elm$file$File$decoder = _File_decoder;
|
||||
var $elm$html$Html$details = _VirtualDom_node('details');
|
||||
var $elm$core$List$drop = F2(
|
||||
|
@ -7247,6 +7455,13 @@ var $elm$core$Dict$fromList = function (assocs) {
|
|||
$elm$core$Dict$empty,
|
||||
assocs);
|
||||
};
|
||||
var $elm$html$Html$Attributes$href = function (url) {
|
||||
return A2(
|
||||
$elm$html$Html$Attributes$stringProperty,
|
||||
'href',
|
||||
_VirtualDom_noJavaScriptUri(url));
|
||||
};
|
||||
var $elm$html$Html$img = _VirtualDom_node('img');
|
||||
var $elm$html$Html$nav = _VirtualDom_node('nav');
|
||||
var $elm$virtual_dom$VirtualDom$MayPreventDefault = function (a) {
|
||||
return {$: 'MayPreventDefault', a: a};
|
||||
|
@ -7260,16 +7475,14 @@ var $elm$html$Html$Events$preventDefaultOn = F2(
|
|||
});
|
||||
var $elm$html$Html$section = _VirtualDom_node('section');
|
||||
var $elm$html$Html$span = _VirtualDom_node('span');
|
||||
var $elm$html$Html$Attributes$src = function (url) {
|
||||
return A2(
|
||||
$elm$html$Html$Attributes$stringProperty,
|
||||
'src',
|
||||
_VirtualDom_noJavaScriptOrHtmlUri(url));
|
||||
};
|
||||
var $elm$html$Html$summary = _VirtualDom_node('summary');
|
||||
var $elm$core$Maybe$withDefault = F2(
|
||||
function (_default, maybe) {
|
||||
if (maybe.$ === 'Just') {
|
||||
var value = maybe.a;
|
||||
return value;
|
||||
} else {
|
||||
return _default;
|
||||
}
|
||||
});
|
||||
var $elm$html$Html$video = _VirtualDom_node('video');
|
||||
var $author$project$App$editor_pane = function (model) {
|
||||
var languages = $elm$core$Dict$fromList(
|
||||
_List_fromArray(
|
||||
|
@ -7281,6 +7494,7 @@ var $author$project$App$editor_pane = function (model) {
|
|||
_Utils_Tuple2('R', 'r'),
|
||||
_Utils_Tuple2('elm', 'elm')
|
||||
]));
|
||||
var file_path = 'file/' + model.file_path;
|
||||
var extension = A2(
|
||||
$elm$core$Maybe$withDefault,
|
||||
'',
|
||||
|
@ -7448,57 +7662,111 @@ var $author$project$App$editor_pane = function (model) {
|
|||
$elm$html$Html$Attributes$method('POST'),
|
||||
$elm$html$Html$Attributes$action('save-file')
|
||||
]),
|
||||
_List_fromArray(
|
||||
[
|
||||
A3(
|
||||
$elm$html$Html$node,
|
||||
'code-editor',
|
||||
_List_fromArray(
|
||||
[
|
||||
A2(
|
||||
$elm$html$Html$Events$on,
|
||||
'change',
|
||||
A2(
|
||||
$elm$json$Json$Decode$map,
|
||||
$author$project$App$SetFileContent,
|
||||
function () {
|
||||
var _v0 = model.mime_type;
|
||||
switch (_v0.$) {
|
||||
case 'Text':
|
||||
return _List_fromArray(
|
||||
[
|
||||
A3(
|
||||
$elm$html$Html$node,
|
||||
'code-editor',
|
||||
_List_fromArray(
|
||||
[
|
||||
A2(
|
||||
$elm$html$Html$Events$on,
|
||||
'change',
|
||||
A2(
|
||||
$elm$json$Json$Decode$map,
|
||||
$author$project$App$SetFileContent,
|
||||
A2(
|
||||
$elm$json$Json$Decode$at,
|
||||
_List_fromArray(
|
||||
['target', 'value']),
|
||||
$elm$json$Json$Decode$string))),
|
||||
A2($elm$html$Html$Attributes$attribute, 'content', model.file_content),
|
||||
A2($elm$html$Html$Attributes$attribute, 'language', language)
|
||||
]),
|
||||
_List_fromArray(
|
||||
[
|
||||
$elm$html$Html$text(model.file_content)
|
||||
])),
|
||||
A2(
|
||||
$elm$json$Json$Decode$at,
|
||||
_List_fromArray(
|
||||
['target', 'value']),
|
||||
$elm$json$Json$Decode$string))),
|
||||
A2($elm$html$Html$Attributes$attribute, 'content', model.file_content),
|
||||
A2($elm$html$Html$Attributes$attribute, 'language', language)
|
||||
]),
|
||||
_List_fromArray(
|
||||
[
|
||||
$elm$html$Html$text(model.file_content)
|
||||
])),
|
||||
A2(
|
||||
$elm$html$Html$input,
|
||||
_List_fromArray(
|
||||
[
|
||||
$elm$html$Html$Attributes$name('path'),
|
||||
$elm$html$Html$Attributes$value(model.file_path),
|
||||
$elm$html$Html$Attributes$type_('hidden')
|
||||
]),
|
||||
_List_Nil),
|
||||
A2(
|
||||
$elm$html$Html$input,
|
||||
_List_fromArray(
|
||||
[
|
||||
$elm$html$Html$Attributes$name('content'),
|
||||
$elm$html$Html$Attributes$value(model.file_content),
|
||||
$elm$html$Html$Attributes$type_('hidden')
|
||||
]),
|
||||
_List_Nil)
|
||||
]))
|
||||
$elm$html$Html$input,
|
||||
_List_fromArray(
|
||||
[
|
||||
$elm$html$Html$Attributes$name('path'),
|
||||
$elm$html$Html$Attributes$value(model.file_path),
|
||||
$elm$html$Html$Attributes$type_('hidden')
|
||||
]),
|
||||
_List_Nil),
|
||||
A2(
|
||||
$elm$html$Html$input,
|
||||
_List_fromArray(
|
||||
[
|
||||
$elm$html$Html$Attributes$name('content'),
|
||||
$elm$html$Html$Attributes$value(model.file_content),
|
||||
$elm$html$Html$Attributes$type_('hidden')
|
||||
]),
|
||||
_List_Nil)
|
||||
]);
|
||||
case 'Image':
|
||||
return _List_fromArray(
|
||||
[
|
||||
A2(
|
||||
$elm$html$Html$img,
|
||||
_List_fromArray(
|
||||
[
|
||||
$elm$html$Html$Attributes$src(file_path)
|
||||
]),
|
||||
_List_Nil)
|
||||
]);
|
||||
case 'Audio':
|
||||
return _List_fromArray(
|
||||
[
|
||||
A2(
|
||||
$elm$html$Html$audio,
|
||||
_List_fromArray(
|
||||
[
|
||||
$elm$html$Html$Attributes$src(file_path),
|
||||
A2($elm$html$Html$Attributes$attribute, 'controls', '')
|
||||
]),
|
||||
_List_Nil)
|
||||
]);
|
||||
case 'Video':
|
||||
return _List_fromArray(
|
||||
[
|
||||
A2(
|
||||
$elm$html$Html$video,
|
||||
_List_fromArray(
|
||||
[
|
||||
$elm$html$Html$Attributes$src(file_path),
|
||||
A2($elm$html$Html$Attributes$attribute, 'controls', '')
|
||||
]),
|
||||
_List_Nil)
|
||||
]);
|
||||
default:
|
||||
return _List_fromArray(
|
||||
[
|
||||
A2(
|
||||
$elm$html$Html$a,
|
||||
_List_fromArray(
|
||||
[
|
||||
$elm$html$Html$Attributes$href(file_path)
|
||||
]),
|
||||
_List_fromArray(
|
||||
[
|
||||
$elm$html$Html$text('Download')
|
||||
]))
|
||||
]);
|
||||
}
|
||||
}())
|
||||
]));
|
||||
};
|
||||
var $elm$core$String$fromFloat = _String_fromNumber;
|
||||
var $author$project$App$SetEditorSize = function (a) {
|
||||
return {$: 'SetEditorSize', a: a};
|
||||
};
|
||||
var $elm$html$Html$a = _VirtualDom_node('a');
|
||||
var $elm$core$Basics$round = _Basics_round;
|
||||
var $author$project$App$as_percentage = function (amount) {
|
||||
return $elm$core$String$fromInt(
|
||||
|
@ -7508,12 +7776,6 @@ var $elm$html$Html$datalist = _VirtualDom_node('datalist');
|
|||
var $elm$json$Json$Decode$float = _Json_decodeFloat;
|
||||
var $elm$html$Html$h1 = _VirtualDom_node('h1');
|
||||
var $elm$html$Html$header = _VirtualDom_node('header');
|
||||
var $elm$html$Html$Attributes$href = function (url) {
|
||||
return A2(
|
||||
$elm$html$Html$Attributes$stringProperty,
|
||||
'href',
|
||||
_VirtualDom_noJavaScriptUri(url));
|
||||
};
|
||||
var $author$project$App$link = F2(
|
||||
function (url, text) {
|
||||
return A2(
|
||||
|
@ -7532,6 +7794,52 @@ var $elm$html$Html$Attributes$max = $elm$html$Html$Attributes$stringProperty('ma
|
|||
var $elm$html$Html$Attributes$min = $elm$html$Html$Attributes$stringProperty('min');
|
||||
var $elm$html$Html$option = _VirtualDom_node('option');
|
||||
var $elm$html$Html$output = _VirtualDom_node('output');
|
||||
var $elm$core$List$any = F2(
|
||||
function (isOkay, list) {
|
||||
any:
|
||||
while (true) {
|
||||
if (!list.b) {
|
||||
return false;
|
||||
} else {
|
||||
var x = list.a;
|
||||
var xs = list.b;
|
||||
if (isOkay(x)) {
|
||||
return true;
|
||||
} else {
|
||||
var $temp$isOkay = isOkay,
|
||||
$temp$list = xs;
|
||||
isOkay = $temp$isOkay;
|
||||
list = $temp$list;
|
||||
continue any;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
var $elm$core$List$member = F2(
|
||||
function (x, xs) {
|
||||
return A2(
|
||||
$elm$core$List$any,
|
||||
function (a) {
|
||||
return _Utils_eq(a, x);
|
||||
},
|
||||
xs);
|
||||
});
|
||||
var $author$project$App$suffix = A2(
|
||||
$elm$core$Basics$composeR,
|
||||
$elm$core$String$split('.'),
|
||||
A2(
|
||||
$elm$core$Basics$composeR,
|
||||
$elm$core$List$reverse,
|
||||
A2(
|
||||
$elm$core$Basics$composeR,
|
||||
$elm$core$List$head,
|
||||
$elm$core$Maybe$withDefault(''))));
|
||||
var $author$project$App$preview_url = function (model) {
|
||||
var page_suffixes = _List_fromArray(
|
||||
['html', 'php']);
|
||||
var file_suffix = $author$project$App$suffix(model.file_path);
|
||||
return A2($elm$core$List$member, file_suffix, page_suffixes) ? (model.preview_url + ('/' + model.file_path)) : model.preview_url;
|
||||
};
|
||||
var $elm$html$Html$Attributes$step = function (n) {
|
||||
return A2($elm$html$Html$Attributes$stringProperty, 'step', n);
|
||||
};
|
||||
|
@ -7563,7 +7871,8 @@ var $author$project$App$header = function (model) {
|
|||
_List_fromArray(
|
||||
[
|
||||
$elm$html$Html$Attributes$target('preview'),
|
||||
$elm$html$Html$Attributes$href(model.preview_url)
|
||||
$elm$html$Html$Attributes$href(
|
||||
$author$project$App$preview_url(model))
|
||||
]),
|
||||
_List_fromArray(
|
||||
[
|
||||
|
@ -7887,6 +8196,7 @@ var $author$project$App$SetCommand = function (a) {
|
|||
};
|
||||
var $author$project$App$ShowCommitModal = {$: 'ShowCommitModal'};
|
||||
var $author$project$App$Upload = {$: 'Upload'};
|
||||
var $elm$html$Html$Attributes$enctype = $elm$html$Html$Attributes$stringProperty('enctype');
|
||||
var $elm$html$Html$li = _VirtualDom_node('li');
|
||||
var $elm$core$Basics$not = _Basics_not;
|
||||
var $elm$html$Html$Events$onClick = function (msg) {
|
||||
|
@ -8066,6 +8376,50 @@ var $author$project$App$main_nav = function (model) {
|
|||
$elm$html$Html$text('Run')
|
||||
]))
|
||||
])),
|
||||
A3(
|
||||
$author$project$App$form,
|
||||
model,
|
||||
_List_fromArray(
|
||||
[
|
||||
$elm$html$Html$Attributes$method('POST'),
|
||||
$elm$html$Html$Attributes$action('upload-files'),
|
||||
$elm$html$Html$Attributes$enctype('multipart/form-data'),
|
||||
A2(
|
||||
$elm$html$Html$Events$stopPropagationOn,
|
||||
'drop',
|
||||
$elm$json$Json$Decode$succeed(
|
||||
_Utils_Tuple2($author$project$App$NoOp, true))),
|
||||
A2(
|
||||
$elm$html$Html$Events$stopPropagationOn,
|
||||
'dragover',
|
||||
$elm$json$Json$Decode$succeed(
|
||||
_Utils_Tuple2($author$project$App$NoOp, true)))
|
||||
]),
|
||||
_List_fromArray(
|
||||
[
|
||||
A2(
|
||||
$elm$html$Html$input,
|
||||
_List_fromArray(
|
||||
[
|
||||
A2($elm$html$Html$Attributes$attribute, 'aria-labelledby', 'upload-files-button'),
|
||||
$elm$html$Html$Attributes$type_('file'),
|
||||
A2($elm$html$Html$Attributes$attribute, 'multiple', ''),
|
||||
$elm$html$Html$Attributes$id('id_files'),
|
||||
$elm$html$Html$Attributes$name('files')
|
||||
]),
|
||||
_List_Nil),
|
||||
A2(
|
||||
$elm$html$Html$button,
|
||||
_List_fromArray(
|
||||
[
|
||||
$elm$html$Html$Attributes$id('upload-files-button'),
|
||||
$elm$html$Html$Attributes$type_('submit')
|
||||
]),
|
||||
_List_fromArray(
|
||||
[
|
||||
$elm$html$Html$text('Upload')
|
||||
]))
|
||||
])),
|
||||
(A2($elm$core$String$right, 4, model.file_path) === '.elm') ? A3(
|
||||
$author$project$App$form,
|
||||
model,
|
||||
|
@ -8167,12 +8521,6 @@ var $author$project$App$TogglePreview = function (a) {
|
|||
return {$: 'TogglePreview', a: a};
|
||||
};
|
||||
var $elm$html$Html$iframe = _VirtualDom_node('iframe');
|
||||
var $elm$html$Html$Attributes$src = function (url) {
|
||||
return A2(
|
||||
$elm$html$Html$Attributes$stringProperty,
|
||||
'src',
|
||||
_VirtualDom_noJavaScriptOrHtmlUri(url));
|
||||
};
|
||||
var $author$project$App$preview_pane = function (model) {
|
||||
return A2(
|
||||
$elm$html$Html$details,
|
||||
|
@ -8210,7 +8558,8 @@ var $author$project$App$preview_pane = function (model) {
|
|||
_List_fromArray(
|
||||
[
|
||||
$elm$html$Html$Attributes$id('preview-frame'),
|
||||
$elm$html$Html$Attributes$src(model.preview_url)
|
||||
$elm$html$Html$Attributes$src(
|
||||
$author$project$App$preview_url(model))
|
||||
]),
|
||||
_List_Nil)
|
||||
]) : _List_Nil));
|
||||
|
|
|
@ -8,8 +8,12 @@
|
|||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
body {
|
||||
--background: hsl(70,100%,8%);
|
||||
--default-background: black;
|
||||
--color: white;
|
||||
--button-bg: #333;
|
||||
}
|
||||
}
|
||||
|
||||
* {
|
||||
|
|
|
@ -12,6 +12,7 @@ urlpatterns = [
|
|||
path('think/<slug:slug>/rename-file', RenameFileView.as_view(), name='rename_file'),
|
||||
path('think/<slug:slug>/delete-file', DeleteFileView.as_view(), name='delete_file'),
|
||||
path('think/<slug:slug>/run-command', RunCommandView.as_view(), name='run_command'),
|
||||
path('think/<slug:slug>/upload-files', UploadFileView.as_view(), name='upload_files'),
|
||||
path('think/<slug:slug>/log', LogView.as_view(), name='log'),
|
||||
path('think/<slug:slug>/jj/status', JJStatusView.as_view(), name='jj_status'),
|
||||
path('think/<slug:slug>/jj/commit', JJCommitView.as_view(), name='jj_commit'),
|
||||
|
|
|
@ -6,6 +6,7 @@ from django.views import generic
|
|||
from django.urls import reverse
|
||||
from itertools import groupby
|
||||
import json
|
||||
import mimetypes
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import shlex
|
||||
|
@ -16,6 +17,7 @@ from .make import ThingMaker
|
|||
from .models import Think
|
||||
from .random_slug import random_slug
|
||||
|
||||
|
||||
class LoginRequiredMixin(AccessMixin):
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
if not request.user.is_authenticated:
|
||||
|
@ -25,10 +27,12 @@ class LoginRequiredMixin(AccessMixin):
|
|||
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
|
||||
class ThinkMixin(LoginRequiredMixin):
|
||||
model = Think
|
||||
context_object_name = 'think'
|
||||
|
||||
|
||||
class IndexView(ThinkMixin, generic.ListView):
|
||||
template_name = 'thinks/index.html'
|
||||
|
||||
|
@ -50,10 +54,12 @@ class IndexView(ThinkMixin, generic.ListView):
|
|||
return JsonResponse({'templates': [t.as_json() for t in context['templates']], 'thinks': [t.as_json() for t in context['thinks']]})
|
||||
return super().get(request, *args, **kwargs)
|
||||
|
||||
|
||||
class CreateThinkView(ThinkMixin, generic.CreateView):
|
||||
template_name = 'thinks/new.html'
|
||||
form_class = forms.CreateThinkForm
|
||||
|
||||
|
||||
class RemixThinkView(ThinkMixin, generic.UpdateView):
|
||||
template_name = 'thinks/remix.html'
|
||||
form_class = forms.RemixThinkForm
|
||||
|
@ -79,6 +85,7 @@ class RemixThinkView(ThinkMixin, generic.UpdateView):
|
|||
return redirect(think.get_absolute_url())
|
||||
|
||||
|
||||
|
||||
class ThinkView(ThinkMixin, generic.DetailView):
|
||||
template_name = "thinks/think.html"
|
||||
|
||||
|
@ -124,28 +131,37 @@ class ThinkView(ThinkMixin, generic.DetailView):
|
|||
|
||||
files = sorted(files, key=lambda x: x['name'].lower())
|
||||
|
||||
if path is not None and path.is_file():
|
||||
with open(path) as f:
|
||||
content = f.read()
|
||||
else:
|
||||
content = ''
|
||||
|
||||
data = context['think_editor_data'] = {
|
||||
'preview_url': think.get_static_url(),
|
||||
'slug': think.slug,
|
||||
'files': files,
|
||||
'file_path': str(relpath),
|
||||
'file_content': content,
|
||||
'is_dir': path is None or path.is_dir(),
|
||||
'no_preview': self.request.GET.get('no-preview') is not None,
|
||||
}
|
||||
|
||||
if path is not None and path.is_file():
|
||||
mime_types = {
|
||||
'.elm': 'text/application+elm',
|
||||
}
|
||||
mime_type, encoding = mimetypes.guess_type(path)
|
||||
if mime_type is None:
|
||||
mime_type = mime_types.get(path.suffix, 'text/plain')
|
||||
category, filetype = mime_type.split('/') if mime_type is not None else ('text', 'plain')
|
||||
binary_categories = ['audio', 'video', 'image']
|
||||
is_binary = category in binary_categories and mime_type != 'image/svg+xml'
|
||||
data['mime_type'] = mime_type
|
||||
if not is_binary:
|
||||
with open(path) as f:
|
||||
data['file_content'] = f.read()
|
||||
|
||||
if path is not None and path.suffix == '.elm':
|
||||
with open('public/elm-packages.json') as f:
|
||||
data['elm_packages'] = json.load(f)
|
||||
|
||||
return context
|
||||
|
||||
|
||||
class RenameThinkView(ThinkMixin, generic.UpdateView):
|
||||
form_class = forms.RenameThinkForm
|
||||
template_name = 'thinks/rename.html'
|
||||
|
@ -160,18 +176,22 @@ class RenameThinkView(ThinkMixin, generic.UpdateView):
|
|||
|
||||
return context
|
||||
|
||||
|
||||
class DeleteThinkView(ThinkMixin, generic.DeleteView):
|
||||
template_name = 'thinks/delete.html'
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse('index')
|
||||
|
||||
|
||||
class ReadFileView(ThinkMixin, generic.DetailView):
|
||||
def get(self, request, *args, **kwargs):
|
||||
think = self.get_object()
|
||||
relpath = self.kwargs['path']
|
||||
path = think.root / relpath
|
||||
print(path)
|
||||
if not path.is_relative_to(think.root):
|
||||
raise Exception(f"Bad path: {relpath}")
|
||||
return redirect(think.get_static_url() + '/' + relpath)
|
||||
|
||||
|
||||
class SaveFileView(ThinkMixin, generic.UpdateView):
|
||||
|
@ -191,6 +211,7 @@ class SaveFileView(ThinkMixin, generic.UpdateView):
|
|||
def get_success_url(self):
|
||||
return self.object.get_absolute_url()+'?path='+str(self.path)
|
||||
|
||||
|
||||
class RenameFileView(ThinkMixin, generic.UpdateView):
|
||||
form_class = forms.RenameFileForm
|
||||
template_name = 'thinks/rename_file.html'
|
||||
|
@ -203,6 +224,7 @@ class RenameFileView(ThinkMixin, generic.UpdateView):
|
|||
def get_success_url(self):
|
||||
return self.object.get_absolute_url()+'?path='+str(self.path)
|
||||
|
||||
|
||||
class DeleteFileView(ThinkMixin, generic.UpdateView):
|
||||
form_class = forms.DeleteFileForm
|
||||
template_name = 'thinks/delete_file.html'
|
||||
|
@ -214,6 +236,7 @@ class DeleteFileView(ThinkMixin, generic.UpdateView):
|
|||
def get_success_url(self):
|
||||
return self.object.get_absolute_url()+'?path='+str(self.path.parent)
|
||||
|
||||
|
||||
class RunCommandView(ThinkMixin, generic.UpdateView):
|
||||
form_class = forms.RunCommandForm
|
||||
|
||||
|
@ -228,6 +251,14 @@ class RunCommandView(ThinkMixin, generic.UpdateView):
|
|||
)
|
||||
return JsonResponse({'stdout': res.stdout, 'stderr': res.stderr})
|
||||
|
||||
|
||||
class UploadFileView(ThinkMixin, generic.UpdateView):
|
||||
form_class = forms.UploadFileForm
|
||||
|
||||
def get_success_url(self):
|
||||
return self.object.get_absolute_url()
|
||||
|
||||
|
||||
class LogView(ThinkMixin, generic.DetailView):
|
||||
template_name = 'thinks/think.html'
|
||||
|
||||
|
@ -236,11 +267,13 @@ class LogView(ThinkMixin, generic.DetailView):
|
|||
|
||||
return HttpResponse(think.get_log(), content_type='text/plain; charset=utf-8')
|
||||
|
||||
|
||||
class JJStatusView(ThinkMixin, generic.detail.DetailView):
|
||||
def get(self, request, *args, **kwargs):
|
||||
status = self.get_object().jj_controller.status()
|
||||
return JsonResponse({'status': status})
|
||||
|
||||
|
||||
class JJCommitView(ThinkMixin, generic.UpdateView):
|
||||
form_class = forms.GitCommitForm
|
||||
|
||||
|
|
Loading…
Reference in a new issue