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

Landing page for FlowFuse Dashboard #2237

Merged
merged 6 commits into from
Jun 25, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
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
37 changes: 37 additions & 0 deletions src/_data/dashboard.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"section2": [
{
"title": "Effortless Development",
"description": "FlowFuse Dashboard's intuitive interface allows you to drag-and-drop widgets, buttons, and other elements to create rich dashboards without writing a single line of code. This significantly reduces development time and empowers non-technical users to build powerful applications."
},
{
"title": "Enhanced User Experience",
"description": "Go beyond simple data visualization. FlowFuse Dashboard lets you create interactive dashboards with features like buttons and user-specific views. This empowers users to explore data, filter results, and take actions directly within the dashboard."
},
{
"title": "Extensible Ecosystem",
"description": "Node-RED actively fosters a growing community of developers. This means a constantly expanding library of widgets and nodes, ensuring you have the tools you need to build any dashboard you can imagine."
},
{
"title": "Flexible deployment with FlowFuse",
"description": "With FlowFuse you can deploy FlowFuse Dashboard along with enterprise-grade features on the cloud or on-premises. This ensures a smooth and efficient development experience, for a high-performance and scalable solution."
}
],
"resources": [
{
"url": "/blog/2024/03/dashboard-getting-started/",
"title": "Getting Started with Node-RED Dashboard 2.0",
"image": "/blog/2024/03/images/getting-started-with-dashboard-2.png"
},
{
"url": "/webinars/2024/node-red-dashboard-multi-user/",
"title": "Personalised Multi User Dashboards with Node-RED Dashboard 2.0",
"image": "/images/webinars/multi-user-dashboard-with-node-red-dashboard-2-0-webinar-2024-february.jpg"
},
{
"url": "/ebooks/ultimate-guide-to-building-applications-with-flowfuse-dashboard-for-node-red/",
"title": "The Ultimate Guide to Building Applications with FlowFuse Dashboard for Node-RED",
"image": "/images/ebooks/ebook_dashboard.png"
}
]
}
5 changes: 3 additions & 2 deletions src/_includes/layouts/base.njk
Original file line number Diff line number Diff line change
Expand Up @@ -216,15 +216,16 @@ eleventyComputed:
</ul>
{% endnavoption %}
{% navoption "Resources", null, 0 %}
<ul class="sm:grid sm:grid-flow-col sm:grid-rows-4 sm:grid-cols-1 sm:pr-9">
<ul class="sm:grid sm:grid-flow-col sm:grid-rows-5 sm:grid-cols-1 sm:pr-9">
{% navoption "Blog", "/blog/", 1, "newspaper" %}{% endnavoption %}
{% navoption "Webinars", "/webinars/", 1, "screen" %}{% endnavoption %}
{% navoption "Github", "https://github.com/FlowFuse/flowfuse", 1, "github", true %}{% endnavoption %}
{% navoption "Docs", "/docs/", 1, "document-text" %}{% endnavoption %}
{% navoption "Support forums", "https://discourse.nodered.org/c/vendors/flowfuse/24/", 1, "chat-bubble-left-right-sm" %}{% endnavoption %}
{% navoption "Customer Stories", "/customer-stories/", 1, "presentation" %}{% endnavoption %}
{% navoption "Node-RED", "/node-red/", 1, "info" %}{% endnavoption %}
{% navoption "Node-RED", "/node-red/", 1, "nr-icon" %}{% endnavoption %}
Yndira-E marked this conversation as resolved.
Show resolved Hide resolved
{% navoption "Unified Namespace", "/unified-namespace/", 1, "info" %}{% endnavoption %}
{% navoption "FlowFuse Dashboard", "/flowfuse-dashboard/", 1, "chart" %}{% endnavoption %}
</ul>
{% endnavoption %}
{% navoption "Docs", "/docs/", 0, false %}{% endnavoption %}
Expand Down
125 changes: 125 additions & 0 deletions src/_includes/migration.njk
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
<div class="nohero w-full">
<div class="m-auto">
<div class="ff-dashboard-migration">
<div>
<div
class="ff-file-drop-zone"
onclick="openFilePicker();"
ondrop="dropHandler(event);"
ondragover="dragOverHandler(event);">
<p id="drag-instruction">Drag a <i>flow.json</i> file containing Node-RED Dashboard 1.0 nodes here.</p>
<p id="file-selected" style="display: none;">
Flow Uploaded: "<i id="file-selected-name">drop zone</i>""
</p>
<input id="dashboard1-flow-file" name="dashboard1-flow-file" type="file" accept="json" onchange="fileSelected()"/>
</div>
<a id="dashboard-2-download" style="display:none"></a>
</div>
<div id="hs-user-form">

</div>
</div>
</div>
</div>

<script>
var d1Flow = null

function openFilePicker () {
// open file selector
document.getElementById("dashboard1-flow-file").click()
}

function fileSelected () {
console.log('file selected')
// get file
var file = document.getElementById("dashboard1-flow-file").files[0]
if (file) {
document.getElementById("file-selected-name").innerText = file.name
// hide drag instructions
document.getElementById("file-selected").style.display = "block"
document.getElementById("drag-instruction").style.display = "none"
} else {
// hide drag instructions
document.getElementById("file-selected").style.display = "none"
document.getElementById("drag-instruction").style.display = "block"
}
}

function downloadFlow (flow) {
var dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(flow))
var dlAnchorElem = document.getElementById('dashboard-2-download')
dlAnchorElem.setAttribute("href", dataStr)
dlAnchorElem.setAttribute("download", "flow-dashboard2.json")
dlAnchorElem.click()
}

function migrateFile() {
// Your migration logic goes here

var file = null
var selectedFile = document.getElementById("dashboard1-flow-file").files
if (selectedFile) {
file = selectedFile[0]
} else {
file = d1Flow
}

if (file) {
fetch('https://dashboard-migration-service.flowfuse.cloud/migrate-flow', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: file
}).then(function (response) {
return response.json()
}).then(function (body) {
downloadFlow(body)
}).catch((err) => {
console.error('Error migrating flow', err)
})
}
}

function dropHandler(event) {

// Prevent default behavior (Prevent file from being opened)
ev.preventDefault()

if (ev.dataTransfer.items) {
// Use DataTransferItemList interface to access the file(s)
[...ev.dataTransfer.items].forEach((item, i) => {
// If dropped items aren't files, reject them
if (item.kind === "file") {
d1Flow = item.getAsFile();
}
});
} else {
// Use DataTransfer interface to access the file(s)
[...ev.dataTransfer.files].forEach((file, i) => {
console.log(`… file[${i}].name = ${dashboard1Flow.name}`)
});
}
}

function dragOverHandler(event) {
event.preventDefault();
}

const PROD = '968a9ab6-3dd8-45b2-991c-3f055dc18787'
const TEST = '1ecbeb84-36a6-4077-b6c8-3f4a5b06bca0'
joepavitt marked this conversation as resolved.
Show resolved Hide resolved

function displayHubSpotForm() {
hbspt.forms.create({
target: '#hs-user-form',
region: "eu1",
portalId: "26586079",
formId: TEST,
onFormSubmitted: function ($form) {
migrateFile()
}
});
}
Yndira-E marked this conversation as resolved.
Show resolved Hide resolved
</script>
<script async type="text/javascript" charset="utf-8" src="//js-eu1.hsforms.net/forms/embed/v2.js" onload="displayHubSpotForm()"></script>
46 changes: 46 additions & 0 deletions src/css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -754,6 +754,52 @@ h4:hover .header-anchor {
transform: translateX(0);
}

/*
Migration Service
*/

.ff-file-drop-zone {
background-color: theme(colors.blue.50);
border: 1px dashed theme(colors.blue.300);
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
height: 100%;
padding: 64px;
text-align: center;
}

.ff-file-drop-zone:hover {
background-color: theme(colors.blue.100);
border: 1px solid theme(colors.blue.300);
display: flex;
justify-content: center;
align-items: center;
}

.ff-file-drop-zone input[type="file"] {
display: none;
}

.ff-dashboard-migration {
display: grid;
flex-direction: column;
gap: 32px;
justify-content: center;
@apply max-md:px-6;
}

.ff-dashboard-migration-actions {
margin: auto;
}

@media (min-width: 680px) {
.ff-dashboard-migration {
grid-template-columns: 1fr 1fr;
}
}

/*
Footer
*/
Expand Down
119 changes: 119 additions & 0 deletions src/flowfuse-dashboard.njk
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
---
Yndira-E marked this conversation as resolved.
Show resolved Hide resolved
layout: nohero
meta:
title: FlowFuse Dashboard
description: Create visually appealing and functional UIs in minutes with FlowFuse Dashboard for Node-RED, the open-source low-code platform for connecting data endpoints
---
<!--Hero Content-->
<div class="w-full px-6">
<div class="max-w-md sm:max-w-screen-lg pb-6 mt-12 mx-auto">
<div class="text-center md:text-left max-w-xl mx-auto md:mx-0 md:my-auto md:py-10 md:max-w-none">
<h1 class="font-medium m-auto lg:m-0 max-sm:text-4xl">
<span class="text-indigo-600">FlowFuse Dashboard</span> for <span class="inline-block">Node-RED</span>
</h1>
<h4 class="font-light mt-2 text-gray-500">
Build visually appealing and useful UIs in minutes!
</h4>
<div class="justify-center items-center m-auto w-full flex mt-10">
{% image "./images/dashboard/dashboard.svg", "FlowFuse Dashboard", [1920] %}
</div>
<p class="mt-8 text-left">
FlowFuse Dashboard is a revolutionary tool that allows you to create beautiful and functional dashboards
within <a href="/node-red/">Node-RED</a>, the leading open-source low-code platform for wiring together a variety of data
endpoints. Whether you're a long-time user or just getting started with Node-RED, FlowFuse Dashboard
makes it easy to visualize and interact with your data like never before.
</p>
<p class="text-left">
Much like the original Dashboard, FlowFuse Dashboard provides a set of easy-to-use, core nodes, but also
provides complete flexibility for customization and control over theming, layout and behavior. 
</p>
<div class="flex flex-col mt-10">
<div
class="m-auto flex gap-4 items-center justify-center md:items-start md:justify-start md:m-0 flex-row">
<a class="ff-btn ff-btn--primary flex flex-col mb-6" href="https://dashboard.flowfuse.com/"
target="_blank">
<span class="text-base flex gap-2 uppercase items-center">
GET STARTED
</span>
</a>
</div>
</div>
</div>
</div>
</div>

<!-- Secondary Content -->
<div class="w-full px-6">
<div class="max-w-md md:max-w-screen-lg m-auto max-w-5xl">
<h2 class="text-center w-full md:text-left"><span class="text-indigo-600">Empowering Anyone</span> to Build Full-Stack Applications</h2>
<ul class="flex flex-col mx-auto w-full text-center md:grid md:grid-cols-2 gap-12 mt-12 mb-16">
{% for item in dashboard.section2 %}
<li class="flex flex-col items-center md:items-start border-2 border-indigo-100 rounded-md p-6 pb-3 gap-3">
<div class="flex flex-col justify-center md:justify-start gap-3 w-full">
<div class="w-full flex flex-row gap-3 mx-auto md:m-0">
<h5 class="w-full md:m-0 text-xl text-gray-600 text-center md:text-left">
{{ item.title }}
</h5>
</div>
</div>
<div>
<p class="text-center text-lg md:text-left font-light">
{{ item.description }}
</p>
</div>
</li>
{% endfor %}
</ul>
</div>
</div>
<div class="about w-full bg-gray-50 pt-16">
<!-- Migration -->
<div class="w-full px-6 pt-2">
<div class="max-w-md sm:max-w-screen-lg mx-auto pb-14">
<div class="mx-auto w-full md:max-w-screen-lg">
<h2 class="text-center w-full md:text-left">Easily migrate <span class="text-indigo-600">from Dashboard 1.0
Yndira-E marked this conversation as resolved.
Show resolved Hide resolved
to FlowFuse Dashboard</span></h2>
<p class="mt-6">
Get started quickly with your new FlowFuse Dashboard. This migration service will automatically convert
your original Node-RED Dashboard flows, and make them FlowFuse Dashboard-ready.
</p>
<p class="pb-5">
This service will improve over time. Currently, we support the automatic conversion of
<code>ui_tab</code>, <code>ui_link</code> and <code>ui_group</code> nodes.
</p>
</div>
{% include "migration.njk" %}
</div>
</div>
<!-- Learning Resources -->
<div class="bg-white pb-12 md:pb-20 pt-16 px-6 text-center">
<div class="max-w-md sm:max-w-screen-lg mx-auto">
<h2 class="text-center w-full md:text-left">FlowFuse Dashboard <span class="text-indigo-600">Learning Resources</span></h2>
<ul class="mt-10 grid grid-cols-1 md:grid md:grid-cols-3 gap-y-4 m-auto gap-6">
{%- for item in dashboard.resources -%}
<li class="w-full max-w-md m-auto my-2">
<a href="{{ item.url }}" class="w-full flex flex-col group hover:no-underline">
<div class="relative">
<div class="sm:max-h-none md:min-w-[40%] max-w-[448px] ff-image-cover ff-image-rounded scale mx-auto mb-4 aspect-video">
{% set imageSrc = ["./", item.image ] | join %}
{% set imageDescription = ["Image representing ", item.data.title] | join %}

{% image imageSrc, imageDescription, [285] %}
</div>
</div>
<h5 class="mt-1 mb-0 group-hover:underline font-light text-lg text-left text-gray-600">{{ item.title }}</h5>
</a>
</li>
{% endfor %}
</ul>
<div class="flex justify-end">
<a href="/blog/dashboard/" class="font-light hover:underline pt-3 flex flex-row items-center gap-1 cursor-pointer flex-wrap max-md:max-w-md mb-10">
Learn more {% include "components/icons/arrow-long-right.svg" %}
</a>
</div>
<div class="bg-indigo-50 py-1 px-4 rounded-md w-full mx-auto">
<p>Looking for help with your project? <a href="/contact-us/">Contact us</a>; our experts will be happy to provide a solution for your needs.  </p>
</div>
</div>
</div>
</div>
Loading
Loading