🌀 Portal.JS
Create a gateway to your data

* [What is Portal.JS ?](#What-is-Portal.JS) * [Features](#Features) * [For developers](#For-developers) * [Installation and setup](#Installation-and-setup) * [Getting Started](#Getting-Started) * [Tutorial](#Tutorial) * [Build a single Frictionless dataset portal](#Build-a-single-Frictionless-dataset-portal) * [Build a CKAN powered dataset portal](#Build-a-CKAN-powered-dataset-portal) * [Architecture / Reference](#Architecture--Reference) * [Component List](#Component-List) * [UI Components](#UI-Components) * [Dataset Components](#Dataset-Components) * [View Components](#View-Components) * [Search Components](#Search-Components) * [Blog Components](#Blog-Components) * [Misc Components](#Misc-Components) * [Concepts and Terms](#Concepts-and-Terms) * [Dataset](#Dataset) * [Resource](#Resource) * [View Spec](#view-spec) * [Appendix](#Appendix) * [What happened to Recline?](#What-happened-to-Recline?) # What is Portal.JS 🌀 `portal.js` is a framework for rapidly building rich data portal frontends using a modern frontend approach. `portal.js` can be used to present a single dataset or build a full-scale data catalog/portal. `portal.js` is built in Javascript and React on top of the popular [Next.js](https://nextjs.com/) framework. `portal` assumes a "decoupled" approach where the frontend is a separate service from the backend and interacts with backend(s) via an API. It can be used with any backend and has out of the box support for [CKAN](https://ckan.org/). ## Features - 🗺️ Unified sites: present data and content in one seamless site, pulling datasets from a DMS (e.g. CKAN) and content from a CMS (e.g. wordpress) with a common internal API. - 👩‍💻 Developer friendly: built with familiar frontend tech Javascript, React etc - 🔋 Batteries included: Full set of portal components out of the box e.g. catalog search, dataset showcase, blog etc. - 🎨 Easy to theme and customize: installable themes, use standard CSS and React+CSS tooling. Add new routes quickly. - 🧱 Extensible: quickly extend and develop/import your own React components - 📝 Well documented: full set of documentation plus the documentation of NextJS and Apollo. ### For developers - 🏗 Build with modern, familiar frontend tech such as Javascript and React. - 🚀 NextJS framework: so everything in NextJS for free React, SSR, static site generation, huge number of examples and integrations etc. - SSR => unlimited number of pages, SEO etc whilst still using React. - Static Site Generation (SSG) (good for small sites) => ultra-simple deployment, great performance and lighthouse scores etc # Installation and setup Before installation, ensure your system satisfies the following requirements: - Node.js 10.13 or later - Nextjs 10.0.3 - MacOS, Windows (including WSL), and Linux are supported > Note: We also recommend instead of npm using `yarn` instead of `npm`. > Portal.js is built with React on top of Nextjs framework, so for a quick setup, you can bootstrap a Nextjs app and install portal.js as demonstrated in the code below: ```bash= ## Create a react app npx create-next-app # or yarn create next-app ``` After the installation is complete, follow the instructions to start the development server. Try editing pages/index.js and see the result on your browser. > For more information on how to use create-next-app, you can review the [create-next-app](https://nextjs.org/docs/api-reference/create-next-app) documentation. Once you have Nextjs created, you can install portal.js: ```bash= yarn add https://github.com/datopian/portal.js.git ``` You're now ready to use portal.js in your next app. To test portal.js, open your `index.js` file in the pages folder. By default you should have some autogenerated code in the `index.js` file: Which outputs a page with the following content: ![](https://i.imgur.com/GVh0P6p.png) Now, we are going to do some clean up and add a table component. In the `index.js` file, import a [Table]() component from portal as shown below: ```javascript import Head from 'next/head' import { Table } from 'portal' //import Table component import styles from '../styles/Home.module.css' export default function Home() { const columns = [ { field: 'id', headerName: 'ID' }, { field: 'firstName', headerName: 'First name' }, { field: 'lastName', headerName: 'Last name' }, { field: 'age', headerName: 'Age' } ]; const rows = [ { id: 1, lastName: 'Snow', firstName: 'Jon', age: 35 }, { id: 2, lastName: 'Lannister', firstName: 'Cersei', age: 42 }, { id: 3, lastName: 'Lannister', firstName: 'Jaime', age: 45 }, { id: 4, lastName: 'Stark', firstName: 'Arya', age: 16 }, { id: 7, lastName: 'Clifford', firstName: 'Ferrara', age: 44 }, { id: 8, lastName: 'Frances', firstName: 'Rossini', age: 36 }, { id: 9, lastName: 'Roxie', firstName: 'Harvey', age: 65 }, ]; return (
Create Portal App

Welcome to Portal.JS

{/* Use table component */} ) } ``` Now, your page should look like the following: ![](https://i.imgur.com/n0vSjY4.png) > **Note**: You can learn more about individual portal components, as well as their prop types in the [components reference](#Component-List). ___ # Getting Started If you're new to Portal.js we recommend that you start with the step-by-step guide below. You can also check out the following examples of projects built with portal.js. * [A portal for a single Frictionless dataset](#Build-a-single-Frictionless-dataset-portal) * [A portal with a CKAN backend](#Build-a-CKAN-powered-dataset-portal) > The [`examples` directory](https://github.com/datopian/portal.js/tree/main/examples) is regularly updated with different portal examples. If you have questions about anything related to Portal.js, you're always welcome to ask our community on [GitHub Discussions](https://github.com/datopian/portal.js/discussions). ___ # Tutorial ## Build a single Frictionless dataset portal This tutorial will guide you through building a portal for a single Frictionless dataset. In this tutorial, you’ll learn Portal.js basics by creating a very simple portal app. [Here’s](https://portal-js.vercel.app/) an example of the final result. Let’s get started! > This tutorial assumes basic knowledge of JavaScript, React and Nextjs. If you are not familiar with React or Nextjs, it is advisable to learn them first. We provide some links below to get you started: * [Learn NextJS](https://nextjs.org/docs/getting-started) * [Getting started with React](https://reactjs.org/docs/getting-started.html#learn-react) ### Setup TODO ## Build a CKAN powered dataset portal TODO ___ # Architecture / Reference ## Component List Portal.js supports many components that can help you build amazing data portals similar to [this](https://catalog-portal-js.vercel.app/) and [this](https://portal-js.vercel.app/). In this section, we'll cover all supported components in depth, and help you understand their use as well as the expected properties. Components are grouped under the following sections: * [UI](https://github.com/datopian/portal.js/tree/main/src/components/ui): Components like Nav bar, Footer, e.t.c * [Dataset](https://github.com/datopian/portal.js/tree/main/src/components/dataset): Components used for displaying a Frictionless dataset and resources * [Search](https://github.com/datopian/portal.js/tree/main/src/components/search): Components used for building a search interface for datasets * [Blog](https://github.com/datopian/portal.js/tree/main/src/components/blog): Components for building a simple blog for datasets * [Views](https://github.com/datopian/portal.js/tree/main/src/components/views): Components like charts, tables, maps for generating data views * [Misc](https://github.com/datopian/portal.js/tree/main/src/components/misc): Miscellaneous components like errors, custom links, etc used for extra design. ### UI Components In the UI we group all components that can be used for building generic page sections. These are components for building sections like the Navigation bar, Footer, Side pane, Recent datasets, e.t.c. #### [Nav Component](https://github.com/datopian/portal.js/blob/main/src/components/ui/Nav.js) To build a navigation bar, you can use the `Nav` component as demonstrated below: ```javascript import { Nav } from 'portal' export default function Home(){ const navMenu = [{ title: 'Blog', path: '/blog' }, { title: 'Search', path: '/search' }] return ( <>
) } ``` > Note: Under the hood, Table component uses the [DataGrid Material UI table](https://material-ui.com/components/data-grid/), and as such all supported params in data and columns are supported. #### Table Component Prop Types Table component accepts two properties: * **data**: An array of column names with properties: e.g [{field: "col1", headerName: "col1"}, {field: "col2", headerName: "col2"}] * **columns**: An array of data objects e.g. [ {col1: 1, col2: 2}, {col1: 5, col2: 7} ] ### [Search Components](https://github.com/datopian/portal.js/tree/main/src/components/search) Search components groups together components that can be used for creating a search interface. This includes search forms, search item as well as search result list. #### [Form Component](https://github.com/datopian/portal.js/blob/main/src/components/search/Form.js) The search`Form` component is a simple search input and submit button. See example of a search form [here](https://catalog-portal-js.vercel.app/search). The search `form` requires a submit handler (`handleSubmit`). This handler function receives the search term, and handles actual search. In the example below, we demonstrate how to use the `Form` component. ```javascript import { Form } from 'portal' export default function Home() { const handleSearchSubmit = (searchQuery) => { // Write your custom code to perform search in db console.log(searchQuery); } return ( ) } ``` #### Form Component Prop Types The `Form` component accepts a single property: * **handleSubmit**: A function that receives the search text, and can be customize to perform the actual search. #### [Item Component](https://github.com/datopian/portal.js/blob/main/src/components/search/Item.js) The search`Item` component can be used to display a single search result. In the example below, we demonstrate how to use the `Item` component. ```javascript import { Item } from 'portal' export default function Home() { const datapackage = { "name": "finance-vix", "title": "VIX - CBOE Volatility Index", "homepage": "http://www.cboe.com/micro/VIX/", "version": "0.1.0", "description": "This is a test organization description", "resources": [ { "name": "vix-daily", "path": "vix-daily.csv", "format": "csv", "size": 20982, "mediatype": "text/csv", } ] } return ( ) } ``` #### Item Component Prop Types The `Item` component accepts a single property: * **dataset**: A [Frictionless data package descriptor](https://specs.frictionlessdata.io/data-package/#descriptor) #### [ItemTotal Component](https://github.com/datopian/portal.js/blob/main/src/components/search/Item.js) The search`ItemTotal` is a simple component for displaying the total search result In the example below, we demonstrate how to use the `ItemTotal` component. ```javascript import { ItemTotal } from 'portal' export default function Home() { //do some custom search to get results const search = (text) => { return [{ name: "data1" }, { name: "data2" }] } //get the total result count const searchTotal = search("some text").length return ( ) } ``` #### ItemTotal Component Prop Types The `ItemTotal` component accepts a single property: * **count**: An integer of the total number of results. ### [Blog Components](https://github.com/datopian/portal.js/tree/main/src/components/blog) These are group of components for building a portal blog. See example of portal blog [here](https://catalog-portal-js.vercel.app/blog) #### [PostList Components](https://github.com/datopian/portal.js/tree/main/src/components/misc) The `PostList` component is used to display a list of blog posts with the title and a short excerpts from the content. In the example below, we demonstrate how to use the `PostList` component. ```javascript import { PostList } from 'portal' export default function Home() { const posts = [ { title: "Blog post 1", excerpt: "This is the first blog excerpts in this list." }, { title: "Blog post 2", excerpt: "This is the second blog excerpts in this list." }, { title: "Blog post 3", excerpt: "This is the third blog excerpts in this list." }, ] return ( ) } ``` #### PostList Component Prop Types The `PostList` component accepts a single property: * **posts**: An array of post list objects with the following properties: ```javascript [ { title: "The title of the blog post", excerpt: "A short excerpt from the post content", }, ] ``` #### [Post Components](https://github.com/datopian/portal.js/tree/main/src/components/misc) The `Post` component is used to display a blog post. See an example of a blog post [here](https://catalog-portal-js.vercel.app/blog/nyt-pa-platformen-opdateringsfrekvens-og-andres-data) In the example below, we demonstrate how to use the `Post` component. ```javascript import { Post } from 'portal' import * as dayjs from 'dayjs' //For converting UTC time to relative format import relativeTime from 'dayjs/plugin/relativeTime' dayjs.extend(relativeTime) export default function Home() { const post = { title: "This is a sample blog post", content: `

A simple header

The PostList component is used to display a list of blog posts with the title and a short excerpts from the content. In the example below, we demonstrate how to use the PostList component.`, createdAt: dayjs().to(dayjs(1620649596902)), featuredImage: "https://pixabay.com/get/ge9a766d1f7b5fe0eccbf0f439501a2cf2b191997290e7ab15e6a402574acc2fdba48a82d278dca3547030e0202b7906d_640.jpg" } return ( ) } ``` #### Post Component Prop Types The `Post` component accepts a single property: * **post**: An object with the following properties: ```javascript { title: content: createdAt: featuredImage: < Url/relative url to post cover image> } ``` ### [Misc Components](https://github.com/datopian/portal.js/tree/main/src/components/misc) These are group of miscellaneous/extra components for extending your portal. They include components like Errors, custom links, etc. #### [Error Component](https://github.com/datopian/portal.js/blob/main/src/components/misc/Error.js) The `Error` component is used to display a custom error message. In the example below, we demonstrate how to use the `Error` component. ```javascript import { Error } from 'portal' export default function Home() { return ( ) } ``` #### Error Component Prop Types The `Error` component accepts a single property: * **message**: A string with the error message to display. #### [Custom Component](https://github.com/datopian/portal.js/blob/main/src/components/misc/Error.js) The `CustomLink` component is used to create a link with a consistent style to other portal components. In the example below, we demonstrate how to use the `CustomLink` component. ```javascript import { CustomLink } from 'portal' export default function Home() { return ( ) } ``` #### CustomLink Component Prop Types The `CustomLink` component accepts the following properties: * **url**: A string. The relative or absolute url of the link. * **title**: A string. The title of the link ___ ## Concepts and Terms In this section, we explain some of the terms and concepts used throughtout the portal.js documentation. > Some of these concepts are part of official specs, and when appropriate, we'll link to the sources where you can get more details. ### Dataset A dataset extends the [Frictionless data package](https://specs.frictionlessdata.io/data-package/#metadata) to add an extra organization property. The organization property describes the organization the dataset belongs to, and it should have the following properties: ```javascript organization = { name: "some org name", title: "Some optional org title", description: "A description of the organization" } ``` An example of dataset with organization properties is given below: ```javascript datasets = [{ organization: { name: "some org name", title: "Some optional org title", description: "A description of the organization" }, title: "Data package title", name: "Data package name", description: "description of data package", resources: [...], licences: [...], sources: [...] } ] ``` ### Resource TODO ### view spec --- ## Deploying portal build to github pages * [Deploying single frictionless dataset to Github](./scripts/README.md) ## Showcases ### Single Dataset with Default Theme ![Single Dataset Example](./examples/dataset-frictionless/assets/demo.gif) --- # Appendix ## What happened to Recline? Portal.JS used to be Recline(JS). If you are looking for the old Recline codebase it still exists: see the [`recline` branch](https://github.com/datopian/portal.js/tree/recline). If you want context for the rename see [this issue](https://github.com/datopian/portal.js/issues/520).