-
Notifications
You must be signed in to change notification settings - Fork 4.4k
Database aliases, new terminologies and a migration to modules #9693
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
Open
ItzNotABug
wants to merge
122
commits into
1.7.x
Choose a base branch
from
database-aliases
base: 1.7.x
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 1 commit
Commits
Show all changes
122 commits
Select commit
Hold shift + click to select a range
814be66
update: use new terminologies on path params and local variables.
ItzNotABug 4f1f9bb
add: filter for latest changes.
ItzNotABug 2171544
fix|update: database tests for new error messages.
ItzNotABug 89ce5a6
add: todo.
ItzNotABug 949f585
change: events system.
ItzNotABug f94ecc8
fix: tests as per new events system.
ItzNotABug 9cccd89
fix: graphql tests.
ItzNotABug 9bf1fdc
fix: graphql tests.
ItzNotABug 7ffd5cf
fix: graphql tests, again.
ItzNotABug b3b9961
init: move to module structure for database; start with columns.
ItzNotABug 9c1ec6f
update: move the init hook.
ItzNotABug 1945a64
update: move DB ops to module.
ItzNotABug 8efc154
update: move Table ops to module.
ItzNotABug 3271ef5
update: move Index ops to module.
ItzNotABug 76785d5
fix: imports, lint.
ItzNotABug fd7801f
add: register index and table modules.
ItzNotABug 286c695
add: move and register row modules.
ItzNotABug 4cd8f49
add: usage.
ItzNotABug 57a9218
remove: database controller 👋
ItzNotABug ad16bd2
add: database module to platform registry.
ItzNotABug 6fac164
update: keep message same.
ItzNotABug c3d3665
Merge branch '1.7.x' into database-aliases
ItzNotABug 2554adb
update: error messages.
ItzNotABug e0a4c69
fix: `float` column creation!
ItzNotABug d184d1c
fix: lint!
ItzNotABug 8504fbc
update: `collection` response model to `table`.
ItzNotABug 675d404
update: `attribute*` response model to `column*`.
ItzNotABug 7a53680
update: `document` response model to `row`; refactor: old collection …
ItzNotABug cabf325
update: return keys.
ItzNotABug 6cb4439
update: services.
ItzNotABug bdfab30
Merge branch 'database-aliases' into response-filters-for-databases
ItzNotABug 71ad9c2
fix: response modals, mappings, filters.
ItzNotABug d30fd56
patch: index module to use/specify `columns` instead of `attributes`.
ItzNotABug e2202e9
remove: old attributes anyway.
ItzNotABug 75c9db8
update: tests to use the 1.7.x changes on databases.
ItzNotABug 37fb34a
wip: events compat based on version.
ItzNotABug b905af9
fix: project usage `documents` to `rows`.
ItzNotABug 67a8f52
fix: project and general usage tests.
ItzNotABug 565e6b2
fix: migrations test <> csv imports.
ItzNotABug 56077d5
fix: graphql tests.
ItzNotABug 9e1105b
update: tests.
ItzNotABug 253c428
remove: filter.
ItzNotABug 3a8f097
fix: realtime channels; update: row model.
ItzNotABug 86d195c
update: request, response filters.
ItzNotABug 9ec897f
fix: filtering
ItzNotABug b1735ef
remove: aliasing filter.
ItzNotABug a0ffcd5
Merge branch 'response-filters-for-databases' into events-compatibility
ItzNotABug d70d001
add: backported channels.
ItzNotABug 59e5ce0
update: `collections` <> `tables` errors.
ItzNotABug 6e8dbfc
update: `documents` <> `rows` errors.
ItzNotABug 7a52ace
update: `attributes` <> `columns` errors.
ItzNotABug 6eb1c3a
update: rename remaining variables.
ItzNotABug 3e813f6
update: change filter name for collections <> tables.
ItzNotABug ed9306e
update: change filter name for attributes <> columns.
ItzNotABug 9a45a0f
Merge branch 'response-filters-for-databases' into events-compatibility
ItzNotABug 80915fc
Merge branch 'events-compatibility' into update-exceptions
ItzNotABug ee117b8
manage: events and channels.
ItzNotABug 0261509
Merge pull request #9722 from appwrite/events-compatibility
ItzNotABug 46ccf6f
update: re-add legacy models; remove: filters.
ItzNotABug 7f023f2
update: keep both tables and collections api errors.
ItzNotABug 0266376
Merge branch 'response-filters-for-databases' into update-exceptions
ItzNotABug 28a74e6
Merge pull request #9728 from appwrite/update-exceptions
ItzNotABug 8610687
update: events schema, response models for database usages.
ItzNotABug 04386ee
Merge pull request #9720 from appwrite/response-filters-for-databases
ItzNotABug f2f23be
update: events, errors, realtime.
ItzNotABug 6d1afea
misc.
ItzNotABug 0f94b80
update: abstraction over table and collection apis.
ItzNotABug b534d38
Merge branch '1.7.x' into database-aliases
ItzNotABug 69cc4f0
update: handle the context logic, use defaults.
ItzNotABug bc8a38b
update: abstraction over attribute and column apis [WIP].
ItzNotABug 6493759
Merge remote-tracking branch 'origin/database-aliases' into database-…
ItzNotABug b55521e
update: address minor comments by `coderabbitai`.
ItzNotABug fc456b4
update: abstraction over attribute and column apis.
ItzNotABug cb64484
update: abstraction over document and row apis.
ItzNotABug 96b8969
update: use `abstract` for `getResponseModel`.
ItzNotABug da70da9
update: use nested directory structure.
ItzNotABug fe693a9
add: indexes api to tables.
ItzNotABug 6fba4a5
update: sdk namespaces.
ItzNotABug 97d1a53
fix: missing path :\
ItzNotABug d7023b5
fix: namespaces.
ItzNotABug eafa9bb
fix: namespaces, again.
ItzNotABug c4a26fb
fix: another pesky sdk namespace 🤨.
ItzNotABug 4e83fc8
update: split service registrations into smaller registries.
ItzNotABug 44a5fef
misc: name fixes.
ItzNotABug 8006c9d
misc: fixes.
ItzNotABug 36e6617
update: the usage modals.
ItzNotABug 5c07174
update: the usage model.
ItzNotABug c5074fd
update: move around tests.
ItzNotABug 2d74765
update: fix exception.
ItzNotABug 0ecd97d
fix: wrong param.
ItzNotABug ef30e82
misc: changes to the databases worker.
ItzNotABug 938b376
fix: var ref.
ItzNotABug 65dbebd
misc: fix error types.
ItzNotABug a8dc5c3
add: table tests to usage.
ItzNotABug a807dd9
fix: realtime events.
ItzNotABug f10be55
update: short the callbacks.
ItzNotABug d3f1c4f
revert: tests to `collections` API.
ItzNotABug 94fbf19
fix|add: tables api tests to realtime.
ItzNotABug 1756acd
fix: realtime channel count.
ItzNotABug f16ba8d
add: table api tests.
ItzNotABug 241779e
add: table api tests to abuse.
ItzNotABug d5e94a5
revert: graphql tests for collections api.
ItzNotABug c542ba0
patch: graphql tests <> collections.
ItzNotABug a067b77
update: model; add|update: graphql tests [wip].
ItzNotABug e1c5b3f
Merge branch '1.7.x' into database-aliases
ItzNotABug d1ae065
update: realtime events logic.
ItzNotABug 02af05b
fix: endpoint in abuse test.
ItzNotABug 594f859
update: database server test for graphql <> tables api.
ItzNotABug 68994f2
fix: graphql tests.
ItzNotABug 5022a05
update: test coverage for databases.
ItzNotABug fbe2609
update: simplify setting events context param.
ItzNotABug 5dca1ff
update: fix test variable.
ItzNotABug ba26eae
Merge remote-tracking branch 'origin/database-aliases' into database-…
ItzNotABug 45370f9
add: table apis to webhook tests.
ItzNotABug afa8341
add: table apis to webhook custom server tests.
ItzNotABug 6bdfe3b
address naming comments.
ItzNotABug 15e0385
update: exception name.
ItzNotABug 9ba29d4
update: var name.
ItzNotABug e50d7df
fix: audits event.
ItzNotABug 63d591e
fix: method name.
ItzNotABug b0d9215
fix: abuse tests!
ItzNotABug 087ccfe
remove: todo.
ItzNotABug File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
add: table api tests.
- Loading branch information
commit f16ba8dee3d8c0e3924b9f13c25ee574d59693d3
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
4,919 changes: 4,919 additions & 0 deletions
4,919
tests/e2e/Services/Databases/Tables/DatabasesBase.php
Large diffs are not rendered by default.
Oops, something went wrong.
336 changes: 336 additions & 0 deletions
336
tests/e2e/Services/Databases/Tables/DatabasesConsoleClientTest.php
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,336 @@ | ||
<?php | ||
|
||
namespace Tests\E2E\Services\Databases\Tables; | ||
|
||
use Tests\E2E\Client; | ||
use Tests\E2E\Scopes\ProjectCustom; | ||
use Tests\E2E\Scopes\Scope; | ||
use Tests\E2E\Scopes\SideConsole; | ||
use Utopia\Database\Helpers\ID; | ||
use Utopia\Database\Helpers\Permission; | ||
use Utopia\Database\Helpers\Role; | ||
use Utopia\Database\Query; | ||
|
||
class DatabasesConsoleClientTest extends Scope | ||
{ | ||
use ProjectCustom; | ||
use SideConsole; | ||
|
||
public function testCreateCollection(): array | ||
{ | ||
$database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([ | ||
'content-type' => 'application/json', | ||
'x-appwrite-project' => $this->getProject()['$id'], | ||
], $this->getHeaders()), [ | ||
'databaseId' => ID::unique(), | ||
'name' => 'invalidDocumentDatabase', | ||
]); | ||
$this->assertEquals(201, $database['headers']['status-code']); | ||
$this->assertEquals('invalidDocumentDatabase', $database['body']['name']); | ||
$this->assertTrue($database['body']['enabled']); | ||
|
||
$databaseId = $database['body']['$id']; | ||
|
||
/** | ||
* Test for SUCCESS | ||
*/ | ||
$movies = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/tables', array_merge([ | ||
'content-type' => 'application/json', | ||
'x-appwrite-project' => $this->getProject()['$id'], | ||
], $this->getHeaders()), [ | ||
'tableId' => ID::unique(), | ||
'name' => 'Movies', | ||
'permissions' => [ | ||
Permission::read(Role::any()), | ||
Permission::create(Role::any()), | ||
Permission::update(Role::any()), | ||
Permission::delete(Role::any()), | ||
], | ||
'documentSecurity' => true, | ||
]); | ||
|
||
$this->assertEquals(201, $movies['headers']['status-code']); | ||
$this->assertEquals($movies['body']['name'], 'Movies'); | ||
|
||
/** | ||
* Test when database is disabled but can still create collections | ||
*/ | ||
$database = $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId, array_merge([ | ||
'content-type' => 'application/json', | ||
'x-appwrite-project' => $this->getProject()['$id'], | ||
], $this->getHeaders()), [ | ||
'name' => 'invalidDocumentDatabase Updated', | ||
'enabled' => false, | ||
]); | ||
|
||
$this->assertFalse($database['body']['enabled']); | ||
|
||
$tvShows = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/tables', array_merge([ | ||
'content-type' => 'application/json', | ||
'x-appwrite-project' => $this->getProject()['$id'], | ||
], $this->getHeaders()), [ | ||
'tableId' => ID::unique(), | ||
'name' => 'TvShows', | ||
'permissions' => [ | ||
Permission::read(Role::any()), | ||
Permission::create(Role::any()), | ||
Permission::update(Role::any()), | ||
Permission::delete(Role::any()), | ||
], | ||
'documentSecurity' => true, | ||
]); | ||
|
||
/** | ||
* Test when collection is disabled but can still modify collections | ||
*/ | ||
$database = $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId . '/tables/' . $movies['body']['$id'], array_merge([ | ||
'content-type' => 'application/json', | ||
'x-appwrite-project' => $this->getProject()['$id'], | ||
], $this->getHeaders()), [ | ||
'name' => 'Movies', | ||
'enabled' => false, | ||
]); | ||
|
||
$this->assertEquals(201, $tvShows['headers']['status-code']); | ||
$this->assertEquals($tvShows['body']['name'], 'TvShows'); | ||
|
||
return ['moviesId' => $movies['body']['$id'], 'databaseId' => $databaseId, 'tvShowsId' => $tvShows['body']['$id']]; | ||
} | ||
|
||
/** | ||
* @depends testCreateCollection | ||
* @param array $data | ||
* @throws \Exception | ||
*/ | ||
public function testListCollection(array $data) | ||
ItzNotABug marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
/** | ||
* Test when database is disabled but can still call list collections | ||
*/ | ||
$databaseId = $data['databaseId']; | ||
|
||
$tables = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/tables', array_merge([ | ||
'content-type' => 'application/json', | ||
'x-appwrite-project' => $this->getProject()['$id'] | ||
], $this->getHeaders())); | ||
|
||
$this->assertEquals(200, $tables['headers']['status-code']); | ||
$this->assertEquals(2, $tables['body']['total']); | ||
} | ||
|
||
/** | ||
* @depends testCreateCollection | ||
* @param array $data | ||
* @throws \Exception | ||
*/ | ||
public function testGetCollection(array $data) | ||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
$databaseId = $data['databaseId']; | ||
$moviesCollectionId = $data['moviesId']; | ||
|
||
/** | ||
* Test when database and collection are disabled but can still call get collection | ||
*/ | ||
$table = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/tables/' . $moviesCollectionId, array_merge([ | ||
'content-type' => 'application/json', | ||
'x-appwrite-project' => $this->getProject()['$id'], | ||
], $this->getHeaders())); | ||
|
||
$this->assertEquals(200, $table['headers']['status-code']); | ||
$this->assertEquals('Movies', $table['body']['name']); | ||
$this->assertEquals($moviesCollectionId, $table['body']['$id']); | ||
$this->assertFalse($table['body']['enabled']); | ||
} | ||
|
||
/** | ||
* @depends testCreateCollection | ||
* @param array $data | ||
* @throws \Exception | ||
* @throws \Exception | ||
*/ | ||
public function testUpdateCollection(array $data) | ||
ItzNotABug marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
$databaseId = $data['databaseId']; | ||
$moviesCollectionId = $data['moviesId']; | ||
|
||
/** | ||
* Test When database and collection are disabled but can still call update collection | ||
*/ | ||
$table = $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId . '/tables/' . $moviesCollectionId, array_merge([ | ||
'content-type' => 'application/json', | ||
'x-appwrite-project' => $this->getProject()['$id'], | ||
], $this->getHeaders()), [ | ||
'name' => 'Movies Updated', | ||
'enabled' => false | ||
]); | ||
|
||
$this->assertEquals(200, $table['headers']['status-code']); | ||
$this->assertEquals('Movies Updated', $table['body']['name']); | ||
$this->assertEquals($moviesCollectionId, $table['body']['$id']); | ||
$this->assertFalse($table['body']['enabled']); | ||
} | ||
|
||
/** | ||
* @depends testCreateCollection | ||
* @param array $data | ||
* @throws \Exception | ||
* @throws \Exception | ||
*/ | ||
public function testDeleteCollection(array $data) | ||
ItzNotABug marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
$databaseId = $data['databaseId']; | ||
$tvShowsId = $data['tvShowsId']; | ||
|
||
/** | ||
* Test when database and collection are disabled but can still call delete collection | ||
*/ | ||
$response = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/tables/' . $tvShowsId, array_merge([ | ||
'content-type' => 'application/json', | ||
'x-appwrite-project' => $this->getProject()['$id'], | ||
], $this->getHeaders())); | ||
|
||
$this->assertEquals(204, $response['headers']['status-code']); | ||
$this->assertEquals($response['body'], ""); | ||
} | ||
|
||
/** | ||
* @depends testCreateCollection | ||
*/ | ||
public function testGetDatabaseUsage(array $data) | ||
{ | ||
$databaseId = $data['databaseId']; | ||
/** | ||
* Test for FAILURE | ||
*/ | ||
|
||
$response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/usage', array_merge([ | ||
'content-type' => 'application/json', | ||
'x-appwrite-project' => $this->getProject()['$id'] | ||
], $this->getHeaders()), [ | ||
'range' => '32h' | ||
]); | ||
|
||
$this->assertEquals(400, $response['headers']['status-code']); | ||
|
||
/** | ||
* Test for SUCCESS | ||
*/ | ||
|
||
$response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/usage', array_merge([ | ||
'content-type' => 'application/json', | ||
'x-appwrite-project' => $this->getProject()['$id'] | ||
], $this->getHeaders()), [ | ||
'range' => '24h' | ||
]); | ||
|
||
|
||
|
||
$this->assertEquals(200, $response['headers']['status-code']); | ||
$this->assertEquals(15, count($response['body'])); | ||
$this->assertEquals('24h', $response['body']['range']); | ||
$this->assertIsNumeric($response['body']['rowsTotal']); | ||
$this->assertIsNumeric($response['body']['tablesTotal']); | ||
$this->assertIsArray($response['body']['tables']); | ||
$this->assertIsArray($response['body']['rows']); | ||
} | ||
|
||
|
||
/** | ||
* @depends testCreateCollection | ||
*/ | ||
public function testGetCollectionUsage(array $data) | ||
ItzNotABug marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
$databaseId = $data['databaseId']; | ||
/** | ||
* Test for FAILURE | ||
*/ | ||
|
||
$response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/tables/' . $data['moviesId'] . '/usage', array_merge([ | ||
'content-type' => 'application/json', | ||
'x-appwrite-project' => $this->getProject()['$id'] | ||
], $this->getHeaders()), [ | ||
'range' => '32h' | ||
]); | ||
|
||
$this->assertEquals(400, $response['headers']['status-code']); | ||
|
||
$response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/tables/randomCollectionId/usage', array_merge([ | ||
'content-type' => 'application/json', | ||
'x-appwrite-project' => $this->getProject()['$id'] | ||
], $this->getHeaders()), [ | ||
'range' => '24h' | ||
]); | ||
|
||
$this->assertEquals(404, $response['headers']['status-code']); | ||
|
||
/** | ||
* Test for SUCCESS | ||
*/ | ||
$response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/tables/' . $data['moviesId'] . '/usage', array_merge([ | ||
'content-type' => 'application/json', | ||
'x-appwrite-project' => $this->getProject()['$id'] | ||
], $this->getHeaders()), [ | ||
'range' => '24h' | ||
]); | ||
$this->assertEquals(200, $response['headers']['status-code']); | ||
$this->assertEquals(3, count($response['body'])); | ||
$this->assertEquals('24h', $response['body']['range']); | ||
$this->assertIsNumeric($response['body']['rowsTotal']); | ||
$this->assertIsArray($response['body']['rows']); | ||
} | ||
|
||
/** | ||
* @depends testCreateCollection | ||
* @throws \Utopia\Database\Exception\Query | ||
*/ | ||
public function testGetCollectionLogs(array $data) | ||
ItzNotABug marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
$databaseId = $data['databaseId']; | ||
/** | ||
* Test for SUCCESS | ||
*/ | ||
$logs = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/tables/' . $data['moviesId'] . '/logs', array_merge([ | ||
'content-type' => 'application/json', | ||
'x-appwrite-project' => $this->getProject()['$id'], | ||
], $this->getHeaders())); | ||
|
||
$this->assertEquals(200, $logs['headers']['status-code']); | ||
$this->assertIsArray($logs['body']['logs']); | ||
$this->assertIsNumeric($logs['body']['total']); | ||
|
||
$logs = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/tables/' . $data['moviesId'] . '/logs', array_merge([ | ||
'content-type' => 'application/json', | ||
'x-appwrite-project' => $this->getProject()['$id'], | ||
], $this->getHeaders()), [ | ||
'queries' => [Query::limit(1)->toString()] | ||
]); | ||
|
||
$this->assertEquals(200, $logs['headers']['status-code']); | ||
$this->assertIsArray($logs['body']['logs']); | ||
$this->assertLessThanOrEqual(1, count($logs['body']['logs'])); | ||
$this->assertIsNumeric($logs['body']['total']); | ||
|
||
$logs = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/tables/' . $data['moviesId'] . '/logs', array_merge([ | ||
'content-type' => 'application/json', | ||
'x-appwrite-project' => $this->getProject()['$id'], | ||
], $this->getHeaders()), [ | ||
'queries' => [Query::offset(1)->toString()] | ||
]); | ||
|
||
$this->assertEquals(200, $logs['headers']['status-code']); | ||
$this->assertIsArray($logs['body']['logs']); | ||
$this->assertIsNumeric($logs['body']['total']); | ||
|
||
$logs = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/tables/' . $data['moviesId'] . '/logs', array_merge([ | ||
'content-type' => 'application/json', | ||
'x-appwrite-project' => $this->getProject()['$id'], | ||
], $this->getHeaders()), [ | ||
'queries' => [Query::offset(1)->toString(), Query::limit(1)->toString()] | ||
]); | ||
|
||
$this->assertEquals(200, $logs['headers']['status-code']); | ||
$this->assertIsArray($logs['body']['logs']); | ||
$this->assertLessThanOrEqual(1, count($logs['body']['logs'])); | ||
$this->assertIsNumeric($logs['body']['total']); | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.