Compare commits

..

No commits in common. "dcdb3d87be26266bd2e7bbf8019af1a0701299d0" and "1b6a9956c5c4cab05c7dd078ca649327221f1dc0" have entirely different histories.

7 changed files with 149 additions and 600 deletions

View file

@ -3,7 +3,6 @@ from django.conf import settings
from .models import Think from .models import Think
class CreateThinkForm(forms.ModelForm): class CreateThinkForm(forms.ModelForm):
class Meta: class Meta:
model = Think model = Think
@ -16,13 +15,11 @@ class CreateThinkForm(forms.ModelForm):
instance.root.mkdir(exist_ok=True,parents=True) instance.root.mkdir(exist_ok=True,parents=True)
return instance return instance
class RemixThinkForm(forms.ModelForm): class RemixThinkForm(forms.ModelForm):
class Meta: class Meta:
model = Think model = Think
fields = [] fields = []
class RenameThinkForm(forms.ModelForm): class RenameThinkForm(forms.ModelForm):
class Meta: class Meta:
model = Think model = Think
@ -52,7 +49,6 @@ class RenameThinkForm(forms.ModelForm):
instance = super().save(commit) instance = super().save(commit)
return instance return instance
class SaveFileForm(forms.ModelForm): class SaveFileForm(forms.ModelForm):
path = forms.CharField() path = forms.CharField()
content = forms.CharField(required=False, widget=forms.Textarea) content = forms.CharField(required=False, widget=forms.Textarea)
@ -76,7 +72,6 @@ class SaveFileForm(forms.ModelForm):
return super().save(commit) return super().save(commit)
class RenameFileForm(forms.ModelForm): class RenameFileForm(forms.ModelForm):
path = forms.CharField() path = forms.CharField()
newpath = forms.CharField() newpath = forms.CharField()
@ -105,7 +100,6 @@ class RenameFileForm(forms.ModelForm):
return super().save(commit) return super().save(commit)
class DeleteFileForm(forms.ModelForm): class DeleteFileForm(forms.ModelForm):
path = forms.CharField() path = forms.CharField()
@ -127,7 +121,6 @@ class DeleteFileForm(forms.ModelForm):
return super().save(commit) return super().save(commit)
class RunCommandForm(forms.ModelForm): class RunCommandForm(forms.ModelForm):
command = forms.CharField() command = forms.CharField()
@ -135,51 +128,9 @@ class RunCommandForm(forms.ModelForm):
model = Think model = Think
fields = [] fields = []
class GitCommitForm(forms.ModelForm): class GitCommitForm(forms.ModelForm):
message = forms.CharField() message = forms.CharField()
class Meta: class Meta:
model = Think model = Think
fields = [] 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)

View file

@ -26,19 +26,14 @@ class JJController:
) )
return res return res
def init_jj(self, force=False): def init_jj(self):
print("Init jj") print("Init jj")
res = self.run(['jj','git','remote','list']) if not (self.root / '.jj').exists():
if force or not (self.root / '.jj').exists():
self.run(['jj','git','init']) self.run(['jj','git','init'])
self.ignore_paths(['.make.*']) self.ignore_paths(['.make.*'])
git_url = settings.GIT_REPO_URL_TEMPLATE.format(name=self.think.slug) git_url = settings.GIT_REPO_URL_TEMPLATE.format(name=self.think.slug)
self.run(['jj','git','remote','add','origin', git_url]) 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 @ensure_jj
def ignore_paths(self, paths): def ignore_paths(self, paths):
paths = self.clean_paths(paths) paths = self.clean_paths(paths)

View file

@ -109,13 +109,9 @@ input:not([type="hidden"]) ~ button {
input { input {
border: thin solid currentColor; border: thin solid currentColor;
height: 100%;
background: var(--default-background);
}
input[type="file"] {
font-size: 0.66rem;
} }
.field { .field {
display: flex; display: flex;
gap: var(--quarter-spacing); gap: var(--quarter-spacing);
@ -243,12 +239,6 @@ input[type="file"] {
z-index: 1; z-index: 1;
} }
& #file-form {
& > :is(img,video) {
width: 100%;
}
}
& code-editor { & code-editor {
background: var(--default-background); background: var(--default-background);
display: block; display: block;

View file

@ -5546,8 +5546,7 @@ var $author$project$App$Model = function (show_preview) {
return function (file_content) { return function (file_content) {
return function (is_dir) { return function (is_dir) {
return function (elm_packages) { return function (elm_packages) {
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, preview_url: preview_url, selected_package: selected_package, show_log: show_log, show_preview: show_preview, slug: slug};
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};
}; };
}; };
}; };
@ -5565,11 +5564,6 @@ 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_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$json$Json$Decode$bool = _Json_decodeBool;
var $elm$core$Basics$composeR = F3( var $elm$core$Basics$composeR = F3(
@ -5603,201 +5597,8 @@ 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, '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, 'is_dir', $elm$json$Json$Decode$bool),
A2($elm$json$Json$Decode$field, 'path', $elm$json$Json$Decode$string)); 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$NotLoaded = {$: 'NotLoaded'};
var $author$project$App$init_model = { 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'};
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$list = _Json_decodeList;
var $elm$json$Json$Decode$oneOf = _Json_oneOf; var $elm$json$Json$Decode$oneOf = _Json_oneOf;
var $elm$core$Result$withDefault = F2( var $elm$core$Result$withDefault = F2(
@ -5812,15 +5613,6 @@ var $elm$core$Result$withDefault = F2(
var $author$project$App$load_flags = A2( var $author$project$App$load_flags = A2(
$elm$core$Basics$composeR, $elm$core$Basics$composeR,
$elm$json$Json$Decode$decodeValue( $elm$json$Json$Decode$decodeValue(
A2(
$elm_community$json_extra$Json$Decode$Extra$andMap,
$elm$json$Json$Decode$oneOf(
_List_fromArray(
[
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( A2(
$elm_community$json_extra$Json$Decode$Extra$andMap, $elm_community$json_extra$Json$Decode$Extra$andMap,
$elm$json$Json$Decode$oneOf( $elm$json$Json$Decode$oneOf(
@ -5837,12 +5629,7 @@ var $author$project$App$load_flags = A2(
A2($elm$json$Json$Decode$field, 'is_dir', $elm$json$Json$Decode$bool), A2($elm$json$Json$Decode$field, 'is_dir', $elm$json$Json$Decode$bool),
A2( A2(
$elm_community$json_extra$Json$Decode$Extra$andMap, $elm_community$json_extra$Json$Decode$Extra$andMap,
$elm$json$Json$Decode$oneOf(
_List_fromArray(
[
A2($elm$json$Json$Decode$field, 'file_content', $elm$json$Json$Decode$string), A2($elm$json$Json$Decode$field, 'file_content', $elm$json$Json$Decode$string),
$elm$json$Json$Decode$succeed('')
])),
A2( A2(
$elm_community$json_extra$Json$Decode$Extra$andMap, $elm_community$json_extra$Json$Decode$Extra$andMap,
A2($elm$json$Json$Decode$field, 'file_path', $elm$json$Json$Decode$string), A2($elm$json$Json$Decode$field, 'file_path', $elm$json$Json$Decode$string),
@ -5862,7 +5649,7 @@ var $author$project$App$load_flags = A2(
$elm_community$json_extra$Json$Decode$Extra$andMap, $elm_community$json_extra$Json$Decode$Extra$andMap,
A2($elm$json$Json$Decode$field, 'csrf_token', $elm$json$Json$Decode$string), A2($elm$json$Json$Decode$field, 'csrf_token', $elm$json$Json$Decode$string),
$elm$json$Json$Decode$succeed( $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)))))))))))), 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)); $elm$core$Result$withDefault($author$project$App$init_model));
var $author$project$App$SetLog = function (a) { var $author$project$App$SetLog = function (a) {
return {$: 'SetLog', a: a}; return {$: 'SetLog', a: a};
@ -6660,8 +6447,8 @@ var $author$project$App$FileSaved = F2(
function (a, b) { function (a, b) {
return {$: 'FileSaved', a: a, b: b}; return {$: 'FileSaved', a: a, b: b};
}); });
var $author$project$App$FilesUploaded = function (a) { var $author$project$App$FileUploaded = function (a) {
return {$: 'FilesUploaded', a: a}; return {$: 'FileUploaded', a: a};
}; };
var $author$project$App$HttpError = function (a) { var $author$project$App$HttpError = function (a) {
return {$: 'HttpError', a: a}; return {$: 'HttpError', a: a};
@ -6693,6 +6480,10 @@ var $author$project$App$SaveContent = function (a) {
var $author$project$App$SetFileContent = function (a) { var $author$project$App$SetFileContent = function (a) {
return {$: 'SetFileContent', a: 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 $elm$core$Platform$Cmd$batch = _Platform_batch;
var $author$project$App$decode_command_response = $elm$json$Json$Decode$oneOf( var $author$project$App$decode_command_response = $elm$json$Json$Decode$oneOf(
_List_fromArray( _List_fromArray(
@ -6772,7 +6563,6 @@ var $author$project$App$fetch_jj_status = $elm$http$Http$get(
A2($elm$json$Json$Decode$field, 'status', $elm$json$Json$Decode$string)), A2($elm$json$Json$Decode$field, 'status', $elm$json$Json$Decode$string)),
url: 'jj/status' url: 'jj/status'
}); });
var $elm$http$Http$filePart = _Http_pair;
var $elm$url$Url$Builder$toQueryPair = function (_v0) { var $elm$url$Url$Builder$toQueryPair = function (_v0) {
var key = _v0.a; var key = _v0.a;
var value = _v0.b; var value = _v0.b;
@ -6974,10 +6764,10 @@ var $author$project$App$update = F2(
case 'DropFiles': case 'DropFiles':
var action = msg.a; var action = msg.a;
var files = msg.b; 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( return _Utils_Tuple2(
model, model,
A2( A2(
@ -6985,47 +6775,51 @@ var $author$project$App$update = F2(
$author$project$App$SetFileContent, $author$project$App$SetFileContent,
$elm$file$File$toString(file))); $elm$file$File$toString(file)));
} else { } else {
return _Utils_Tuple2(model, $elm$core$Platform$Cmd$none); return _Utils_Tuple2(
model,
A2(
$elm$core$Task$perform,
$author$project$App$UploadFile(file),
$elm$file$File$toString(file)));
} }
} else { } else {
return _Utils_Tuple2(model, $elm$core$Platform$Cmd$none);
}
case 'UploadFile':
var file = msg.a;
var contents = msg.b;
return _Utils_Tuple2( return _Utils_Tuple2(
model, model,
$elm$http$Http$post( $elm$http$Http$post(
{ {
body: $elm$http$Http$multipartBody( body: $elm$http$Http$multipartBody(
_Utils_ap(
_List_fromArray( _List_fromArray(
[ [
A2($elm$http$Http$stringPart, 'csrfmiddlewaretoken', model.csrf_token)
]),
A2( A2(
$elm$core$List$map, $elm$http$Http$stringPart,
$elm$http$Http$filePart('files'), 'path',
files))), $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( expect: $elm$http$Http$expectWhatever(
function (r) { function (r) {
if (r.$ === 'Ok') { if (r.$ === 'Ok') {
return $author$project$App$FilesUploaded(files); return $author$project$App$FileUploaded(file);
} else { } else {
return $author$project$App$NoOp; return $author$project$App$NoOp;
} }
}), }),
url: 'upload-files' url: 'save-file'
})); }));
} case 'FileUploaded':
case 'FilesUploaded': var file = msg.a;
var files = msg.a;
if (files.b) {
var file = files.a;
var name = $elm$file$File$name(file); var name = $elm$file$File$name(file);
var url = $author$project$App$file_edit_url( var url = $author$project$App$file_edit_url(
{is_dir: false, name: name, path: name}); {is_dir: false, name: name, path: name});
return _Utils_Tuple2( return _Utils_Tuple2(
model, model,
$elm$browser$Browser$Navigation$load(url)); $elm$browser$Browser$Navigation$load(url));
} else {
return $author$project$App$nocmd(model);
}
case 'SetCommand': case 'SetCommand':
var cmd = msg.a; var cmd = msg.a;
return $author$project$App$nocmd( return $author$project$App$nocmd(
@ -7390,14 +7184,12 @@ var $author$project$App$DropFiles = F2(
function (a, b) { function (a, b) {
return {$: 'DropFiles', a: a, b: b}; return {$: 'DropFiles', a: a, b: b};
}); });
var $elm$html$Html$a = _VirtualDom_node('a');
var $elm$html$Html$Attributes$action = function (uri) { var $elm$html$Html$Attributes$action = function (uri) {
return A2( return A2(
$elm$html$Html$Attributes$stringProperty, $elm$html$Html$Attributes$stringProperty,
'action', 'action',
_VirtualDom_noJavaScriptUri(uri)); _VirtualDom_noJavaScriptUri(uri));
}; };
var $elm$html$Html$audio = _VirtualDom_node('audio');
var $elm$file$File$decoder = _File_decoder; var $elm$file$File$decoder = _File_decoder;
var $elm$html$Html$details = _VirtualDom_node('details'); var $elm$html$Html$details = _VirtualDom_node('details');
var $elm$core$List$drop = F2( var $elm$core$List$drop = F2(
@ -7455,13 +7247,6 @@ var $elm$core$Dict$fromList = function (assocs) {
$elm$core$Dict$empty, $elm$core$Dict$empty,
assocs); 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$html$Html$nav = _VirtualDom_node('nav');
var $elm$virtual_dom$VirtualDom$MayPreventDefault = function (a) { var $elm$virtual_dom$VirtualDom$MayPreventDefault = function (a) {
return {$: 'MayPreventDefault', a: a}; return {$: 'MayPreventDefault', a: a};
@ -7475,14 +7260,16 @@ var $elm$html$Html$Events$preventDefaultOn = F2(
}); });
var $elm$html$Html$section = _VirtualDom_node('section'); var $elm$html$Html$section = _VirtualDom_node('section');
var $elm$html$Html$span = _VirtualDom_node('span'); 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$html$Html$summary = _VirtualDom_node('summary');
var $elm$html$Html$video = _VirtualDom_node('video'); 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$editor_pane = function (model) { var $author$project$App$editor_pane = function (model) {
var languages = $elm$core$Dict$fromList( var languages = $elm$core$Dict$fromList(
_List_fromArray( _List_fromArray(
@ -7494,7 +7281,6 @@ var $author$project$App$editor_pane = function (model) {
_Utils_Tuple2('R', 'r'), _Utils_Tuple2('R', 'r'),
_Utils_Tuple2('elm', 'elm') _Utils_Tuple2('elm', 'elm')
])); ]));
var file_path = 'file/' + model.file_path;
var extension = A2( var extension = A2(
$elm$core$Maybe$withDefault, $elm$core$Maybe$withDefault,
'', '',
@ -7662,11 +7448,7 @@ var $author$project$App$editor_pane = function (model) {
$elm$html$Html$Attributes$method('POST'), $elm$html$Html$Attributes$method('POST'),
$elm$html$Html$Attributes$action('save-file') $elm$html$Html$Attributes$action('save-file')
]), ]),
function () { _List_fromArray(
var _v0 = model.mime_type;
switch (_v0.$) {
case 'Text':
return _List_fromArray(
[ [
A3( A3(
$elm$html$Html$node, $elm$html$Html$node,
@ -7709,64 +7491,14 @@ var $author$project$App$editor_pane = function (model) {
$elm$html$Html$Attributes$type_('hidden') $elm$html$Html$Attributes$type_('hidden')
]), ]),
_List_Nil) _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 $elm$core$String$fromFloat = _String_fromNumber;
var $author$project$App$SetEditorSize = function (a) { var $author$project$App$SetEditorSize = function (a) {
return {$: 'SetEditorSize', a: a}; return {$: 'SetEditorSize', a: a};
}; };
var $elm$html$Html$a = _VirtualDom_node('a');
var $elm$core$Basics$round = _Basics_round; var $elm$core$Basics$round = _Basics_round;
var $author$project$App$as_percentage = function (amount) { var $author$project$App$as_percentage = function (amount) {
return $elm$core$String$fromInt( return $elm$core$String$fromInt(
@ -7776,6 +7508,12 @@ var $elm$html$Html$datalist = _VirtualDom_node('datalist');
var $elm$json$Json$Decode$float = _Json_decodeFloat; var $elm$json$Json$Decode$float = _Json_decodeFloat;
var $elm$html$Html$h1 = _VirtualDom_node('h1'); var $elm$html$Html$h1 = _VirtualDom_node('h1');
var $elm$html$Html$header = _VirtualDom_node('header'); 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( var $author$project$App$link = F2(
function (url, text) { function (url, text) {
return A2( return A2(
@ -7794,52 +7532,6 @@ 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$Attributes$min = $elm$html$Html$Attributes$stringProperty('min');
var $elm$html$Html$option = _VirtualDom_node('option'); var $elm$html$Html$option = _VirtualDom_node('option');
var $elm$html$Html$output = _VirtualDom_node('output'); 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) { var $elm$html$Html$Attributes$step = function (n) {
return A2($elm$html$Html$Attributes$stringProperty, 'step', n); return A2($elm$html$Html$Attributes$stringProperty, 'step', n);
}; };
@ -7871,8 +7563,7 @@ var $author$project$App$header = function (model) {
_List_fromArray( _List_fromArray(
[ [
$elm$html$Html$Attributes$target('preview'), $elm$html$Html$Attributes$target('preview'),
$elm$html$Html$Attributes$href( $elm$html$Html$Attributes$href(model.preview_url)
$author$project$App$preview_url(model))
]), ]),
_List_fromArray( _List_fromArray(
[ [
@ -8196,7 +7887,6 @@ var $author$project$App$SetCommand = function (a) {
}; };
var $author$project$App$ShowCommitModal = {$: 'ShowCommitModal'}; var $author$project$App$ShowCommitModal = {$: 'ShowCommitModal'};
var $author$project$App$Upload = {$: 'Upload'}; 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$html$Html$li = _VirtualDom_node('li');
var $elm$core$Basics$not = _Basics_not; var $elm$core$Basics$not = _Basics_not;
var $elm$html$Html$Events$onClick = function (msg) { var $elm$html$Html$Events$onClick = function (msg) {
@ -8376,50 +8066,6 @@ var $author$project$App$main_nav = function (model) {
$elm$html$Html$text('Run') $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( (A2($elm$core$String$right, 4, model.file_path) === '.elm') ? A3(
$author$project$App$form, $author$project$App$form,
model, model,
@ -8521,6 +8167,12 @@ var $author$project$App$TogglePreview = function (a) {
return {$: 'TogglePreview', a: a}; return {$: 'TogglePreview', a: a};
}; };
var $elm$html$Html$iframe = _VirtualDom_node('iframe'); 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) { var $author$project$App$preview_pane = function (model) {
return A2( return A2(
$elm$html$Html$details, $elm$html$Html$details,
@ -8558,8 +8210,7 @@ var $author$project$App$preview_pane = function (model) {
_List_fromArray( _List_fromArray(
[ [
$elm$html$Html$Attributes$id('preview-frame'), $elm$html$Html$Attributes$id('preview-frame'),
$elm$html$Html$Attributes$src( $elm$html$Html$Attributes$src(model.preview_url)
$author$project$App$preview_url(model))
]), ]),
_List_Nil) _List_Nil)
]) : _List_Nil)); ]) : _List_Nil));

View file

@ -8,12 +8,8 @@
} }
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
body {
--background: hsl(70,100%,8%); --background: hsl(70,100%,8%);
--default-background: black;
--color: white; --color: white;
--button-bg: #333;
}
} }
* { * {

View file

@ -12,7 +12,6 @@ urlpatterns = [
path('think/<slug:slug>/rename-file', RenameFileView.as_view(), name='rename_file'), 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>/delete-file', DeleteFileView.as_view(), name='delete_file'),
path('think/<slug:slug>/run-command', RunCommandView.as_view(), name='run_command'), 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>/log', LogView.as_view(), name='log'),
path('think/<slug:slug>/jj/status', JJStatusView.as_view(), name='jj_status'), path('think/<slug:slug>/jj/status', JJStatusView.as_view(), name='jj_status'),
path('think/<slug:slug>/jj/commit', JJCommitView.as_view(), name='jj_commit'), path('think/<slug:slug>/jj/commit', JJCommitView.as_view(), name='jj_commit'),

View file

@ -6,7 +6,6 @@ from django.views import generic
from django.urls import reverse from django.urls import reverse
from itertools import groupby from itertools import groupby
import json import json
import mimetypes
from pathlib import Path from pathlib import Path
import shutil import shutil
import shlex import shlex
@ -17,7 +16,6 @@ from .make import ThingMaker
from .models import Think from .models import Think
from .random_slug import random_slug from .random_slug import random_slug
class LoginRequiredMixin(AccessMixin): class LoginRequiredMixin(AccessMixin):
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
if not request.user.is_authenticated: if not request.user.is_authenticated:
@ -27,12 +25,10 @@ class LoginRequiredMixin(AccessMixin):
return super().dispatch(request, *args, **kwargs) return super().dispatch(request, *args, **kwargs)
class ThinkMixin(LoginRequiredMixin): class ThinkMixin(LoginRequiredMixin):
model = Think model = Think
context_object_name = 'think' context_object_name = 'think'
class IndexView(ThinkMixin, generic.ListView): class IndexView(ThinkMixin, generic.ListView):
template_name = 'thinks/index.html' template_name = 'thinks/index.html'
@ -54,12 +50,10 @@ 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 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) return super().get(request, *args, **kwargs)
class CreateThinkView(ThinkMixin, generic.CreateView): class CreateThinkView(ThinkMixin, generic.CreateView):
template_name = 'thinks/new.html' template_name = 'thinks/new.html'
form_class = forms.CreateThinkForm form_class = forms.CreateThinkForm
class RemixThinkView(ThinkMixin, generic.UpdateView): class RemixThinkView(ThinkMixin, generic.UpdateView):
template_name = 'thinks/remix.html' template_name = 'thinks/remix.html'
form_class = forms.RemixThinkForm form_class = forms.RemixThinkForm
@ -85,7 +79,6 @@ class RemixThinkView(ThinkMixin, generic.UpdateView):
return redirect(think.get_absolute_url()) return redirect(think.get_absolute_url())
class ThinkView(ThinkMixin, generic.DetailView): class ThinkView(ThinkMixin, generic.DetailView):
template_name = "thinks/think.html" template_name = "thinks/think.html"
@ -131,37 +124,28 @@ class ThinkView(ThinkMixin, generic.DetailView):
files = sorted(files, key=lambda x: x['name'].lower()) 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'] = { data = context['think_editor_data'] = {
'preview_url': think.get_static_url(), 'preview_url': think.get_static_url(),
'slug': think.slug, 'slug': think.slug,
'files': files, 'files': files,
'file_path': str(relpath), 'file_path': str(relpath),
'file_content': content,
'is_dir': path is None or path.is_dir(), 'is_dir': path is None or path.is_dir(),
'no_preview': self.request.GET.get('no-preview') is not None, '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': if path is not None and path.suffix == '.elm':
with open('public/elm-packages.json') as f: with open('public/elm-packages.json') as f:
data['elm_packages'] = json.load(f) data['elm_packages'] = json.load(f)
return context return context
class RenameThinkView(ThinkMixin, generic.UpdateView): class RenameThinkView(ThinkMixin, generic.UpdateView):
form_class = forms.RenameThinkForm form_class = forms.RenameThinkForm
template_name = 'thinks/rename.html' template_name = 'thinks/rename.html'
@ -176,22 +160,18 @@ class RenameThinkView(ThinkMixin, generic.UpdateView):
return context return context
class DeleteThinkView(ThinkMixin, generic.DeleteView): class DeleteThinkView(ThinkMixin, generic.DeleteView):
template_name = 'thinks/delete.html' template_name = 'thinks/delete.html'
def get_success_url(self): def get_success_url(self):
return reverse('index') return reverse('index')
class ReadFileView(ThinkMixin, generic.DetailView): class ReadFileView(ThinkMixin, generic.DetailView):
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
think = self.get_object() think = self.get_object()
relpath = self.kwargs['path'] relpath = self.kwargs['path']
path = think.root / relpath path = think.root / relpath
if not path.is_relative_to(think.root): print(path)
raise Exception(f"Bad path: {relpath}")
return redirect(think.get_static_url() + '/' + relpath)
class SaveFileView(ThinkMixin, generic.UpdateView): class SaveFileView(ThinkMixin, generic.UpdateView):
@ -211,7 +191,6 @@ class SaveFileView(ThinkMixin, generic.UpdateView):
def get_success_url(self): def get_success_url(self):
return self.object.get_absolute_url()+'?path='+str(self.path) return self.object.get_absolute_url()+'?path='+str(self.path)
class RenameFileView(ThinkMixin, generic.UpdateView): class RenameFileView(ThinkMixin, generic.UpdateView):
form_class = forms.RenameFileForm form_class = forms.RenameFileForm
template_name = 'thinks/rename_file.html' template_name = 'thinks/rename_file.html'
@ -224,7 +203,6 @@ class RenameFileView(ThinkMixin, generic.UpdateView):
def get_success_url(self): def get_success_url(self):
return self.object.get_absolute_url()+'?path='+str(self.path) return self.object.get_absolute_url()+'?path='+str(self.path)
class DeleteFileView(ThinkMixin, generic.UpdateView): class DeleteFileView(ThinkMixin, generic.UpdateView):
form_class = forms.DeleteFileForm form_class = forms.DeleteFileForm
template_name = 'thinks/delete_file.html' template_name = 'thinks/delete_file.html'
@ -236,7 +214,6 @@ class DeleteFileView(ThinkMixin, generic.UpdateView):
def get_success_url(self): def get_success_url(self):
return self.object.get_absolute_url()+'?path='+str(self.path.parent) return self.object.get_absolute_url()+'?path='+str(self.path.parent)
class RunCommandView(ThinkMixin, generic.UpdateView): class RunCommandView(ThinkMixin, generic.UpdateView):
form_class = forms.RunCommandForm form_class = forms.RunCommandForm
@ -251,14 +228,6 @@ class RunCommandView(ThinkMixin, generic.UpdateView):
) )
return JsonResponse({'stdout': res.stdout, 'stderr': res.stderr}) 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): class LogView(ThinkMixin, generic.DetailView):
template_name = 'thinks/think.html' template_name = 'thinks/think.html'
@ -267,13 +236,11 @@ class LogView(ThinkMixin, generic.DetailView):
return HttpResponse(think.get_log(), content_type='text/plain; charset=utf-8') return HttpResponse(think.get_log(), content_type='text/plain; charset=utf-8')
class JJStatusView(ThinkMixin, generic.detail.DetailView): class JJStatusView(ThinkMixin, generic.detail.DetailView):
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
status = self.get_object().jj_controller.status() status = self.get_object().jj_controller.status()
return JsonResponse({'status': status}) return JsonResponse({'status': status})
class JJCommitView(ThinkMixin, generic.UpdateView): class JJCommitView(ThinkMixin, generic.UpdateView):
form_class = forms.GitCommitForm form_class = forms.GitCommitForm