Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal for Deployed Dashboards Enhancement Using Drag & Drop Functionality #2052

Closed
wants to merge 36 commits into from
Closed
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
cd87376
add gridstack.js to create app dashboard pages
jannikbecher Jul 7, 2023
953dadb
save layout and show in deployed app
jannikbecher Jul 7, 2023
c83c4e6
WIP
jannikbecher Jul 8, 2023
2526763
WIP
jannikbecher Jul 10, 2023
a10fbdd
WIP
jannikbecher Jul 10, 2023
e17bb5b
WIP
jannikbecher Jul 10, 2023
eeebf8d
WIP
jannikbecher Jul 11, 2023
a7a5cc6
Add new canvas view
jannikbecher Jul 11, 2023
5bf643e
Send canvas_settings update to canvas
jannikbecher Jul 11, 2023
1e92ccd
Render iframes in canvas
jannikbecher Jul 11, 2023
e3b3b2d
remove old deploy functionality
jannikbecher Jul 11, 2023
46ae045
add pop out functionality
jannikbecher Jul 11, 2023
408ba9a
formatting
jannikbecher Jul 11, 2023
6d55169
WIP deploy app
jannikbecher Jul 11, 2023
1489455
Apply indicators suggestions
jannikbecher Jul 12, 2023
e0473e6
hide move to canvas button when output is already on canvas
jannikbecher Jul 12, 2023
3dc3635
Add move output to notebook button
jannikbecher Jul 12, 2023
8a3e33c
hide canvas options in sub menu
jannikbecher Jul 12, 2023
3370fd6
Implement suggested view mode UI
jannikbecher Jul 12, 2023
8b70d5e
fix nasty popped out window bug
jannikbecher Jul 12, 2023
6439841
Apply suggestions
jannikbecher Jul 17, 2023
91e956d
Fix click twice to enable canvas mode bug
jannikbecher Jul 17, 2023
386f0ab
Use pubsub for window popin/popout communication
jannikbecher Jul 17, 2023
1c5a61d
Since Broadcast Channel API is used for client PubSub, broadcast func…
jannikbecher Jul 18, 2023
9bbe1b2
Revert "Since Broadcast Channel API is used for client PubSub, broadc…
jannikbecher Jul 18, 2023
bfe0ebe
Revert "Use pubsub for window popin/popout communication"
jannikbecher Jul 18, 2023
f0241db
Move eventlistener to gridstack hook
jannikbecher Jul 18, 2023
50bbf44
Some refactoring
jannikbecher Jul 19, 2023
e106553
Add gridstack to popped out window
jannikbecher Jul 20, 2023
59a66f1
Add show canvas options to app settings
jannikbecher Jul 20, 2023
23449fd
Add canvas deployment
jannikbecher Jul 20, 2023
0859c43
Remove canvas settings
jannikbecher Jul 20, 2023
d30b795
Get session updates in popout window
jannikbecher Jul 20, 2023
ff8b531
Some cleanup
jannikbecher Jul 20, 2023
992e9fd
Add client_id to popout window & handle /popout-window navigation
jannikbecher Jul 20, 2023
ade354f
Fix not rendering markdown
jannikbecher Jul 21, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 62 additions & 2 deletions assets/css/js_interop.css
Original file line number Diff line number Diff line change
Expand Up @@ -286,8 +286,60 @@ solely client-side operations.
@apply hidden;
}

[data-el-session][data-js-view^="canvas"]
~ #app-settings-modal
[data-el-app-settings-enable-canvas-button] {
@apply hidden;
}

[data-el-session]:not([data-js-view="canvas-popped-out"])
~ #app-settings-modal
[data-el-app-settings-popin-canvas-button] {
@apply hidden;
}

/* === Views === */

[data-el-session]:not([data-js-view]) [data-el-view-deactivate-button] {
@apply hidden;
}

[data-el-session][data-js-view] [data-el-view-toggle="canvas"],
[data-el-session][data-js-view] [data-el-view-toggle="code-zen"],
[data-el-session][data-js-view] [data-el-view-toggle="presentation"] {
@apply pointer-events-none;
}

[data-el-session]:not([data-js-view="canvas"]) [data-el-canvas],
[data-el-cell][data-el-js-cell-output-location-canvas]
[data-el-move-output-to-canvas-button],
[data-el-cell]:not([data-el-js-cell-output-location-canvas])
[data-el-move-output-to-notebook-button],
[data-el-session]:not([data-js-view^="canvas"]) [data-el-canvas-menu],
[data-el-session]:not([data-js-view="canvas-popped-out"])
[data-el-canvas-popin-button],
[data-el-session]:not([data-js-view="canvas"]) [data-el-canvas-popout-button],
[data-el-session]:not([data-js-view="canvas"]) [data-el-canvas-close-button] {
@apply hidden;
}

[data-el-session][data-js-view="canvas"] [data-el-notebook-indicators] {
@apply fixed bottom-[0.4rem] right-1/2;
}

[data-el-session][data-js-view^="canvas"] [data-el-view-toggle="canvas"],
[data-el-session][data-js-view^="canvas"]
[data-el-view-canvas-poppedout-button] {
@apply text-green-bright-400;
}

[data-el-session]:not([data-js-view="canvas-popped-out"])
[data-el-view-canvas-poppedout-button],
[data-el-session][data-js-view="canvas-popped-out"]
[data-el-view-toggle="canvas"] {
@apply hidden;
}

[data-el-session][data-js-view="code-zen"] [data-el-section-headline],
[data-el-session][data-js-view="code-zen"] [data-el-section-subheadline],
[data-el-session][data-js-view="code-zen"]
Expand Down Expand Up @@ -329,12 +381,20 @@ solely client-side operations.
@apply text-green-bright-400;
}

[data-el-session]:is([data-js-view="code-zen"], [data-js-view="presentation"])
[data-el-session]:is(
[data-js-view^="canvas"],
[data-js-view="code-zen"],
[data-js-view="presentation"]
)
[data-el-views-disabled] {
@apply hidden;
}

[data-el-session]:not([data-js-view="code-zen"], [data-js-view="presentation"])
[data-el-session]:not(
[data-js-view=^="canvas"],
[data-js-view="code-zen"],
[data-js-view="presentation"]
)
[data-el-views-enabled] {
@apply hidden;
}
36 changes: 36 additions & 0 deletions assets/js/hooks/app_canvas.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import "gridstack/dist/gridstack.min.css";
import { GridStack } from "gridstack";

/**
* A hook for creating app dashboard.
*/
const AppCanvas = {
mounted() {
const self = this;

const options = {
staticGrid: true,
float: true,
margin: 0,
cellHeight: "4rem",
};

this.grid = GridStack.init(options, this.el);

this.handleEvent("init", ({ payload }) => {
const grid_items = Object.entries(payload).map(([id, value]) => ({
id,
...value,
}));
this.grid.load(grid_items);
console.log(this.grid.el.children);
Array.from(this.grid.el.children).forEach((item) => {
const output_id = `[id^=outputs-${item.id}]`;
const output_el = document.querySelector(output_id);
item.firstChild.appendChild(output_el);
});
});
},
};

export default AppCanvas;
77 changes: 77 additions & 0 deletions assets/js/hooks/canvas.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { getAttributeOrThrow, parseInteger } from "../lib/attribute";
import { globalPubSub } from "../lib/pub_sub";
import "gridstack/dist/gridstack.min.css";
import { GridStack } from "gridstack";

/**
* A hook for creating a canvas with gridstackjs.
*/
const Canvas = {
mounted() {
this.props = this.getProps();
console.log("Gridstack mounted");
const self = this;

const options = {
styleInHead: true,
float: true,
resizable: { handles: "all" },
margin: 0,
cellHeight: "4rem",
};

this.grid = GridStack.init(options, this.el);

this.handleEvent("reload", ({ payload }) => {
const grid_items = Object.entries(payload).map(([id, value]) => ({
id,
...value,
}));
this.grid.load(grid_items);
Array.from(this.grid.el.children).forEach((item) => {
console.log(item.attributes);
const output_id = `[id^=outputs-${item.attributes["gs-id"].value}]`;
const output_el = document.querySelector(output_id);
item.firstChild.appendChild(output_el);
});
Comment on lines +31 to +36
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably very bad idea to do it this way, but I couldn't come up with another solution...
I just remount the existing outputs into the gridstack items

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

didn't put more effort into it yet, because I'm tinkering around with implementing a liveview compatible drag&drop solution

});

this.grid.on("change", function (event, items) {
console.log("ITEMS changed: ", items);
let new_items = items.reduce((acc, item) => {
acc[item.id] = {
x: item.x,
y: item.y,
w: item.w,
h: item.h,
};
return acc;
}, {});
self.pushEventTo(self.props.phxTarget, "items_changed", new_items);
self.repositionIframe();
});

this.grid.on("removed", (event, items) => {
console.log("REMOVED", event);
});

this.grid.on("drag", function (event, item) {
// TODO update iframe position when dragging
//self.repositionIframe();
});
},
updated() {
this.props = this.getProps();
console.log("Gridstack updated", this.grid);
},
getProps() {
return {
phxTarget: getAttributeOrThrow(this.el, "data-phx-target", parseInteger),
};
},
repositionIframe() {
globalPubSub.broadcast("js_views", { type: "reposition" });
},
};

export default Canvas;
6 changes: 6 additions & 0 deletions assets/js/hooks/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import AppAuth from "./app_auth";
import AppCanvas from "./app_canvas";
import AudioInput from "./audio_input";
import Canvas from "./canvas";
import Cell from "./cell";
import CellEditor from "./cell_editor";
import Dropzone from "./dropzone";
Expand All @@ -13,6 +15,7 @@ import ImageOutput from "./image_output";
import JSView from "./js_view";
import KeyboardControl from "./keyboard_control";
import MarkdownRenderer from "./markdown_renderer";
import PopoutWindow from "./popout_window";
import ScrollOnUpdate from "./scroll_on_update";
import Session from "./session";
import TextareaAutosize from "./textarea_autosize";
Expand All @@ -24,7 +27,9 @@ import VirtualizedLines from "./virtualized_lines";

export default {
AppAuth,
AppCanvas,
AudioInput,
Canvas,
Cell,
CellEditor,
Dropzone,
Expand All @@ -38,6 +43,7 @@ export default {
JSView,
KeyboardControl,
MarkdownRenderer,
PopoutWindow,
ScrollOnUpdate,
Session,
TextareaAutosize,
Expand Down
45 changes: 45 additions & 0 deletions assets/js/hooks/popout_window.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* A hook for popped out windows.
*/
const PopoutWindow = {
mounted() {
this.props = this.getProps();
console.log("PopoutWindow mounted");
const self = this;

this.handleBeforeUnloadEvent = this.handleBeforeUnloadEvent.bind(this);
window.addEventListener("beforeunload", this.handleBeforeUnloadEvent);
this.getElement("canvas-close-button").addEventListener("click", (event) =>
this.handleCanvasCloseClick()
);
this.getElement("canvas-popin-button").addEventListener("click", (event) =>
this.handleCanvasPopinClick()
);
},
updated() {
this.props = this.getProps();
console.log("PopoutWindow updated");
},
getProps() {
return {};
},
handleBeforeUnloadEvent(event) {
this.sendToParent("canvas_popin_clicked");
},
handleCanvasCloseClick() {
window.removeEventListener("beforeunload", this.handleBeforeUnloadEvent);
this.sendToParent("canvas_close_clicked");
},
handleCanvasPopinClick() {
window.removeEventListener("beforeunload", this.handleBeforeUnloadEvent);
this.sendToParent("canvas_popin_clicked");
},
getElement(name) {
return document.querySelector(`[data-el-${name}]`);
},
sendToParent(message) {
window.opener.postMessage(message, window.location.origin);
},
};

export default PopoutWindow;
Loading