Skip to content

Commit

Permalink
wip: file field
Browse files Browse the repository at this point in the history
  • Loading branch information
eaguad1337 committed Nov 1, 2023
1 parent 3983f71 commit ef5d5c5
Show file tree
Hide file tree
Showing 15 changed files with 156 additions and 10 deletions.
24 changes: 24 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"dependencies": {
"@hookform/resolvers": "^3.3.1",
"@radix-ui/react-alert-dialog": "^1.0.5",
"@radix-ui/react-aspect-ratio": "^1.0.3",
"@radix-ui/react-avatar": "^1.0.4",
"@radix-ui/react-checkbox": "^1.0.4",
"@radix-ui/react-dropdown-menu": "^2.0.5",
Expand Down
41 changes: 41 additions & 0 deletions src/collapsar/File.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"""FileField definition"""
from typing import Callable, Union, TYPE_CHECKING
from masonite.facades.Hash import Hash
from .Field import Field

if TYPE_CHECKING:
from masoniteorm.models.Model import Model


class File(Field):
"""FileField definition"""

type = "file"

def __init__(
self, name: str, attribute: Union[str, Callable] = None, resolve_callback: Callable = None
):
# Field's component
self.component = "FileField"
# Field's suggestions callback
self.suggestions = None

super().__init__(name, attribute, resolve_callback)

def fill(self, request, model: "Model"):
"""Fill the field"""

storage = request.app.make("storage")
path = storage.disk("local").put_file("collapsar/storage/", request.input(self.attribute))
setattr(model, self.attribute, path)

return None

def json_serialize(self):
"""
Prepare the element for JSON serialization.
:return: dict
"""
serialized = super().json_serialize()
return serialized
41 changes: 41 additions & 0 deletions src/collapsar/assets/js/components/fields/FileField.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Input } from "@/components/ui/input";
import { AspectRatio } from "@radix-ui/react-aspect-ratio";
import { useState } from "react";

export function FileField(props: any) {
const [replaceImage, setReplaceImage] = useState(true);

const displayRender = () => {
return (
<div className="flex items-center space-x-2 max-h-[200px]">
<img className="h-full" src={`/${props.value}`} alt="" />
</div>
);
};

if (props.renderForDisplay || !props.fieldConfig) {
return displayRender();
}

const handleOnChange = (e: any) => {
props.onChange(e.target.files ? e.target.files[0] : null)
}

return (
<>
{props.value && !replaceImage ? (
<AspectRatio ratio={5 / 3} className="bg-muted">
<img className="min-h-full min-w-full" src={props.value} alt="" onClick={() => setReplaceImage(true)} />
</AspectRatio>
) : (
<Input
type="file"
readOnly={props.fieldConfig.readonly}
onChange={handleOnChange}

name={props.name}
/>
)}
</>
);
}
1 change: 1 addition & 0 deletions src/collapsar/assets/js/components/fields/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export { SelectField } from './SelectField';
export { BooleanField } from './BooleanField';
export { RichTextField } from './RichTextField';
export { CalendarField } from './CalendarField';
export { FileField } from './FileField';
export { BelongsToField } from './BelongsToField';

export { Field } from './Field';
5 changes: 5 additions & 0 deletions src/collapsar/assets/js/components/ui/aspect-ratio.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import * as AspectRatioPrimitive from "@radix-ui/react-aspect-ratio"

const AspectRatio = AspectRatioPrimitive.Root

export { AspectRatio }
17 changes: 10 additions & 7 deletions src/collapsar/assets/js/pages/ResourceEdit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ export function ResourceEdit() {
let schema: z.ZodTypeAny;

switch (field.type) {
case "file":
schema = z.instanceof(File);
break;
case "boolean":
schema = z.boolean();
break;
Expand Down Expand Up @@ -128,16 +131,16 @@ export function ResourceEdit() {

function onSubmit(values: any) {
// filter values object to remove computed fields
values = Object.keys(values)
const formData = new FormData()
Object.keys(values)
.filter((key) => !key.startsWith("computed"))
.reduce((obj, key) => {
obj[key] = values[key];
return obj;
}, {});
.forEach(key => {
formData.append(key, values[key])
});

if (isCreating) {
return axios
.put(`/collapsar-api/${params.resource}/`, values)
.put(`/collapsar-api/${params.resource}/`, formData)
.then((response) => {
console.log("Success");
console.log(response.data);
Expand All @@ -149,7 +152,7 @@ export function ResourceEdit() {
}

axios
.patch(`/collapsar-api/${params.resource}/${data.data.id}`, values)
.patch(`/collapsar-api/${params.resource}/${data.data.id}`, formData)
.then((response) => {
console.log("Success");
console.log(response.data);
Expand Down
6 changes: 6 additions & 0 deletions src/collapsar/controllers/CollapsarController.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,9 @@ def get_css(self, response: Response):
def get_asset(self, filename):
"""Return file path."""
return os.path.dirname(__file__) + "/../dist/assets/" + filename

def get_storage(self, request: Request, response: Response):
"""Return file path."""
storage = request.app.make("storage")
file_name = request.environ.get('PATH_INFO').split('/')[-1].replace('..', '')
return response.download(file_name, storage.disk('local').get_path('collapsar/storage/' + file_name))
1 change: 1 addition & 0 deletions src/collapsar/providers/CollapsarProvider.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ def register(self):

super().register()

# TODO: Make this configurable
resources_path = config("collapsar.resources_path", "app/collapsar/resources")

self.application.bind("Collapsar", Collapsar(self.application))
Expand Down
5 changes: 4 additions & 1 deletion src/collapsar/routes/web.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@
Route.post("/auth/login", AuthController.login),
Route.get("/auth/logout", AuthController.logout),

Route.get("/storage/.*", CollapsarController.get_storage),
Route.get("/assets/app.js", CollapsarController.get_js),
Route.get("/assets/style.css", CollapsarController.get_css),

Route.get('.*', CollapsarController.index).middleware('auth',)

# Route.get('', CollapsarController.index).middleware('auth',),
Route.get('.*', CollapsarController.index).middleware('auth',),
],
prefix="/collapsar",
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from tests.integrations.app.models.Article import Article
from UserResource import UserResource

from src.collapsar import Resource
from src.collapsar.TextInput import TextInput
from src.collapsar.Id import Id
from src.collapsar.RichText import RichText
from src.collapsar.BelongsTo import BelongsTo
from src.collapsar.File import File


class ArticleResource(Resource):
Expand All @@ -26,6 +26,7 @@ def fields(cls):

return [
Id("Id", "id").readonly(),
File("Image", "image"),
TextInput("Title", "title").rules("required"),
RichText("Content", "content").rules("required").hide_from_index(),
BelongsTo("User", "user", "UserResource").rules("required"),
Expand Down
2 changes: 1 addition & 1 deletion tests/integrations/app/models/Article.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
class Article(Model, UUIDPrimaryKeyMixin):
"""Article Model"""

__fillable__ = ["title", "content", "user_id"]
__fillable__ = ["title", "content", "user_id", "image"]

@belongs_to('user_id', 'id')
def user(self):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
"""ArticlesAddImage Migration."""

from masoniteorm.migrations import Migration


class ArticlesAddImage(Migration):
def up(self):
"""
Run the migrations.
"""
with self.schema.table("articles") as table:
table.string("image").nullable()

def down(self):
"""
Revert the migrations.
"""
with self.schema.table("articles") as table:
table.drop_column("image")
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit ef5d5c5

Please sign in to comment.