-
Notifications
You must be signed in to change notification settings - Fork 36
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
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-
TextLongdeprecated since v0.5.0 and NC >= 26 -
TextRichnew since v0.5.0 and NC26 TextLinkNumberNumberStarsNumberProgressSelectionSelectionMultiSelectionCheckDatetimeDatetimeDateDatetimeTime
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-longtext-link- ...
It is not necessary to have a subtype, for example for 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 that group multiple column types with similar content. They currently are:
AbstractNumberColumnAbstractDatetimeColumnAbstractTextColumnAbstractSelectionColumn
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.
-
numberfor NumberColumn -
text-longfor TextLongColumn - ...
You can fetch all served column-types from the capabilities (since v0.5.0):
curl http://admin:[email protected]/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, ...)
To create a new column type the following steps have to be done
- Add an enum value in the ColumnTypes
- In file
src/shared/components/ncTable/mixins/columnHandler.jsadd an entry : ''
- In file
- Create a new class for you column type (for help compare to an existing column class)
- In
src/shared/components/ncTable/mixins/columnsTypes/create a new file with the name of your column type in camelCase. - In this file create a class for your column type that extends either from the AbstractColumn or any abstract subclass of it.
- The constructor gets the data of the colum. Pass the data to the super constructor and set the type attribute to the in 1. created ColumnType.
- Implement all relevant methods. In particular methods
sort,isSearchStringFound,isFilterFoundare likely to have to be implemented.
- In
- Create a form for your column type to be able to create and edit it.
- In
src/shared/components/ncTable/partials/columnTypePartials/forms/create and implement a new .vue file to fill the relevant informtion for your column type - In
src/shared/components/ncTable/partials/columnTypePartials/tableDisplay/create and implement a .vue file to show the current information about your column type when editing the columns
- Compare to forms of other column types for help
- In
- Edit
src/modules/main/modals/CreateColumns.vueto be able to open your form- Import your form and add it to
components - In
src/modules/main/partials/ColumnTypeSelection.vueadd your column type to thetypeOptionsand adjust the template - Add a div in
src/modules/main/modals/that shows your form when your column type is selected
- Import your form and add it to
- Edit
src/modules/main/modals/EditColumns.vueto be able to edit the column of your column type- Import and add your tableDisplay component and the form component to be displayed conditionally.
- In
src/modules/main/partials/ColumnFormComponent.vueimport and add your form to the components - In
tables/src/shared/components/ncTable/mixins/columnParser.jsimport your column class and add your case in the switch - In
src/shared/components/ncTable/mixins/filter.jsadd your ColumnType to all filters that should be compatible with it - In
src/shared/components/ncTable/partials/create aTableCell<YourColumnType>.vuefile to adjust how the table cell content is displayed in the table- Compare to files of other column types for help
- Import the newly created
TableCell<YourColumnType>.vuetosrc/shared/components/ncTable/partials/TableRow.vueand add your case to the switch
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-dexample '2023-12-24' - Time
H:iexample '09:00' - Datetime
Y-m-d H:iexample '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.
Some components could be useful over the whole project. They don't have any dependencies.
components This components could also be in the NcVue library.
ncTable
- NcTable
- partials
- TableHeader
- TableRow
- TableCell* {Html, Progress, Stars, ...} [RENDER TABLE CELL]
ncBox | NcCard
- NcBox
**mixins**
*Generic mixins, could be injected where needed.*
- Formatting
- TablePermissions?
**modals**
*Generic modals, will be loaded everywhere.*
- DialogConfirmation
**API**
*API library to inject where needed.*
- Share
- Table
- ...
These are business scopes that handle their business. Communication via eventBus.
**navigation**
- Navigation
- sections
- TableList
- Filter
- Modals
- partials
- NavigationTableItem
**main**
- TableContent
- sections
- OptionsBar
- TableViewMode -> use NcTable
- BoxViewMode -> use NcBox
- BlogViewMode
- Modals [newRow -> FORM FOR TABLE CELL]
- partials
- BlogItem
**sidebar**
- Sidebar
- sections
- Sharing
**charts**
.. maybe one day
Pages are the layout for the main content part.
- DefaultContentView
- Startpage
- store {activeTableId, ...}
- tables
- rows
- viewConfig
Manage:
- tables list
- active table ID
- rows for active table (view)
- view config
Events:
- addedNewShare
- Every store has its own loading state.
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 |
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.
Views can filter columns by an operator for different values. Magic values can be used. They will be filtered in the frontend you just offer useful magic values.
A single filter is defined by a json object like this:
{
"columnId": 1,
"operator": "contains",
"value": "Christmas"
}The following operators are allowed
| 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 |
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.
The complete filter definition for a view contains a outer array that holds all groups. And an inner array for each group that holds all the filter definitions.
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.
- From the
nextcloud-docker-devdirectory, open a bash shell in the container:docker compose exec nextcloud bash - Change into the
tablesdirectory. This might beapps-extra/tablesorapps/tablesinstead, depending on where you installed it.cd apps-shared/tables - Install required dependencies
composer install - To run unit tests:
sudo -u www-data make test-unit - To run integration tests:
sudo -u www-data make test-behat
E2e testing is done with Cypress. To run these tests, do the following in the tables directory.
- Install Cypress and other dependencies
npm ci - To run all e2e tests:
npx cypress run - To run a specific tests:
npx cypress run --spec 'link/to/test.cy.js'