-
Notifications
You must be signed in to change notification settings - Fork 23
Developing
This was added with version 0.5.1.
- Open code spaces or the repository in VS Code to start the dev container
- The container will automatically install all dependencies and build the app
- Nextcloud will be installed from the master development branch and be available on a port exposed by the container
To build you will need to have Node.js and Composer installed.
# Clone repository into the app-directory:
cd /path/to/apps && git clone https://github.com/nextcloud/tables && cd tables`
# Install PHP dependencies:
composer install
# Install JS dependencies:
npm ci
# Build JavaScript for the frontend
npm run dev
# or for instand compiling
npm run watch
There is a namespace overlap between the app and some 3rd party dev-dependency. If you get errors on running for example occ commands, please remove the composer dev-dependencies like this:
# go to repository
cd /path/to/apps/tables
rm -r vendor
composer install --no-dev
Tables can define their own structure by incorporating columns. A column type determines information about what kind of information is intended to store in it. Depending on this column type different attributes enrich the column such as max and min values for number columns or the selection options for a selection column.
Following column types are known:
TextLine
-
TextLong
deprecated since v0.5.0 and NC >= 26 -
TextRich
new since v0.5.0 and NC26 TextLink
Number
NumberStars
NumberProgress
Selection
SelectionMulti
SelectionCheck
Datetime
DatetimeDate
DatetimeTime
The tables app uses a default internal format to store data. This look like the following (related to the php DateTime class):
- Date
Y-m-d
example '2023-12-24' - Time
H:i
example '09:00' - Datetime
Y-m-d H:i
example '2023-12-24 12:00'
You should use this format. We also support iso date string (example 2019-09-07T15:50:00+01:00) for importing data.
Starting with the version 0.6 the tables app knows views. Here are some good-to-know-facts about views:
- Each Table can have multiple views. Views always belong to one table.
- Views control permissions. If you share it, you share it with the configuration by a view. So only the selected columns will be accessible and so on.
- If you want to create or edit views you have to be the owner or a manager of the table.
- A link to a single row always needs an underlying view or the default view is used. This is needed because the view will configure which columns in what order are shown and how they are formatted etc.
Filter Views can have more than one filter, and they can be combined within groups. To simplify the UX for the user we use the following logic to handle grouping:
- Every view can have unlimited groups.
- Groups are combined with an OR operator.
- Every group can have unlimited filters.
- Filters inside a group are combined with an AND operator.
Every column has a set attribute with the name type
that indicates a kind of technical category. There might be individual fields for this type that are explicit stored in the db. Second we have a subtype
, that always belongs to a main type. This can make use of the individual fields from the main type, but don't have own properties (except for inline props stored in the main type props). This way we can have components that handle all subtypes for a main type, if possible. Or we need individual components for each subtype, depending on the use case.
Example would be the main type text
, which has several subtypes as line
, link
or rich
.
Especially in the front end we use the combined type joined with a dash (-), so we get:
text-long
text-link
- ...
It is not necessary to have a subtype, for example for plain numbers number
. The combined column type is also number
in that case.
A column is a class with the superclass AbstractColumn. This superclass unifies common attributes such as tableID, title, etc. There are further AbstractColumn types for each main type. They currently are:
AbstractNumberColumn
AbstractDatetimeColumn
AbstractTextColumn
AbstractSelectionColumn
Finally, the single column classes extend directly the AbstractColumn (currently none) or one abstract subclass of it. They implement the logic that differs between the single column types like sort
, isSearchStringFound
, isFilterFound
and more. Also the column type, which is stored as an attribute, is set in them. It is formatted as snake_case with dashes:
E.g.
-
number
for NumberColumn -
text-long
for TextLongColumn - ...
You can fetch all served column-types from the capabilities (since v0.5.0):
curl http://admin:admin@nextcloud.local/ocs/v1.php/cloud/capabilities\?format\=json -H 'OCS-APIRequest: true' | jq .ocs.data.capabilities.tables.column_types
The text-link column holds a simple url since the first version of the tables app. Beginning with version 0.6 it is possible to insert all known resources that implement a search-provider. The tables app reuses these as described.
If you want to make use of the new resources, you have to define which search provider are allowed.
These can be fetched via the search API. Write them into the textAllowedPattern
comma seperated.
Example:
url,mail,calendar,search-deck-card-board
To insert a value for a row, please use an encoded json-object that should look like the following:
{
"thumbnailUrl": "http://nextcloud.local/index.php/core/preview?fileId=7&x=32&y=32",
"title": "photo-1503991721143-75f95ebf1e55.jpeg",
"subline": "Files",
"resourceUrl": "http://nextcloud.local/index.php/f/7",
"icon": "/index.php/apps/theming/img/core/filetypes/image.svg?v=21421e36",
"providerId": "files"
}
- If there is no thumbnailUrl or the destination of it can't be reached, the icon will be displayed.
- If there is no icon, a default link-icon will be displayed.
- The subline should hold a name for the source like the source app name. (Contacts, Mail, Files, ...)
Subset #1
This subset describes a reusable structure. It will be referenced by the following parts.
You can have different mixins for this particular subset that goes into the mixed
folder.
Partial
s are small UI components that can have internal UI logic like animations, or error hints.
But they are always self-contained. Interact with them via props and local emitting events.
Between the different components like data layer, partials and layout pages we need some kind of glue to bring them all together.
This is covered by the sections
. They can fetch data, organize partials and will be used within pages once or multiple times.
modules
We have different business units to split up the hole tables project a bit. Each module handles their business inside of this folder.
We assume that if a module wants to communicate with another module, this is a common event and might be interesting for other modules as well. That's why communication across multiple modules should go over the event bus system.
Each module can have a subset structure like in the picture subset #1
.
Look at the general description about this subset.
modals
The modals module is a bit special. It holds all modals that can be opened and will be included in all mother component (see pages for details).
pages Pages are the layout for the main content part. It holds the navigation section, the main content parts (sections) and also the sidebar if needed.
shared Sometimes we create a component with the idea that this one could be reused all over the tables app and maybe also in other apps. Let's put them into the shared folder to indicate that these components are made to reuse. Maybe these can mature over time and might be merged into the vue library one day.
assets
The assets holds some shared static assets like icons.
components
Complete vue components that are completely independent goes in here.
The components make use of the subset #1
.
mixins
If you have a mixin that is not related to a specific module and might be reused, here's a good place for them. Think about typical helpers.
modals
If you have a modal that is not related to a specific module and might be reused, here's a good place for them.
utils
If you need native js utils, put it in here.
store
The store holds all data that are often reused by multiple modules. Otherwise, this data could be hold by a section.
Metadata like the actual view mode, active table ID or loading states goes in here as well.
views
This views
folder is unrelated to the 'views' in tables.
This contains components that are used by integration parts such as the smart picker, widget rendering etc.
They can also make use of the subset #1
.
There are some points where you can use (insert) magic-values.
Magic values are variables which can be selected by the users and which get live rendered during a request. They are called magic because they will replace the values related to the context of a request. This could be the username, user ID, local time, timezone etc.
For example the "magic value" could be me
, that means the program will replace this with your individual userId
.
This gives you the ability to create views that are filtered by the users who open this view (means depending on who is logged in).
Following magic values are known:
Name | id | Replacement |
---|---|---|
Me (user ID) | me | User ID |
Me (name) | my-name | Display name |
checked | checked | β |
unchecked | unchecked | β |
stars-1 | stars-1 | β ββββ |
... | ... | |
stars-5 | stars-5 | β β β β β |
Today | datetime-date-today | Today's date |
Start of the year | datetime-date-start-of-year | |
Start of the month | datetime-date-start-of-month | |
Start of the week | datetime-date-start-of-week | |
Now | datetime-time-now | Actual time |
Now | datetime-now | Actual date and time |
Views and tables can filter columns by an operator for different values. Magic values can be used. They will be filtered in the frontend.
The following operators exists and are allowed for specific column types:
Operator | Good for | Hints |
---|---|---|
contains | All | Takes every value as string |
begins-with | String/Text | |
ends-with | String/Text | |
is-equal | All | |
is-greater-than | Number/Date/Time | |
is-greater-than-or-equal | Number/Date/Time | |
is-lower-than | Number/Date/Time | |
is-lower-than-or-equal | Number/Date/Time | |
is-empty | All |
The complete filter definition for a view contains an outer array that holds all groups. And an inner array for each group that holds all the filter definitions.
example
We want to show all my tasks that are urgent or overdue. Let's assume the due date can be found in the column with id 5 and the urgent flag is stored in column with id 6. Column id 2 holds the userId who is in charge of that task.
[
[
{
"columnId": 6,
"operator": "is-equal",
"value": "[checked]"
},
{
"columnId": 2,
"operator": "is-equal",
"value": "[me]"
}
],
[
{
"columnId": 5,
"operator": "is-lower-than",
"value": "[datetime-date-today]"
},
{
"columnId": 2,
"operator": "is-equal",
"value": "[me]"
}
]
]
These instructions assume you're running Nextcloud locally using nextcloud-docker-dev. Ensure your Docker nextcloud container running and the Tables app is enabled.
- To run all tests:
make test
- To run unit tests:
make test-unit
- To run integration tests:
make test-behat
- To run all e2e tests:
make test-cypress