-
Notifications
You must be signed in to change notification settings - Fork 43
🔢 Reorder and sort table columns #2481
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
Changes from all commits
d5cc9a8
c79bd78
a62b53f
3e89d2b
f48f67b
0f00589
5cbb8a3
e26fd70
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -130,12 +130,14 @@ public function showScheme(int $id): DataResponse { | |
| * @param string $description description | ||
| * @param list<TablesColumn> $columns columns | ||
| * @param list<TablesView> $views views | ||
| * @param list<array{columnId: int, order: int, readonly: bool}> $columnOrder Default column order settings | ||
| * @param list<array{columnId: int, mode: 'ASC'|'DESC'}> $sort Default sort rules | ||
| * @return DataResponse<Http::STATUS_OK, TablesTable, array{}>|DataResponse<Http::STATUS_INTERNAL_SERVER_ERROR, array{message: string}, array{}> | ||
| * | ||
| * 200: Tables returned | ||
| */ | ||
| #[NoAdminRequired] | ||
| public function createFromScheme(string $title, string $emoji, string $description, array $columns, array $views): DataResponse { | ||
| public function createFromScheme(string $title, string $emoji, string $description, array $columns, array $views, array $columnOrder = [], array $sort = []): DataResponse { | ||
| try { | ||
| $this->db->beginTransaction(); | ||
| $table = $this->service->create($title, 'custom', $emoji, $description); | ||
|
|
@@ -175,6 +177,21 @@ public function createFromScheme(string $title, string $emoji, string $descripti | |
| ); | ||
| $colMap[$column['id']] = $col->getId(); | ||
| } | ||
| if (!empty($columnOrder) || !empty($sort)) { | ||
| $remappedColumnOrder = !empty($columnOrder) ? array_map(static function (array $entry) use ($colMap): array { | ||
| if (isset($entry['columnId']) && $entry['columnId'] > 0) { | ||
| $entry['columnId'] = $colMap[$entry['columnId']] ?? $entry['columnId']; | ||
| } | ||
| return $entry; | ||
| }, $columnOrder) : null; | ||
| $remappedSort = !empty($sort) ? array_map(static function (array $entry) use ($colMap): array { | ||
| if (isset($entry['columnId']) && $entry['columnId'] > 0) { | ||
| $entry['columnId'] = $colMap[$entry['columnId']] ?? $entry['columnId']; | ||
| } | ||
| return $entry; | ||
| }, $sort) : null; | ||
| $table = $this->service->update($table->getId(), null, null, null, null, $this->userId, $remappedColumnOrder, $remappedSort); | ||
| } | ||
| foreach ($views as $view) { | ||
| $newView = $this->viewService->create( | ||
| $view['title'], | ||
|
|
@@ -262,6 +279,8 @@ public function create(string $title, ?string $emoji, ?string $description, stri | |
| * @param string|null $emoji New table emoji | ||
| * @param bool $archived whether the table is archived | ||
| * @param string $description the tables description | ||
| * @param list<array{columnId: int, order: int, readonly: bool}>|string|null $columnSettings Default column order settings (array or JSON string) | ||
| * @param list<array{columnId: int, mode: 'ASC'|'DESC'}>|string|null $sort Default sort rules (array or JSON string) | ||
| * @return DataResponse<Http::STATUS_OK, TablesTable, array{}>|DataResponse<Http::STATUS_FORBIDDEN|Http::STATUS_INTERNAL_SERVER_ERROR|Http::STATUS_NOT_FOUND, array{message: string}, array{}> | ||
| * | ||
| * 200: Tables returned | ||
|
|
@@ -270,9 +289,15 @@ public function create(string $title, ?string $emoji, ?string $description, stri | |
| */ | ||
| #[NoAdminRequired] | ||
| #[RequirePermission(permission: Application::PERMISSION_MANAGE, type: Application::NODE_TYPE_TABLE, idParam: 'id')] | ||
| public function update(int $id, ?string $title = null, ?string $emoji = null, ?string $description = null, ?bool $archived = null): DataResponse { | ||
| public function update(int $id, ?string $title = null, ?string $emoji = null, ?string $description = null, ?bool $archived = null, null|array|string $columnSettings = null, null|array|string $sort = null): DataResponse { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same here for |
||
| if (is_string($columnSettings)) { | ||
| $columnSettings = json_decode($columnSettings, true) ?? null; | ||
| } | ||
| if (is_string($sort)) { | ||
| $sort = json_decode($sort, true) ?? null; | ||
| } | ||
| try { | ||
| return new DataResponse($this->service->update($id, $title, $emoji, $description, $archived, $this->userId)->jsonSerialize()); | ||
| return new DataResponse($this->service->update($id, $title, $emoji, $description, $archived, $this->userId, $columnSettings, $sort)->jsonSerialize()); | ||
| } catch (PermissionError $e) { | ||
| return $this->handlePermissionError($e); | ||
| } catch (InternalError $e) { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -70,9 +70,15 @@ public function destroy(int $id): DataResponse { | |
|
|
||
| #[NoAdminRequired] | ||
| #[RequirePermission(permission: Application::PERMISSION_MANAGE, type: Application::NODE_TYPE_TABLE, idParam: 'id')] | ||
| public function update(int $id, ?string $title = null, ?string $emoji = null, ?bool $archived = null): DataResponse { | ||
| return $this->handleError(function () use ($id, $title, $emoji, $archived) { | ||
| return $this->service->update($id, $title, $emoji, null, $archived, $this->userId); | ||
| public function update(int $id, ?string $title = null, ?string $emoji = null, ?bool $archived = null, null|array|string $columnSettings = null, null|array|string $sort = null): DataResponse { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. and here |
||
| if (is_string($columnSettings)) { | ||
| $columnSettings = json_decode($columnSettings, true) ?? null; | ||
| } | ||
| if (is_string($sort)) { | ||
| $sort = json_decode($sort, true) ?? null; | ||
| } | ||
| return $this->handleError(function () use ($id, $title, $emoji, $archived, $columnSettings, $sort) { | ||
| return $this->service->update($id, $title, $emoji, null, $archived, $this->userId, $columnSettings, $sort); | ||
| }); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,7 +9,9 @@ | |
|
|
||
| use JsonSerializable; | ||
| use OCA\Tables\Model\Permissions; | ||
| use OCA\Tables\Model\SortRuleSet; | ||
| use OCA\Tables\ResponseDefinitions; | ||
| use OCA\Tables\Service\ValueObject\ViewColumnInformation; | ||
|
|
||
| /** | ||
| * @psalm-suppress PropertyNotSetInConstructor | ||
|
|
@@ -46,6 +48,10 @@ | |
| * @method setViews(array $views) | ||
| * @method getColumns(): array | ||
| * @method setColumns(array $columns) | ||
| * @method getColumnOrder(): ?string | ||
| * @method setColumnOrder(?string $columnOrder) | ||
| * @method getSort(): ?string | ||
| * @method setSort(?string $sort) | ||
| * @method getCreatedBy(): string | ||
| * @method setCreatedBy(string $createdBy) | ||
| * @method getCreatedAt(): string | ||
|
|
@@ -66,6 +72,9 @@ class Table extends EntitySuper implements JsonSerializable { | |
| protected bool $archived = false; | ||
| protected ?string $description = null; | ||
|
|
||
| protected ?string $columnOrder = null; // json | ||
| protected ?string $sort = null; // json | ||
|
|
||
| // virtual properties | ||
| protected ?bool $isShared = null; | ||
| protected ?Permissions $onSharePermissions = null; | ||
|
|
@@ -107,6 +116,8 @@ public function jsonSerialize(): array { | |
| 'columnsCount' => $this->columnsCount ?: 0, | ||
| 'views' => $this->getViewsArray(), | ||
| 'description' => $this->description ?:'', | ||
| 'columnOrder' => $this->getColumnOrderSettingsArray(), | ||
| 'sort' => $this->getSortArray(), | ||
| ]; | ||
| } | ||
|
|
||
|
|
@@ -121,4 +132,53 @@ private function getSharePermissions(): ?Permissions { | |
| private function getViewsArray(): array { | ||
| return $this->getViews() ?: []; | ||
| } | ||
|
|
||
| /** | ||
| * @psalm-suppress MismatchingDocblockReturnType | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. red flag |
||
| * @return int[] | ||
| */ | ||
| public function getColumnOrderArray(): array { | ||
| $columnSettings = $this->getColumnOrderSettingsArray(); | ||
| usort($columnSettings, static function (ViewColumnInformation $a, ViewColumnInformation $b) { | ||
| return $a->getOrder() - $b->getOrder(); | ||
| }); | ||
| return array_map(static fn (ViewColumnInformation $vci): int => $vci->getId(), $columnSettings); | ||
| } | ||
|
|
||
| /** | ||
| * @return array<ViewColumnInformation> | ||
| */ | ||
| public function getColumnOrderSettingsArray(): array { | ||
| $columns = $this->getArray($this->getColumnOrder()); | ||
| if (empty($columns)) { | ||
| return []; | ||
| } | ||
|
|
||
| if (is_array(reset($columns))) { | ||
| return array_values(array_map(static fn (array $a): ViewColumnInformation => ViewColumnInformation::fromArray($a), $columns)); | ||
| } | ||
|
|
||
| $result = []; | ||
| foreach ($columns as $index => $columnId) { | ||
| $result[] = new ViewColumnInformation($columnId, order: (int)$index + 1); | ||
| } | ||
| return $result; | ||
| } | ||
|
|
||
| /** | ||
| * @psalm-suppress MismatchingDocblockReturnType | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. red flag
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am also not entirely confident about the code generated here, but it is a bit vague gut feeling yet. |
||
| * @return list<array{columnId: int, mode: 'ASC'|'DESC'}> | ||
| */ | ||
| public function getSortArray(): array { | ||
| $rawSortRules = $this->getArray($this->getSort()); | ||
| return SortRuleSet::createFromInputArray($rawSortRules)->jsonSerialize(); | ||
| } | ||
|
|
||
| private function getArray(?string $json): array { | ||
| if ($json !== '' && $json !== null && $json !== 'null') { | ||
| return \json_decode($json, true); | ||
| } else { | ||
| return []; | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| /** | ||
| * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors | ||
| * SPDX-License-Identifier: AGPL-3.0-or-later | ||
| */ | ||
|
|
||
| namespace OCA\Tables\Migration; | ||
|
|
||
| use Closure; | ||
| use OCP\DB\ISchemaWrapper; | ||
| use OCP\DB\Types; | ||
| use OCP\Migration\IOutput; | ||
| use OCP\Migration\SimpleMigrationStep; | ||
| use Override; | ||
|
|
||
| class Version2010Date20260414000000 extends SimpleMigrationStep { | ||
|
|
||
| #[Override] | ||
| public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper { | ||
| /** @var ISchemaWrapper $schema */ | ||
| $schema = $schemaClosure(); | ||
|
|
||
| if (!$schema->hasTable('tables_tables')) { | ||
| return null; | ||
| } | ||
|
|
||
| $tablesTables = $schema->getTable('tables_tables'); | ||
|
|
||
| if (!$tablesTables->hasColumn('column_order')) { | ||
| $tablesTables->addColumn('column_order', Types::TEXT, [ | ||
| 'notnull' => false, | ||
| 'default' => null, | ||
| 'comment' => 'JSON array of ViewColumnInformation — default column order for the table', | ||
| ]); | ||
| } | ||
|
|
||
| if (!$tablesTables->hasColumn('sort')) { | ||
| $tablesTables->addColumn('sort', Types::TEXT, [ | ||
| 'notnull' => false, | ||
| 'default' => null, | ||
| 'comment' => 'JSON array of sort rules — default row sort for the table', | ||
| ]); | ||
| } | ||
|
|
||
| return $schema; | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
did not check further down the code, but
$columnOrderand$sortare not tested or sanitized for expected input format.