mirror of
https://github.com/wasp-lang/wasp.git
synced 2024-11-23 19:29:17 +03:00
Removed lang-design/ dir.
This commit is contained in:
parent
8af6cf3696
commit
5b4519be3c
@ -1,105 +0,0 @@
|
|||||||
entity Task {
|
|
||||||
done : Boolean,
|
|
||||||
description : String
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Opcenito smisliti kako se mijesa javascript kod sa Wasp kodom.
|
|
||||||
// Uglavnom se svodimo na to da Wasp-u dajemo funkcije.
|
|
||||||
// Smisli kako mu ih se sve moze dati, i kako da one mogu raditi vise manje
|
|
||||||
// bilo sto, te sto je sa dependency injectionim, importovima, constraintovima
|
|
||||||
// na to sto rade ili vracaju, ... .
|
|
||||||
|
|
||||||
routes {
|
|
||||||
route "/" -> HomePage @default
|
|
||||||
route "/task/:taskId" -> TaskPage // Ovo je jednostavna deklarativna verzija, parametri se sami salju u TaskPage.
|
|
||||||
// Ovo je naprednija, ne-deklarativna verzija.
|
|
||||||
// TODO: Kako znamo da je ova funkcija pozvala page? Ili mozda to niti ne provjeravamo.
|
|
||||||
// Otkud joj uopce taj goToPage? Da joj to injectamo?
|
|
||||||
route "/task/:taskId" -> (taskId) => { goToPage("TaskPage", taskId) }
|
|
||||||
route "/task/bytext/:query" -> ?
|
|
||||||
route "/home" -> route "/"
|
|
||||||
route "*" -> Page404()
|
|
||||||
}
|
|
||||||
|
|
||||||
page HomePage {
|
|
||||||
route = /home @default
|
|
||||||
component = Main
|
|
||||||
}
|
|
||||||
|
|
||||||
page TaskPage (taskId) {
|
|
||||||
//route = '/task/:taskId'
|
|
||||||
component = TaskView(taskId) // HM
|
|
||||||
}
|
|
||||||
|
|
||||||
component TaskView (taskId) {
|
|
||||||
source: 'asdf.js'
|
|
||||||
queries: {
|
|
||||||
task: getTask(taskId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
goToPage(TaskPage, taskId) -> url := /task/taskId
|
|
||||||
/task/4
|
|
||||||
|
|
||||||
@query @acl admin
|
|
||||||
getAllTasks = query ...
|
|
||||||
|
|
||||||
// Pitanja:
|
|
||||||
// 1. Moze li query imati argumente (na razini Wasp-a)?
|
|
||||||
// Teoretski mozemo reci da query nemaju argumente.
|
|
||||||
// Mislim da to bas i ne bi bilo prakticno ipak, iako bi moglo raditi vjerojatno.
|
|
||||||
// 2.
|
|
||||||
@query getAllTasksForUser ~ (Task)
|
|
||||||
{=js
|
|
||||||
(Task, user, params) => {
|
|
||||||
return Task.find({author: user.id})
|
|
||||||
}
|
|
||||||
js=}
|
|
||||||
|
|
||||||
// TODO(martin): how do we import js stuff?
|
|
||||||
// Pitanje: Koji je odnos injectanih stvari i argumenata? Ovako sad ne izgleda bas jasno sto je injectano a sto je argument.
|
|
||||||
// Iako je i to mozda ok posto su injectane stvari i dalje argumenti, ali ipak hm.
|
|
||||||
@action ~ (Task) // -> Stuff from here gets injected. We love injecting as it enables testing.
|
|
||||||
{=js
|
|
||||||
function addNewTask (Task, newTaskData) {
|
|
||||||
Task.insert(newTask)
|
|
||||||
}
|
|
||||||
js=}
|
|
||||||
|
|
||||||
// Do we add this to component under "actions"?
|
|
||||||
// That way it would be inject as prop (we have to do that),
|
|
||||||
// but that is cool because that makes code decoupled and all.
|
|
||||||
// Alternative is that user imports it into react component.
|
|
||||||
// But are they importing directly function then, or are they
|
|
||||||
// importing an action? If they are importing an action (what does that even mean),
|
|
||||||
// that needs to be in some special manner.
|
|
||||||
// What does it even mean that this is action, if we are not aware of any side effect,
|
|
||||||
// does it make sense to declare it as an action, should it instead just be function?
|
|
||||||
@action
|
|
||||||
{=js
|
|
||||||
function sendAnEmail (text) {
|
|
||||||
sendgrid.sendEmail(text) // Kako smo importali sendgrid?
|
|
||||||
}
|
|
||||||
js=}
|
|
||||||
|
|
||||||
|
|
||||||
//action addNewTask ...
|
|
||||||
|
|
||||||
component Main {
|
|
||||||
source = "mycomp.js"
|
|
||||||
queries = {tasks: getAllTasksForUser(f)} // This ends up as prop.
|
|
||||||
actions = [addNewTask] // This ends up as prop.
|
|
||||||
}
|
|
||||||
|
|
||||||
component MainAdmin {
|
|
||||||
source = "mycomp.js"
|
|
||||||
queries = {allTasks: getAllTasks}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
---------------------------------------
|
|
||||||
Entityi (Wasp) -> Prisma, ... .
|
|
||||||
Komponente (React)
|
|
||||||
Operacije (JS) -> query vs akcija, server vs client, custom vs built-in.
|
|
||||||
|
|
@ -1,55 +0,0 @@
|
|||||||
onMount = fetchTasksAction()
|
|
||||||
|
|
||||||
render () {
|
|
||||||
button title="refresh" onClick = fetchTasksAction
|
|
||||||
button title="onlyDoneTasks" onClick = fetchOnlyDoneTasksAction
|
|
||||||
return tasks
|
|
||||||
}
|
|
||||||
|
|
||||||
connect(state)
|
|
||||||
tasks: () => getTasksSel(state)
|
|
||||||
onlyDoneTasks = () => ...
|
|
||||||
fetchTasksAction: fetchTasksAction
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
render () {
|
|
||||||
tasks = if nesto then doQuery(GET_TASKS, args) else doQuery(GET_TASKS, other args)
|
|
||||||
return tasks
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Problem?: We fetch all queries before component even starts, we don't fetch them lazily. Could we solve that with annotations like @default, @required and similar? So those would say: don't load it upfront, or do load it upfront, or use this as default value until something is loaded, ...
|
|
||||||
// Another problem: While in Redux and Apollo, dev can choose when and under which condition to fetch certain pieces of state,
|
|
||||||
// while we say: this is what needs to be fetched upfront for this component and that is it.
|
|
||||||
// Can we solve this by providing user with actions that can run queries? So if they want to manually refresh certain query from the component,
|
|
||||||
// they could define an action that calls that query in it (with refetch on true) and then call that action from the component, conditionally or whatever.
|
|
||||||
queries: {
|
|
||||||
tasks: getTasks(arg) @default([]) @required
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
|
||||||
button title="refresh" onClick = this.props.getTasks(otherArg)
|
|
||||||
button title="onlyDoneTasks" onClick = this.props.getOnlyDoneTasks()
|
|
||||||
|
|
||||||
this.props.tasks
|
|
||||||
}
|
|
||||||
|
|
||||||
// Komponenta slusa i koristi u zivotu x querya, kondicionalno ili kako god. Takodjer i radi odredjene akcije.
|
|
||||||
// Sto ako ona zeli neki query na silu pokrenuti / refetchati / refreshati?
|
|
||||||
// Sto ako zeli neki query "lazy"/"on demand" izvrsiti -> dakle da se on desi tek kad joj treba, da se ne executa odmah cim se komponenta loada ili nesto.
|
|
||||||
|
|
||||||
// Sto ako komponenta zeli "na zivo" promijeniti koje querye slusa (na temelju propova ili necega)? ---> TO SE CINI PROBLEM HM.
|
|
||||||
// Ostali to rade tako da: ako se promjene propovi komponente, onda imas priliku redefinirati selectore/querye.
|
|
||||||
// Da napravimo da definicija vezanih querya ovisi o propovima, da je funkcija propova? A sto je s lokalnim stateom?
|
|
||||||
|
|
||||||
// This could be solution, but it seems too "black boxed" -> if it is JS black box and it is happening in runtime, how are we going to translate this into smth else?
|
|
||||||
queries: (props, state) => {
|
|
||||||
return {
|
|
||||||
tasks: getTasks(props.taskId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,80 +0,0 @@
|
|||||||
// TODO app in Wasp - try #1
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ------- main.wasp
|
|
||||||
|
|
||||||
page MainPage {
|
|
||||||
route: "/",
|
|
||||||
component: MainPageComponent
|
|
||||||
}
|
|
||||||
|
|
||||||
component MainPageComponent {
|
|
||||||
source: "MainPageComponent.js",
|
|
||||||
queries: {
|
|
||||||
tasks: getAllTasks
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
entity Task {
|
|
||||||
description: String,
|
|
||||||
isDone: Boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
query getAllTasks {
|
|
||||||
uses: [Task],
|
|
||||||
fn: {=js
|
|
||||||
(Task) => {
|
|
||||||
return Task.find({})
|
|
||||||
}
|
|
||||||
js=}
|
|
||||||
// OR source: { import: "getAllTasks", from: "queries.js" }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ------- MainPageComponent.js
|
|
||||||
|
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
export default class MainPageComponent extends React.Component {
|
|
||||||
static propTypes = {
|
|
||||||
tasks: PropTypes.array.object
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return <div>
|
|
||||||
{ this.props.tasks.map(t => (
|
|
||||||
<div>
|
|
||||||
<span> { t.isDone } </span>
|
|
||||||
<span> { t.description } </span>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// -------- CLI
|
|
||||||
wasp init
|
|
||||||
wasp install
|
|
||||||
wasp start
|
|
||||||
|
|
||||||
|
|
||||||
// -------- Ideas
|
|
||||||
// TODO: When inline JS, figure out how to import. Existing system? Smth new?
|
|
||||||
query getAllTasks ~ Task {=js
|
|
||||||
(Task) => {
|
|
||||||
return Task.find({})
|
|
||||||
}
|
|
||||||
js=}
|
|
||||||
|
|
||||||
@uses(Task)
|
|
||||||
query getAllTasks (Task) {
|
|
||||||
return Task.find({})
|
|
||||||
}
|
|
@ -1,131 +0,0 @@
|
|||||||
// Goal of this file is to re-create a TODO app from http://todomvc.com
|
|
||||||
// This file has "advanced" features in the sense that they might not yet be implemented by Wasp: this is just a proposal.
|
|
||||||
|
|
||||||
app todoMVC {
|
|
||||||
title: "ToDo MVC"
|
|
||||||
}
|
|
||||||
|
|
||||||
entity Task {
|
|
||||||
description :: string,
|
|
||||||
isDone :: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
// IDEA: `@connect Task as taskList` -> this would make it more obvious what is available, also we don't need to automatically try to guess what to import.
|
|
||||||
page Main {
|
|
||||||
route: "/",
|
|
||||||
|
|
||||||
content: {=jsx
|
|
||||||
<div className="mainContainer">
|
|
||||||
<h1>todos</h1>
|
|
||||||
|
|
||||||
<div className="createTaskForm">
|
|
||||||
{/* Toggle all */}
|
|
||||||
<button onClick={() => {
|
|
||||||
const setIsDoneTo = false
|
|
||||||
if (this.props.taskList.some(t => !t.isDone)) setIsDoneTo = true
|
|
||||||
|
|
||||||
this.props.taskList.map(t => this.props.updateTask(t, { isDone: setIsDoneTo }))
|
|
||||||
}}>
|
|
||||||
<Icon id="arrow-down" />
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<CreateTaskForm />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="taskListContainer">
|
|
||||||
<TaskList filter={this.state.taskFilter} /> { /* Filter here -> that is not supported by TaskList yet. */ }
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="footer">
|
|
||||||
{ /* TODO: This is maybe not very nice, inlined like this.
|
|
||||||
Also, we directly address taskList here, while in TaskList and in CreateTaskForm we address
|
|
||||||
it implicitly. */ }
|
|
||||||
<span>
|
|
||||||
{ this.props.taskList.filter(task => !task.isDone).length } items left
|
|
||||||
</span>
|
|
||||||
{ /* TODO: Can we also make this nicer? */ }
|
|
||||||
<button onClick={() => this.setState({ taskFilter: () => true })}> All </button>
|
|
||||||
<button onClick={() => this.setState({ taskFilter: task => !task.isDone })}> Active </button>
|
|
||||||
<button onClick={() => this.setState({ taskFilter: task => task.isDone })}> Completed </button>
|
|
||||||
|
|
||||||
{/* Clear completed */}
|
|
||||||
{ this.props.taskList.some(t => t.isDone) &&
|
|
||||||
<button onClick={() => { this.state.taskList.map(t => if (t.isDone) this.props.deleteTask(t)) }}>Clear completed</button>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
jsx=},
|
|
||||||
|
|
||||||
style: {=css
|
|
||||||
div {
|
|
||||||
color: green;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mainContainer {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.taskListContainer {
|
|
||||||
width: 60%;
|
|
||||||
}
|
|
||||||
css=}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: This part is not currently supported at all.
|
|
||||||
entity-form<Task> CreateTaskForm {
|
|
||||||
fields: {
|
|
||||||
description: {
|
|
||||||
placeholder: "What do you want to do?"
|
|
||||||
},
|
|
||||||
isDone: {
|
|
||||||
show: false,
|
|
||||||
defaultValue: false // Although not shown, this field will be set to "false".
|
|
||||||
}
|
|
||||||
},
|
|
||||||
submit: {
|
|
||||||
button: { show: false },
|
|
||||||
onEnter: true,
|
|
||||||
// Resets fields to their initial values after the submission.
|
|
||||||
resetAllFields: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: This part is not currently supported at all.
|
|
||||||
entity-list<Task> TaskList {
|
|
||||||
allowItemEditing: true,
|
|
||||||
allowItemDeletion: true, // Items can be deleted, and this also deletes them for real.
|
|
||||||
|
|
||||||
fields: {
|
|
||||||
description: {
|
|
||||||
// The contract for render is: user can provide a function that:
|
|
||||||
// - receives a task as an input
|
|
||||||
// - returns a React Node or something that can be rendered by JSX
|
|
||||||
// - does not depend on any outer context
|
|
||||||
render: {=js
|
|
||||||
(task) => {
|
|
||||||
if (task.isDone) return (<s>{task.description}</s>)
|
|
||||||
return task.description
|
|
||||||
}
|
|
||||||
js=}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: This part is not currently supported at all.
|
|
||||||
// Idea would be to generate a script (bash) that does deployment and would be called
|
|
||||||
// with `npm deploy`, from generated frontend.
|
|
||||||
// NOTE: For now we don't care about environments (staging) yet, there is just one environment to deploy to (production).
|
|
||||||
deployment {
|
|
||||||
frontend: {
|
|
||||||
// TODO: In case of github, this would go into CNAME file.
|
|
||||||
// NOTE: optional.
|
|
||||||
customDomain: 'todo-app.examples.wasp-lang.dev',
|
|
||||||
github: { // NOTE: For now we allow only one deployment method (in this case "github") at once.
|
|
||||||
branch: 'gh-pages' // NOTE: optional.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user