Skip to content

Commit

Permalink
Add documentation for tables
Browse files Browse the repository at this point in the history
  • Loading branch information
Polleps committed Aug 21, 2024
1 parent 4a1bbd7 commit cc89ad7
Show file tree
Hide file tree
Showing 9 changed files with 137 additions and 101 deletions.
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
import { useCallback, useState } from 'react';
import { useLocation, useNavigate } from 'react-router-dom';
import {
Client,
core,
dataBrowser,
useCanWrite,
useResource,
} from '@tomic/react';
import { Client, core, useCanWrite, useResource } from '@tomic/react';
import {
editURL,
dataURL,
Expand All @@ -31,7 +25,6 @@ import {
FaShare,
FaTrash,
FaPlus,
FaFileCsv,
} from 'react-icons/fa6';
import { useQueryScopeHandler } from '../../hooks/useQueryScope';
import {
Expand All @@ -44,7 +37,6 @@ import { useCurrentSubject } from '../../helpers/useCurrentSubject';
import { ResourceCodeUsageDialog } from '../../views/CodeUsage/ResourceCodeUsageDialog';
import { useNewRoute } from '../../helpers/useNewRoute';
import { addIf } from '../../helpers/addIf';
import { TableExportDialog } from '../../views/TablePage/TableExportDialog';

export enum ContextMenuOptions {
View = 'view',
Expand Down Expand Up @@ -90,7 +82,6 @@ function ResourceContextMenu({
const resource = useResource(subject);
const [showDeleteDialog, setShowDeleteDialog] = useState(false);
const [showCodeUsageDialog, setShowCodeUsageDialog] = useState(false);
const [showExportDialog, setShowExportDialog] = useState(false);
const handleAddClick = useNewRoute(subject);
const [currentSubject] = useCurrentSubject();
const [canWrite] = useCanWrite(resource);
Expand Down Expand Up @@ -208,13 +199,6 @@ function ResourceContextMenu({
onClick: () => setShowDeleteDialog(true),
},
),
...addIf(resource.hasClasses(dataBrowser.classes.table), {
id: ContextMenuOptions.Export,
icon: <FaFileCsv />,
label: 'Export to csv',
helper: 'Export the table as a CSV file',
onClick: () => setShowExportDialog(true),
}),
];

const filteredItems = showOnly
Expand Down Expand Up @@ -254,11 +238,6 @@ function ResourceContextMenu({
<ResourceUsage resource={resource} />
</>
</ConfirmationDialog>
<TableExportDialog
subject={subject}
show={showExportDialog}
bindShow={setShowExportDialog}
/>
{currentSubject && (
<ResourceCodeUsageDialog
subject={currentSubject}
Expand Down
13 changes: 11 additions & 2 deletions browser/data-browser/src/components/SideBar/AppMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@ import { constructOpenURL } from '../../helpers/navigation';
import { useCurrentSubject } from '../../helpers/useCurrentSubject';
import { SideBarMenuItem } from './SideBarMenuItem';
import { paths } from '../../routes/paths';
import { unknownSubject, useCurrentAgent, useResource } from '@tomic/react';
import {
core,
unknownSubject,
useCurrentAgent,
useResource,
} from '@tomic/react';

// Non standard event type so we have to type it ourselfs for now.
type BeforeInstallPromptEvent = {
Expand Down Expand Up @@ -59,7 +64,11 @@ export function AppMenu({ onItemClick }: AppMenuProps): JSX.Element {
<section aria-label='App menu'>
<SideBarMenuItem
icon={<FaUser />}
label={agent ? agentResource.title : 'Login'}
label={
agent
? agentResource.get(core.properties.name) ?? 'User Settings'
: 'Login'
}
helper='See and edit the current Agent / User (u)'
path={paths.agentSettings}
onClick={onItemClick}
Expand Down
75 changes: 55 additions & 20 deletions browser/data-browser/src/views/TablePage/TablePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,23 @@ import {
createResourceDeletedHistoryItem,
useTableHistory,
} from './helpers/useTableHistory';
import { Row as FlexRow, Column } from '../../components/Row';
import { useHandleClearCells } from './helpers/useHandleClearCells';
import { useHandleCopyCommand } from './helpers/useHandleCopyCommand';
import { ExpandedRowDialog } from './ExpandedRowDialog';
import { IconButton } from '../../components/IconButton/IconButton';
import { FaCode, FaFileCsv } from 'react-icons/fa6';
import { ResourceCodeUsageDialog } from '../CodeUsage/ResourceCodeUsageDialog';
import { TableExportDialog } from './TableExportDialog';

const columnToKey = (column: Property) => column.subject;

export function TablePage({ resource }: ResourcePageProps): JSX.Element {
const store = useStore();
const titleId = useId();

const [showCodeUsageDialog, setShowCodeUsageDialog] = useState(false);
const [showExportDialog, setShowExportDialog] = useState(false);
const { tableClass, sorting, setSortBy, collection, invalidateCollection } =
useTableData(resource);

Expand Down Expand Up @@ -114,32 +121,60 @@ export function TablePage({ resource }: ResourcePageProps): JSX.Element {
return (
<ContainerFull>
<TablePageContext.Provider value={tablePageContext}>
<EditableTitle resource={resource} id={titleId} />
<FancyTable
columns={columns}
columnSizes={columnSizes}
itemCount={collection.totalMembers + 1}
columnToKey={columnToKey}
labelledBy={titleId}
onClearRow={handleDeleteRow}
onCellResize={handleColumnResize}
onClearCells={handleClearCells}
onCopyCommand={handleCopyCommand}
onPasteCommand={handlePaste}
onUndoCommand={undoLastItem}
onColumnReorder={reorderColumns}
onRowExpand={handleRowExpand}
HeadingComponent={TableHeading}
NewColumnButtonComponent={NewColumnButton}
>
{Row}
</FancyTable>
<Column>
<FlexRow justify='space-between'>
<EditableTitle resource={resource} id={titleId} />
<FlexRow style={{ marginRight: '1rem' }}>
<IconButton
title='Use in code'
onClick={() => setShowCodeUsageDialog(true)}
>
<FaCode />
</IconButton>
<IconButton
title='Use in code'
onClick={() => setShowExportDialog(true)}
>
<FaFileCsv />
</IconButton>
</FlexRow>
</FlexRow>
<FancyTable
columns={columns}
columnSizes={columnSizes}
itemCount={collection.totalMembers + 1}
columnToKey={columnToKey}
labelledBy={titleId}
onClearRow={handleDeleteRow}
onCellResize={handleColumnResize}
onClearCells={handleClearCells}
onCopyCommand={handleCopyCommand}
onPasteCommand={handlePaste}
onUndoCommand={undoLastItem}
onColumnReorder={reorderColumns}
onRowExpand={handleRowExpand}
HeadingComponent={TableHeading}
NewColumnButtonComponent={NewColumnButton}
>
{Row}
</FancyTable>
</Column>
<ExpandedRowDialog
subject={expandedRowSubject ?? unknownSubject}
open={showExpandedRowDialog}
bindOpen={setShowExpandedRowDialog}
/>
</TablePageContext.Provider>
<ResourceCodeUsageDialog
subject={resource.subject}
show={showCodeUsageDialog}
bindShow={setShowCodeUsageDialog}
/>
<TableExportDialog
subject={resource.subject}
show={showExportDialog}
bindShow={setShowExportDialog}
/>
</ContainerFull>
);
}
3 changes: 2 additions & 1 deletion docs/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
- [AtomicServer](atomic-server.md)
- [When (not) to use it](atomicserver/when-to-use.md)
- [Installation](atomicserver/installation.md)
- [Getting started with the GUI](atomicserver/gui.md)
- [Using the GUI](atomicserver/gui.md)
- [Tables](atomicserver/gui/tables.md)
- [API](atomicserver/API.md)
- [Creating a JSON-AD file](create-json-ad.md)
- [FAQ & troubleshooting](atomicserver/faq.md)
Expand Down
Binary file added docs/src/assets/ui-guide/gui-tables-example.avif
Binary file not shown.
Binary file not shown.
88 changes: 35 additions & 53 deletions docs/src/atomicserver/gui.md
Original file line number Diff line number Diff line change
@@ -1,73 +1,55 @@
# Using the AtomicServer GUI

## Creating the first Agent on AtomicData.dev

Before you can create new things on AtomicData.dev, you'll need an _Agent_.
This is your virtual User, which can create, sign and own things.

Simply open the [demo invite](https://atomicdata.dev/invites/1) and press accept.

Copy the `secret` from the user settings page and save it somewhere safe, like in a password manager.

## Using your local AtomicServer

After [running the server](installation.md), open it in your browser.
By default, that's at [`http://localhost:9883`](http://localhost:9883).
<!-- (Fun fact: `&#9883;` is HTML entity code for the Atom icon: ⚛.) -->
> Fun fact: `&#9883;` is HTML entity code for the Atom icon: ⚛
The first screen should show you your main [_Drive_](https://atomicdata.dev/classes/Drive).
You can think of this as your root folder.
You can think of this as the root of the server.
It is the resource hosted at the root URL, effectively being the home page of your server.

There's an instruction on the screen about the `/setup` page.
Click this, and you'll get a screen showing an [_Invite_](https://atomicdata.dev/classes/Invite).
Normally, you could `Accept as new user`, but **since you're running on `localhost`, you won't be able to use the newly created Agent on non-local Atomic-Servers**.

Therefore, it may be best to create an Agent on some _other_ running server, such as the [demo Invite on AtomicData.dev](https://atomicdata.dev/invites/1).
And after that, copy the Secret from the `User settings` panel from AtomicData.dev, go back to your `localhost` version, and press `sign in`.
Paste the Secret, and voila! You're signed in.

Now, again go to `/setup`. This time, you can `Accept as {user}`.
After clicking, your Agent has gotten `write` rights for the Drive!
You can verify this by hovering over the description field, clicking the edit icon, and making a few changes.
You can also press the menu button (three dots, top left) and press `Data view` to see your agent after the `write` field.
Note that you can now edit every field.
You can also fetch your data now as various formats.

Try checking out the other features in the menu bar, and check out the `collections`.
In the sidebar you will see a list of resources in the current drive.
At the start these will be:

Again, check out the [README](https://github.com/atomicdata-dev/atomic-server) for more information and guides!
- The setup invite that's used to configure the root agent.
- A resource named `collections`. This is a group of collections that shows collections for all classes in the server, essentially a list of all resources.
- The default ontology. Ontologies are used to define new classes and properties and show to relation between them.

Now, let's create some data.
![The AtomicServer GUI](../assets/ui-guide/ui-guide-fresh-install.avif)

## Creating your first Atomic Data
## Creating an agent
To create data in AtomicServer you'll need an agent.
An agent is like a user account, it signs the changes (commits) you make to data so that others can verify that you made them.
Agents can be used on any AtomicServer as long as they have permission to do so.

Now let's create a [_Table_](https://atomicdata.dev/classes/Table).
A Class represents an abstract concept, such as a `BlogPost` (which we'll do here).
We can do this in a couple of ways:
If your AtomicServer is not reachable from the outside we recommend you create an agent on a public server like [atomicdata.dev](https://atomicdata.dev) as an agent created on a local server can only be used on that server.
The server that hosts your agent cannot do anything on your behalf because your private key is not stored on the server. They can however delete your agent making it unusable.

- Press the `+ icon` button on the left menu (only visible when logged in), and selecting Class
- Opening [Class](https://atomicdata.dev/classes/Class) and pressing `new class`
- Going to the [Classes Collection](https://atomicdata.dev/classes/) and pressing the plus icon
To create an agent on atomicdata.dev you can use the [demo invite](https://atomicdata.dev/invites/1).
If you want to create the agent on your own server you can use the `/setup` invite that was created when you first started the server.

The result is the same: we end up with a form in which we can fill in some details.
Click the "Accept as new user" button and navigate to the User Settings page.
Here you'll find the agent secret. This secret is what you use to login so keep it somewhere safe, like in a password manager. If you lose it you won't be able to recover your account.

Let's add a shortname (singular), and then a description.
After that, we'll add the `required` properties.
This form you're looking at is constructed by using the `required` and `recommended` Properties defined in `Class`.
We can use these same fields to generate our BlogPost resource!
Which fields would be required in a `BlogPost`?
A `name`, and a `description`, probably.
### Setting up the root Agent
Next, we'll set up the root Agent that has write access to the Drive.
If you've chosen to create an Agent on this server using the `/setup` invite, you can skip this step.

So click on the `+ icon` under `requires` and search for these Properties to add them.
Head to the `setup` page by selecting it in the sidebar.
You'll see a button that either says `Accept as <Your agent>` or `Accept as new user`.
If it says 'as new user`, click on login, paste your secret in the input field and return to the invite page.

Now, we can skip the `recommended` properties, and get right to saving our newly created `BlogPost` class.
So, press save, and now look at what you created.
After clicking the accept button you'll be redirected to the home page and you will have write access to the Drive.
You can verify this by hovering over the description field, clicking the edit icon, and making a few changes.
You can also press the menu button (three dots, top left) and press `Data view` to see your agent after the `write` field.
Note that you can now edit every field.

Notice a couple of things:
The `/setup`-invite can only be used once use and will therefore not work anymore.
If you want to re-enable the invite to change the root agent you can start AtomicServer with the `--initialize` flag.

- Your Class has its own URL.
- It has a `parent`, shown in the top of the screen. This has impact on the visibility and rights of your Resource. We'll get to that [later in the documentation](../hierarchy.md).
## Creating your first Atomic Data

Now, go to the navigation bar, which is by default at the bottom of the window. Use its context menu to open the `Data View`.
This view gives you some more insight into your newly created data, and various ways in which you can serialize it.
Now that everything is up and running you can start creating some resources.
To create a new resource, click the + button in the sidebar.
You will be presented with a list of resource types to choose from like Tables, Folders, Documents etc.
You can also create your own types by using ontologies.
31 changes: 31 additions & 0 deletions docs/src/atomicserver/gui/tables.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Tables

Tables are a way to create and group large amounts of structured data.

![Table](../../assets/ui-guide/gui-tables-example.avif)

Tables consist of rows of resources that share the same parent and class.
The properties of that class are represented as columns in the table.
This means that each column is type-safe, a number column can not contain text data for example.

## Creating a table

To create a table, click the "+" button in the sidebar or a folder and select "Table".
A dialog will appear prompting you to enter a name.
This name will be used as the title of the table as well as the name for the underlying class of the rows.
This new class will already have a `name` property. Using the `name` property as titles on your resources is a best practice as it helps with compatibility between other tools and makes your resources findable by AtomicServer's search functionality.
If you do not want to use the `name` property, you can remove it by clicking on the three dots in the column header and selecting "Remove".

While creating a new table you can also choose to use an existing class by selecting "Use existing class" in the dialog and selecting the desired class from the dropdown.

Classes created by tables are automatically added to the default ontology of the drive. Same goes for the columns of the table.
If you chose to use an existing class, any columns created will be added to the ontology containing that class.

## Features

- **Rearange columns**: You can drag and drop columns to rearrange them.
- **Resize columns**: You can resize columns by dragging the edges of the column header.
- **Sort rows**: Click on a column header to sort the rows by that column.
- **Fast keyboard navigation**: Use the arrow keys to navigate the table with hotkeys similar to Excel.
- **Copy & paste multiple cells**: You can copy and paste multiple cells by selecting them and using `Ctrl/Cmd + C` and `Ctrl/Cmd + V`. Pasting also works across different tables and even different applications that support HTML Table data (Most spreadsheet applications).
- **Export data to CSV**: You can export the data of a table to a CSV file by clicking the "Export" button in the top right.
5 changes: 2 additions & 3 deletions docs/src/atomicserver/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ You can run AtomicServer in different ways:
3. Using [Cargo](https://doc.rust-lang.org/cargo/getting-started/installation.html) from crates.io: `cargo install atomic-server`
4. Manually from source

When you're running AtomicServer, go to [Initial setup and configuration](#Initial-setup-and-configuration).
If you want to run this locally as a developer / contributor, check out [the Contributors guide](https://github.com/atomicdata-dev/atomic-server/blob/develop/CONTRIBUTING.md).
If you want to run AtomicServer locally as a developer / contributor, check out [the Contributors guide](https://github.com/atomicdata-dev/atomic-server/blob/develop/CONTRIBUTING.md).

## 1. Run using docker

Expand Down Expand Up @@ -59,7 +58,7 @@ sudo apt-get install -y build-essential pkg-config libssl-dev --fix-missing
- The server loads the `.env` from the current path by default. Create a `.env` file from the default template in your current directory with `atomic-server generate-dotenv`
- After running the server, check the logs and take note of the `Agent Subject` and `Private key`. You should use these in the [`atomic-cli`](https://crates.io/crates/atomic-cli) and [atomic-data-browser](https://github.com/atomicdata-dev/atomic-data-browser) clients for authorization.
- A directory is made: `~/.config/atomic`, which stores your newly created Agent keys, the HTTPS certificates other configuration. Depending on your OS, the actual data is stored in different locations. See use the `show-config` command to find out where, if you need the files.
- Visit `http://localhost:9883/setup` to **register your first (admin) user**. You can use an existing Agent, or create a new one. Note that if you create a `localhost` agent, it cannot be used on the web (since, well, it's local).
- Visit `http://localhost:9883/setup` to **register your first (admin) user**. You can use an existing Agent, or create a new one. Note that if you create a `localhost` agent, it cannot be used on the web (since, well, it's local). More info and steps in [getting started with the GUI](gui.md).

## Running using a tunneling service (easy mode)

Expand Down

0 comments on commit cc89ad7

Please sign in to comment.