diff --git a/appinfo/info.xml b/appinfo/info.xml index e6f1c544c..53672fbe8 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -56,6 +56,8 @@ Have a good time and manage whatever you want. OCA\Tables\Command\RemoveTable OCA\Tables\Command\RenameTable OCA\Tables\Command\ChangeOwnershipTable + OCA\Tables\Command\ListContexts + OCA\Tables\Command\ShowContext OCA\Tables\Command\Clean OCA\Tables\Command\CleanLegacy OCA\Tables\Command\TransferLegacyRows diff --git a/appinfo/routes.php b/appinfo/routes.php index f3c58beb5..b3d285cf7 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -128,5 +128,14 @@ ['name' => 'ApiFavorite#create', 'url' => '/api/2/favorites/{nodeType}/{nodeId}', 'verb' => 'POST', 'requirements' => ['nodeType' => '(\d+)', 'nodeId' => '(\d+)']], ['name' => 'ApiFavorite#destroy', 'url' => '/api/2/favorites/{nodeType}/{nodeId}', 'verb' => 'DELETE', 'requirements' => ['nodeType' => '(\d+)', 'nodeId' => '(\d+)']], + ['name' => 'Context#index', 'url' => '/api/2/contexts', 'verb' => 'GET'], + ['name' => 'Context#show', 'url' => '/api/2/contexts/{contextId}', 'verb' => 'GET'], + ['name' => 'Context#create', 'url' => '/api/2/contexts', 'verb' => 'POST'], + ['name' => 'Context#update', 'url' => '/api/2/contexts/{contextId}', 'verb' => 'PUT'], + ['name' => 'Context#destroy', 'url' => '/api/2/contexts/{contextId}', 'verb' => 'DELETE'], + ['name' => 'Context#transfer', 'url' => '/api/2/contexts/{contextId}/transfer', 'verb' => 'PUT'], + ['name' => 'Context#addNode', 'url' => '/api/2/contexts/{contextId}/nodes', 'verb' => 'POST'], + ['name' => 'Context#removeNode', 'url' => '/api/2/contexts/{contextId}/nodes/{nodeRelId}', 'verb' => 'DELETE'], + ['name' => 'Context#updateContentOrder', 'url' => '/api/2/contexts/{contextId}/pages/{pageId}', 'verb' => 'PUT'], ] ]; diff --git a/build/fetch-material-icons.sh b/build/fetch-material-icons.sh new file mode 100755 index 000000000..270adaaee --- /dev/null +++ b/build/fetch-material-icons.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +set -x +set -e + +REPO_URL="https://github.com/Templarian/MaterialDesign" +CLONE_PATH="/tmp/material-design-icons" +TARGET_PATH="$PWD/img/material" + +if [ ! -d "${CLONE_PATH}" ]; then + git clone "${REPO_URL}" --depth 1 "${CLONE_PATH}" +fi + +mkdir -p "$TARGET_PATH" + +cp $CLONE_PATH/LICENSE $TARGET_PATH/LICENSE + +cat $CLONE_PATH/meta.json | + jq '.[]|select(.author == "Google" and (.name | contains("-") | not))' > $TARGET_PATH/meta.json + +cat $TARGET_PATH/meta.json | + jq " .name | \"$CLONE_PATH/svg/\" + . + \".svg\"" -r | + xargs -I{} cp {} $PWD/img/material/ + +find "${TARGET_PATH}" -name '*.svg' -exec sed -i 's_/>_fill=\"#fff\" />_' {} + ; diff --git a/cypress/e2e/tables-archive.cy.js b/cypress/e2e/tables-archive.cy.js index 673dc3011..0db3988b1 100644 --- a/cypress/e2e/tables-archive.cy.js +++ b/cypress/e2e/tables-archive.cy.js @@ -11,6 +11,7 @@ describe('Archive tables/views', () => { beforeEach(function() { cy.login(localUser) cy.visit('apps/tables') + cy.wait(1000) }) it('can archive tables', () => { diff --git a/cypress/e2e/tables-favorite.cy.js b/cypress/e2e/tables-favorite.cy.js index a430566bc..973a9d6a0 100644 --- a/cypress/e2e/tables-favorite.cy.js +++ b/cypress/e2e/tables-favorite.cy.js @@ -11,6 +11,7 @@ describe('Favorite tables/views', () => { beforeEach(function() { cy.login(localUser) cy.visit('apps/tables') + cy.wait(1000) }) it('can favorite tables', () => { diff --git a/img/material/LICENSE b/img/material/LICENSE new file mode 100644 index 000000000..382f8a138 --- /dev/null +++ b/img/material/LICENSE @@ -0,0 +1,20 @@ +Pictogrammers Free License +-------------------------- + +This icon collection is released as free, open source, and GPL friendly by +the [Pictogrammers](http://pictogrammers.com/) icon group. You may use it +for commercial projects, open source projects, or anything really. + +# Icons: Apache 2.0 (https://www.apache.org/licenses/LICENSE-2.0) +Some of the icons are redistributed under the Apache 2.0 license. All other +icons are either redistributed under their respective licenses or are +distributed under the Apache 2.0 license. + +# Fonts: Apache 2.0 (https://www.apache.org/licenses/LICENSE-2.0) +All web and desktop fonts are distributed under the Apache 2.0 license. Web +and desktop fonts contain some icons that are redistributed under the Apache +2.0 license. All other icons are either redistributed under their respective +licenses or are distributed under the Apache 2.0 license. + +# Code: MIT (https://opensource.org/licenses/MIT) +The MIT license applies to all non-font and non-icon files. diff --git a/img/material/account.svg b/img/material/account.svg new file mode 100644 index 000000000..c7b42fa4c --- /dev/null +++ b/img/material/account.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/adjust.svg b/img/material/adjust.svg new file mode 100644 index 000000000..729e2b531 --- /dev/null +++ b/img/material/adjust.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/alarm.svg b/img/material/alarm.svg new file mode 100644 index 000000000..d09eb8208 --- /dev/null +++ b/img/material/alarm.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/album.svg b/img/material/album.svg new file mode 100644 index 000000000..fa4d73323 --- /dev/null +++ b/img/material/album.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/alert.svg b/img/material/alert.svg new file mode 100644 index 000000000..64d616889 --- /dev/null +++ b/img/material/alert.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/anchor.svg b/img/material/anchor.svg new file mode 100644 index 000000000..4827330a8 --- /dev/null +++ b/img/material/anchor.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/android.svg b/img/material/android.svg new file mode 100644 index 000000000..e0d8f34e4 --- /dev/null +++ b/img/material/android.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/animation.svg b/img/material/animation.svg new file mode 100644 index 000000000..b7cd84f15 --- /dev/null +++ b/img/material/animation.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/antenna.svg b/img/material/antenna.svg new file mode 100644 index 000000000..c65ed6243 --- /dev/null +++ b/img/material/antenna.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/api.svg b/img/material/api.svg new file mode 100644 index 000000000..feffa416c --- /dev/null +++ b/img/material/api.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/apps.svg b/img/material/apps.svg new file mode 100644 index 000000000..3cc406616 --- /dev/null +++ b/img/material/apps.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/assistant.svg b/img/material/assistant.svg new file mode 100644 index 000000000..2b38a1c06 --- /dev/null +++ b/img/material/assistant.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/at.svg b/img/material/at.svg new file mode 100644 index 000000000..c5fc3a519 --- /dev/null +++ b/img/material/at.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/atm.svg b/img/material/atm.svg new file mode 100644 index 000000000..830d9c492 --- /dev/null +++ b/img/material/atm.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/attachment.svg b/img/material/attachment.svg new file mode 100644 index 000000000..a26e6bc4d --- /dev/null +++ b/img/material/attachment.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/atv.svg b/img/material/atv.svg new file mode 100644 index 000000000..ed306856f --- /dev/null +++ b/img/material/atv.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/autorenew.svg b/img/material/autorenew.svg new file mode 100644 index 000000000..3b136b39b --- /dev/null +++ b/img/material/autorenew.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/baby.svg b/img/material/baby.svg new file mode 100644 index 000000000..470eef30f --- /dev/null +++ b/img/material/baby.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/backspace.svg b/img/material/backspace.svg new file mode 100644 index 000000000..7f5c828ed --- /dev/null +++ b/img/material/backspace.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/balcony.svg b/img/material/balcony.svg new file mode 100644 index 000000000..a5961cac0 --- /dev/null +++ b/img/material/balcony.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/ballot.svg b/img/material/ballot.svg new file mode 100644 index 000000000..69aa13fea --- /dev/null +++ b/img/material/ballot.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/bandage.svg b/img/material/bandage.svg new file mode 100644 index 000000000..3baad3f86 --- /dev/null +++ b/img/material/bandage.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/bank.svg b/img/material/bank.svg new file mode 100644 index 000000000..686e33137 --- /dev/null +++ b/img/material/bank.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/barrel.svg b/img/material/barrel.svg new file mode 100644 index 000000000..e9310414d --- /dev/null +++ b/img/material/barrel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/basket.svg b/img/material/basket.svg new file mode 100644 index 000000000..e5a55499b --- /dev/null +++ b/img/material/basket.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/basketball.svg b/img/material/basketball.svg new file mode 100644 index 000000000..2466437a7 --- /dev/null +++ b/img/material/basketball.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/bathtub.svg b/img/material/bathtub.svg new file mode 100644 index 000000000..d54332d0c --- /dev/null +++ b/img/material/bathtub.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/battery.svg b/img/material/battery.svg new file mode 100644 index 000000000..649164209 --- /dev/null +++ b/img/material/battery.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/bed.svg b/img/material/bed.svg new file mode 100644 index 000000000..98ae1fc53 --- /dev/null +++ b/img/material/bed.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/bee.svg b/img/material/bee.svg new file mode 100644 index 000000000..a67b47c90 --- /dev/null +++ b/img/material/bee.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/bell.svg b/img/material/bell.svg new file mode 100644 index 000000000..722130c10 --- /dev/null +++ b/img/material/bell.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/biathlon.svg b/img/material/biathlon.svg new file mode 100644 index 000000000..55b1b5542 --- /dev/null +++ b/img/material/biathlon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/bike.svg b/img/material/bike.svg new file mode 100644 index 000000000..6275e925f --- /dev/null +++ b/img/material/bike.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/blender.svg b/img/material/blender.svg new file mode 100644 index 000000000..e3de9644d --- /dev/null +++ b/img/material/blender.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/blur.svg b/img/material/blur.svg new file mode 100644 index 000000000..78926528d --- /dev/null +++ b/img/material/blur.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/book.svg b/img/material/book.svg new file mode 100644 index 000000000..1ff2ddb00 --- /dev/null +++ b/img/material/book.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/bookmark.svg b/img/material/bookmark.svg new file mode 100644 index 000000000..c8f597fd3 --- /dev/null +++ b/img/material/bookmark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/boombox.svg b/img/material/boombox.svg new file mode 100644 index 000000000..b39c902d5 --- /dev/null +++ b/img/material/boombox.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/briefcase.svg b/img/material/briefcase.svg new file mode 100644 index 000000000..de27c6204 --- /dev/null +++ b/img/material/briefcase.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/broadcast.svg b/img/material/broadcast.svg new file mode 100644 index 000000000..a775877a4 --- /dev/null +++ b/img/material/broadcast.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/brush.svg b/img/material/brush.svg new file mode 100644 index 000000000..d20e0df11 --- /dev/null +++ b/img/material/brush.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/bug.svg b/img/material/bug.svg new file mode 100644 index 000000000..a84191b2a --- /dev/null +++ b/img/material/bug.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/bullhorn.svg b/img/material/bullhorn.svg new file mode 100644 index 000000000..8474711b3 --- /dev/null +++ b/img/material/bullhorn.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/bus.svg b/img/material/bus.svg new file mode 100644 index 000000000..5dda3f2b3 --- /dev/null +++ b/img/material/bus.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/cached.svg b/img/material/cached.svg new file mode 100644 index 000000000..105aa4a85 --- /dev/null +++ b/img/material/cached.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/cake.svg b/img/material/cake.svg new file mode 100644 index 000000000..4fe04f77c --- /dev/null +++ b/img/material/cake.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/calendar.svg b/img/material/calendar.svg new file mode 100644 index 000000000..aabf087d0 --- /dev/null +++ b/img/material/calendar.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/camera.svg b/img/material/camera.svg new file mode 100644 index 000000000..86640d2bd --- /dev/null +++ b/img/material/camera.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/cancel.svg b/img/material/cancel.svg new file mode 100644 index 000000000..83ad9215b --- /dev/null +++ b/img/material/cancel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/candle.svg b/img/material/candle.svg new file mode 100644 index 000000000..189a87b16 --- /dev/null +++ b/img/material/candle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/car.svg b/img/material/car.svg new file mode 100644 index 000000000..19f74fbfb --- /dev/null +++ b/img/material/car.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/carabiner.svg b/img/material/carabiner.svg new file mode 100644 index 000000000..14908c5bc --- /dev/null +++ b/img/material/carabiner.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/cart.svg b/img/material/cart.svg new file mode 100644 index 000000000..2e3413ac2 --- /dev/null +++ b/img/material/cart.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/cast.svg b/img/material/cast.svg new file mode 100644 index 000000000..156e2e7ee --- /dev/null +++ b/img/material/cast.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/cellphone.svg b/img/material/cellphone.svg new file mode 100644 index 000000000..441e36738 --- /dev/null +++ b/img/material/cellphone.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/charity.svg b/img/material/charity.svg new file mode 100644 index 000000000..3e0384b9a --- /dev/null +++ b/img/material/charity.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/check.svg b/img/material/check.svg new file mode 100644 index 000000000..b0087483a --- /dev/null +++ b/img/material/check.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/checkbook.svg b/img/material/checkbook.svg new file mode 100644 index 000000000..4b076b548 --- /dev/null +++ b/img/material/checkbook.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/church.svg b/img/material/church.svg new file mode 100644 index 000000000..f399d3483 --- /dev/null +++ b/img/material/church.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/city.svg b/img/material/city.svg new file mode 100644 index 000000000..63889d46f --- /dev/null +++ b/img/material/city.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/clock.svg b/img/material/clock.svg new file mode 100644 index 000000000..b9d6c43d2 --- /dev/null +++ b/img/material/clock.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/close.svg b/img/material/close.svg new file mode 100644 index 000000000..d84e11f9e --- /dev/null +++ b/img/material/close.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/cloud.svg b/img/material/cloud.svg new file mode 100644 index 000000000..66cccd880 --- /dev/null +++ b/img/material/cloud.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/coffee.svg b/img/material/coffee.svg new file mode 100644 index 000000000..c599414ae --- /dev/null +++ b/img/material/coffee.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/cog.svg b/img/material/cog.svg new file mode 100644 index 000000000..9bc1fe42c --- /dev/null +++ b/img/material/cog.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/cogs.svg b/img/material/cogs.svg new file mode 100644 index 000000000..40ad761db --- /dev/null +++ b/img/material/cogs.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/collage.svg b/img/material/collage.svg new file mode 100644 index 000000000..3f3b01d51 --- /dev/null +++ b/img/material/collage.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/compare.svg b/img/material/compare.svg new file mode 100644 index 000000000..741a857a8 --- /dev/null +++ b/img/material/compare.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/compass.svg b/img/material/compass.svg new file mode 100644 index 000000000..33f9aeca3 --- /dev/null +++ b/img/material/compass.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/compost.svg b/img/material/compost.svg new file mode 100644 index 000000000..f33e8a9da --- /dev/null +++ b/img/material/compost.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/contacts.svg b/img/material/contacts.svg new file mode 100644 index 000000000..e035527b1 --- /dev/null +++ b/img/material/contacts.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/controller.svg b/img/material/controller.svg new file mode 100644 index 000000000..e7b854209 --- /dev/null +++ b/img/material/controller.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/cookie.svg b/img/material/cookie.svg new file mode 100644 index 000000000..9311f5af1 --- /dev/null +++ b/img/material/cookie.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/copyright.svg b/img/material/copyright.svg new file mode 100644 index 000000000..d0f565beb --- /dev/null +++ b/img/material/copyright.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/countertop.svg b/img/material/countertop.svg new file mode 100644 index 000000000..35a9cce24 --- /dev/null +++ b/img/material/countertop.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/cradle.svg b/img/material/cradle.svg new file mode 100644 index 000000000..59a224e63 --- /dev/null +++ b/img/material/cradle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/creation.svg b/img/material/creation.svg new file mode 100644 index 000000000..dd511b166 --- /dev/null +++ b/img/material/creation.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/cricket.svg b/img/material/cricket.svg new file mode 100644 index 000000000..c7c1b1514 --- /dev/null +++ b/img/material/cricket.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/crop.svg b/img/material/crop.svg new file mode 100644 index 000000000..780364134 --- /dev/null +++ b/img/material/crop.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/crosshairs.svg b/img/material/crosshairs.svg new file mode 100644 index 000000000..fda5dc6eb --- /dev/null +++ b/img/material/crosshairs.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/crowd.svg b/img/material/crowd.svg new file mode 100644 index 000000000..889044550 --- /dev/null +++ b/img/material/crowd.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/delete.svg b/img/material/delete.svg new file mode 100644 index 000000000..63342f50d --- /dev/null +++ b/img/material/delete.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/delta.svg b/img/material/delta.svg new file mode 100644 index 000000000..50145cc55 --- /dev/null +++ b/img/material/delta.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/details.svg b/img/material/details.svg new file mode 100644 index 000000000..7438818e3 --- /dev/null +++ b/img/material/details.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/devices.svg b/img/material/devices.svg new file mode 100644 index 000000000..1c574cdaa --- /dev/null +++ b/img/material/devices.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/dialpad.svg b/img/material/dialpad.svg new file mode 100644 index 000000000..955d7c4ab --- /dev/null +++ b/img/material/dialpad.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/directions.svg b/img/material/directions.svg new file mode 100644 index 000000000..61613435f --- /dev/null +++ b/img/material/directions.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/dishwasher.svg b/img/material/dishwasher.svg new file mode 100644 index 000000000..335224a5d --- /dev/null +++ b/img/material/dishwasher.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/diving.svg b/img/material/diving.svg new file mode 100644 index 000000000..fb0171689 --- /dev/null +++ b/img/material/diving.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/dns.svg b/img/material/dns.svg new file mode 100644 index 000000000..0db78dcec --- /dev/null +++ b/img/material/dns.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/domain.svg b/img/material/domain.svg new file mode 100644 index 000000000..01a1595a4 --- /dev/null +++ b/img/material/domain.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/download.svg b/img/material/download.svg new file mode 100644 index 000000000..4966ddb62 --- /dev/null +++ b/img/material/download.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/dumbbell.svg b/img/material/dumbbell.svg new file mode 100644 index 000000000..c1d96134c --- /dev/null +++ b/img/material/dumbbell.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/earth.svg b/img/material/earth.svg new file mode 100644 index 000000000..bb8358cea --- /dev/null +++ b/img/material/earth.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/eject.svg b/img/material/eject.svg new file mode 100644 index 000000000..9f7b38edb --- /dev/null +++ b/img/material/eject.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/email.svg b/img/material/email.svg new file mode 100644 index 000000000..eac910c61 --- /dev/null +++ b/img/material/email.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/emoticon.svg b/img/material/emoticon.svg new file mode 100644 index 000000000..047c1c592 --- /dev/null +++ b/img/material/emoticon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/equalizer.svg b/img/material/equalizer.svg new file mode 100644 index 000000000..170f62496 --- /dev/null +++ b/img/material/equalizer.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/eye.svg b/img/material/eye.svg new file mode 100644 index 000000000..84207a049 --- /dev/null +++ b/img/material/eye.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/fax.svg b/img/material/fax.svg new file mode 100644 index 000000000..66ff01531 --- /dev/null +++ b/img/material/fax.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/fencing.svg b/img/material/fencing.svg new file mode 100644 index 000000000..b7bf5bc06 --- /dev/null +++ b/img/material/fencing.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/ferry.svg b/img/material/ferry.svg new file mode 100644 index 000000000..c7b3cac21 --- /dev/null +++ b/img/material/ferry.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/file.svg b/img/material/file.svg new file mode 100644 index 000000000..68f73df74 --- /dev/null +++ b/img/material/file.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/film.svg b/img/material/film.svg new file mode 100644 index 000000000..34212c0b6 --- /dev/null +++ b/img/material/film.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/filmstrip.svg b/img/material/filmstrip.svg new file mode 100644 index 000000000..b0118f220 --- /dev/null +++ b/img/material/filmstrip.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/finance.svg b/img/material/finance.svg new file mode 100644 index 000000000..79e00e700 --- /dev/null +++ b/img/material/finance.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/fingerprint.svg b/img/material/fingerprint.svg new file mode 100644 index 000000000..278d1e1e1 --- /dev/null +++ b/img/material/fingerprint.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/fire.svg b/img/material/fire.svg new file mode 100644 index 000000000..0209a1bd6 --- /dev/null +++ b/img/material/fire.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/firebase.svg b/img/material/firebase.svg new file mode 100644 index 000000000..24c082567 --- /dev/null +++ b/img/material/firebase.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/flag.svg b/img/material/flag.svg new file mode 100644 index 000000000..aa0eae2de --- /dev/null +++ b/img/material/flag.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/flare.svg b/img/material/flare.svg new file mode 100644 index 000000000..1db0c1cec --- /dev/null +++ b/img/material/flare.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/flash.svg b/img/material/flash.svg new file mode 100644 index 000000000..1c53af4af --- /dev/null +++ b/img/material/flash.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/flower.svg b/img/material/flower.svg new file mode 100644 index 000000000..9e3d4eb54 --- /dev/null +++ b/img/material/flower.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/folder.svg b/img/material/folder.svg new file mode 100644 index 000000000..803e010cd --- /dev/null +++ b/img/material/folder.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/food.svg b/img/material/food.svg new file mode 100644 index 000000000..932df7f9d --- /dev/null +++ b/img/material/food.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/football.svg b/img/material/football.svg new file mode 100644 index 000000000..8e7de7ff8 --- /dev/null +++ b/img/material/football.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/forest.svg b/img/material/forest.svg new file mode 100644 index 000000000..68d9bc537 --- /dev/null +++ b/img/material/forest.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/forum.svg b/img/material/forum.svg new file mode 100644 index 000000000..eb609bfbf --- /dev/null +++ b/img/material/forum.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/forward.svg b/img/material/forward.svg new file mode 100644 index 000000000..be030adae --- /dev/null +++ b/img/material/forward.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/fullscreen.svg b/img/material/fullscreen.svg new file mode 100644 index 000000000..8f0125456 --- /dev/null +++ b/img/material/fullscreen.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/gamepad.svg b/img/material/gamepad.svg new file mode 100644 index 000000000..3d20834cb --- /dev/null +++ b/img/material/gamepad.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/gauge.svg b/img/material/gauge.svg new file mode 100644 index 000000000..f7b2d4dfc --- /dev/null +++ b/img/material/gauge.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/gesture.svg b/img/material/gesture.svg new file mode 100644 index 000000000..4240ba4e7 --- /dev/null +++ b/img/material/gesture.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/gmail.svg b/img/material/gmail.svg new file mode 100644 index 000000000..508b4f72d --- /dev/null +++ b/img/material/gmail.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/golf.svg b/img/material/golf.svg new file mode 100644 index 000000000..54efe202b --- /dev/null +++ b/img/material/golf.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/google.svg b/img/material/google.svg new file mode 100644 index 000000000..2fe2bd45c --- /dev/null +++ b/img/material/google.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/grain.svg b/img/material/grain.svg new file mode 100644 index 000000000..5046af12d --- /dev/null +++ b/img/material/grain.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/grass.svg b/img/material/grass.svg new file mode 100644 index 000000000..63fd3fc81 --- /dev/null +++ b/img/material/grass.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/grid.svg b/img/material/grid.svg new file mode 100644 index 000000000..3cd4895d9 --- /dev/null +++ b/img/material/grid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/grill.svg b/img/material/grill.svg new file mode 100644 index 000000000..b0610ac38 --- /dev/null +++ b/img/material/grill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/gymnastics.svg b/img/material/gymnastics.svg new file mode 100644 index 000000000..0919daf13 --- /dev/null +++ b/img/material/gymnastics.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/hail.svg b/img/material/hail.svg new file mode 100644 index 000000000..44a2eb2e4 --- /dev/null +++ b/img/material/hail.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/hammer.svg b/img/material/hammer.svg new file mode 100644 index 000000000..318879226 --- /dev/null +++ b/img/material/hammer.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/handball.svg b/img/material/handball.svg new file mode 100644 index 000000000..92a2f03de --- /dev/null +++ b/img/material/handball.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/hdr.svg b/img/material/hdr.svg new file mode 100644 index 000000000..c5af793bf --- /dev/null +++ b/img/material/hdr.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/headphones.svg b/img/material/headphones.svg new file mode 100644 index 000000000..42b5290b0 --- /dev/null +++ b/img/material/headphones.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/headset.svg b/img/material/headset.svg new file mode 100644 index 000000000..366a287bd --- /dev/null +++ b/img/material/headset.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/heart.svg b/img/material/heart.svg new file mode 100644 index 000000000..07f86833e --- /dev/null +++ b/img/material/heart.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/hiking.svg b/img/material/hiking.svg new file mode 100644 index 000000000..48e6c5496 --- /dev/null +++ b/img/material/hiking.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/history.svg b/img/material/history.svg new file mode 100644 index 000000000..d87fa2fc4 --- /dev/null +++ b/img/material/history.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/home.svg b/img/material/home.svg new file mode 100644 index 000000000..7877fd523 --- /dev/null +++ b/img/material/home.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/hub.svg b/img/material/hub.svg new file mode 100644 index 000000000..e5281f291 --- /dev/null +++ b/img/material/hub.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/human.svg b/img/material/human.svg new file mode 100644 index 000000000..e21960e41 --- /dev/null +++ b/img/material/human.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/hvac.svg b/img/material/hvac.svg new file mode 100644 index 000000000..07b640630 --- /dev/null +++ b/img/material/hvac.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/image.svg b/img/material/image.svg new file mode 100644 index 000000000..d99c5c680 --- /dev/null +++ b/img/material/image.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/inbox.svg b/img/material/inbox.svg new file mode 100644 index 000000000..d89a3afb3 --- /dev/null +++ b/img/material/inbox.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/information.svg b/img/material/information.svg new file mode 100644 index 000000000..10f30e896 --- /dev/null +++ b/img/material/information.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/iron.svg b/img/material/iron.svg new file mode 100644 index 000000000..cfc1c22fc --- /dev/null +++ b/img/material/iron.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/kabaddi.svg b/img/material/kabaddi.svg new file mode 100644 index 000000000..b5ea8e61c --- /dev/null +++ b/img/material/kabaddi.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/karate.svg b/img/material/karate.svg new file mode 100644 index 000000000..639f8721d --- /dev/null +++ b/img/material/karate.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/kayaking.svg b/img/material/kayaking.svg new file mode 100644 index 000000000..7e5adcf2a --- /dev/null +++ b/img/material/kayaking.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/key.svg b/img/material/key.svg new file mode 100644 index 000000000..37763409a --- /dev/null +++ b/img/material/key.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/keyboard.svg b/img/material/keyboard.svg new file mode 100644 index 000000000..b3994a019 --- /dev/null +++ b/img/material/keyboard.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/kite.svg b/img/material/kite.svg new file mode 100644 index 000000000..9f6f8105b --- /dev/null +++ b/img/material/kite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/kitesurfing.svg b/img/material/kitesurfing.svg new file mode 100644 index 000000000..20451d365 --- /dev/null +++ b/img/material/kitesurfing.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/label.svg b/img/material/label.svg new file mode 100644 index 000000000..43bbc9a99 --- /dev/null +++ b/img/material/label.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/ladybug.svg b/img/material/ladybug.svg new file mode 100644 index 000000000..faff1f9eb --- /dev/null +++ b/img/material/ladybug.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/landslide.svg b/img/material/landslide.svg new file mode 100644 index 000000000..9b7ae576e --- /dev/null +++ b/img/material/landslide.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/laptop.svg b/img/material/laptop.svg new file mode 100644 index 000000000..eb69d4420 --- /dev/null +++ b/img/material/laptop.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/launch.svg b/img/material/launch.svg new file mode 100644 index 000000000..56e0a1b2b --- /dev/null +++ b/img/material/launch.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/layers.svg b/img/material/layers.svg new file mode 100644 index 000000000..18f6cd2e5 --- /dev/null +++ b/img/material/layers.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/leak.svg b/img/material/leak.svg new file mode 100644 index 000000000..dc5fc4801 --- /dev/null +++ b/img/material/leak.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/library.svg b/img/material/library.svg new file mode 100644 index 000000000..57230e4d6 --- /dev/null +++ b/img/material/library.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/license.svg b/img/material/license.svg new file mode 100644 index 000000000..9cbb26438 --- /dev/null +++ b/img/material/license.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/lightbulb.svg b/img/material/lightbulb.svg new file mode 100644 index 000000000..ce02c2144 --- /dev/null +++ b/img/material/lightbulb.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/link.svg b/img/material/link.svg new file mode 100644 index 000000000..223c64fa1 --- /dev/null +++ b/img/material/link.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/liquor.svg b/img/material/liquor.svg new file mode 100644 index 000000000..b0a6f4fda --- /dev/null +++ b/img/material/liquor.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/lock.svg b/img/material/lock.svg new file mode 100644 index 000000000..81cc9bfce --- /dev/null +++ b/img/material/lock.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/login.svg b/img/material/login.svg new file mode 100644 index 000000000..535396cb1 --- /dev/null +++ b/img/material/login.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/logout.svg b/img/material/logout.svg new file mode 100644 index 000000000..3354f4dfe --- /dev/null +++ b/img/material/logout.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/looks.svg b/img/material/looks.svg new file mode 100644 index 000000000..cfb04f0f9 --- /dev/null +++ b/img/material/looks.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/loupe.svg b/img/material/loupe.svg new file mode 100644 index 000000000..0b1849ccc --- /dev/null +++ b/img/material/loupe.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/magnify.svg b/img/material/magnify.svg new file mode 100644 index 000000000..93914e501 --- /dev/null +++ b/img/material/magnify.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/map.svg b/img/material/map.svg new file mode 100644 index 000000000..56bbec011 --- /dev/null +++ b/img/material/map.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/marker.svg b/img/material/marker.svg new file mode 100644 index 000000000..92a0d243a --- /dev/null +++ b/img/material/marker.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/medication.svg b/img/material/medication.svg new file mode 100644 index 000000000..dbe63cf4c --- /dev/null +++ b/img/material/medication.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/meditation.svg b/img/material/meditation.svg new file mode 100644 index 000000000..4f7f98b2c --- /dev/null +++ b/img/material/meditation.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/memory.svg b/img/material/memory.svg new file mode 100644 index 000000000..9039a7b2d --- /dev/null +++ b/img/material/memory.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/menu.svg b/img/material/menu.svg new file mode 100644 index 000000000..dca983ee3 --- /dev/null +++ b/img/material/menu.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/merge.svg b/img/material/merge.svg new file mode 100644 index 000000000..9304d9b5a --- /dev/null +++ b/img/material/merge.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/message.svg b/img/material/message.svg new file mode 100644 index 000000000..598889647 --- /dev/null +++ b/img/material/message.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/meta.json b/img/material/meta.json new file mode 100644 index 000000000..e3f274490 --- /dev/null +++ b/img/material/meta.json @@ -0,0 +1,5207 @@ +[ + { + "id": "E76EC23F-AB71-49B3-9173-841544527A20", + "baseIconId": "E76EC23F-AB71-49B3-9173-841544527A20", + "name": "account", + "codepoint": "F0004", + "aliases": [ + "person", + "user" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Account / User", + "Home Automation" + ], + "author": "Google" + }, + { + "id": "3334E19F-962D-45B4-BE11-F009E1192165", + "baseIconId": "3334E19F-962D-45B4-BE11-F009E1192165", + "name": "adjust", + "codepoint": "F001A", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "9A1AAF33-6F36-4987-9E8C-798E34D919A9", + "baseIconId": "9A1AAF33-6F36-4987-9E8C-798E34D919A9", + "name": "alarm", + "codepoint": "F0020", + "aliases": [ + "access-alarms", + "alarm-clock" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Date / Time" + ], + "author": "Google" + }, + { + "id": "8529D611-F581-4808-95BE-271FB1A6C2FD", + "baseIconId": "8529D611-F581-4808-95BE-271FB1A6C2FD", + "name": "album", + "codepoint": "F0025", + "aliases": [ + "vinyl", + "record" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Audio", + "Music" + ], + "author": "Google" + }, + { + "id": "9FF7DF3F-D575-433B-9C9A-69C58363C186", + "baseIconId": "9FF7DF3F-D575-433B-9C9A-69C58363C186", + "name": "alert", + "codepoint": "F0026", + "aliases": [ + "warning", + "report-problem" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Alert / Error" + ], + "author": "Google" + }, + { + "id": "8A3C8CCE-D798-446B-A283-90129AD847C9", + "baseIconId": "8A3C8CCE-D798-446B-A283-90129AD847C9", + "name": "anchor", + "codepoint": "F0031", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Transportation + Water" + ], + "author": "Google" + }, + { + "id": "4633B767-FF29-411D-8C04-69057C6B65B2", + "baseIconId": "4633B767-FF29-411D-8C04-69057C6B65B2", + "name": "android", + "codepoint": "F0032", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": true, + "tags": [ + "Brand / Logo" + ], + "author": "Google" + }, + { + "id": "4FE8F135-8FF9-427B-8857-122FBB0A300A", + "baseIconId": "4FE8F135-8FF9-427B-8857-122FBB0A300A", + "name": "animation", + "codepoint": "F05D8", + "aliases": [ + "auto-awesome-motion" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "B6F97155-147F-4D03-9C71-7668E5EA2712", + "baseIconId": "B6F97155-147F-4D03-9C71-7668E5EA2712", + "name": "antenna", + "codepoint": "F1119", + "aliases": [], + "styles": [], + "version": "4.3.95", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "ABE80259-E64D-4BF4-BC6E-1D8FFA16636F", + "baseIconId": "ABE80259-E64D-4BF4-BC6E-1D8FFA16636F", + "name": "api", + "codepoint": "F109B", + "aliases": [], + "styles": [], + "version": "4.2.95", + "deprecated": false, + "tags": [ + "Developer / Languages" + ], + "author": "Google" + }, + { + "id": "7F5B9650-26E7-4A88-A6D1-2C338778651D", + "baseIconId": "7F5B9650-26E7-4A88-A6D1-2C338778651D", + "name": "apps", + "codepoint": "F003B", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "View" + ], + "author": "Google" + }, + { + "id": "0C612FE5-D7CC-44F3-945A-4BD15A7E39BA", + "baseIconId": "0C612FE5-D7CC-44F3-945A-4BD15A7E39BA", + "name": "assistant", + "codepoint": "F0064", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "9FC24609-9C8B-4DBA-A473-F5EFAFCC90DF", + "baseIconId": "9FC24609-9C8B-4DBA-A473-F5EFAFCC90DF", + "name": "at", + "codepoint": "F0065", + "aliases": [ + "alternate-email" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "A35ABE08-C956-4177-935C-1E1FB835772D", + "baseIconId": "A35ABE08-C956-4177-935C-1E1FB835772D", + "name": "atm", + "codepoint": "F0D47", + "aliases": [], + "styles": [], + "version": "3.4.93", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "E3C20B38-A6D3-4EF0-817D-863B25E555BA", + "baseIconId": "E3C20B38-A6D3-4EF0-817D-863B25E555BA", + "name": "attachment", + "codepoint": "F0066", + "aliases": [ + "paperclip-horizontal" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "0086E21E-2ABC-4983-8BA7-C9C31B55D6B9", + "baseIconId": "0086E21E-2ABC-4983-8BA7-C9C31B55D6B9", + "name": "atv", + "codepoint": "F1B70", + "aliases": [ + "quad", + "trike", + "two-wheeler", + "all-terrain-vehicle" + ], + "styles": [], + "version": "7.0.96", + "deprecated": false, + "tags": [ + "Transportation + Other", + "Sport" + ], + "author": "Google" + }, + { + "id": "00598C19-1255-479D-914A-1AADFDBC4868", + "baseIconId": "00598C19-1255-479D-914A-1AADFDBC4868", + "name": "autorenew", + "codepoint": "F006A", + "aliases": [ + "clockwise-arrows", + "circular-arrows", + "circle-arrows", + "sync" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Arrow" + ], + "author": "Google" + }, + { + "id": "2CD51EFC-51B6-4323-B1EA-429EB58BFF7F", + "baseIconId": "2CD51EFC-51B6-4323-B1EA-429EB58BFF7F", + "name": "baby", + "codepoint": "F006C", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "People / Family" + ], + "author": "Google" + }, + { + "id": "2AAC06E6-8ABD-418B-B9A4-8554B62D7C04", + "baseIconId": "2AAC06E6-8ABD-418B-B9A4-8554B62D7C04", + "name": "backspace", + "codepoint": "F006E", + "aliases": [ + "erase", + "clear" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "005E0382-9004-4606-AA2A-07E27AF1E77E", + "baseIconId": "005E0382-9004-4606-AA2A-07E27AF1E77E", + "name": "balcony", + "codepoint": "F1817", + "aliases": [ + "terrace", + "patio", + "veranda" + ], + "styles": [], + "version": "6.1.95", + "deprecated": false, + "tags": [ + "Home Automation" + ], + "author": "Google" + }, + { + "id": "27AB71F3-1EFD-484F-8E63-C1E4C694E392", + "baseIconId": "27AB71F3-1EFD-484F-8E63-C1E4C694E392", + "name": "ballot", + "codepoint": "F09C9", + "aliases": [ + "vote" + ], + "styles": [], + "version": "2.5.94", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "6CDF527A-26C1-4175-A56B-5D65FD5E46E2", + "baseIconId": "6CDF527A-26C1-4175-A56B-5D65FD5E46E2", + "name": "bandage", + "codepoint": "F0DAF", + "aliases": [ + "band-aid", + "plaster" + ], + "styles": [], + "version": "3.5.94", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "FE08919F-CFFC-4A25-994C-CEDEB299908B", + "baseIconId": "FE08919F-CFFC-4A25-994C-CEDEB299908B", + "name": "bank", + "codepoint": "F0070", + "aliases": [ + "account-balance", + "museum" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Banking", + "Places" + ], + "author": "Google" + }, + { + "id": "CD3098D2-892F-49F5-9FA7-1A5FDC53A15C", + "baseIconId": "CD3098D2-892F-49F5-9FA7-1A5FDC53A15C", + "name": "barrel", + "codepoint": "F0074", + "aliases": [ + "oil-barrel", + "energy", + "fossil-fuel" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "4E334FE9-DF93-469A-B7D7-AC88BBF25D84", + "baseIconId": "4E334FE9-DF93-469A-B7D7-AC88BBF25D84", + "name": "basket", + "codepoint": "F0076", + "aliases": [ + "shopping-basket", + "skip" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Shopping" + ], + "author": "Google" + }, + { + "id": "FD797202-9EF1-407E-A290-97C014B8F37E", + "baseIconId": "FD797202-9EF1-407E-A290-97C014B8F37E", + "name": "basketball", + "codepoint": "F0806", + "aliases": [ + "youtube-sports" + ], + "styles": [], + "version": "2.1.19", + "deprecated": false, + "tags": [ + "Sport" + ], + "author": "Google" + }, + { + "id": "4DB5FCB7-2D9E-4612-8087-4F78B0053305", + "baseIconId": "4DB5FCB7-2D9E-4612-8087-4F78B0053305", + "name": "bathtub", + "codepoint": "F1818", + "aliases": [], + "styles": [], + "version": "6.1.95", + "deprecated": false, + "tags": [ + "Home Automation" + ], + "author": "Google" + }, + { + "id": "C12D919F-7D0D-4355-8109-912BA37154B5", + "baseIconId": "C12D919F-7D0D-4355-8109-912BA37154B5", + "name": "battery", + "codepoint": "F0079", + "aliases": [ + "battery-full", + "battery-std", + "battery-100" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Battery", + "Home Automation", + "Automotive" + ], + "author": "Google" + }, + { + "id": "EA62EF73-ACC7-4E54-87EF-D5E1683BE58F", + "baseIconId": "EA62EF73-ACC7-4E54-87EF-D5E1683BE58F", + "name": "bed", + "codepoint": "F02E3", + "aliases": [ + "hotel", + "guest-room" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Home Automation", + "Holiday" + ], + "author": "Google" + }, + { + "id": "8B580447-CD93-41E8-BDB0-F37DAE420D3A", + "baseIconId": "8B580447-CD93-41E8-BDB0-F37DAE420D3A", + "name": "bee", + "codepoint": "F0FA1", + "aliases": [ + "fly", + "insect" + ], + "styles": [], + "version": "4.0.96", + "deprecated": false, + "tags": [ + "Nature", + "Agriculture", + "Animal" + ], + "author": "Google" + }, + { + "id": "45fea174-07db-11e4-bf19-842b2b6cfe1b", + "baseIconId": "45fea174-07db-11e4-bf19-842b2b6cfe1b", + "name": "bell", + "codepoint": "F009A", + "aliases": [ + "notifications" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Notification", + "Home Automation", + "Music" + ], + "author": "Google" + }, + { + "id": "7E88D677-5560-4DF1-A3D0-FC2814BF6612", + "baseIconId": "7E88D677-5560-4DF1-A3D0-FC2814BF6612", + "name": "biathlon", + "codepoint": "F0E14", + "aliases": [ + "human-biathlon" + ], + "styles": [], + "version": "3.6.95", + "deprecated": false, + "tags": [ + "Sport", + "People / Family" + ], + "author": "Google" + }, + { + "id": "627C7FF1-BCAD-4741-966E-7CED73B35DC2", + "baseIconId": "627C7FF1-BCAD-4741-966E-7CED73B35DC2", + "name": "bike", + "codepoint": "F00A3", + "aliases": [ + "bicycle", + "cycling", + "directions-bike" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Transportation + Other", + "Sport" + ], + "author": "Google" + }, + { + "id": "AC980D29-7F19-4356-970E-A147CFEB64E3", + "baseIconId": "AC980D29-7F19-4356-970E-A147CFEB64E3", + "name": "blender", + "codepoint": "F0CEB", + "aliases": [ + "food-processor" + ], + "styles": [], + "version": "3.3.92", + "deprecated": false, + "tags": [ + "Food / Drink", + "Home Automation" + ], + "author": "Google" + }, + { + "id": "FAFCB184-2AAD-4E83-924F-1C37F1EDF956", + "baseIconId": "FAFCB184-2AAD-4E83-924F-1C37F1EDF956", + "name": "blur", + "codepoint": "F00B5", + "aliases": [ + "blur-on" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "FFF82791-D12F-4643-8128-71CF5FE38C9B", + "baseIconId": "FFF82791-D12F-4643-8128-71CF5FE38C9B", + "name": "book", + "codepoint": "F00BA", + "aliases": [ + "git-repository" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "690787DD-F7B0-4D32-A668-32657D3A3AE8", + "baseIconId": "690787DD-F7B0-4D32-A668-32657D3A3AE8", + "name": "bookmark", + "codepoint": "F00C0", + "aliases": [ + "turned-in" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "DAA06443-AE25-4881-BC62-8033C4420B8E", + "baseIconId": "DAA06443-AE25-4881-BC62-8033C4420B8E", + "name": "boombox", + "codepoint": "F05DC", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Home Automation" + ], + "author": "Google" + }, + { + "id": "15A9F4A5-3EB6-443C-8283-547A077CB0C4", + "baseIconId": "15A9F4A5-3EB6-443C-8283-547A077CB0C4", + "name": "briefcase", + "codepoint": "F00D6", + "aliases": [ + "work" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "F5E24182-366C-4D23-BA0E-8D2E25B88230", + "baseIconId": "F5E24182-366C-4D23-BA0E-8D2E25B88230", + "name": "broadcast", + "codepoint": "F1720", + "aliases": [ + "signal" + ], + "styles": [], + "version": "5.9.55", + "deprecated": false, + "tags": [ + "Weather" + ], + "author": "Google" + }, + { + "id": "B5C72984-BCCF-4729-A7D3-2A07D5794014", + "baseIconId": "B5C72984-BCCF-4729-A7D3-2A07D5794014", + "name": "brush", + "codepoint": "F00E3", + "aliases": [ + "paintbrush" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Drawing / Art" + ], + "author": "Google" + }, + { + "id": "09A131FB-EE06-49B8-80C3-49B294BCA612", + "baseIconId": "09A131FB-EE06-49B8-80C3-49B294BCA612", + "name": "bug", + "codepoint": "F00E4", + "aliases": [ + "bug-report" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Nature", + "Animal" + ], + "author": "Google" + }, + { + "id": "A5D2E199-03A1-4C23-9C63-954D63DEBEB4", + "baseIconId": "A5D2E199-03A1-4C23-9C63-954D63DEBEB4", + "name": "bullhorn", + "codepoint": "F00E6", + "aliases": [ + "announcement", + "megaphone", + "loudspeaker" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "F6516F38-B29E-4CC9-A7E2-706817121D45", + "baseIconId": "F6516F38-B29E-4CC9-A7E2-706817121D45", + "name": "bus", + "codepoint": "F00E7", + "aliases": [ + "directions-bus" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Navigation", + "Transportation + Road" + ], + "author": "Google" + }, + { + "id": "7DFE345F-A336-43BC-89BE-18FE3C902BFC", + "baseIconId": "7DFE345F-A336-43BC-89BE-18FE3C902BFC", + "name": "cached", + "codepoint": "F00E8", + "aliases": [ + "counterclockwise-arrows", + "circular-arrows", + "circle-arrows", + "sync" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Arrow" + ], + "author": "Google" + }, + { + "id": "E5BFDCE4-1033-4062-9677-94B95E028B6E", + "baseIconId": "E5BFDCE4-1033-4062-9677-94B95E028B6E", + "name": "cake", + "codepoint": "F00E9", + "aliases": [ + "birthday-cake" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Holiday", + "Food / Drink" + ], + "author": "Google" + }, + { + "id": "23C8742A-612C-4C55-B184-2A0ABB387746", + "baseIconId": "23C8742A-612C-4C55-B184-2A0ABB387746", + "name": "calendar", + "codepoint": "F00ED", + "aliases": [ + "event", + "insert-invitation" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Date / Time" + ], + "author": "Google" + }, + { + "id": "236D9E8E-E38C-4EA9-9539-0E8B1447003A", + "baseIconId": "236D9E8E-E38C-4EA9-9539-0E8B1447003A", + "name": "camera", + "codepoint": "F0100", + "aliases": [ + "photography", + "camera-alt", + "local-see", + "photo-camera" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Photography", + "Home Automation" + ], + "author": "Google" + }, + { + "id": "02F70DD2-E16E-43FD-9C2A-267C965E3919", + "baseIconId": "02F70DD2-E16E-43FD-9C2A-267C965E3919", + "name": "cancel", + "codepoint": "F073A", + "aliases": [ + "prohibited", + "ban", + "do-not-disturb-alt", + "denied", + "block", + "forbid", + "no", + "clear" + ], + "styles": [], + "version": "1.9.32", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "4FB0AA38-406A-4877-8B0C-15C7ED95F22C", + "baseIconId": "4FB0AA38-406A-4877-8B0C-15C7ED95F22C", + "name": "candle", + "codepoint": "F05E2", + "aliases": [ + "candle-flame", + "candle-fire" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Holiday", + "Home Automation" + ], + "author": "Google" + }, + { + "id": "FCF4FF57-4547-4C11-A20A-3D26252780EC", + "baseIconId": "FCF4FF57-4547-4C11-A20A-3D26252780EC", + "name": "car", + "codepoint": "F010B", + "aliases": [ + "directions-car", + "drive-eta", + "time-to-leave" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Transportation + Road", + "Navigation", + "Automotive" + ], + "author": "Google" + }, + { + "id": "077EABE1-1DBC-4AC9-AA0E-B45386391968", + "baseIconId": "077EABE1-1DBC-4AC9-AA0E-B45386391968", + "name": "carabiner", + "codepoint": "F14C0", + "aliases": [ + "karabiner", + "rock-climbing" + ], + "styles": [], + "version": "5.3.45", + "deprecated": false, + "tags": [ + "Sport" + ], + "author": "Google" + }, + { + "id": "97563623-CF1C-43AE-87D8-DF54802D442B", + "baseIconId": "97563623-CF1C-43AE-87D8-DF54802D442B", + "name": "cart", + "codepoint": "F0110", + "aliases": [ + "trolley", + "local-grocery-store", + "shopping-cart" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Shopping" + ], + "author": "Google" + }, + { + "id": "996A1644-29FB-4221-9225-FD5CF8AAD5CE", + "baseIconId": "996A1644-29FB-4221-9225-FD5CF8AAD5CE", + "name": "cast", + "codepoint": "F0118", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Home Automation" + ], + "author": "Google" + }, + { + "id": "8898488F-1BE6-40A0-84B7-1C0832AA4754", + "baseIconId": "8898488F-1BE6-40A0-84B7-1C0832AA4754", + "name": "cellphone", + "codepoint": "F011C", + "aliases": [ + "mobile-phone", + "smartphone", + "stay-current-portrait", + "stay-primary-portrait" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Cellphone / Phone", + "Device / Tech" + ], + "author": "Google" + }, + { + "id": "B5589411-20E7-4552-BEC5-A394068B23A7", + "baseIconId": "B5589411-20E7-4552-BEC5-A394068B23A7", + "name": "charity", + "codepoint": "F0C4F", + "aliases": [ + "super-chat-for-good" + ], + "styles": [], + "version": "3.2.89", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "F789CE44-7EA3-4E97-88FB-BEC22EB2030C", + "baseIconId": "F789CE44-7EA3-4E97-88FB-BEC22EB2030C", + "name": "check", + "codepoint": "F012C", + "aliases": [ + "tick", + "done", + "success" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Form" + ], + "author": "Google" + }, + { + "id": "F35E17AA-A0E8-4AEE-9504-6DC07F3ACEAD", + "baseIconId": "F35E17AA-A0E8-4AEE-9504-6DC07F3ACEAD", + "name": "checkbook", + "codepoint": "F0A9D", + "aliases": [ + "chequebook", + "cheque-book" + ], + "styles": [], + "version": "2.7.94", + "deprecated": false, + "tags": [ + "Banking" + ], + "author": "Google" + }, + { + "id": "82E4FDFE-C9C8-4087-ABCC-DF51F760379A", + "baseIconId": "82E4FDFE-C9C8-4087-ABCC-DF51F760379A", + "name": "church", + "codepoint": "F0144", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Religion", + "Places" + ], + "author": "Google" + }, + { + "id": "5A5AC571-1818-45D0-8259-A9177DBED615", + "baseIconId": "5A5AC571-1818-45D0-8259-A9177DBED615", + "name": "city", + "codepoint": "F0146", + "aliases": [ + "location-city" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Places" + ], + "author": "Google" + }, + { + "id": "90E7BBD9-12C3-4339-94DE-99A049C8D4B1", + "baseIconId": "90E7BBD9-12C3-4339-94DE-99A049C8D4B1", + "name": "clock", + "codepoint": "F0954", + "aliases": [ + "watch-later" + ], + "styles": [], + "version": "2.4.85", + "deprecated": false, + "tags": [ + "Date / Time" + ], + "author": "Google" + }, + { + "id": "FEA26660-7D6A-4C2A-9F13-7AE125FBA543", + "baseIconId": "FEA26660-7D6A-4C2A-9F13-7AE125FBA543", + "name": "close", + "codepoint": "F0156", + "aliases": [ + "clear", + "multiply", + "remove", + "cancel", + "times" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Math", + "Form" + ], + "author": "Google" + }, + { + "id": "CF07C502-388E-4A65-BD89-FACCFD00C245", + "baseIconId": "CF07C502-388E-4A65-BD89-FACCFD00C245", + "name": "cloud", + "codepoint": "F015F", + "aliases": [ + "wb-cloudy" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Cloud", + "Weather" + ], + "author": "Google" + }, + { + "id": "C95D04C5-F5EE-411A-88F7-A9872B2B4021", + "baseIconId": "C95D04C5-F5EE-411A-88F7-A9872B2B4021", + "name": "coffee", + "codepoint": "F0176", + "aliases": [ + "tea", + "cup", + "free-breakfast", + "local-cafe", + "drink" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Food / Drink" + ], + "author": "Google" + }, + { + "id": "E4A14909-3821-4DB1-A739-4DA464ABEEB7", + "baseIconId": "E4A14909-3821-4DB1-A739-4DA464ABEEB7", + "name": "cog", + "codepoint": "F0493", + "aliases": [ + "settings", + "gear" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Settings" + ], + "author": "Google" + }, + { + "id": "2EF56130-ECE9-4432-B59E-36F646DE1C86", + "baseIconId": "E4A14909-3821-4DB1-A739-4DA464ABEEB7", + "name": "cogs", + "codepoint": "F08D6", + "aliases": [ + "settings", + "manufacturing" + ], + "styles": [ + "multiple" + ], + "version": "2.3.50", + "deprecated": false, + "tags": [ + "Settings" + ], + "author": "Google" + }, + { + "id": "8FD44CCD-5073-4C73-98BE-139F777F6E94", + "baseIconId": "8FD44CCD-5073-4C73-98BE-139F777F6E94", + "name": "collage", + "codepoint": "F0640", + "aliases": [ + "auto-awesome-mosaic" + ], + "styles": [], + "version": "1.6.50", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "A9786B48-6664-4170-B56C-6F2868D5000D", + "baseIconId": "A9786B48-6664-4170-B56C-6F2868D5000D", + "name": "compare", + "codepoint": "F018A", + "aliases": [ + "theme-light-dark" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "8FE64B61-0FD6-4056-9A4F-E62408CE70FE", + "baseIconId": "8FE64B61-0FD6-4056-9A4F-E62408CE70FE", + "name": "compass", + "codepoint": "F018B", + "aliases": [ + "explore" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Navigation", + "Geographic Information System" + ], + "author": "Google" + }, + { + "id": "75C5A894-CC25-4326-A270-6F70BE0D8AAB", + "baseIconId": "75C5A894-CC25-4326-A270-6F70BE0D8AAB", + "name": "compost", + "codepoint": "F1A38", + "aliases": [ + "regeneration", + "regenerative-agriculture" + ], + "styles": [], + "version": "6.7.96", + "deprecated": false, + "tags": [ + "Agriculture", + "Nature" + ], + "author": "Google" + }, + { + "id": "5A68EA78-9792-4223-808D-17E5205765E6", + "baseIconId": "5A68EA78-9792-4223-808D-17E5205765E6", + "name": "contacts", + "codepoint": "F06CB", + "aliases": [], + "styles": [], + "version": "1.8.36", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "605CAD46-2EA0-47AE-8A41-953C1F27F9CD", + "baseIconId": "605CAD46-2EA0-47AE-8A41-953C1F27F9CD", + "name": "controller", + "codepoint": "F02B4", + "aliases": [ + "gamepad" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Gaming / RPG" + ], + "author": "Google" + }, + { + "id": "8E3FB537-B293-41A6-B6C5-B2BE927091F5", + "baseIconId": "8E3FB537-B293-41A6-B6C5-B2BE927091F5", + "name": "cookie", + "codepoint": "F0198", + "aliases": [ + "biscuit" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Food / Drink" + ], + "author": "Google" + }, + { + "id": "34B43A77-9873-4723-AA65-45D42992748E", + "baseIconId": "34B43A77-9873-4723-AA65-45D42992748E", + "name": "copyright", + "codepoint": "F05E6", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "795A2085-78E1-4721-BF6F-007B20CF92AF", + "baseIconId": "795A2085-78E1-4721-BF6F-007B20CF92AF", + "name": "countertop", + "codepoint": "F181C", + "aliases": [ + "kitchen-counter", + "sink" + ], + "styles": [], + "version": "6.1.95", + "deprecated": false, + "tags": [ + "Home Automation" + ], + "author": "Google" + }, + { + "id": "74B57630-EBF9-48DB-886C-36FA79D4350B", + "baseIconId": "74B57630-EBF9-48DB-886C-36FA79D4350B", + "name": "cradle", + "codepoint": "F198B", + "aliases": [ + "crib", + "bassinet", + "baby", + "nursery", + "baby-room" + ], + "styles": [], + "version": "6.5.95", + "deprecated": false, + "tags": [ + "People / Family", + "Home Automation" + ], + "author": "Google" + }, + { + "id": "598B7931-3DF8-4CFA-A6E6-80550CA31372", + "baseIconId": "598B7931-3DF8-4CFA-A6E6-80550CA31372", + "name": "creation", + "codepoint": "F0674", + "aliases": [ + "auto-awesome", + "sparkles", + "stars", + "shimmer" + ], + "styles": [], + "version": "1.7.12", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "9C7DBA7B-099C-460D-BD51-2B2F70EBE39A", + "baseIconId": "9C7DBA7B-099C-460D-BD51-2B2F70EBE39A", + "name": "cricket", + "codepoint": "F0D6D", + "aliases": [ + "cricket-bat" + ], + "styles": [], + "version": "3.4.93", + "deprecated": false, + "tags": [ + "Sport" + ], + "author": "Google" + }, + { + "id": "FA68ACCA-389F-453E-B886-FF3DAFE10530", + "baseIconId": "FA68ACCA-389F-453E-B886-FF3DAFE10530", + "name": "crop", + "codepoint": "F019E", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "33845FDE-0003-4780-8DC9-07FC29D46599", + "baseIconId": "33845FDE-0003-4780-8DC9-07FC29D46599", + "name": "crosshairs", + "codepoint": "F01A3", + "aliases": [ + "gps-not-fixed", + "location-searching" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Geographic Information System" + ], + "author": "Google" + }, + { + "id": "FEE6305B-081C-429E-9584-5A5C6D8FD38F", + "baseIconId": "FEE6305B-081C-429E-9584-5A5C6D8FD38F", + "name": "crowd", + "codepoint": "F1975", + "aliases": [ + "family", + "crowd-source", + "crowdsource" + ], + "styles": [], + "version": "6.5.95", + "deprecated": false, + "tags": [ + "Account / User", + "People / Family" + ], + "author": "Google" + }, + { + "id": "71CD492D-A1E8-4A7A-961A-51DA30952BAD", + "baseIconId": "71CD492D-A1E8-4A7A-961A-51DA30952BAD", + "name": "delete", + "codepoint": "F01B4", + "aliases": [ + "trash", + "bin", + "rubbish", + "garbage", + "rubbish-bin", + "trash-can", + "garbage-can" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "D4B29470-8EE3-4ED8-BB01-6C942CE7E748", + "baseIconId": "D4B29470-8EE3-4ED8-BB01-6C942CE7E748", + "name": "delta", + "codepoint": "F01C2", + "aliases": [ + "change-history" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Math", + "Alpha / Numeric" + ], + "author": "Google" + }, + { + "id": "21A2819F-3B97-49D0-A588-30CF7B8915F5", + "baseIconId": "21A2819F-3B97-49D0-A588-30CF7B8915F5", + "name": "details", + "codepoint": "F01C6", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "D8990892-9C02-46AC-9A91-3D4D9A2EFF19", + "baseIconId": "D8990892-9C02-46AC-9A91-3D4D9A2EFF19", + "name": "devices", + "codepoint": "F0FB0", + "aliases": [ + "monitor", + "watch", + "smartwatch", + "smartphone", + "cellphone", + "television" + ], + "styles": [], + "version": "4.0.96", + "deprecated": false, + "tags": [ + "Device / Tech", + "Home Automation", + "Cellphone / Phone" + ], + "author": "Google" + }, + { + "id": "B732FAD7-93A7-478E-810F-835069DE6EDB", + "baseIconId": "B732FAD7-93A7-478E-810F-835069DE6EDB", + "name": "dialpad", + "codepoint": "F061C", + "aliases": [ + "keypad" + ], + "styles": [], + "version": "1.6.50", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "4C84603B-BEB6-4282-B6CE-D9AD3C098627", + "baseIconId": "4C84603B-BEB6-4282-B6CE-D9AD3C098627", + "name": "directions", + "codepoint": "F01D0", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "41CB517E-41F5-47D4-A8A2-E9512CB065DD", + "baseIconId": "41CB517E-41F5-47D4-A8A2-E9512CB065DD", + "name": "dishwasher", + "codepoint": "F0AAC", + "aliases": [], + "styles": [], + "version": "2.7.94", + "deprecated": false, + "tags": [ + "Home Automation" + ], + "author": "Google" + }, + { + "id": "813D489B-3127-4F32-9D6E-4BB8A6F51605", + "baseIconId": "813D489B-3127-4F32-9D6E-4BB8A6F51605", + "name": "diving", + "codepoint": "F1977", + "aliases": [ + "swim-dive", + "human-diving" + ], + "styles": [], + "version": "6.5.95", + "deprecated": false, + "tags": [ + "Sport", + "People / Family" + ], + "author": "Google" + }, + { + "id": "D4A20191-F5B8-4323-A0A8-F4C15A86A83B", + "baseIconId": "D4A20191-F5B8-4323-A0A8-F4C15A86A83B", + "name": "dns", + "codepoint": "F01D6", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "CA264BA4-62A9-4823-A172-22DD413A6CF5", + "baseIconId": "CA264BA4-62A9-4823-A172-22DD413A6CF5", + "name": "domain", + "codepoint": "F01D7", + "aliases": [ + "building", + "company", + "business" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Places" + ], + "author": "Google" + }, + { + "id": "704F7397-0E85-4213-8D76-FE156DF1795F", + "baseIconId": "704F7397-0E85-4213-8D76-FE156DF1795F", + "name": "download", + "codepoint": "F01DA", + "aliases": [ + "file-download", + "get-app" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "E792948B-8E66-49B5-83E7-8CDF1ECE6C5D", + "baseIconId": "E792948B-8E66-49B5-83E7-8CDF1ECE6C5D", + "name": "dumbbell", + "codepoint": "F01E6", + "aliases": [ + "weights", + "fitness-center", + "gym", + "barbell" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Sport" + ], + "author": "Google" + }, + { + "id": "0D1618BF-A3AD-4B4A-92EA-5DBF93BF7625", + "baseIconId": "0D1618BF-A3AD-4B4A-92EA-5DBF93BF7625", + "name": "earth", + "codepoint": "F01E7", + "aliases": [ + "globe", + "public", + "planet", + "world" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Geographic Information System", + "Navigation" + ], + "author": "Google" + }, + { + "id": "4B57E9DF-354F-460D-9551-65C0DB55D788", + "baseIconId": "4B57E9DF-354F-460D-9551-65C0DB55D788", + "name": "eject", + "codepoint": "F01EA", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "14AAE073-8399-4D67-9F7E-8E9424328681", + "baseIconId": "14AAE073-8399-4D67-9F7E-8E9424328681", + "name": "email", + "codepoint": "F01EE", + "aliases": [ + "local-post-office", + "mail", + "markunread", + "envelope" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "E8F2B8BE-F4EC-4B9C-BB15-001752B29FFD", + "baseIconId": "E8F2B8BE-F4EC-4B9C-BB15-001752B29FFD", + "name": "emoticon", + "codepoint": "F0C68", + "aliases": [ + "smiley", + "face", + "emoji" + ], + "styles": [], + "version": "3.2.89", + "deprecated": false, + "tags": [ + "Emoji" + ], + "author": "Google" + }, + { + "id": "4F6A532E-58ED-4CB5-9BBB-9E77C128D536", + "baseIconId": "4F6A532E-58ED-4CB5-9BBB-9E77C128D536", + "name": "equalizer", + "codepoint": "F0EA2", + "aliases": [], + "styles": [], + "version": "3.7.94", + "deprecated": false, + "tags": [ + "Audio" + ], + "author": "Google" + }, + { + "id": "3C2B7DF3-97FE-4EC4-B6A9-69A75FB26B67", + "baseIconId": "3C2B7DF3-97FE-4EC4-B6A9-69A75FB26B67", + "name": "eye", + "codepoint": "F0208", + "aliases": [ + "show", + "visibility", + "remove-red-eye" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "2C398569-5DBF-4405-AF73-6F5CA629AEE1", + "baseIconId": "2C398569-5DBF-4405-AF73-6F5CA629AEE1", + "name": "fax", + "codepoint": "F0212", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Printer", + "Cellphone / Phone" + ], + "author": "Google" + }, + { + "id": "325210DA-E889-4CBD-B0A7-8A32D706322B", + "baseIconId": "325210DA-E889-4CBD-B0A7-8A32D706322B", + "name": "fencing", + "codepoint": "F14C1", + "aliases": [ + "sword-fight" + ], + "styles": [], + "version": "5.3.45", + "deprecated": false, + "tags": [ + "Sport" + ], + "author": "Google" + }, + { + "id": "F138AC6A-406B-4EB0-BB85-0FDB5415B6F8", + "baseIconId": "F138AC6A-406B-4EB0-BB85-0FDB5415B6F8", + "name": "ferry", + "codepoint": "F0213", + "aliases": [ + "cargo-ship", + "boat", + "ship", + "directions-boat", + "directions-ferry" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Transportation + Water", + "Navigation" + ], + "author": "Google" + }, + { + "id": "BFF59001-B52D-47E6-A217-C9095F81C3B8", + "baseIconId": "BFF59001-B52D-47E6-A217-C9095F81C3B8", + "name": "file", + "codepoint": "F0214", + "aliases": [ + "insert-drive-file", + "draft", + "paper" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Files / Folders" + ], + "author": "Google" + }, + { + "id": "2EFEE436-9663-4C09-AD65-6727A0ED2AFD", + "baseIconId": "2EFEE436-9663-4C09-AD65-6727A0ED2AFD", + "name": "film", + "codepoint": "F022F", + "aliases": [ + "camera-roll" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Photography", + "Video / Movie" + ], + "author": "Google" + }, + { + "id": "10A06B6D-A551-425C-B084-DA3F2239DFA1", + "baseIconId": "10A06B6D-A551-425C-B084-DA3F2239DFA1", + "name": "filmstrip", + "codepoint": "F0230", + "aliases": [ + "local-movies", + "theaters" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Video / Movie" + ], + "author": "Google" + }, + { + "id": "C39421CD-2A2D-4D92-B59B-69D70A328DF4", + "baseIconId": "C39421CD-2A2D-4D92-B59B-69D70A328DF4", + "name": "finance", + "codepoint": "F081F", + "aliases": [ + "chart-finance", + "report-finance", + "graph-bar" + ], + "styles": [], + "version": "2.1.19", + "deprecated": false, + "tags": [ + "Banking", + "Math" + ], + "author": "Google" + }, + { + "id": "F71C897D-9858-40AE-8DB4-253CE675D823", + "baseIconId": "F71C897D-9858-40AE-8DB4-253CE675D823", + "name": "fingerprint", + "codepoint": "F0237", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "5259DBA5-B2FB-4112-B1F2-5DC17002205C", + "baseIconId": "5259DBA5-B2FB-4112-B1F2-5DC17002205C", + "name": "fire", + "codepoint": "F0238", + "aliases": [ + "whatshot", + "flame", + "gas", + "natural-gas", + "hot" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Home Automation" + ], + "author": "Google" + }, + { + "id": "3A3D9EFD-ABA4-444F-9CB5-A2D8C1322B2C", + "baseIconId": "3A3D9EFD-ABA4-444F-9CB5-A2D8C1322B2C", + "name": "firebase", + "codepoint": "F0967", + "aliases": [], + "styles": [], + "version": "2.4.85", + "deprecated": true, + "tags": [ + "Brand / Logo" + ], + "author": "Google" + }, + { + "id": "55271063-77EF-43FA-917C-657E57135A24", + "baseIconId": "55271063-77EF-43FA-917C-657E57135A24", + "name": "flag", + "codepoint": "F023B", + "aliases": [ + "assistant-photo" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "8F4F8B2A-9E7D-432F-978E-F3F108DA701B", + "baseIconId": "8F4F8B2A-9E7D-432F-978E-F3F108DA701B", + "name": "flare", + "codepoint": "F0D72", + "aliases": [ + "star" + ], + "styles": [], + "version": "3.4.93", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "EF3D6923-793B-410C-B349-90A6A338F06C", + "baseIconId": "EF3D6923-793B-410C-B349-90A6A338F06C", + "name": "flash", + "codepoint": "F0241", + "aliases": [ + "lightning-bolt", + "flash-on", + "electricity" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Weather" + ], + "author": "Google" + }, + { + "id": "D73BB486-A112-48C1-A4EE-993825164C43", + "baseIconId": "D73BB486-A112-48C1-A4EE-993825164C43", + "name": "flower", + "codepoint": "F024A", + "aliases": [ + "local-florist", + "plant" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Nature", + "Agriculture" + ], + "author": "Google" + }, + { + "id": "9D8C1CEE-19BE-4B0B-85CC-DEB829F9F045", + "baseIconId": "9D8C1CEE-19BE-4B0B-85CC-DEB829F9F045", + "name": "folder", + "codepoint": "F024B", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Files / Folders" + ], + "author": "Google" + }, + { + "id": "140954DE-20F5-4A8B-BFC3-DB8E49922AF3", + "baseIconId": "140954DE-20F5-4A8B-BFC3-DB8E49922AF3", + "name": "food", + "codepoint": "F025A", + "aliases": [ + "fast-food", + "burger", + "cup", + "drink", + "hamburger" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Food / Drink" + ], + "author": "Google" + }, + { + "id": "3C0488C6-E807-401D-9689-7770550EC2E7", + "baseIconId": "3C0488C6-E807-401D-9689-7770550EC2E7", + "name": "football", + "codepoint": "F025D", + "aliases": [ + "football-american" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Sport" + ], + "author": "Google" + }, + { + "id": "70EFA358-6CE3-4CC1-9F46-6283D491F2E2", + "baseIconId": "70EFA358-6CE3-4CC1-9F46-6283D491F2E2", + "name": "forest", + "codepoint": "F1897", + "aliases": [ + "forestry", + "pine-tree-multiple" + ], + "styles": [], + "version": "6.2.95", + "deprecated": false, + "tags": [ + "Nature", + "Agriculture", + "Places" + ], + "author": "Google" + }, + { + "id": "3AC84477-2308-4445-868C-9666AE25B054", + "baseIconId": "3AC84477-2308-4445-868C-9666AE25B054", + "name": "forum", + "codepoint": "F028C", + "aliases": [ + "message-group", + "question-answer", + "chat", + "dialogue", + "conversation", + "discussion" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "EAE07425-A6D5-4B33-A9C5-6D7E9E9E1908", + "baseIconId": "EAE07425-A6D5-4B33-A9C5-6D7E9E9E1908", + "name": "forward", + "codepoint": "F028D", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Arrow" + ], + "author": "Google" + }, + { + "id": "A4F7E2E4-704C-4A71-99D5-4BD19AD8E755", + "baseIconId": "A4F7E2E4-704C-4A71-99D5-4BD19AD8E755", + "name": "fullscreen", + "codepoint": "F0293", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "5C29EFA9-0FF3-4101-BC87-C9C15ACBA7AB", + "baseIconId": "5C29EFA9-0FF3-4101-BC87-C9C15ACBA7AB", + "name": "gamepad", + "codepoint": "F0296", + "aliases": [ + "games", + "controller" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Home Automation", + "Gaming / RPG" + ], + "author": "Google" + }, + { + "id": "EC7B7499-25F1-43D4-9A09-9742F5B6D3F2", + "baseIconId": "EC7B7499-25F1-43D4-9A09-9742F5B6D3F2", + "name": "gauge", + "codepoint": "F029A", + "aliases": [ + "swap-driving-apps-wheel", + "barometer" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Home Automation", + "Automotive" + ], + "author": "Google" + }, + { + "id": "FFC2833D-65AB-47BB-AC7C-8CFA41DF9250", + "baseIconId": "FFC2833D-65AB-47BB-AC7C-8CFA41DF9250", + "name": "gesture", + "codepoint": "F07CB", + "aliases": [ + "freehand-line" + ], + "styles": [], + "version": "2.0.46", + "deprecated": false, + "tags": [ + "Drawing / Art" + ], + "author": "Google" + }, + { + "id": "259F5EC9-395F-40C8-9389-6B6A82D9997C", + "baseIconId": "259F5EC9-395F-40C8-9389-6B6A82D9997C", + "name": "gmail", + "codepoint": "F02AB", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": true, + "tags": [ + "Brand / Logo" + ], + "author": "Google" + }, + { + "id": "80A4F47A-3512-4C76-AA10-C0232C57E624", + "baseIconId": "80A4F47A-3512-4C76-AA10-C0232C57E624", + "name": "golf", + "codepoint": "F0823", + "aliases": [ + "golf-course" + ], + "styles": [], + "version": "2.1.19", + "deprecated": false, + "tags": [ + "Sport" + ], + "author": "Google" + }, + { + "id": "F787FBCA-3C54-43CC-AE16-E23436AD0720", + "baseIconId": "F787FBCA-3C54-43CC-AE16-E23436AD0720", + "name": "google", + "codepoint": "F02AD", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": true, + "tags": [ + "Brand / Logo" + ], + "author": "Google" + }, + { + "id": "D1784DB9-E2F2-44AA-AF8D-E562D8E3CBBC", + "baseIconId": "D1784DB9-E2F2-44AA-AF8D-E562D8E3CBBC", + "name": "grain", + "codepoint": "F0D7C", + "aliases": [], + "styles": [], + "version": "3.4.93", + "deprecated": false, + "tags": [ + "Photography", + "Video / Movie", + "Agriculture" + ], + "author": "Google" + }, + { + "id": "8688646A-F06F-421F-83B1-8AA8FABF7BD8", + "baseIconId": "8688646A-F06F-421F-83B1-8AA8FABF7BD8", + "name": "grass", + "codepoint": "F1510", + "aliases": [ + "lawn" + ], + "styles": [], + "version": "5.4.55", + "deprecated": false, + "tags": [ + "Nature", + "Agriculture" + ], + "author": "Google" + }, + { + "id": "8D4C203D-A1F0-42DA-997A-AB7BAC63D97B", + "baseIconId": "8D4C203D-A1F0-42DA-997A-AB7BAC63D97B", + "name": "grid", + "codepoint": "F02C1", + "aliases": [ + "grid-on" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "22C8B00E-9BA8-4C66-994B-A2F0B4D369DD", + "baseIconId": "22C8B00E-9BA8-4C66-994B-A2F0B4D369DD", + "name": "grill", + "codepoint": "F0E45", + "aliases": [ + "bbq", + "barbecue", + "charcoal" + ], + "styles": [], + "version": "3.6.95", + "deprecated": false, + "tags": [ + "Food / Drink" + ], + "author": "Google" + }, + { + "id": "450F9873-EC55-4361-99EB-BBFF202647C6", + "baseIconId": "450F9873-EC55-4361-99EB-BBFF202647C6", + "name": "gymnastics", + "codepoint": "F1A41", + "aliases": [], + "styles": [], + "version": "6.7.96", + "deprecated": false, + "tags": [ + "Sport" + ], + "author": "Google" + }, + { + "id": "B4AC04DD-9F29-4F55-ABB6-A4AE4F272EC4", + "baseIconId": "B4AC04DD-9F29-4F55-ABB6-A4AE4F272EC4", + "name": "hail", + "codepoint": "F0AC1", + "aliases": [ + "hail-taxi", + "hail-cab" + ], + "styles": [], + "version": "2.7.94", + "deprecated": false, + "tags": [ + "Transportation + Road", + "Navigation" + ], + "author": "Google" + }, + { + "id": "A3F55E77-82C2-48F6-B1B1-92C9259C9C26", + "baseIconId": "A3F55E77-82C2-48F6-B1B1-92C9259C9C26", + "name": "hammer", + "codepoint": "F08EA", + "aliases": [], + "styles": [], + "version": "2.3.50", + "deprecated": false, + "tags": [ + "Hardware / Tools" + ], + "author": "Google" + }, + { + "id": "845C7000-7198-490F-8043-EC1F61CE4F53", + "baseIconId": "845C7000-7198-490F-8043-EC1F61CE4F53", + "name": "handball", + "codepoint": "F0F53", + "aliases": [ + "volleyball", + "human-handball" + ], + "styles": [], + "version": "3.9.97", + "deprecated": false, + "tags": [ + "Sport", + "People / Family" + ], + "author": "Google" + }, + { + "id": "81182C14-380B-4F56-AFF9-EF636EC7BF7E", + "baseIconId": "81182C14-380B-4F56-AFF9-EF636EC7BF7E", + "name": "hdr", + "codepoint": "F0D7D", + "aliases": [], + "styles": [], + "version": "3.4.93", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "51F72F83-1559-4037-8BF9-2D8AE3BCB1A8", + "baseIconId": "51F72F83-1559-4037-8BF9-2D8AE3BCB1A8", + "name": "headphones", + "codepoint": "F02CB", + "aliases": [ + "headset" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Audio", + "Device / Tech", + "Music" + ], + "author": "Google" + }, + { + "id": "AFF98802-E02B-4EC8-8AFF-F0F5373D86C5", + "baseIconId": "51F72F83-1559-4037-8BF9-2D8AE3BCB1A8", + "name": "headset", + "codepoint": "F02CE", + "aliases": [ + "headset-mic" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Audio", + "Device / Tech" + ], + "author": "Google" + }, + { + "id": "32B56DB2-B6BF-4B54-AD0C-9444106B1C1D", + "baseIconId": "32B56DB2-B6BF-4B54-AD0C-9444106B1C1D", + "name": "heart", + "codepoint": "F02D1", + "aliases": [ + "favorite", + "favourite" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Shape", + "Gaming / RPG", + "Medical / Hospital" + ], + "author": "Google" + }, + { + "id": "DA3D64F2-C874-420A-917A-0F66C9854D84", + "baseIconId": "DA3D64F2-C874-420A-917A-0F66C9854D84", + "name": "hiking", + "codepoint": "F0D7F", + "aliases": [ + "human-hiking" + ], + "styles": [], + "version": "3.4.93", + "deprecated": false, + "tags": [ + "Sport", + "People / Family" + ], + "author": "Google" + }, + { + "id": "55AF2D53-7FAD-4A1D-8440-10301C95D3B8", + "baseIconId": "55AF2D53-7FAD-4A1D-8440-10301C95D3B8", + "name": "history", + "codepoint": "F02DA", + "aliases": [ + "recent", + "latest", + "clock-arrow", + "counterclockwise", + "restore-clock" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Date / Time" + ], + "author": "Google" + }, + { + "id": "5D085274-15B9-42EC-8CCE-2F94C5EC039C", + "baseIconId": "5D085274-15B9-42EC-8CCE-2F94C5EC039C", + "name": "home", + "codepoint": "F02DC", + "aliases": [ + "house" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Home Automation", + "Places" + ], + "author": "Google" + }, + { + "id": "0BEA7CE4-5642-406D-A995-E2502E85D184", + "baseIconId": "0BEA7CE4-5642-406D-A995-E2502E85D184", + "name": "hub", + "codepoint": "F1C95", + "aliases": [], + "styles": [], + "version": "7.3.67", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "B05E458D-886A-491D-9969-156562C52105", + "baseIconId": "10E7CAB4-7B15-4F73-82B1-E42562B9103C", + "name": "human", + "codepoint": "F02E6", + "aliases": [ + "accessibility" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "People / Family" + ], + "author": "Google" + }, + { + "id": "EE07113F-BD81-424C-B228-7EC802F7CFB2", + "baseIconId": "EE07113F-BD81-424C-B228-7EC802F7CFB2", + "name": "hvac", + "codepoint": "F1352", + "aliases": [ + "heating", + "ventilation", + "air-conditioning" + ], + "styles": [], + "version": "4.9.95", + "deprecated": false, + "tags": [ + "Home Automation" + ], + "author": "Google" + }, + { + "id": "3238BA72-FEE8-4C90-A440-AD701359A7BC", + "baseIconId": "3238BA72-FEE8-4C90-A440-AD701359A7BC", + "name": "image", + "codepoint": "F02E9", + "aliases": [ + "insert-photo" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "4DDB79C2-C3AE-41DC-B560-AFBF3F689E86", + "baseIconId": "4DDB79C2-C3AE-41DC-B560-AFBF3F689E86", + "name": "inbox", + "codepoint": "F0687", + "aliases": [], + "styles": [], + "version": "1.7.12", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "2BC4A4B6-119B-4637-BF3D-1FB9394E1F38", + "baseIconId": "2BC4A4B6-119B-4637-BF3D-1FB9394E1F38", + "name": "information", + "codepoint": "F02FC", + "aliases": [ + "about", + "information-circle", + "info-circle", + "about-circle", + "info" + ], + "styles": [ + "circle" + ], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Settings" + ], + "author": "Google" + }, + { + "id": "43DA7407-CFBA-44CE-9857-D75DF5581CE2", + "baseIconId": "43DA7407-CFBA-44CE-9857-D75DF5581CE2", + "name": "iron", + "codepoint": "F1824", + "aliases": [ + "flatiron", + "smoothing-iron" + ], + "styles": [], + "version": "6.1.95", + "deprecated": false, + "tags": [ + "Home Automation", + "Clothing" + ], + "author": "Google" + }, + { + "id": "24CB8442-6875-4A22-A265-0C625118C7E7", + "baseIconId": "24CB8442-6875-4A22-A265-0C625118C7E7", + "name": "kabaddi", + "codepoint": "F0D87", + "aliases": [ + "wrestling", + "human-kabaddi" + ], + "styles": [], + "version": "3.4.93", + "deprecated": false, + "tags": [ + "Sport", + "People / Family" + ], + "author": "Google" + }, + { + "id": "85144563-B019-4B8A-AB76-3DE0797D517E", + "baseIconId": "85144563-B019-4B8A-AB76-3DE0797D517E", + "name": "karate", + "codepoint": "F082C", + "aliases": [ + "martial-arts", + "kickboxing", + "human-karate" + ], + "styles": [], + "version": "2.1.19", + "deprecated": false, + "tags": [ + "Sport", + "People / Family" + ], + "author": "Google" + }, + { + "id": "21C7383B-5839-4F3E-A4EC-81A9980F531B", + "baseIconId": "21C7383B-5839-4F3E-A4EC-81A9980F531B", + "name": "kayaking", + "codepoint": "F08AF", + "aliases": [ + "human-kayaking" + ], + "styles": [], + "version": "2.2.43", + "deprecated": false, + "tags": [ + "Sport", + "People / Family" + ], + "author": "Google" + }, + { + "id": "D6208581-CF7F-438A-8578-B6ADEE462212", + "baseIconId": "D6208581-CF7F-438A-8578-B6ADEE462212", + "name": "key", + "codepoint": "F0306", + "aliases": [ + "vpn-key" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Automotive" + ], + "author": "Google" + }, + { + "id": "520C8488-DD34-43E1-AEA0-A188B2DE6B01", + "baseIconId": "520C8488-DD34-43E1-AEA0-A188B2DE6B01", + "name": "keyboard", + "codepoint": "F030C", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "8B89609E-5F12-4A3B-99AE-F6698FEA48E4", + "baseIconId": "8B89609E-5F12-4A3B-99AE-F6698FEA48E4", + "name": "kite", + "codepoint": "F1985", + "aliases": [], + "styles": [], + "version": "6.5.95", + "deprecated": false, + "tags": [ + "Sport" + ], + "author": "Google" + }, + { + "id": "2B23BD24-9796-4D72-85CC-76BE23854F0F", + "baseIconId": "2B23BD24-9796-4D72-85CC-76BE23854F0F", + "name": "kitesurfing", + "codepoint": "F1744", + "aliases": [], + "styles": [], + "version": "6.1.95", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "C749E06B-E75E-4D9B-97A6-47E9399D01FC", + "baseIconId": "C749E06B-E75E-4D9B-97A6-47E9399D01FC", + "name": "label", + "codepoint": "F0315", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "97AFF594-E421-4757-BE72-1D6C428E27AE", + "baseIconId": "97AFF594-E421-4757-BE72-1D6C428E27AE", + "name": "ladybug", + "codepoint": "F082D", + "aliases": [ + "bugfood", + "ladybird" + ], + "styles": [], + "version": "2.1.19", + "deprecated": false, + "tags": [ + "Nature" + ], + "author": "Google" + }, + { + "id": "AD048AA5-6C71-49DF-B5B2-427F634C3538", + "baseIconId": "AD048AA5-6C71-49DF-B5B2-427F634C3538", + "name": "landslide", + "codepoint": "F1A48", + "aliases": [ + "avalanche", + "mudslide" + ], + "styles": [], + "version": "6.7.96", + "deprecated": false, + "tags": [ + "Nature" + ], + "author": "Google" + }, + { + "id": "A8B6481F-EE91-4F90-81AC-DEB8A096F45A", + "baseIconId": "A8B6481F-EE91-4F90-81AC-DEB8A096F45A", + "name": "laptop", + "codepoint": "F0322", + "aliases": [ + "computer" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Device / Tech", + "Home Automation" + ], + "author": "Google" + }, + { + "id": "ED8AF9CE-E555-49C9-8E7E-F9B85CD94CDF", + "baseIconId": "ED8AF9CE-E555-49C9-8E7E-F9B85CD94CDF", + "name": "launch", + "codepoint": "F0327", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "36A9B462-C487-458E-BFB6-2415739BC968", + "baseIconId": "36A9B462-C487-458E-BFB6-2415739BC968", + "name": "layers", + "codepoint": "F0328", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Geographic Information System" + ], + "author": "Google" + }, + { + "id": "D648ECFA-B185-4041-8B54-6D1C125CD08E", + "baseIconId": "D648ECFA-B185-4041-8B54-6D1C125CD08E", + "name": "leak", + "codepoint": "F0DD7", + "aliases": [ + "proximity-sensor" + ], + "styles": [], + "version": "3.5.94", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "45FA5A9C-DFF1-4D7E-B683-DB7DE2BAEFC7", + "baseIconId": "45FA5A9C-DFF1-4D7E-B683-DB7DE2BAEFC7", + "name": "library", + "codepoint": "F0331", + "aliases": [ + "local-library" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Places" + ], + "author": "Google" + }, + { + "id": "8398466C-F905-444F-81E6-B5B2103BD873", + "baseIconId": "8398466C-F905-444F-81E6-B5B2103BD873", + "name": "license", + "codepoint": "F0FC3", + "aliases": [ + "ribbon", + "prize", + "award", + "seal" + ], + "styles": [], + "version": "4.0.96", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "ECC94305-DFA6-4D9B-85C8-CC79F3F05FB5", + "baseIconId": "ECC94305-DFA6-4D9B-85C8-CC79F3F05FB5", + "name": "lightbulb", + "codepoint": "F0335", + "aliases": [ + "idea", + "bulb" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Home Automation" + ], + "author": "Google" + }, + { + "id": "462769C2-0A30-4B31-B66C-55168B10D705", + "baseIconId": "462769C2-0A30-4B31-B66C-55168B10D705", + "name": "link", + "codepoint": "F0337", + "aliases": [ + "insert-link" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "48C6596F-07B5-495C-82E2-683B09DD7040", + "baseIconId": "48C6596F-07B5-495C-82E2-683B09DD7040", + "name": "liquor", + "codepoint": "F191E", + "aliases": [ + "booze", + "alcohol", + "beverages", + "whiskey", + "rum", + "wine", + "tequila", + "beer", + "spirits" + ], + "styles": [], + "version": "6.4.95", + "deprecated": false, + "tags": [ + "Food / Drink" + ], + "author": "Google" + }, + { + "id": "D711AFDE-2B8D-4932-82AC-A04E7B2810AE", + "baseIconId": "D711AFDE-2B8D-4932-82AC-A04E7B2810AE", + "name": "lock", + "codepoint": "F033E", + "aliases": [ + "https", + "password", + "secure", + "protected", + "encryption" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Lock", + "Home Automation", + "Automotive" + ], + "author": "Google" + }, + { + "id": "63D8BFA5-7AE4-4002-A4C2-C464638C38FC", + "baseIconId": "63D8BFA5-7AE4-4002-A4C2-C464638C38FC", + "name": "login", + "codepoint": "F0342", + "aliases": [ + "log-in", + "sign-in" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "47DF41F2-49C7-4081-8419-F49C7894E7F1", + "baseIconId": "47DF41F2-49C7-4081-8419-F49C7894E7F1", + "name": "logout", + "codepoint": "F0343", + "aliases": [ + "log-out", + "sign-out" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "3633613A-B8A7-49D0-8C1B-5415EC76F426", + "baseIconId": "3633613A-B8A7-49D0-8C1B-5415EC76F426", + "name": "looks", + "codepoint": "F0344", + "aliases": [ + "rainbow" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Weather", + "Color" + ], + "author": "Google" + }, + { + "id": "DB75FD27-01F6-4232-AA23-86C115751A0C", + "baseIconId": "DB75FD27-01F6-4232-AA23-86C115751A0C", + "name": "loupe", + "codepoint": "F0345", + "aliases": [ + "zoom-plus", + "circle-plus-outline", + "magnify" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "C2889545-7F08-4AE1-9142-ECF9B79957E1", + "baseIconId": "C2889545-7F08-4AE1-9142-ECF9B79957E1", + "name": "magnify", + "codepoint": "F0349", + "aliases": [ + "search" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Geographic Information System" + ], + "author": "Google" + }, + { + "id": "99738FF8-01AE-420D-8481-8B9E1402255B", + "baseIconId": "99738FF8-01AE-420D-8481-8B9E1402255B", + "name": "map", + "codepoint": "F034D", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Navigation", + "Geographic Information System" + ], + "author": "Google" + }, + { + "id": "71E6D8F0-A3D2-43CB-8940-16AA4E1D9825", + "baseIconId": "71E6D8F0-A3D2-43CB-8940-16AA4E1D9825", + "name": "marker", + "codepoint": "F0652", + "aliases": [ + "highlighter" + ], + "styles": [], + "version": "1.6.50", + "deprecated": false, + "tags": [ + "Text / Content / Format" + ], + "author": "Google" + }, + { + "id": "57211BE3-0055-4D43-B05C-3CD0FE10322C", + "baseIconId": "57211BE3-0055-4D43-B05C-3CD0FE10322C", + "name": "medication", + "codepoint": "F1B14", + "aliases": [ + "pill-bottle", + "medicine-bottle", + "bottle-plus" + ], + "styles": [], + "version": "6.9.96", + "deprecated": false, + "tags": [ + "Health / Beauty", + "Medical / Hospital" + ], + "author": "Google" + }, + { + "id": "B68AA118-B8B5-4A2A-BCA2-A12C8C119319", + "baseIconId": "B68AA118-B8B5-4A2A-BCA2-A12C8C119319", + "name": "meditation", + "codepoint": "F117B", + "aliases": [ + "human-meditation" + ], + "styles": [], + "version": "4.4.95", + "deprecated": false, + "tags": [ + "Sport", + "People / Family" + ], + "author": "Google" + }, + { + "id": "E404434E-17DB-4E90-9D97-5355258E1FCF", + "baseIconId": "E404434E-17DB-4E90-9D97-5355258E1FCF", + "name": "memory", + "codepoint": "F035B", + "aliases": [ + "chip" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "0BD2CD08-CCFB-4EC3-B96D-08B0B8230A91", + "baseIconId": "0BD2CD08-CCFB-4EC3-B96D-08B0B8230A91", + "name": "menu", + "codepoint": "F035C", + "aliases": [ + "hamburger-menu" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "0D0E7E15-9615-4A66-8933-8BC98675AE3D", + "baseIconId": "0D0E7E15-9615-4A66-8933-8BC98675AE3D", + "name": "merge", + "codepoint": "F0F5C", + "aliases": [], + "styles": [], + "version": "3.9.97", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "99DA4752-8C79-44D8-8286-6EBD696F0B45", + "baseIconId": "99DA4752-8C79-44D8-8286-6EBD696F0B45", + "name": "message", + "codepoint": "F0361", + "aliases": [ + "chat-bubble" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "18C99959-2A0E-4095-BAEA-F5B266377648", + "baseIconId": "18C99959-2A0E-4095-BAEA-F5B266377648", + "name": "microphone", + "codepoint": "F036C", + "aliases": [ + "keyboard-voice" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Music" + ], + "author": "Google" + }, + { + "id": "2CEA6B7B-E7C9-4D52-9D9D-286E50001B70", + "baseIconId": "2CEA6B7B-E7C9-4D52-9D9D-286E50001B70", + "name": "minus", + "codepoint": "F0374", + "aliases": [ + "remove", + "horizontal-line", + "minimize" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Math" + ], + "author": "Google" + }, + { + "id": "35091AEB-2AF7-4F92-A249-2955F01404A3", + "baseIconId": "35091AEB-2AF7-4F92-A249-2955F01404A3", + "name": "monitor", + "codepoint": "F0379", + "aliases": [ + "desktop-windows" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Device / Tech" + ], + "author": "Google" + }, + { + "id": "DC294862-E625-444E-83A4-7D5F2255EE0C", + "baseIconId": "DC294862-E625-444E-83A4-7D5F2255EE0C", + "name": "moped", + "codepoint": "F1086", + "aliases": [ + "scooter", + "vespa", + "delivery-dining" + ], + "styles": [], + "version": "4.2.95", + "deprecated": false, + "tags": [ + "Transportation + Road", + "Transportation + Other" + ], + "author": "Google" + }, + { + "id": "6284690E-A12C-4209-A779-18284E241DE3", + "baseIconId": "6284690E-A12C-4209-A779-18284E241DE3", + "name": "more", + "codepoint": "F037B", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "55847C89-2AE5-4F91-85AA-761FD8CE57F0", + "baseIconId": "55847C89-2AE5-4F91-85AA-761FD8CE57F0", + "name": "mosque", + "codepoint": "F0D45", + "aliases": [ + "islam", + "muslim" + ], + "styles": [], + "version": "3.4.93", + "deprecated": false, + "tags": [ + "Religion" + ], + "author": "Google" + }, + { + "id": "D5136ED4-FC45-44D8-9DE4-C266844D5131", + "baseIconId": "D5136ED4-FC45-44D8-9DE4-C266844D5131", + "name": "motion", + "codepoint": "F15B2", + "aliases": [], + "styles": [], + "version": "5.5.55", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "D6AADAF8-D44E-44C0-8647-E578B277441D", + "baseIconId": "D6AADAF8-D44E-44C0-8647-E578B277441D", + "name": "motorbike", + "codepoint": "F037C", + "aliases": [ + "motorcycle" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Transportation + Road", + "Sport" + ], + "author": "Google" + }, + { + "id": "965CDBD7-9E52-4169-B363-E0428C75C19D", + "baseIconId": "965CDBD7-9E52-4169-B363-E0428C75C19D", + "name": "mouse", + "codepoint": "F037D", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "122C53AA-C8BC-41B3-89B2-B9A9F8BB56DC", + "baseIconId": "122C53AA-C8BC-41B3-89B2-B9A9F8BB56DC", + "name": "movie", + "codepoint": "F0381", + "aliases": [ + "slate", + "clapperboard", + "film", + "movie-creation" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Video / Movie" + ], + "author": "Google" + }, + { + "id": "766E10EA-23CD-42BD-9DB8-633FBF8C584A", + "baseIconId": "766E10EA-23CD-42BD-9DB8-633FBF8C584A", + "name": "mustache", + "codepoint": "F15DE", + "aliases": [], + "styles": [], + "version": "5.6.55", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "C5FCAD4F-C7E6-4BDB-9F2F-A665CB68B7FD", + "baseIconId": "C5FCAD4F-C7E6-4BDB-9F2F-A665CB68B7FD", + "name": "nature", + "codepoint": "F038E", + "aliases": [ + "plant" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Nature", + "Agriculture" + ], + "author": "Google" + }, + { + "id": "DAAF6988-6EE9-4595-A758-294C83C7304B", + "baseIconId": "DAAF6988-6EE9-4595-A758-294C83C7304B", + "name": "navigation", + "codepoint": "F0390", + "aliases": [ + "arrow-compass" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Navigation" + ], + "author": "Google" + }, + { + "id": "EE440B14-2E25-4C8E-99A7-A3C98CBC9151", + "baseIconId": "EE440B14-2E25-4C8E-99A7-A3C98CBC9151", + "name": "newspaper", + "codepoint": "F0395", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "1655675D-A197-44BD-83E9-76E2BAD31740", + "baseIconId": "1655675D-A197-44BD-83E9-76E2BAD31740", + "name": "noodles", + "codepoint": "F117E", + "aliases": [ + "food-ramen", + "asian-noodles" + ], + "styles": [], + "version": "4.4.95", + "deprecated": false, + "tags": [ + "Food / Drink" + ], + "author": "Google" + }, + { + "id": "27C36043-E269-4223-ADCE-568B1EFB4623", + "baseIconId": "27C36043-E269-4223-ADCE-568B1EFB4623", + "name": "opacity", + "codepoint": "F05CC", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "059B5D2A-9B8B-412D-BAF1-F3F9B7E14A44", + "baseIconId": "059B5D2A-9B8B-412D-BAF1-F3F9B7E14A44", + "name": "overscan", + "codepoint": "F1005", + "aliases": [ + "fullscreen" + ], + "styles": [], + "version": "4.0.96", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "954CCE2B-7FEE-4F9C-9923-4E1D567607C3", + "baseIconId": "954CCE2B-7FEE-4F9C-9923-4E1D567607C3", + "name": "palette", + "codepoint": "F03D8", + "aliases": [ + "color-lens", + "colour-lens", + "paint", + "art", + "color" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Color", + "Drawing / Art" + ], + "author": "Google" + }, + { + "id": "4054A322-F348-49BA-B85F-B978EFC1BDAD", + "baseIconId": "4054A322-F348-49BA-B85F-B978EFC1BDAD", + "name": "panorama", + "codepoint": "F03DC", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Photography" + ], + "author": "Google" + }, + { + "id": "27BCEC7F-ABF8-4506-B339-EE2425E1BAF9", + "baseIconId": "27BCEC7F-ABF8-4506-B339-EE2425E1BAF9", + "name": "paperclip", + "codepoint": "F03E2", + "aliases": [ + "attachment-vertical", + "attach-file" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "24CD918E-9458-4D8D-A00C-746F8AB5D17E", + "baseIconId": "24CD918E-9458-4D8D-A00C-746F8AB5D17E", + "name": "paragliding", + "codepoint": "F1745", + "aliases": [ + "parasail", + "paraglide" + ], + "styles": [], + "version": "6.1.95", + "deprecated": false, + "tags": [ + "Sport" + ], + "author": "Google" + }, + { + "id": "07C8266A-A135-443C-B2DD-4148CD718C51", + "baseIconId": "07C8266A-A135-443C-B2DD-4148CD718C51", + "name": "parking", + "codepoint": "F03E3", + "aliases": [ + "car-park", + "local-parking" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Places" + ], + "author": "Google" + }, + { + "id": "8288CA76-67E5-4EEA-82CD-DE0E0842F34D", + "baseIconId": "8288CA76-67E5-4EEA-82CD-DE0E0842F34D", + "name": "pasta", + "codepoint": "F1160", + "aliases": [ + "food-italian", + "spaghetti" + ], + "styles": [], + "version": "4.4.95", + "deprecated": false, + "tags": [ + "Food / Drink" + ], + "author": "Google" + }, + { + "id": "2A1F0831-13CA-4419-BBD7-1F1FAF62A32B", + "baseIconId": "2A1F0831-13CA-4419-BBD7-1F1FAF62A32B", + "name": "pause", + "codepoint": "F03E4", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Home Automation" + ], + "author": "Google" + }, + { + "id": "BB27CE6C-769A-4C0C-A53C-F1B10B9C4423", + "baseIconId": "BB27CE6C-769A-4C0C-A53C-F1B10B9C4423", + "name": "pencil", + "codepoint": "F03EB", + "aliases": [ + "edit", + "create", + "mode-edit" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Drawing / Art", + "Edit / Modify" + ], + "author": "Google" + }, + { + "id": "B5BA809F-FCE8-476C-8388-6A9CFFF73015", + "baseIconId": "B5BA809F-FCE8-476C-8388-6A9CFFF73015", + "name": "phone", + "codepoint": "F03F2", + "aliases": [ + "call", + "local-phone", + "telephone" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Cellphone / Phone" + ], + "author": "Google" + }, + { + "id": "E7651219-1BF9-4D06-9B4A-7599A2E0A407", + "baseIconId": "E7651219-1BF9-4D06-9B4A-7599A2E0A407", + "name": "piano", + "codepoint": "F067D", + "aliases": [], + "styles": [], + "version": "1.7.12", + "deprecated": false, + "tags": [ + "Music" + ], + "author": "Google" + }, + { + "id": "B1337135-0E57-465F-8C0C-E658C9981A19", + "baseIconId": "B1337135-0E57-465F-8C0C-E658C9981A19", + "name": "pin", + "codepoint": "F0403", + "aliases": [ + "keep" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "BB298846-B608-4289-987C-A8F2A904409F", + "baseIconId": "BB298846-B608-4289-987C-A8F2A904409F", + "name": "pinwheel", + "codepoint": "F0AD5", + "aliases": [ + "toys" + ], + "styles": [], + "version": "2.7.94", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "E617E8BD-2C63-4E59-B1F4-EB3F9F3916D3", + "baseIconId": "E617E8BD-2C63-4E59-B1F4-EB3F9F3916D3", + "name": "pizza", + "codepoint": "F0409", + "aliases": [ + "pizzeria", + "local-pizza" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Food / Drink", + "Places" + ], + "author": "Google" + }, + { + "id": "90AD6D2A-7986-49D0-8DA5-DC92F9F92A15", + "baseIconId": "90AD6D2A-7986-49D0-8DA5-DC92F9F92A15", + "name": "play", + "codepoint": "F040A", + "aliases": [ + "play-arrow" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Home Automation" + ], + "author": "Google" + }, + { + "id": "2DE4F8E6-F25C-4FCA-8405-109FA8918B78", + "baseIconId": "2DE4F8E6-F25C-4FCA-8405-109FA8918B78", + "name": "plus", + "codepoint": "F0415", + "aliases": [ + "add" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Math" + ], + "author": "Google" + }, + { + "id": "56B37BA8-E973-4B53-812A-7F47BCFF217A", + "baseIconId": "56B37BA8-E973-4B53-812A-7F47BCFF217A", + "name": "podcast", + "codepoint": "F0994", + "aliases": [], + "styles": [], + "version": "2.4.85", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "5ACE4E72-9576-405A-A17F-314A1FF864C8", + "baseIconId": "5ACE4E72-9576-405A-A17F-314A1FF864C8", + "name": "polo", + "codepoint": "F14C3", + "aliases": [], + "styles": [], + "version": "5.3.45", + "deprecated": false, + "tags": [ + "Sport" + ], + "author": "Google" + }, + { + "id": "9B1DF082-5266-408A-A057-92E9AEB81BFA", + "baseIconId": "9B1DF082-5266-408A-A057-92E9AEB81BFA", + "name": "post", + "codepoint": "F1008", + "aliases": [ + "blog" + ], + "styles": [], + "version": "4.0.96", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "C945D203-9737-4C25-87CA-29D97B862DD2", + "baseIconId": "C945D203-9737-4C25-87CA-29D97B862DD2", + "name": "power", + "codepoint": "F0425", + "aliases": [ + "power-settings-new", + "shutdown" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Home Automation" + ], + "author": "Google" + }, + { + "id": "7365D689-4C10-4EBA-AD9A-09189B8091EE", + "baseIconId": "7365D689-4C10-4EBA-AD9A-09189B8091EE", + "name": "printer", + "codepoint": "F042A", + "aliases": [ + "local-printshop", + "local-print-shop" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Printer", + "Home Automation" + ], + "author": "Google" + }, + { + "id": "7E1AC29D-46E3-4C7C-9A00-D8803E502795", + "baseIconId": "7E1AC29D-46E3-4C7C-9A00-D8803E502795", + "name": "publish", + "codepoint": "F06A7", + "aliases": [], + "styles": [], + "version": "1.7.12", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "0773D18C-C6A2-41B5-9685-F3E0507E1770", + "baseIconId": "0773D18C-C6A2-41B5-9685-F3E0507E1770", + "name": "puzzle", + "codepoint": "F0431", + "aliases": [ + "extension", + "jigsaw" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Gaming / RPG" + ], + "author": "Google" + }, + { + "id": "0E46DC98-E185-4B26-A4E9-FC1CEC750172", + "baseIconId": "0E46DC98-E185-4B26-A4E9-FC1CEC750172", + "name": "racquetball", + "codepoint": "F0D94", + "aliases": [ + "lacrosse", + "squash" + ], + "styles": [], + "version": "3.4.93", + "deprecated": false, + "tags": [ + "Sport" + ], + "author": "Google" + }, + { + "id": "73BD6C2A-0D5B-4DF6-9FA3-EC489AFBF947", + "baseIconId": "73BD6C2A-0D5B-4DF6-9FA3-EC489AFBF947", + "name": "radar", + "codepoint": "F0437", + "aliases": [ + "track-changes" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "2FA21C1E-99C3-4C9B-AF46-8DF6B9F2A8FC", + "baseIconId": "2FA21C1E-99C3-4C9B-AF46-8DF6B9F2A8FC", + "name": "radio", + "codepoint": "F0439", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Audio", + "Device / Tech" + ], + "author": "Google" + }, + { + "id": "0B304D53-8218-4F49-9330-1AB9CCB11C01", + "baseIconId": "0B304D53-8218-4F49-9330-1AB9CCB11C01", + "name": "raw", + "codepoint": "F1A0F", + "aliases": [], + "styles": [], + "version": "6.6.96", + "deprecated": false, + "tags": [ + "Photography" + ], + "author": "Google" + }, + { + "id": "7061BAB7-4413-4666-A919-9DD8C4F405F9", + "baseIconId": "7061BAB7-4413-4666-A919-9DD8C4F405F9", + "name": "redo", + "codepoint": "F044E", + "aliases": [ + "arrow" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "AD3C7A2B-0B64-4183-9452-C96EAAF3E08E", + "baseIconId": "AD3C7A2B-0B64-4183-9452-C96EAAF3E08E", + "name": "refresh", + "codepoint": "F0450", + "aliases": [ + "loop" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Arrow" + ], + "author": "Google" + }, + { + "id": "1BD93F0A-87D1-4B55-A0EF-D9F05A8B3826", + "baseIconId": "1BD93F0A-87D1-4B55-A0EF-D9F05A8B3826", + "name": "reminder", + "codepoint": "F088C", + "aliases": [], + "styles": [], + "version": "2.1.99", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "49C7BBC2-6C7F-442E-A6EE-B58AB758A8D4", + "baseIconId": "49C7BBC2-6C7F-442E-A6EE-B58AB758A8D4", + "name": "remote", + "codepoint": "F0454", + "aliases": [ + "settings-remote" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Home Automation" + ], + "author": "Google" + }, + { + "id": "43D55245-34B8-4F1B-953A-CCE75AF35866", + "baseIconId": "43D55245-34B8-4F1B-953A-CCE75AF35866", + "name": "rename", + "codepoint": "F1C18", + "aliases": [], + "styles": [], + "version": "7.1.96", + "deprecated": false, + "tags": [ + "Edit / Modify" + ], + "author": "Google" + }, + { + "id": "9AEE0CB7-46B9-414F-A8A8-AFB127CB7057", + "baseIconId": "9AEE0CB7-46B9-414F-A8A8-AFB127CB7057", + "name": "repeat", + "codepoint": "F0456", + "aliases": [ + "repost" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Arrow" + ], + "author": "Google" + }, + { + "id": "A15D2CB0-E938-4894-8BF3-BC6C628E6433", + "baseIconId": "A15D2CB0-E938-4894-8BF3-BC6C628E6433", + "name": "replay", + "codepoint": "F0459", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "CC3BEE2C-0FEA-46D2-BC53-F7D248AAF47C", + "baseIconId": "CC3BEE2C-0FEA-46D2-BC53-F7D248AAF47C", + "name": "reply", + "codepoint": "F045A", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Arrow" + ], + "author": "Google" + }, + { + "id": "15954B5D-3ADA-4B6B-BE15-F95B6A5D4659", + "baseIconId": "15954B5D-3ADA-4B6B-BE15-F95B6A5D4659", + "name": "restart", + "codepoint": "F0709", + "aliases": [], + "styles": [], + "version": "1.8.36", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "FF1CAAB4-2192-442F-88F1-08DEB67E21F0", + "baseIconId": "FF1CAAB4-2192-442F-88F1-08DEB67E21F0", + "name": "restore", + "codepoint": "F099B", + "aliases": [ + "loop", + "rotate-counter-clockwise" + ], + "styles": [], + "version": "2.4.85", + "deprecated": false, + "tags": [ + "Arrow" + ], + "author": "Google" + }, + { + "id": "28BCDF41-AA93-4C25-B87A-95A3F5DD8805", + "baseIconId": "28BCDF41-AA93-4C25-B87A-95A3F5DD8805", + "name": "rewind", + "codepoint": "F045F", + "aliases": [ + "fast-rewind" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "1C09CB9B-162B-486B-966C-1FCB18C0F633", + "baseIconId": "1C09CB9B-162B-486B-966C-1FCB18C0F633", + "name": "ribbon", + "codepoint": "F0460", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "96BE0E43-42AB-4F93-8045-0C7B61BF69CC", + "baseIconId": "96BE0E43-42AB-4F93-8045-0C7B61BF69CC", + "name": "rocket", + "codepoint": "F0463", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Transportation + Flying", + "Science" + ], + "author": "Google" + }, + { + "id": "AA8B7EA9-2DB2-4591-94E0-A457373E64C1", + "baseIconId": "AA8B7EA9-2DB2-4591-94E0-A457373E64C1", + "name": "rodent", + "codepoint": "F1327", + "aliases": [ + "mouse", + "rat" + ], + "styles": [], + "version": "4.9.95", + "deprecated": false, + "tags": [ + "Animal" + ], + "author": "Google" + }, + { + "id": "72F11BA0-1557-4500-8235-2E3F2346FE69", + "baseIconId": "72F11BA0-1557-4500-8235-2E3F2346FE69", + "name": "rowing", + "codepoint": "F0608", + "aliases": [ + "human-rowing" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Sport", + "Transportation + Water", + "People / Family" + ], + "author": "Google" + }, + { + "id": "9E877D76-9BC5-496D-99E4-1E6029DE1B4D", + "baseIconId": "9E877D76-9BC5-496D-99E4-1E6029DE1B4D", + "name": "rss", + "codepoint": "F046B", + "aliases": [ + "rss-feed" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "19489FCE-DD25-4670-BC6F-4FC3AF1E66D3", + "baseIconId": "19489FCE-DD25-4670-BC6F-4FC3AF1E66D3", + "name": "rugby", + "codepoint": "F0D99", + "aliases": [ + "rugby-ball" + ], + "styles": [], + "version": "3.4.93", + "deprecated": false, + "tags": [ + "Sport" + ], + "author": "Google" + }, + { + "id": "2A869029-60EB-4965-9BE4-9B3DB964C707", + "baseIconId": "2A869029-60EB-4965-9BE4-9B3DB964C707", + "name": "run", + "codepoint": "F070E", + "aliases": [ + "directions-run", + "human-run" + ], + "styles": [], + "version": "1.8.36", + "deprecated": false, + "tags": [ + "Sport", + "People / Family" + ], + "author": "Google" + }, + { + "id": "D77BED79-19CC-45A9-9940-5EB621E95C11", + "baseIconId": "D77BED79-19CC-45A9-9940-5EB621E95C11", + "name": "satellite", + "codepoint": "F0470", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "64F494E1-5B39-488D-B46E-0FC1B9567478", + "baseIconId": "64F494E1-5B39-488D-B46E-0FC1B9567478", + "name": "saxophone", + "codepoint": "F0609", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Music" + ], + "author": "Google" + }, + { + "id": "BE9A1BD3-1DF7-407F-98B7-24070994D472", + "baseIconId": "BE9A1BD3-1DF7-407F-98B7-24070994D472", + "name": "scanner", + "codepoint": "F06AB", + "aliases": [], + "styles": [], + "version": "1.7.12", + "deprecated": false, + "tags": [ + "Device / Tech" + ], + "author": "Google" + }, + { + "id": "A671C11E-0A75-4F41-AA32-EAA99955DEDE", + "baseIconId": "A671C11E-0A75-4F41-AA32-EAA99955DEDE", + "name": "school", + "codepoint": "F0474", + "aliases": [ + "graduation-cap", + "university", + "college", + "academic-cap", + "education", + "learn" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "0299DD49-341B-4979-91A9-FB3BF6AEFB87", + "baseIconId": "0299DD49-341B-4979-91A9-FB3BF6AEFB87", + "name": "scooter", + "codepoint": "F15BD", + "aliases": [], + "styles": [], + "version": "5.6.55", + "deprecated": false, + "tags": [ + "Transportation + Other" + ], + "author": "Google" + }, + { + "id": "68B68EDB-6CDA-4488-A213-5E6DF4146EA6", + "baseIconId": "68B68EDB-6CDA-4488-A213-5E6DF4146EA6", + "name": "sd", + "codepoint": "F0479", + "aliases": [ + "sd-card", + "sd-storage" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "C9A796D6-1A7D-47AD-A036-B3B9035FBDA3", + "baseIconId": "C9A796D6-1A7D-47AD-A036-B3B9035FBDA3", + "name": "seat", + "codepoint": "F0CC3", + "aliases": [ + "event-seat", + "chair", + "chair-accent", + "home-theater", + "home-theatre" + ], + "styles": [], + "version": "3.2.89", + "deprecated": false, + "tags": [ + "Home Automation" + ], + "author": "Google" + }, + { + "id": "0C2F3617-9710-4265-AFB5-29C52AD2FBE0", + "baseIconId": "0C2F3617-9710-4265-AFB5-29C52AD2FBE0", + "name": "security", + "codepoint": "F0483", + "aliases": [ + "shield", + "uac", + "user-access-control", + "administrator" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "5AFE282B-CAE1-4D7F-A2BF-37E8655537DD", + "baseIconId": "E56EAB24-6D70-49E0-BEC8-D9164A93CB63", + "name": "segment", + "codepoint": "F0ECB", + "aliases": [], + "styles": [], + "version": "3.7.94", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "6791A1E4-DBF8-471C-AA27-0D4540A23678", + "baseIconId": "6791A1E4-DBF8-471C-AA27-0D4540A23678", + "name": "send", + "codepoint": "F048A", + "aliases": [ + "paper-airplane", + "paper-plane" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "B29246C8-6014-4019-8CCC-F803DBC0FA95", + "baseIconId": "B29246C8-6014-4019-8CCC-F803DBC0FA95", + "name": "shape", + "codepoint": "F0831", + "aliases": [ + "category", + "theme" + ], + "styles": [], + "version": "2.1.19", + "deprecated": false, + "tags": [ + "Shape" + ], + "author": "Google" + }, + { + "id": "F0053E35-64B2-45D5-92D6-EE9F8A8839A1", + "baseIconId": "F0053E35-64B2-45D5-92D6-EE9F8A8839A1", + "name": "share", + "codepoint": "F0496", + "aliases": [ + "forward" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Arrow" + ], + "author": "Google" + }, + { + "id": "7A5ED547-B142-4921-8050-647B2B9F4DC0", + "baseIconId": "7A5ED547-B142-4921-8050-647B2B9F4DC0", + "name": "shopping", + "codepoint": "F049A", + "aliases": [ + "local-mall", + "marketplace" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Shopping" + ], + "author": "Google" + }, + { + "id": "99537665-2115-40D6-9725-0F4B4730C99A", + "baseIconId": "99537665-2115-40D6-9725-0F4B4730C99A", + "name": "shuffle", + "codepoint": "F049D", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Arrow" + ], + "author": "Google" + }, + { + "id": "59A98F47-9067-492A-8454-42BEFA2391C1", + "baseIconId": "59A98F47-9067-492A-8454-42BEFA2391C1", + "name": "sigma", + "codepoint": "F04A0", + "aliases": [ + "summation" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Math" + ], + "author": "Google" + }, + { + "id": "F7C26535-863F-4295-9E48-9847B740FEE7", + "baseIconId": "F7C26535-863F-4295-9E48-9847B740FEE7", + "name": "silverware", + "codepoint": "F04A3", + "aliases": [ + "local-dining", + "restaurant-menu", + "local-restaurant", + "cutlery", + "utensils" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Food / Drink" + ], + "author": "Google" + }, + { + "id": "93020F21-A0FE-427D-8685-B74EE39B9921", + "baseIconId": "93020F21-A0FE-427D-8685-B74EE39B9921", + "name": "sim", + "codepoint": "F04A7", + "aliases": [ + "sim-card", + "subscriber-identity-module", + "subscriber-identification-module" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Cellphone / Phone" + ], + "author": "Google" + }, + { + "id": "CB0C6DC2-0A4E-41C8-9E6A-9A8531F754CF", + "baseIconId": "CB0C6DC2-0A4E-41C8-9E6A-9A8531F754CF", + "name": "skate", + "codepoint": "F0D35", + "aliases": [ + "ice-skate" + ], + "styles": [], + "version": "3.3.92", + "deprecated": false, + "tags": [ + "Sport" + ], + "author": "Google" + }, + { + "id": "56BF6222-BEC1-44B6-845C-AD6F84552D90", + "baseIconId": "56BF6222-BEC1-44B6-845C-AD6F84552D90", + "name": "skateboard", + "codepoint": "F14C2", + "aliases": [], + "styles": [], + "version": "5.3.45", + "deprecated": false, + "tags": [ + "Sport" + ], + "author": "Google" + }, + { + "id": "47F1C290-ED78-4459-B33C-6E2ACC867CC6", + "baseIconId": "47F1C290-ED78-4459-B33C-6E2ACC867CC6", + "name": "skateboarding", + "codepoint": "F0501", + "aliases": [ + "human-skateboarding" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Sport", + "People / Family" + ], + "author": "Google" + }, + { + "id": "197B0D1A-34DB-4FD7-825B-FFE5C28297BB", + "baseIconId": "197B0D1A-34DB-4FD7-825B-FFE5C28297BB", + "name": "ski", + "codepoint": "F1304", + "aliases": [ + "human-ski" + ], + "styles": [], + "version": "4.8.95", + "deprecated": false, + "tags": [ + "Sport", + "People / Family" + ], + "author": "Google" + }, + { + "id": "E67044BA-8025-4D61-916C-56DF4D6FFE6D", + "baseIconId": "E67044BA-8025-4D61-916C-56DF4D6FFE6D", + "name": "sledding", + "codepoint": "F041B", + "aliases": [ + "human-sledding" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Sport", + "People / Family" + ], + "author": "Google" + }, + { + "id": "C9CF20D8-55F4-4997-8019-F8056ED86702", + "baseIconId": "C9CF20D8-55F4-4997-8019-F8056ED86702", + "name": "sleep", + "codepoint": "F04B2", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "20A9F2BB-C53E-410E-A433-4CEE2305AD49", + "baseIconId": "20A9F2BB-C53E-410E-A433-4CEE2305AD49", + "name": "smoking", + "codepoint": "F04B4", + "aliases": [ + "cigarette", + "smoking-area", + "smoking-rooms" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Automotive" + ], + "author": "Google" + }, + { + "id": "C2A03E16-166E-4FAA-A5DB-462CE38C44FE", + "baseIconId": "C2A03E16-166E-4FAA-A5DB-462CE38C44FE", + "name": "snowboard", + "codepoint": "F1307", + "aliases": [ + "human-snowboard" + ], + "styles": [], + "version": "4.8.95", + "deprecated": false, + "tags": [ + "Sport", + "People / Family" + ], + "author": "Google" + }, + { + "id": "5675A747-D467-473E-9A1D-1C61E1B5C619", + "baseIconId": "5675A747-D467-473E-9A1D-1C61E1B5C619", + "name": "snowflake", + "codepoint": "F0717", + "aliases": [ + "power-hibernate" + ], + "styles": [], + "version": "1.8.36", + "deprecated": false, + "tags": [ + "Weather", + "Holiday", + "Automotive" + ], + "author": "Google" + }, + { + "id": "A4C7D4DF-2B1F-424B-9502-6618F88C9A65", + "baseIconId": "A4C7D4DF-2B1F-424B-9502-6618F88C9A65", + "name": "snowmobile", + "codepoint": "F06DD", + "aliases": [], + "styles": [], + "version": "1.8.36", + "deprecated": false, + "tags": [ + "Transportation + Other", + "Sport" + ], + "author": "Google" + }, + { + "id": "D9F59FE2-7B27-4B54-8935-AC2A83CE084B", + "baseIconId": "D9F59FE2-7B27-4B54-8935-AC2A83CE084B", + "name": "snowshoeing", + "codepoint": "F1A72", + "aliases": [], + "styles": [], + "version": "6.7.96", + "deprecated": false, + "tags": [ + "Sport" + ], + "author": "Google" + }, + { + "id": "B4AFB6A4-C315-4B06-AE4D-AC633F3ED0A7", + "baseIconId": "B4AFB6A4-C315-4B06-AE4D-AC633F3ED0A7", + "name": "soccer", + "codepoint": "F04B8", + "aliases": [ + "football" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Sport" + ], + "author": "Google" + }, + { + "id": "84F00C86-0380-4554-B142-286C3B80BA3A", + "baseIconId": "84F00C86-0380-4554-B142-286C3B80BA3A", + "name": "spa", + "codepoint": "F0CD1", + "aliases": [ + "flower-lotus", + "plant" + ], + "styles": [], + "version": "3.2.89", + "deprecated": false, + "tags": [ + "Nature" + ], + "author": "Google" + }, + { + "id": "43C37FC5-E271-40FA-BB50-C139DDD5B15B", + "baseIconId": "43C37FC5-E271-40FA-BB50-C139DDD5B15B", + "name": "speaker", + "codepoint": "F04C3", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Audio", + "Home Automation" + ], + "author": "Google" + }, + { + "id": "72253002-9545-40A4-95A4-49401269B553", + "baseIconId": "72253002-9545-40A4-95A4-49401269B553", + "name": "spellcheck", + "codepoint": "F04C6", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "5FDB24B6-FF16-4575-A794-E5CCEB95CC81", + "baseIconId": "5FDB24B6-FF16-4575-A794-E5CCEB95CC81", + "name": "stadium", + "codepoint": "F0FF9", + "aliases": [ + "arena" + ], + "styles": [], + "version": "4.0.96", + "deprecated": false, + "tags": [ + "Sport", + "Places" + ], + "author": "Google" + }, + { + "id": "53D81A11-D8FF-46F4-A0CB-B7F668BA720D", + "baseIconId": "53D81A11-D8FF-46F4-A0CB-B7F668BA720D", + "name": "star", + "codepoint": "F04CE", + "aliases": [ + "grade", + "star-rate", + "favorite" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Shape" + ], + "author": "Google" + }, + { + "id": "A2FE9DC5-BC17-4265-9D2C-4CA20135C4BB", + "baseIconId": "A2FE9DC5-BC17-4265-9D2C-4CA20135C4BB", + "name": "steering", + "codepoint": "F04D4", + "aliases": [ + "search-hands-free" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Automotive" + ], + "author": "Google" + }, + { + "id": "F1057179-EA45-4D87-A14D-D05442C06503", + "baseIconId": "F1057179-EA45-4D87-A14D-D05442C06503", + "name": "stop", + "codepoint": "F04DB", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "3C3AEDE0-B6DA-4CB9-A686-869634678D5D", + "baseIconId": "3C3AEDE0-B6DA-4CB9-A686-869634678D5D", + "name": "store", + "codepoint": "F04DC", + "aliases": [ + "shop", + "store-mall-directory" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Places", + "Shopping" + ], + "author": "Google" + }, + { + "id": "9808EEC5-35FB-45B1-AFCB-065E9CF469E4", + "baseIconId": "9808EEC5-35FB-45B1-AFCB-065E9CF469E4", + "name": "subtitles", + "codepoint": "F0A16", + "aliases": [], + "styles": [], + "version": "2.5.94", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "769FB684-BA81-4E2A-B623-4C8B6F3DCD2C", + "baseIconId": "769FB684-BA81-4E2A-B623-4C8B6F3DCD2C", + "name": "subway", + "codepoint": "F06AC", + "aliases": [ + "metro", + "tube", + "underground" + ], + "styles": [], + "version": "1.7.12", + "deprecated": false, + "tags": [ + "Transportation + Other" + ], + "author": "Google" + }, + { + "id": "13371A33-E911-4D02-B921-CECC9D1BDB50", + "baseIconId": "13371A33-E911-4D02-B921-CECC9D1BDB50", + "name": "surfing", + "codepoint": "F1746", + "aliases": [], + "styles": [], + "version": "6.1.95", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "9013848A-21D4-4AF4-BA8A-6CF76128FE17", + "baseIconId": "9013848A-21D4-4AF4-BA8A-6CF76128FE17", + "name": "synagogue", + "codepoint": "F1B04", + "aliases": [ + "shul", + "temple", + "jewish" + ], + "styles": [], + "version": "6.9.96", + "deprecated": false, + "tags": [ + "Places", + "Religion" + ], + "author": "Google" + }, + { + "id": "E8CE455E-8C08-48F4-B989-8D91E185E8AE", + "baseIconId": "E8CE455E-8C08-48F4-B989-8D91E185E8AE", + "name": "sync", + "codepoint": "F04E6", + "aliases": [ + "loop", + "counterclockwise-arrows", + "circular-arrows", + "circle-arrows" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "76D6AAA9-7D7F-4C7A-818E-D9947744A23C", + "baseIconId": "76D6AAA9-7D7F-4C7A-818E-D9947744A23C", + "name": "tab", + "codepoint": "F04E9", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "703B639C-E17D-40F1-8025-2B2950B1961D", + "baseIconId": "703B639C-E17D-40F1-8025-2B2950B1961D", + "name": "tablet", + "codepoint": "F04F6", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Device / Tech" + ], + "author": "Google" + }, + { + "id": "0BE85AB2-0D51-411C-B119-789E9E317216", + "baseIconId": "0BE85AB2-0D51-411C-B119-789E9E317216", + "name": "tag", + "codepoint": "F04F9", + "aliases": [ + "local-offer" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "32F3835A-EBD0-4927-9497-6F67F7075EAF", + "baseIconId": "32F3835A-EBD0-4927-9497-6F67F7075EAF", + "name": "taxi", + "codepoint": "F04FF", + "aliases": [ + "local-taxi", + "cab" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Transportation + Road", + "Navigation" + ], + "author": "Google" + }, + { + "id": "D1759BBF-821F-4902-AAF5-8323A179912F", + "baseIconId": "C95D04C5-F5EE-411A-88F7-A9872B2B4021", + "name": "tea", + "codepoint": "F0D9E", + "aliases": [], + "styles": [ + "variant" + ], + "version": "3.4.93", + "deprecated": false, + "tags": [ + "Food / Drink" + ], + "author": "Google" + }, + { + "id": "1B699A99-578E-450C-9523-934F4D281F72", + "baseIconId": "1B699A99-578E-450C-9523-934F4D281F72", + "name": "television", + "codepoint": "F0502", + "aliases": [ + "tv" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Device / Tech", + "Home Automation" + ], + "author": "Google" + }, + { + "id": "CE166270-170C-4292-8D6F-FE787AF6B021", + "baseIconId": "CE166270-170C-4292-8D6F-FE787AF6B021", + "name": "tennis", + "codepoint": "F0DA0", + "aliases": [ + "tennis-racquet", + "tennis-racket" + ], + "styles": [], + "version": "3.4.93", + "deprecated": false, + "tags": [ + "Sport" + ], + "author": "Google" + }, + { + "id": "1F98A781-6023-4368-AC06-5A421D166FCC", + "baseIconId": "1F98A781-6023-4368-AC06-5A421D166FCC", + "name": "terrain", + "codepoint": "F0509", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Nature" + ], + "author": "Google" + }, + { + "id": "E56EAB24-6D70-49E0-BEC8-D9164A93CB63", + "baseIconId": "E56EAB24-6D70-49E0-BEC8-D9164A93CB63", + "name": "text", + "codepoint": "F09A8", + "aliases": [ + "notes" + ], + "styles": [], + "version": "2.4.85", + "deprecated": false, + "tags": [ + "Text / Content / Format" + ], + "author": "Google" + }, + { + "id": "E3A06403-51B5-4D00-9349-53517553A324", + "baseIconId": "E3A06403-51B5-4D00-9349-53517553A324", + "name": "texture", + "codepoint": "F050C", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "628D16E2-7E57-43CA-8451-012B8AB852DA", + "baseIconId": "628D16E2-7E57-43CA-8451-012B8AB852DA", + "name": "thermostat", + "codepoint": "F0393", + "aliases": [ + "nest" + ], + "styles": [ + "circle" + ], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Device / Tech", + "Home Automation" + ], + "author": "Google" + }, + { + "id": "18F55984-07FD-4630-BB11-8285F83AA838", + "baseIconId": "18F55984-07FD-4630-BB11-8285F83AA838", + "name": "ticket", + "codepoint": "F0516", + "aliases": [ + "local-activity", + "local-play", + "local-attraction" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "348DB89A-B4E2-4CB9-A7A4-B86973243ADE", + "baseIconId": "348DB89A-B4E2-4CB9-A7A4-B86973243ADE", + "name": "timelapse", + "codepoint": "F051A", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Date / Time" + ], + "author": "Google" + }, + { + "id": "79D1B3B8-FC3E-4978-AA8E-C78A1360B880", + "baseIconId": "79D1B3B8-FC3E-4978-AA8E-C78A1360B880", + "name": "toolbox", + "codepoint": "F09AC", + "aliases": [], + "styles": [], + "version": "2.4.85", + "deprecated": false, + "tags": [ + "Hardware / Tools" + ], + "author": "Google" + }, + { + "id": "B6E1232A-3A43-4200-BE34-1BC436B34BF1", + "baseIconId": "B6E1232A-3A43-4200-BE34-1BC436B34BF1", + "name": "train", + "codepoint": "F052C", + "aliases": [ + "directions-railway", + "locomotive", + "railroad" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Navigation", + "Transportation + Other" + ], + "author": "Google" + }, + { + "id": "13AE3C37-5323-4FE6-86F7-3B30B635969F", + "baseIconId": "13AE3C37-5323-4FE6-86F7-3B30B635969F", + "name": "tram", + "codepoint": "F052D", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Navigation", + "Transportation + Other" + ], + "author": "Google" + }, + { + "id": "2650CA0F-8423-4DE2-A821-9D7D1E5547C0", + "baseIconId": "2650CA0F-8423-4DE2-A821-9D7D1E5547C0", + "name": "transition", + "codepoint": "F0915", + "aliases": [ + "animation", + "motion", + "translate" + ], + "styles": [], + "version": "2.3.50", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "4486DD26-4110-457E-BBD7-B5D19DF72E4E", + "baseIconId": "4486DD26-4110-457E-BBD7-B5D19DF72E4E", + "name": "translate", + "codepoint": "F05CA", + "aliases": [ + "language" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "A0B91DEA-DB9A-4737-B2F4-26B805B88648", + "baseIconId": "A0B91DEA-DB9A-4737-B2F4-26B805B88648", + "name": "truck", + "codepoint": "F053D", + "aliases": [ + "lorry", + "local-shipping", + "courier" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Transportation + Road" + ], + "author": "Google" + }, + { + "id": "23DCD596-6B2A-4556-AF71-A37AE9FE4D99", + "baseIconId": "23DCD596-6B2A-4556-AF71-A37AE9FE4D99", + "name": "tsunami", + "codepoint": "F1A81", + "aliases": [], + "styles": [], + "version": "6.7.96", + "deprecated": false, + "tags": [ + "Nature", + "Weather" + ], + "author": "Google" + }, + { + "id": "B1F7C2ED-4017-4162-A4C7-31D8761D8DC3", + "baseIconId": "B1F7C2ED-4017-4162-A4C7-31D8761D8DC3", + "name": "tune", + "codepoint": "F062E", + "aliases": [ + "mixer-settings", + "equaliser", + "settings" + ], + "styles": [], + "version": "1.6.50", + "deprecated": false, + "tags": [ + "Settings", + "Audio" + ], + "author": "Google" + }, + { + "id": "C9D6F6DE-E9F7-4AC9-B9F1-41160A4C2B0E", + "baseIconId": "C9D6F6DE-E9F7-4AC9-B9F1-41160A4C2B0E", + "name": "undo", + "codepoint": "F054C", + "aliases": [ + "arrow" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "1B274396-AAE7-4CD8-8D57-27E31D915F68", + "baseIconId": "1B274396-AAE7-4CD8-8D57-27E31D915F68", + "name": "update", + "codepoint": "F06B0", + "aliases": [ + "clockwise", + "clock-arrow" + ], + "styles": [], + "version": "1.7.12", + "deprecated": false, + "tags": [ + "Date / Time" + ], + "author": "Google" + }, + { + "id": "08F8FCE9-67A0-4696-9B83-0B1F11EA959E", + "baseIconId": "08F8FCE9-67A0-4696-9B83-0B1F11EA959E", + "name": "upload", + "codepoint": "F0552", + "aliases": [ + "file-upload" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "25033E0B-3AD4-414D-9972-559F2690FC1D", + "baseIconId": "25033E0B-3AD4-414D-9972-559F2690FC1D", + "name": "usb", + "codepoint": "F0553", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "280D39D7-C3B6-4C48-827F-D944B4773B0C", + "baseIconId": "280D39D7-C3B6-4C48-827F-D944B4773B0C", + "name": "vacuum", + "codepoint": "F19A1", + "aliases": [ + "vacuum-cleaner" + ], + "styles": [], + "version": "6.5.95", + "deprecated": false, + "tags": [ + "Home Automation" + ], + "author": "Google" + }, + { + "id": "68E64FD4-A020-4DEF-B2CB-5EA5BAA80E42", + "baseIconId": "68E64FD4-A020-4DEF-B2CB-5EA5BAA80E42", + "name": "vibrate", + "codepoint": "F0566", + "aliases": [ + "vibration" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "B1337ECC-EF1F-481B-9E75-6A8DB7A01BB9", + "baseIconId": "B1337ECC-EF1F-481B-9E75-6A8DB7A01BB9", + "name": "video", + "codepoint": "F0567", + "aliases": [ + "videocam" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Video / Movie", + "Home Automation" + ], + "author": "Google" + }, + { + "id": "D6702650-990F-416E-BF27-F6F2B86BFB8D", + "baseIconId": "D6702650-990F-416E-BF27-F6F2B86BFB8D", + "name": "violin", + "codepoint": "F060F", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Music" + ], + "author": "Google" + }, + { + "id": "04CEF7C6-E77F-4A66-89F3-2F5B544C482B", + "baseIconId": "04CEF7C6-E77F-4A66-89F3-2F5B544C482B", + "name": "voicemail", + "codepoint": "F057D", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "F319008C-CAC3-4D75-8DED-8164D252A015", + "baseIconId": "F319008C-CAC3-4D75-8DED-8164D252A015", + "name": "volcano", + "codepoint": "F1A83", + "aliases": [ + "eruption" + ], + "styles": [], + "version": "6.7.96", + "deprecated": false, + "tags": [ + "Nature" + ], + "author": "Google" + }, + { + "id": "3978DABC-FC98-4D3E-A971-88716AD5D600", + "baseIconId": "3978DABC-FC98-4D3E-A971-88716AD5D600", + "name": "volleyball", + "codepoint": "F09B4", + "aliases": [], + "styles": [], + "version": "2.4.85", + "deprecated": false, + "tags": [ + "Sport" + ], + "author": "Google" + }, + { + "id": "61CDB722-3238-4F21-9A3F-77DC47A51755", + "baseIconId": "61CDB722-3238-4F21-9A3F-77DC47A51755", + "name": "vote", + "codepoint": "F0A1F", + "aliases": [ + "how-to-vote" + ], + "styles": [], + "version": "2.5.94", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "DA42DA16-21E0-4A08-89E4-F634EBBCF85A", + "baseIconId": "DA42DA16-21E0-4A08-89E4-F634EBBCF85A", + "name": "walk", + "codepoint": "F0583", + "aliases": [ + "directions-walk", + "walker", + "walking", + "human-walk" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Sport", + "Transportation + Other", + "People / Family" + ], + "author": "Google" + }, + { + "id": "C5ABA786-D897-4770-AA78-CE4CB2A9230E", + "baseIconId": "C5ABA786-D897-4770-AA78-CE4CB2A9230E", + "name": "wallet", + "codepoint": "F0584", + "aliases": [ + "account-balance-wallet" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Currency", + "Banking" + ], + "author": "Google" + }, + { + "id": "350FE9C5-BFF1-462D-9318-BA2DDC55E11E", + "baseIconId": "350FE9C5-BFF1-462D-9318-BA2DDC55E11E", + "name": "wallpaper", + "codepoint": "F0E09", + "aliases": [], + "styles": [], + "version": "3.5.94", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "3389F6CD-3E46-47DE-B26A-341C1B65D6BF", + "baseIconId": "3389F6CD-3E46-47DE-B26A-341C1B65D6BF", + "name": "watch", + "codepoint": "F0589", + "aliases": [], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Device / Tech" + ], + "author": "Google" + }, + { + "id": "17EEE663-92E4-4AB1-87FE-94F2CD296C4B", + "baseIconId": "17EEE663-92E4-4AB1-87FE-94F2CD296C4B", + "name": "water", + "codepoint": "F058C", + "aliases": [ + "drop", + "blood", + "water-drop", + "trans-fat", + "ink" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Home Automation", + "Health / Beauty", + "Food / Drink", + "Weather", + "Agriculture" + ], + "author": "Google" + }, + { + "id": "20907A4A-11CA-447E-A4F5-D0F0901D197E", + "baseIconId": "20907A4A-11CA-447E-A4F5-D0F0901D197E", + "name": "watermark", + "codepoint": "F0612", + "aliases": [ + "branding-watermark" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "DA9C32CA-8C31-4462-B123-479169C31587", + "baseIconId": "DA9C32CA-8C31-4462-B123-479169C31587", + "name": "web", + "codepoint": "F059F", + "aliases": [ + "language", + "globe", + "internet", + "world-wide-web" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Geographic Information System" + ], + "author": "Google" + }, + { + "id": "419C0A49-C751-4204-8C82-7E43B0896BD9", + "baseIconId": "419C0A49-C751-4204-8C82-7E43B0896BD9", + "name": "widgets", + "codepoint": "F072C", + "aliases": [], + "styles": [], + "version": "1.8.36", + "deprecated": false, + "tags": [], + "author": "Google" + }, + { + "id": "CACAAE64-D38D-423E-8C84-68EFF0EA0F8A", + "baseIconId": "CACAAE64-D38D-423E-8C84-68EFF0EA0F8A", + "name": "wrench", + "codepoint": "F05B7", + "aliases": [ + "build", + "spanner" + ], + "styles": [], + "version": "1.5.54", + "deprecated": false, + "tags": [ + "Hardware / Tools" + ], + "author": "Google" + }, + { + "id": "0A078909-90AF-41F5-8E76-CAB565D49AAA", + "baseIconId": "0A078909-90AF-41F5-8E76-CAB565D49AAA", + "name": "youtube", + "codepoint": "F05C3", + "aliases": [ + "video-youtube", + "youtube-play" + ], + "styles": [], + "version": "1.5.54", + "deprecated": true, + "tags": [ + "Brand / Logo", + "Social Media" + ], + "author": "Google" + } +] \ No newline at end of file diff --git a/img/material/microphone.svg b/img/material/microphone.svg new file mode 100644 index 000000000..1848e3520 --- /dev/null +++ b/img/material/microphone.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/minus.svg b/img/material/minus.svg new file mode 100644 index 000000000..a8949adc6 --- /dev/null +++ b/img/material/minus.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/monitor.svg b/img/material/monitor.svg new file mode 100644 index 000000000..45fb5db73 --- /dev/null +++ b/img/material/monitor.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/moped.svg b/img/material/moped.svg new file mode 100644 index 000000000..81b1c2b4a --- /dev/null +++ b/img/material/moped.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/more.svg b/img/material/more.svg new file mode 100644 index 000000000..3e627ad5c --- /dev/null +++ b/img/material/more.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/mosque.svg b/img/material/mosque.svg new file mode 100644 index 000000000..606c1bbb8 --- /dev/null +++ b/img/material/mosque.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/motion.svg b/img/material/motion.svg new file mode 100644 index 000000000..e2a3bc6c4 --- /dev/null +++ b/img/material/motion.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/motorbike.svg b/img/material/motorbike.svg new file mode 100644 index 000000000..2192f7b7e --- /dev/null +++ b/img/material/motorbike.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/mouse.svg b/img/material/mouse.svg new file mode 100644 index 000000000..4e0c2d4b9 --- /dev/null +++ b/img/material/mouse.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/movie.svg b/img/material/movie.svg new file mode 100644 index 000000000..e19ab72dc --- /dev/null +++ b/img/material/movie.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/mustache.svg b/img/material/mustache.svg new file mode 100644 index 000000000..fc350d992 --- /dev/null +++ b/img/material/mustache.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/nature.svg b/img/material/nature.svg new file mode 100644 index 000000000..c7b97e22b --- /dev/null +++ b/img/material/nature.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/navigation.svg b/img/material/navigation.svg new file mode 100644 index 000000000..f5e46144b --- /dev/null +++ b/img/material/navigation.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/newspaper.svg b/img/material/newspaper.svg new file mode 100644 index 000000000..ccf6b8200 --- /dev/null +++ b/img/material/newspaper.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/noodles.svg b/img/material/noodles.svg new file mode 100644 index 000000000..509a71b2d --- /dev/null +++ b/img/material/noodles.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/opacity.svg b/img/material/opacity.svg new file mode 100644 index 000000000..ad34d2c94 --- /dev/null +++ b/img/material/opacity.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/overscan.svg b/img/material/overscan.svg new file mode 100644 index 000000000..8e481d079 --- /dev/null +++ b/img/material/overscan.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/palette.svg b/img/material/palette.svg new file mode 100644 index 000000000..b80106e90 --- /dev/null +++ b/img/material/palette.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/panorama.svg b/img/material/panorama.svg new file mode 100644 index 000000000..99f359771 --- /dev/null +++ b/img/material/panorama.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/paperclip.svg b/img/material/paperclip.svg new file mode 100644 index 000000000..f529af29d --- /dev/null +++ b/img/material/paperclip.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/paragliding.svg b/img/material/paragliding.svg new file mode 100644 index 000000000..4df8c45ec --- /dev/null +++ b/img/material/paragliding.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/parking.svg b/img/material/parking.svg new file mode 100644 index 000000000..63a90bd57 --- /dev/null +++ b/img/material/parking.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/pasta.svg b/img/material/pasta.svg new file mode 100644 index 000000000..07310c016 --- /dev/null +++ b/img/material/pasta.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/pause.svg b/img/material/pause.svg new file mode 100644 index 000000000..9881c56d4 --- /dev/null +++ b/img/material/pause.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/pencil.svg b/img/material/pencil.svg new file mode 100644 index 000000000..1aa02032a --- /dev/null +++ b/img/material/pencil.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/phone.svg b/img/material/phone.svg new file mode 100644 index 000000000..417e68341 --- /dev/null +++ b/img/material/phone.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/piano.svg b/img/material/piano.svg new file mode 100644 index 000000000..9e4b12326 --- /dev/null +++ b/img/material/piano.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/pin.svg b/img/material/pin.svg new file mode 100644 index 000000000..0b73b5f91 --- /dev/null +++ b/img/material/pin.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/pinwheel.svg b/img/material/pinwheel.svg new file mode 100644 index 000000000..00a086fb0 --- /dev/null +++ b/img/material/pinwheel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/pizza.svg b/img/material/pizza.svg new file mode 100644 index 000000000..5d3fc6f33 --- /dev/null +++ b/img/material/pizza.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/play.svg b/img/material/play.svg new file mode 100644 index 000000000..5212830bb --- /dev/null +++ b/img/material/play.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/plus.svg b/img/material/plus.svg new file mode 100644 index 000000000..ab25166a1 --- /dev/null +++ b/img/material/plus.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/podcast.svg b/img/material/podcast.svg new file mode 100644 index 000000000..fad4b9513 --- /dev/null +++ b/img/material/podcast.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/polo.svg b/img/material/polo.svg new file mode 100644 index 000000000..d5f0b31df --- /dev/null +++ b/img/material/polo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/post.svg b/img/material/post.svg new file mode 100644 index 000000000..6b992d581 --- /dev/null +++ b/img/material/post.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/power.svg b/img/material/power.svg new file mode 100644 index 000000000..e419bedb7 --- /dev/null +++ b/img/material/power.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/printer.svg b/img/material/printer.svg new file mode 100644 index 000000000..71ebba4c8 --- /dev/null +++ b/img/material/printer.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/publish.svg b/img/material/publish.svg new file mode 100644 index 000000000..055911ba3 --- /dev/null +++ b/img/material/publish.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/puzzle.svg b/img/material/puzzle.svg new file mode 100644 index 000000000..27c10c362 --- /dev/null +++ b/img/material/puzzle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/racquetball.svg b/img/material/racquetball.svg new file mode 100644 index 000000000..77c370bf1 --- /dev/null +++ b/img/material/racquetball.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/radar.svg b/img/material/radar.svg new file mode 100644 index 000000000..286eb56ef --- /dev/null +++ b/img/material/radar.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/radio.svg b/img/material/radio.svg new file mode 100644 index 000000000..5199555e2 --- /dev/null +++ b/img/material/radio.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/raw.svg b/img/material/raw.svg new file mode 100644 index 000000000..b8d3682e5 --- /dev/null +++ b/img/material/raw.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/redo.svg b/img/material/redo.svg new file mode 100644 index 000000000..418ebfefa --- /dev/null +++ b/img/material/redo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/refresh.svg b/img/material/refresh.svg new file mode 100644 index 000000000..1a0cf666a --- /dev/null +++ b/img/material/refresh.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/reminder.svg b/img/material/reminder.svg new file mode 100644 index 000000000..87dbcf80d --- /dev/null +++ b/img/material/reminder.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/remote.svg b/img/material/remote.svg new file mode 100644 index 000000000..e75d2ecd9 --- /dev/null +++ b/img/material/remote.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/rename.svg b/img/material/rename.svg new file mode 100644 index 000000000..e773d9206 --- /dev/null +++ b/img/material/rename.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/repeat.svg b/img/material/repeat.svg new file mode 100644 index 000000000..c768e9fef --- /dev/null +++ b/img/material/repeat.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/replay.svg b/img/material/replay.svg new file mode 100644 index 000000000..d50f1639d --- /dev/null +++ b/img/material/replay.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/reply.svg b/img/material/reply.svg new file mode 100644 index 000000000..30e46cfc6 --- /dev/null +++ b/img/material/reply.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/restart.svg b/img/material/restart.svg new file mode 100644 index 000000000..8ed6dfab7 --- /dev/null +++ b/img/material/restart.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/restore.svg b/img/material/restore.svg new file mode 100644 index 000000000..db0569e2e --- /dev/null +++ b/img/material/restore.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/rewind.svg b/img/material/rewind.svg new file mode 100644 index 000000000..2556f1de8 --- /dev/null +++ b/img/material/rewind.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/ribbon.svg b/img/material/ribbon.svg new file mode 100644 index 000000000..cf787d30c --- /dev/null +++ b/img/material/ribbon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/rocket.svg b/img/material/rocket.svg new file mode 100644 index 000000000..40079f695 --- /dev/null +++ b/img/material/rocket.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/rodent.svg b/img/material/rodent.svg new file mode 100644 index 000000000..14bd0c349 --- /dev/null +++ b/img/material/rodent.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/rowing.svg b/img/material/rowing.svg new file mode 100644 index 000000000..b14b6936e --- /dev/null +++ b/img/material/rowing.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/rss.svg b/img/material/rss.svg new file mode 100644 index 000000000..d3f9a8ac7 --- /dev/null +++ b/img/material/rss.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/rugby.svg b/img/material/rugby.svg new file mode 100644 index 000000000..91e8cc7c8 --- /dev/null +++ b/img/material/rugby.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/run.svg b/img/material/run.svg new file mode 100644 index 000000000..05f7a4def --- /dev/null +++ b/img/material/run.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/satellite.svg b/img/material/satellite.svg new file mode 100644 index 000000000..face7439f --- /dev/null +++ b/img/material/satellite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/saxophone.svg b/img/material/saxophone.svg new file mode 100644 index 000000000..68545d05c --- /dev/null +++ b/img/material/saxophone.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/scanner.svg b/img/material/scanner.svg new file mode 100644 index 000000000..053bcdea7 --- /dev/null +++ b/img/material/scanner.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/school.svg b/img/material/school.svg new file mode 100644 index 000000000..21668077b --- /dev/null +++ b/img/material/school.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/scooter.svg b/img/material/scooter.svg new file mode 100644 index 000000000..fe5391b08 --- /dev/null +++ b/img/material/scooter.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/sd.svg b/img/material/sd.svg new file mode 100644 index 000000000..c4edfd7d1 --- /dev/null +++ b/img/material/sd.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/seat.svg b/img/material/seat.svg new file mode 100644 index 000000000..8a856418d --- /dev/null +++ b/img/material/seat.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/security.svg b/img/material/security.svg new file mode 100644 index 000000000..47b90088b --- /dev/null +++ b/img/material/security.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/segment.svg b/img/material/segment.svg new file mode 100644 index 000000000..b06f492c7 --- /dev/null +++ b/img/material/segment.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/send.svg b/img/material/send.svg new file mode 100644 index 000000000..5e148402e --- /dev/null +++ b/img/material/send.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/shape.svg b/img/material/shape.svg new file mode 100644 index 000000000..138b3a1c6 --- /dev/null +++ b/img/material/shape.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/share.svg b/img/material/share.svg new file mode 100644 index 000000000..ab05d262a --- /dev/null +++ b/img/material/share.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/shopping.svg b/img/material/shopping.svg new file mode 100644 index 000000000..c4b610b0d --- /dev/null +++ b/img/material/shopping.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/shuffle.svg b/img/material/shuffle.svg new file mode 100644 index 000000000..250c5d5c3 --- /dev/null +++ b/img/material/shuffle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/sigma.svg b/img/material/sigma.svg new file mode 100644 index 000000000..b4324e1a5 --- /dev/null +++ b/img/material/sigma.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/silverware.svg b/img/material/silverware.svg new file mode 100644 index 000000000..5bf39e722 --- /dev/null +++ b/img/material/silverware.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/sim.svg b/img/material/sim.svg new file mode 100644 index 000000000..17bda8962 --- /dev/null +++ b/img/material/sim.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/skate.svg b/img/material/skate.svg new file mode 100644 index 000000000..5291de637 --- /dev/null +++ b/img/material/skate.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/skateboard.svg b/img/material/skateboard.svg new file mode 100644 index 000000000..d3c5e78eb --- /dev/null +++ b/img/material/skateboard.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/skateboarding.svg b/img/material/skateboarding.svg new file mode 100644 index 000000000..87a3ecb60 --- /dev/null +++ b/img/material/skateboarding.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/ski.svg b/img/material/ski.svg new file mode 100644 index 000000000..3eafc0053 --- /dev/null +++ b/img/material/ski.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/sledding.svg b/img/material/sledding.svg new file mode 100644 index 000000000..835567de8 --- /dev/null +++ b/img/material/sledding.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/sleep.svg b/img/material/sleep.svg new file mode 100644 index 000000000..b10d35017 --- /dev/null +++ b/img/material/sleep.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/smoking.svg b/img/material/smoking.svg new file mode 100644 index 000000000..768b2f724 --- /dev/null +++ b/img/material/smoking.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/snowboard.svg b/img/material/snowboard.svg new file mode 100644 index 000000000..ddaa5a154 --- /dev/null +++ b/img/material/snowboard.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/snowflake.svg b/img/material/snowflake.svg new file mode 100644 index 000000000..ff22494a2 --- /dev/null +++ b/img/material/snowflake.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/snowmobile.svg b/img/material/snowmobile.svg new file mode 100644 index 000000000..feb283a94 --- /dev/null +++ b/img/material/snowmobile.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/snowshoeing.svg b/img/material/snowshoeing.svg new file mode 100644 index 000000000..b13fa4b9b --- /dev/null +++ b/img/material/snowshoeing.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/soccer.svg b/img/material/soccer.svg new file mode 100644 index 000000000..3d4e6a557 --- /dev/null +++ b/img/material/soccer.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/spa.svg b/img/material/spa.svg new file mode 100644 index 000000000..2e342f5f2 --- /dev/null +++ b/img/material/spa.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/speaker.svg b/img/material/speaker.svg new file mode 100644 index 000000000..bfc65c044 --- /dev/null +++ b/img/material/speaker.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/spellcheck.svg b/img/material/spellcheck.svg new file mode 100644 index 000000000..8b82ed49b --- /dev/null +++ b/img/material/spellcheck.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/stadium.svg b/img/material/stadium.svg new file mode 100644 index 000000000..7cdca1e58 --- /dev/null +++ b/img/material/stadium.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/star.svg b/img/material/star.svg new file mode 100644 index 000000000..36adc9d23 --- /dev/null +++ b/img/material/star.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/steering.svg b/img/material/steering.svg new file mode 100644 index 000000000..98f93ff43 --- /dev/null +++ b/img/material/steering.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/stop.svg b/img/material/stop.svg new file mode 100644 index 000000000..103878bba --- /dev/null +++ b/img/material/stop.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/store.svg b/img/material/store.svg new file mode 100644 index 000000000..f1263d848 --- /dev/null +++ b/img/material/store.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/subtitles.svg b/img/material/subtitles.svg new file mode 100644 index 000000000..cbf75e727 --- /dev/null +++ b/img/material/subtitles.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/subway.svg b/img/material/subway.svg new file mode 100644 index 000000000..ec5594908 --- /dev/null +++ b/img/material/subway.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/surfing.svg b/img/material/surfing.svg new file mode 100644 index 000000000..04b1854a9 --- /dev/null +++ b/img/material/surfing.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/synagogue.svg b/img/material/synagogue.svg new file mode 100644 index 000000000..cd570510f --- /dev/null +++ b/img/material/synagogue.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/sync.svg b/img/material/sync.svg new file mode 100644 index 000000000..79e1cb0a3 --- /dev/null +++ b/img/material/sync.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/tab.svg b/img/material/tab.svg new file mode 100644 index 000000000..e9824ed1d --- /dev/null +++ b/img/material/tab.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/tablet.svg b/img/material/tablet.svg new file mode 100644 index 000000000..ec927c666 --- /dev/null +++ b/img/material/tablet.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/tag.svg b/img/material/tag.svg new file mode 100644 index 000000000..e6dcd488f --- /dev/null +++ b/img/material/tag.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/taxi.svg b/img/material/taxi.svg new file mode 100644 index 000000000..ffc9af46a --- /dev/null +++ b/img/material/taxi.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/tea.svg b/img/material/tea.svg new file mode 100644 index 000000000..2107e62d3 --- /dev/null +++ b/img/material/tea.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/television.svg b/img/material/television.svg new file mode 100644 index 000000000..72bbad1c6 --- /dev/null +++ b/img/material/television.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/tennis.svg b/img/material/tennis.svg new file mode 100644 index 000000000..cc8ff7412 --- /dev/null +++ b/img/material/tennis.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/terrain.svg b/img/material/terrain.svg new file mode 100644 index 000000000..3ed024dc8 --- /dev/null +++ b/img/material/terrain.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/text.svg b/img/material/text.svg new file mode 100644 index 000000000..e6efd6394 --- /dev/null +++ b/img/material/text.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/texture.svg b/img/material/texture.svg new file mode 100644 index 000000000..55bc9dd1c --- /dev/null +++ b/img/material/texture.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/thermostat.svg b/img/material/thermostat.svg new file mode 100644 index 000000000..d11f0c6ad --- /dev/null +++ b/img/material/thermostat.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/ticket.svg b/img/material/ticket.svg new file mode 100644 index 000000000..1efa3d404 --- /dev/null +++ b/img/material/ticket.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/timelapse.svg b/img/material/timelapse.svg new file mode 100644 index 000000000..7e4db1b60 --- /dev/null +++ b/img/material/timelapse.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/toolbox.svg b/img/material/toolbox.svg new file mode 100644 index 000000000..d54bb46f9 --- /dev/null +++ b/img/material/toolbox.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/train.svg b/img/material/train.svg new file mode 100644 index 000000000..edc488146 --- /dev/null +++ b/img/material/train.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/tram.svg b/img/material/tram.svg new file mode 100644 index 000000000..c9fa3320e --- /dev/null +++ b/img/material/tram.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/transition.svg b/img/material/transition.svg new file mode 100644 index 000000000..93f296d15 --- /dev/null +++ b/img/material/transition.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/translate.svg b/img/material/translate.svg new file mode 100644 index 000000000..ed973da25 --- /dev/null +++ b/img/material/translate.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/truck.svg b/img/material/truck.svg new file mode 100644 index 000000000..08182b457 --- /dev/null +++ b/img/material/truck.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/tsunami.svg b/img/material/tsunami.svg new file mode 100644 index 000000000..7b0642114 --- /dev/null +++ b/img/material/tsunami.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/tune.svg b/img/material/tune.svg new file mode 100644 index 000000000..dc21d2278 --- /dev/null +++ b/img/material/tune.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/undo.svg b/img/material/undo.svg new file mode 100644 index 000000000..46fe48a5e --- /dev/null +++ b/img/material/undo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/update.svg b/img/material/update.svg new file mode 100644 index 000000000..0474cb3f6 --- /dev/null +++ b/img/material/update.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/upload.svg b/img/material/upload.svg new file mode 100644 index 000000000..67c4e38a9 --- /dev/null +++ b/img/material/upload.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/usb.svg b/img/material/usb.svg new file mode 100644 index 000000000..fc3b4f346 --- /dev/null +++ b/img/material/usb.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/vacuum.svg b/img/material/vacuum.svg new file mode 100644 index 000000000..383caa3cb --- /dev/null +++ b/img/material/vacuum.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/vibrate.svg b/img/material/vibrate.svg new file mode 100644 index 000000000..f831d18cc --- /dev/null +++ b/img/material/vibrate.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/video.svg b/img/material/video.svg new file mode 100644 index 000000000..cf83a26bb --- /dev/null +++ b/img/material/video.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/violin.svg b/img/material/violin.svg new file mode 100644 index 000000000..369051982 --- /dev/null +++ b/img/material/violin.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/voicemail.svg b/img/material/voicemail.svg new file mode 100644 index 000000000..5567b7cae --- /dev/null +++ b/img/material/voicemail.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/volcano.svg b/img/material/volcano.svg new file mode 100644 index 000000000..7c98d8cf0 --- /dev/null +++ b/img/material/volcano.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/volleyball.svg b/img/material/volleyball.svg new file mode 100644 index 000000000..eb875dce7 --- /dev/null +++ b/img/material/volleyball.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/vote.svg b/img/material/vote.svg new file mode 100644 index 000000000..5a9b0c75f --- /dev/null +++ b/img/material/vote.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/walk.svg b/img/material/walk.svg new file mode 100644 index 000000000..d3b625b12 --- /dev/null +++ b/img/material/walk.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/wallet.svg b/img/material/wallet.svg new file mode 100644 index 000000000..2146400fc --- /dev/null +++ b/img/material/wallet.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/wallpaper.svg b/img/material/wallpaper.svg new file mode 100644 index 000000000..12c9bd267 --- /dev/null +++ b/img/material/wallpaper.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/watch.svg b/img/material/watch.svg new file mode 100644 index 000000000..c0f9280a3 --- /dev/null +++ b/img/material/watch.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/water.svg b/img/material/water.svg new file mode 100644 index 000000000..e316e64bc --- /dev/null +++ b/img/material/water.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/watermark.svg b/img/material/watermark.svg new file mode 100644 index 000000000..d355a38f9 --- /dev/null +++ b/img/material/watermark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/web.svg b/img/material/web.svg new file mode 100644 index 000000000..dae2e715c --- /dev/null +++ b/img/material/web.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/widgets.svg b/img/material/widgets.svg new file mode 100644 index 000000000..6f5a15aab --- /dev/null +++ b/img/material/widgets.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/wrench.svg b/img/material/wrench.svg new file mode 100644 index 000000000..31319fc17 --- /dev/null +++ b/img/material/wrench.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/img/material/youtube.svg b/img/material/youtube.svg new file mode 100644 index 000000000..a0dc91101 --- /dev/null +++ b/img/material/youtube.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index 51100c339..4d1ecec19 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -6,9 +6,11 @@ use OCA\Analytics\Datasource\DatasourceEvent; use OCA\Tables\Capabilities; use OCA\Tables\Listener\AnalyticsDatasourceListener; +use OCA\Tables\Listener\BeforeTemplateRenderedListener; use OCA\Tables\Listener\LoadAdditionalListener; use OCA\Tables\Listener\TablesReferenceListener; use OCA\Tables\Listener\UserDeletedListener; +use OCA\Tables\Middleware\PermissionMiddleware; use OCA\Tables\Reference\ContentReferenceProvider; use OCA\Tables\Reference\ReferenceProvider; use OCA\Tables\Search\SearchTablesProvider; @@ -16,6 +18,7 @@ use OCP\AppFramework\Bootstrap\IBootContext; use OCP\AppFramework\Bootstrap\IBootstrap; use OCP\AppFramework\Bootstrap\IRegistrationContext; +use OCP\AppFramework\Http\Events\BeforeTemplateRenderedEvent; use OCP\Collaboration\Reference\RenderReferenceEvent; use OCP\Collaboration\Resources\LoadAdditionalScriptsEvent; use OCP\User\Events\BeforeUserDeletedEvent; @@ -26,6 +29,12 @@ class Application extends App implements IBootstrap { public const NODE_TYPE_TABLE = 0; public const NODE_TYPE_VIEW = 1; + public const OWNER_TYPE_USER = 0; + + public const NAV_ENTRY_MODE_HIDDEN = 0; + public const NAV_ENTRY_MODE_RECIPIENTS = 1; + public const NAV_ENTRY_MODE_ALL = 2; + public function __construct() { parent::__construct(self::APP_ID); } @@ -41,7 +50,7 @@ public function register(IRegistrationContext $context): void { $context->registerEventListener(BeforeUserDeletedEvent::class, UserDeletedListener::class); $context->registerEventListener(DatasourceEvent::class, AnalyticsDatasourceListener::class); $context->registerEventListener(RenderReferenceEvent::class, TablesReferenceListener::class); - + $context->registerEventListener(BeforeTemplateRenderedEvent::class, BeforeTemplateRenderedListener::class); $context->registerEventListener(LoadAdditionalScriptsEvent::class, LoadAdditionalListener::class); $context->registerSearchProvider(SearchTablesProvider::class); @@ -50,6 +59,8 @@ public function register(IRegistrationContext $context): void { $context->registerReferenceProvider(ContentReferenceProvider::class); $context->registerCapability(Capabilities::class); + + $context->registerMiddleware(PermissionMiddleware::class); } public function boot(IBootContext $context): void { diff --git a/lib/Command/ListContexts.php b/lib/Command/ListContexts.php new file mode 100644 index 000000000..3af8e1b52 --- /dev/null +++ b/lib/Command/ListContexts.php @@ -0,0 +1,89 @@ +contextService = $contextService; + $this->logger = $logger; + $this->config = $config; + } + + protected function configure(): void { + parent::configure(); + $this + ->setName('tables:contexts:list') + ->setDescription('Get all contexts or contexts available to a specified user') + ->addArgument( + 'user-id', + InputArgument::OPTIONAL, + 'User ID of the user' + ) + ; + } + + protected function execute(InputInterface $input, OutputInterface $output): int { + $userId = trim($input->getArgument('user-id')); + if ($userId === '') { + $userId = null; + } + + try { + $contexts = $this->contextService->findAll($userId); + } catch (InternalError|Exception $e) { + $output->writeln('Error while reading contexts from DB.'); + $this->logger->warning('Following error occurred during executing occ command "{class}"', + [ + 'app' => 'tables', + 'class' => self::class, + 'exception' => $e, + ] + ); + if ($this->config->getSystemValueBool('debug', false)) { + $output->writeln(sprintf('%s', $e->getMessage())); + $output->writeln(''); + debug_print_backtrace(); + $output->writeln(''); + } + return 1; + } + + foreach ($contexts as $context) { + $contextArray = json_decode(json_encode($context), true); + + $contextArray['ownerType'] = match ($contextArray['ownerType']) { + 1 => 'group', + default => 'user', + }; + + $out = ['ID ' . $contextArray['id'] => $contextArray]; + unset($out[$contextArray['id']]['id']); + $this->writeArrayInOutputFormat($input, $output, $out); + } + + return 0; + } +} diff --git a/lib/Command/ShowContext.php b/lib/Command/ShowContext.php new file mode 100644 index 000000000..239483c51 --- /dev/null +++ b/lib/Command/ShowContext.php @@ -0,0 +1,98 @@ +contextService = $contextService; + $this->logger = $logger; + $this->config = $config; + } + + protected function configure(): void { + parent::configure(); + $this + ->setName('tables:contexts:show') + ->setDescription('Get all contexts or contexts available to a specified user') + ->addArgument( + 'context-id', + InputArgument::REQUIRED, + 'The ID of the context to show' + ) + ->addArgument( + 'user-id', + InputArgument::OPTIONAL, + 'Optionally, showing the context from the perspective of the given user' + ) + ; + } + + protected function execute(InputInterface $input, OutputInterface $output): int { + $contextId = trim($input->getArgument('context-id')); + if ($contextId === '' || !is_numeric($contextId)) { + $output->writeln('Invalid Context ID'); + return 1; + } + + $userId = trim($input->getArgument('user-id')); + if ($userId === '') { + $userId = null; + } + + try { + $context = $this->contextService->findById($contextId, $userId); + } catch (InternalError|Exception $e) { + $output->writeln('Error while reading contexts from DB.'); + $this->logger->warning('Following error occurred during executing occ command "{class}"', + [ + 'app' => 'tables', + 'class' => self::class, + 'exception' => $e, + ] + ); + if ($this->config->getSystemValueBool('debug', false)) { + $output->writeln(sprintf('%s', $e->getMessage())); + $output->writeln(''); + debug_print_backtrace(); + $output->writeln(''); + } + return 1; + } + + $contextArray = json_decode(json_encode($context), true); + + $contextArray['ownerType'] = match ($contextArray['ownerType']) { + 1 => 'group', + default => 'user', + }; + + $out = ['ID ' . $contextArray['id'] => $contextArray]; + unset($out[$contextArray['id']]['id']); + $this->writeArrayInOutputFormat($input, $output, $out); + + return 0; + } +} diff --git a/lib/Controller/AOCSController.php b/lib/Controller/AOCSController.php index 8308a615e..54cd1411f 100644 --- a/lib/Controller/AOCSController.php +++ b/lib/Controller/AOCSController.php @@ -4,6 +4,7 @@ use Exception; use OCA\Tables\AppInfo\Application; +use OCA\Tables\Errors\BadRequestError; use OCA\Tables\Errors\InternalError; use OCA\Tables\Errors\NotFoundError; use OCA\Tables\Errors\PermissionError; @@ -59,4 +60,13 @@ protected function handleNotFoundError(NotFoundError $e): DataResponse { return new DataResponse(['message' => $this->n->t('A not found error occurred. More details can be found in the logs. Please reach out to your administration.')], Http::STATUS_NOT_FOUND); } + /** + * @param BadRequestError $e + * @return DataResponse + */ + protected function handleBadRequestError(BadRequestError $e): DataResponse { + $this->logger->warning('An bad request was encountered: ['. $e->getCode() . ']' . $e->getMessage()); + return new DataResponse(['message' => $this->n->t('An error caused by an invalid request occurred. More details can be found in the logs. Please reach out to your administration.')], Http::STATUS_BAD_REQUEST); + } + } diff --git a/lib/Controller/ContextController.php b/lib/Controller/ContextController.php new file mode 100644 index 000000000..a6bc51521 --- /dev/null +++ b/lib/Controller/ContextController.php @@ -0,0 +1,308 @@ +contextService = $contextService; + $this->userId = $userId; + } + + /** + * [api v3] Get all contexts available to the requesting person + * + * Return an empty array if no contexts were found + * + * @return DataResponse|DataResponse + * + * 200: reporting in available contexts + * + * @NoAdminRequired + */ + public function index(): DataResponse { + try { + $contexts = $this->contextService->findAll($this->userId); + return new DataResponse($this->contextsToArray($contexts)); + } catch (InternalError|Exception $e) { + return $this->handleError($e); + } + } + + /** + * [api v2] Get information about the requests context + * + * @param int $contextId ID of the context + * @return DataResponse|DataResponse + * + * 200: returning the full context information + * 404: context not found or not available anymore + * + * @NoAdminRequired + */ + public function show(int $contextId): DataResponse { + try { + $context = $this->contextService->findById($contextId, $this->userId); + return new DataResponse($context->jsonSerialize()); + } catch (NotFoundError $e) { + return $this->handleNotFoundError($e); + } catch (InternalError|Exception $e) { + return $this->handleError($e); + } + } + + /** + * [api v2] Create a new context and return it + * + * @NoAdminRequired + * + * @param string $name Name of the context + * @param string $iconName Material design icon name of the context + * @param string $description Descriptive text of the context + * @param array{id: int, type: int, permissions: int}|array $nodes optional nodes to be connected to this context + * + * @return DataResponse|DataResponse + * + * 200: returning the full context information + */ + public function create(string $name, string $iconName, string $description = '', array $nodes = []): DataResponse { + try { + return new DataResponse($this->contextService->create($name, $iconName, $description, $nodes, $this->userId, 0)->jsonSerialize()); + } catch (Exception $e) { + return $this->handleError($e); + } + } + + /** + * [api v2] Update an existing context and return it + * + * @param int $contextId ID of the context + * @param ?string $name provide this parameter to set a new name + * @param ?string $iconName provide this parameter to set a new icon + * @param ?string $description provide this parameter to set a new description + * @param ?array{id: int, type: int, permissions: int, order: int} $nodes provide this parameter to set a new list of nodes. + * + * @return DataResponse|DataResponse + * + * 200: returning the full context information + * 403: No permissions + * 404: Not found + * + * @NoAdminRequired + * @CanManageContext + */ + public function update(int $contextId, ?string $name, ?string $iconName, ?string $description, ?array $nodes): DataResponse { + try { + return new DataResponse($this->contextService->update( + $contextId, + $this->userId, + $name, + $iconName, + $description, + $nodes, + )->jsonSerialize()); + } catch (Exception|MultipleObjectsReturnedException $e) { + return $this->handleError($e); + } catch (DoesNotExistException $e) { + return $this->handleNotFoundError(new NotFoundError($e->getMessage(), $e->getCode(), $e)); + } + } + + /** + * [api v2] Delete an existing context and return it + * + * @param int $contextId ID of the context + * @return DataResponse|DataResponse + * + * 200: returning the full context information + * 403: No permissions + * 404: Not found + * + * @NoAdminRequired + * @CanManageContext + */ + public function destroy(int $contextId): DataResponse { + try { + return new DataResponse($this->contextService->delete($contextId, $this->userId)->jsonSerialize()); + } catch (Exception $e) { + return $this->handleError($e); + } catch (NotFoundError $e) { + return $this->handleNotFoundError($e); + } + } + + /** + * [api v2] Transfer the ownership of a context and return it + * + * @param int $contextId ID of the context + * @param string $newOwnerId ID of the new owner + * @param int $newOwnerType any Application::OWNER_TYPE_* constant + * + * @return DataResponse|DataResponse + * + * 200: Ownership transferred + * 400: Invalid request + * 403: No permissions + * 404: Not found + * + * @NoAdminRequired + * @CanManageContext + * + * @psalm-param int<0, max> $contextId + * @psalm-param int<0, 0> $newOwnerType + */ + public function transfer(int $contextId, string $newOwnerId, int $newOwnerType = 0): DataResponse { + try { + return new DataResponse($this->contextService->transfer($contextId, $newOwnerId, $newOwnerType)->jsonSerialize()); + } catch (Exception|MultipleObjectsReturnedException $e) { + return $this->handleError($e); + } catch (DoesNotExistException $e) { + return $this->handleNotFoundError(new NotFoundError($e->getMessage(), $e->getCode(), $e)); + } catch (BadRequestError $e) { + return $this->handleBadRequestError($e); + } + } + + /** + * [api v2] Add a node to a Context + * + * @param int $contextId ID of the context + * @param int $nodeId ID of the node + * @param int $nodeType any Application::NODE_TYPE_* constant + * @param int $permissions bitmask of the permissions for context recipients + * @param ?int $order in which order the node should appear within the context + * + * @return DataResponse|DataResponse + * + * 200: Node added successfully + * 403: No permissions + * 404: Not found + * + * @NoAdminRequired + * @CanManageNode + */ + public function addNode(int $contextId, int $nodeId, int $nodeType, int $permissions, ?int $order = null): DataResponse { + try { + $rel = $this->contextService->addNodeToContextById($contextId, $nodeId, $nodeType, $permissions, $this->userId); + $this->contextService->addNodeRelToPage($rel, $order); + $context = $this->contextService->findById($rel->getContextId(), $this->userId); + return new DataResponse($context->jsonSerialize()); + } catch (NotFoundError $e) { + return $this->handleNotFoundError($e); + } catch (DoesNotExistException $e) { + return $this->handleNotFoundError(new NotFoundError($e->getMessage(), $e->getCode(), $e)); + } catch (MultipleObjectsReturnedException|Exception|InternalError $e) { + return $this->handleError($e); + } + } + + /** + * [api v2] Remove a node from a Context + * + * @param int $contextId ID of the context + * @param int $nodeRelId ID of the node-in-context relation + * + * @return DataResponse|DataResponse + * + * 200: Node removed successfully + * 400: Invalid request + * 403: No permissions + * 404: Not found + * + * @NoAdminRequired + * @CanManageContext + */ + public function removeNode(int $contextId, int $nodeRelId): DataResponse { + // we could do without the contextId, however it is used by the Permission Middleware + // and also results in a more consistent endpoint url + try { + $context = $this->contextService->findById($contextId, $this->userId); + if (!isset($context->getNodes()[$nodeRelId])) { + return $this->handleBadRequestError(new BadRequestError('Node Relation ID not found in given Context')); + } + $nodeRelation = $this->contextService->removeNodeFromContextById($nodeRelId); + $this->contextService->removeNodeRelFromAllPages($nodeRelation); + $context = $this->contextService->findById($contextId, $this->userId); + return new DataResponse($context->jsonSerialize()); + } catch (NotFoundError $e) { + return $this->handleNotFoundError($e); + } catch (DoesNotExistException $e) { + return $this->handleNotFoundError(new NotFoundError($e->getMessage(), $e->getCode(), $e)); + } catch (MultipleObjectsReturnedException|Exception|InternalError $e) { + return $this->handleError($e); + } + } + + /** + * [api v2] Update the order on a page of a context + * + * @param int $contextId ID of the context + * @param int $pageId ID of the page + * @param array{id: int, order: int} $content content items with it and order values + * + * @return DataResponse|DataResponse + * + * @NoAdminRequired + * @CanManageContext + * + * 200: content updated successfully + * 400: Invalid request + * 403: No permissions + * 404: Not found + */ + public function updateContentOrder(int $contextId, int $pageId, array $content): DataResponse { + try { + $context = $this->contextService->findById($contextId, $this->userId); + } catch (Exception|InternalError $e) { + return $this->handleError($e); + } catch (NotFoundError $e) { + return $this->handleNotFoundError($e); + } + if (!isset($context->getPages()[$pageId])) { + return $this->handleBadRequestError(new BadRequestError('Page not found in given Context')); + } + + return new DataResponse($this->contextService->updateContentOrder($pageId, $content)); + } + + /** + * @param Context[] $contexts + * @return array + */ + protected function contextsToArray(array $contexts): array { + $result = []; + foreach ($contexts as $context) { + $result[] = $context->jsonSerialize(); + } + return $result; + } +} diff --git a/lib/Db/Context.php b/lib/Db/Context.php new file mode 100644 index 000000000..8da45c6b3 --- /dev/null +++ b/lib/Db/Context.php @@ -0,0 +1,63 @@ +addType('id', 'integer'); + } + + public function jsonSerialize(): array { + // basic information + $data = [ + 'id' => $this->getId(), + 'name' => $this->getName(), + 'iconName' => $this->getIcon(), + 'description' => $this->getDescription(), + 'owner' => $this->getOwnerId(), + 'ownerType' => $this->getOwnerType() + ]; + + // extended data + if (is_array($this->sharing) || is_array($this->nodes) || is_array($this->pages)) { + $data['sharing'] = $this->getSharing(); + $data['nodes'] = $this->getNodes(); + $data['pages'] = $this->getPages(); + } + + return $data; + } +} diff --git a/lib/Db/ContextMapper.php b/lib/Db/ContextMapper.php new file mode 100644 index 000000000..472c6d3d6 --- /dev/null +++ b/lib/Db/ContextMapper.php @@ -0,0 +1,256 @@ + */ +class ContextMapper extends QBMapper { + protected string $table = 'tables_contexts_context'; + private UserHelper $userHelper; + + public function __construct(IDBConnection $db, UserHelper $userHelper) { + $this->userHelper = $userHelper; + parent::__construct($db, $this->table, Context::class); + } + + protected function getFindContextBaseQuery(?string $userId): IQueryBuilder { + $qb = $this->db->getQueryBuilder(); + + $qb->select( + 'c.*', + 'r.id as node_rel_id', 'r.node_id', 'r.node_type', 'r.permissions', + 'p.id as page_id', 'p.page_type', + 'pc.id as content_id', 'pc.order', + 'n.display_mode as display_mode_default', + 's.id as share_id', 's.receiver', 's.receiver_type' + ) + ->from($this->table, 'c'); + + if ($userId !== null) { + $this->applyOwnedOrSharedQuery($qb, $userId); + $qb->addSelect('n2.display_mode'); + $qb->leftJoin('s', 'tables_contexts_navigation', 'n2', $qb->expr()->andX( + $qb->expr()->eq('s.id', 'n2.share_id'), + $qb->expr()->eq('n2.user_id', $qb->createNamedParameter($userId, IQueryBuilder::PARAM_STR)), + )); + } else { + $qb->leftJoin('c', 'tables_shares', 's', $qb->expr()->andX( + $qb->expr()->eq('c.id', 's.node_id'), + $qb->expr()->eq('s.node_type', $qb->createNamedParameter('context')), + )); + } + + $qb->leftJoin('c', 'tables_contexts_page', 'p', $qb->expr()->eq('c.id', 'p.context_id')); + $qb->leftJoin('p', 'tables_contexts_page_content', 'pc', $qb->expr()->eq('p.id', 'pc.page_id')); + $qb->leftJoin('c', 'tables_contexts_rel_context_node', 'r', $qb->expr()->eq('c.id', 'r.context_id')); + $qb->leftJoin('s', 'tables_contexts_navigation', 'n', $qb->expr()->andX( + $qb->expr()->eq('s.id', 'n.share_id'), + $qb->expr()->eq('n.user_id', $qb->createNamedParameter('')), + )); + + $qb->andWhere($qb->expr()->orX( + $qb->expr()->eq('pc.node_rel_id', 'r.id'), + $qb->expr()->isNull('pc.node_rel_id'), + )); + + $qb->orderBy('pc.order', 'ASC'); + + return $qb; + } + + protected function formatResultRows(array $rows, ?string $userId) { + $formatted = [ + 'id' => $rows[0]['id'], + 'name' => $rows[0]['name'], + 'icon' => $rows[0]['icon'], + 'description' => $rows[0]['description'], + 'owner_id' => $rows[0]['owner_id'], + 'owner_type' => $rows[0]['owner_type'], + ]; + + $formatted['sharing'] = array_reduce($rows, function (array $carry, array $item) use ($userId) { + if ($item['share_id'] === null) { + // empty Context + return $carry; + } + $carry[$item['share_id']] = [ + 'share_id' => $item['share_id'], + 'receiver' => $item['receiver'], + 'receiver_type' => $item['receiver_type'], + 'display_mode_default' => $item['display_mode_default'], + ]; + if ($userId !== null) { + $carry[$item['share_id']]['display_mode'] = $item['display_mode']; + } + return $carry; + }, []); + + $formatted['nodes'] = array_reduce($rows, function (array $carry, array $item) { + if ($item['node_rel_id'] === null) { + // empty Context + return $carry; + } + $carry[$item['node_rel_id']] = [ + 'id' => $item['node_rel_id'], + 'node_id' => $item['node_id'], + 'node_type' => $item['node_type'], + 'permissions' => $item['permissions'], + ]; + return $carry; + }, []); + + $formatted['pages'] = array_reduce($rows, function (array $carry, array $item) { + if ($item['page_id'] === null) { + // empty Context + return $carry; + } + if (!isset($carry[$item['page_id']])) { + $carry[$item['page_id']] = ['content' => []]; + } + $carry[$item['page_id']]['id'] = $item['page_id']; + $carry[$item['page_id']]['page_type'] = $item['page_type']; + if ($item['node_rel_id'] !== null) { + $carry[$item['page_id']]['content'][$item['content_id']] = [ + 'order' => $item['order'], + 'node_rel_id' => $item['node_rel_id'] + ]; + } + + return $carry; + }, []); + + return $this->mapRowToEntity($formatted); + } + + /** + * @return Context[] + * @throws Exception + */ + public function findAll(?string $userId = null): array { + $qb = $this->getFindContextBaseQuery($userId); + + $result = $qb->executeQuery(); + $r = $result->fetchAll(); + + $contextIds = []; + foreach ($r as $row) { + $contextIds[$row['id']] = 1; + } + $contextIds = array_keys($contextIds); + unset($row); + + $resultEntities = []; + foreach ($contextIds as $contextId) { + $workArray = []; + foreach ($r as $row) { + if ($row['id'] === $contextId) { + $workArray[] = $row; + } + } + $resultEntities[] = $this->formatResultRows($workArray, $userId); + } + + return $resultEntities; + } + + public function findForNavBar(string $userId): array { + $qb = $this->getFindContextBaseQuery($userId); + $qb->andWhere($qb->expr()->andX( + // default + $qb->expr()->gt('n.display_mode', $qb->createNamedParameter(Application::NAV_ENTRY_MODE_HIDDEN, IQueryBuilder::PARAM_INT)), + // user override + $qb->expr()->orX( + $qb->expr()->gt('n2.display_mode', $qb->createNamedParameter(Application::NAV_ENTRY_MODE_HIDDEN, IQueryBuilder::PARAM_INT)), + $qb->expr()->isNull('n2.display_mode'), + ) + )); + + $result = $qb->executeQuery(); + $r = $result->fetchAll(); + + $contextIds = []; + foreach ($r as $row) { + $contextIds[$row['id']] = 1; + } + $contextIds = array_keys($contextIds); + unset($row); + + $resultEntities = []; + foreach ($contextIds as $contextId) { + $workArray = []; + foreach ($r as $row) { + if ($row['id'] === $contextId) { + $workArray[] = $row; + } + } + $resultEntities[] = $this->formatResultRows($workArray, $userId); + } + + return $resultEntities; + } + + /** + * @throws Exception + * @throws NotFoundError + */ + public function findById(int $contextId, ?string $userId = null): Context { + $qb = $this->getFindContextBaseQuery($userId); + $qb->andWhere($qb->expr()->eq('c.id', $qb->createNamedParameter($contextId, IQueryBuilder::PARAM_INT))); + + $result = $qb->executeQuery(); + $r = $result->fetchAll(); + + if (empty($r)) { + throw new NotFoundError('Context does not exist'); + } + + return $this->formatResultRows($r, $userId); + } + + protected function applyOwnedOrSharedQuery(IQueryBuilder $qb, string $userId): void { + $sharedToConditions = $qb->expr()->orX(); + + // shared to user clause + $userShare = $qb->expr()->andX( + $qb->expr()->eq('s.receiver_type', $qb->createNamedParameter('user')), + $qb->expr()->eq('s.receiver', $qb->createNamedParameter($userId)), + ); + $sharedToConditions->add($userShare); + + // shared to group clause + $groupIDs = $this->userHelper->getGroupIdsForUser($userId); + if (!empty($groupIDs)) { + $groupShares = $qb->expr()->andX( + $qb->expr()->eq('s.receiver_type', $qb->createNamedParameter('group')), + $qb->expr()->in('s.receiver', $qb->createNamedParameter($groupIDs, IQueryBuilder::PARAM_STR_ARRAY)), + ); + $sharedToConditions->add($groupShares); + } + + // owned contexts + apply share conditions + $qb->leftJoin('c', 'tables_shares', 's', $qb->expr()->andX( + $qb->expr()->eq('c.id', 's.node_id'), + $qb->expr()->eq('s.node_type', $qb->createNamedParameter('context')), + $sharedToConditions, + )); + + $whereExpression = $qb->expr()->orX( + $qb->expr()->eq('owner_id', $qb->createNamedParameter($userId, IQueryBuilder::PARAM_STR)), + $qb->expr()->isNotNull('s.receiver'), + ); + if ($qb->getQueryPart('where') === null) { + $qb->where($whereExpression); + } else { + $qb->andWhere($whereExpression); + } + } +} diff --git a/lib/Db/ContextNodeRelation.php b/lib/Db/ContextNodeRelation.php new file mode 100644 index 000000000..7981ffcd1 --- /dev/null +++ b/lib/Db/ContextNodeRelation.php @@ -0,0 +1,39 @@ +addType('id', 'integer'); + } + + public function jsonSerialize(): array { + return [ + 'id' => $this->getId(), + 'contextId' => $this->getContextId(), + 'nodeId' => $this->getNodeId(), + 'nodeType' => $this->getNodeType(), + 'permissions' => $this->getPermissions() + ]; + } +} diff --git a/lib/Db/ContextNodeRelationMapper.php b/lib/Db/ContextNodeRelationMapper.php new file mode 100644 index 000000000..7709ca5de --- /dev/null +++ b/lib/Db/ContextNodeRelationMapper.php @@ -0,0 +1,35 @@ + */ +class ContextNodeRelationMapper extends QBMapper { + protected string $table = 'tables_contexts_rel_context_node'; + + public function __construct(IDBConnection $db) { + parent::__construct($db, $this->table, ContextNodeRelation::class); + } + + /** + * @throws MultipleObjectsReturnedException + * @throws DoesNotExistException + * @throws Exception + */ + public function findById(int $nodeRelId): ContextNodeRelation { + $qb = $this->db->getQueryBuilder(); + $qb->select('*') + ->from($this->tableName) + ->where($qb->expr()->eq('id', $qb->createNamedParameter($nodeRelId))); + + $row = $this->findOneQuery($qb); + return $this->mapRowToEntity($row); + } +} diff --git a/lib/Db/Page.php b/lib/Db/Page.php new file mode 100644 index 000000000..a7757fb1e --- /dev/null +++ b/lib/Db/Page.php @@ -0,0 +1,32 @@ +addType('id', 'integer'); + } + + public function jsonSerialize(): array { + return [ + 'id' => $this->getId(), + 'contextId' => $this->getContextId(), + 'pageType' => $this->getPageType(), + ]; + } +} diff --git a/lib/Db/PageContent.php b/lib/Db/PageContent.php new file mode 100644 index 000000000..45bb1e735 --- /dev/null +++ b/lib/Db/PageContent.php @@ -0,0 +1,34 @@ +addType('id', 'integer'); + } + + public function jsonSerialize(): array { + return [ + 'id' => $this->getId(), + 'pageId' => $this->getPageId(), + 'nodeRelId' => $this->getNodeRelId(), + 'order' => $this->getOrder(), + ]; + } +} diff --git a/lib/Db/PageContentMapper.php b/lib/Db/PageContentMapper.php new file mode 100644 index 000000000..dcd88fc01 --- /dev/null +++ b/lib/Db/PageContentMapper.php @@ -0,0 +1,60 @@ + */ +class PageContentMapper extends QBMapper { + protected string $table = 'tables_contexts_page_content'; + + public function __construct(IDBConnection $db) { + parent::__construct($db, $this->table, PageContent::class); + } + + /** + * @throws DoesNotExistException + * @throws MultipleObjectsReturnedException + * @throws Exception + */ + public function findById(int $pageContentId): PageContent { + $qb = $this->db->getQueryBuilder(); + $qb->select('*') + ->from($this->tableName) + ->where($qb->expr()->eq('id', $qb->createNamedParameter($pageContentId))); + + return $this->mapRowToEntity($this->findOneQuery($qb)); + } + + /** + * @throws Exception + */ + public function findByPageAndNodeRelation(int $pageId, int $nodeRelId): ?PageContent { + $qb = $this->db->getQueryBuilder(); + $qb->select('*') + ->from($this->table) + ->where($qb->expr()->andX( + $qb->expr()->eq('page_id', $qb->createNamedParameter($pageId)), + $qb->expr()->eq('node_rel_id', $qb->createNamedParameter($nodeRelId)), + )); + + $result = $qb->executeQuery(); + $r = $result->fetch(); + return $r ? $this->mapRowToEntity($r) : null; + } + + public function findByNodeRelation(int $nodeRelId): array { + $qb = $this->db->getQueryBuilder(); + $qb->select('*') + ->from($this->table) + ->where($qb->expr()->andX( + $qb->expr()->eq('node_rel_id', $qb->createNamedParameter($nodeRelId)), + )); + + return $this->findEntities($qb); + } +} diff --git a/lib/Db/PageMapper.php b/lib/Db/PageMapper.php new file mode 100644 index 000000000..6ade694f1 --- /dev/null +++ b/lib/Db/PageMapper.php @@ -0,0 +1,15 @@ + */ +class PageMapper extends QBMapper { + protected string $table = 'tables_contexts_page'; + + public function __construct(IDBConnection $db) { + parent::__construct($db, $this->table, Page::class); + } +} diff --git a/lib/Errors/BadRequestError.php b/lib/Errors/BadRequestError.php new file mode 100644 index 000000000..71fdb8949 --- /dev/null +++ b/lib/Errors/BadRequestError.php @@ -0,0 +1,6 @@ + + */ +class BeforeTemplateRenderedListener implements IEventListener { + public function __construct( + protected INavigationManager $navigationManager, + protected IURLGenerator $urlGenerator, + protected IUserSession $userSession, + protected ContextService $contextService, + ) { + } + + /** + * @inheritDoc + */ + public function handle(Event $event): void { + if (!$event instanceof BeforeTemplateRenderedEvent) { + return; + } + + $user = $this->userSession->getUser(); + if ($user === null) { + return; + } + + // temporarily show all + //$contexts = $this->contextService->findForNavigation($user->getUID()); + $contexts = $this->contextService->findAll($user->getUID()); + foreach ($contexts as $context) { + /* temporarily, show all + if ($context->getOwnerType() === Application::OWNER_TYPE_USER + && $context->getOwnerId() === $user->getUID()) { + + + // filter out entries for owners unless it is set to be visible + $skipEntry = true; + foreach ($context->getSharing() as $shareInfo) { + // TODO: integrate into DB query in Mapper + + if (isset($shareInfo['display_mode']) && $shareInfo['display_mode'] === Application::NAV_ENTRY_MODE_ALL) { + // a custom override makes it visible + $skipEntry = false; + break; + } elseif (!isset($shareInfo['display_mode']) && $shareInfo['display_mode_default'] === Application::NAV_ENTRY_MODE_ALL) { + // no custom override, and visible also for owner by default + $skipEntry = false; + break; + } + } + if ($skipEntry) { + continue; + } + } + */ + + $this->navigationManager->add(function () use ($context) { + $iconRelPath = 'material/' . $context->getIcon() . '.svg'; + if (file_exists(__DIR__ . '/../../img/' . $iconRelPath)) { + $iconUrl = $this->urlGenerator->imagePath(Application::APP_ID, $iconRelPath); + } else { + $iconUrl = $this->urlGenerator->imagePath('core', 'places/default-app-icon.svg'); + } + + $contextUrl = $this->urlGenerator->linkToRoute('tables.page.index'); + $contextUrl .= sprintf('#/application/%d', $context->getId()); + + return [ + 'id' => Application::APP_ID . '_application_' . $context->getId(), + 'name' => $context->getName(), + 'href' => $contextUrl, + 'icon' => $iconUrl, + 'order' => 500, + 'type' => 'link', + ]; + }); + } + } +} diff --git a/lib/Middleware/PermissionMiddleware.php b/lib/Middleware/PermissionMiddleware.php new file mode 100644 index 000000000..49b239936 --- /dev/null +++ b/lib/Middleware/PermissionMiddleware.php @@ -0,0 +1,90 @@ +reflector = $reflector; + $this->permissionsService = $permissionsService; + $this->userId = $userId; + $this->request = $request; + } + + /** + * @throws PermissionError + * @throws InternalError + */ + public function beforeController($controller, $methodName): void { + // we can have type hinting in the signature only after dropping NC26 – calling parent to enforce on newer releases + parent::beforeController($controller, $methodName); + $this->assertCanManageNode(); + $this->assertCanManageContext(); + } + + /** + * @throws PermissionError + * @throws InternalError + */ + protected function assertCanManageNode(): void { + if ($this->reflector->hasAnnotation('CanManageNode')) { + $nodeId = $this->request->getParam('nodeId'); + $nodeType = $this->request->getParam('nodeType'); + + if (!is_numeric($nodeId) || !is_numeric($nodeType)) { + throw new InternalError('Cannot identify node'); + } + + if ($this->userId === null) { + throw new PermissionError('User not authenticated'); + } + + if (!$this->permissionsService->canManageNodeById((int)$nodeType, (int)$nodeId, $this->userId)) { + throw new PermissionError(sprintf('User %s cannot manage node %d (type %d)', + $this->userId, (int)$nodeId, (int)$nodeType + )); + } + } + } + + /** + * @throws PermissionError + * @throws InternalError + */ + protected function assertCanManageContext(): void { + if ($this->reflector->hasAnnotation('CanManageContext')) { + $contextId = $this->request->getParam('contextId'); + + if (!is_numeric($contextId)) { + throw new InternalError('Cannot identify context'); + } + + if ($this->userId === null) { + throw new PermissionError('User not authenticated'); + } + + if (!$this->permissionsService->canManageContextById((int)$contextId, $this->userId)) { + throw new PermissionError(sprintf('User %s cannot manage context %d', + $this->userId, (int)$contextId + )); + } + } + } +} diff --git a/lib/Migration/Version000800Date20240213123743.php b/lib/Migration/Version000800Date20240213123743.php new file mode 100644 index 000000000..09669b590 --- /dev/null +++ b/lib/Migration/Version000800Date20240213123743.php @@ -0,0 +1,133 @@ + + * + * @author Arthur Schiwon + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCA\Tables\Migration; + +use Closure; +use Doctrine\DBAL\Schema\SchemaException; +use Doctrine\DBAL\Schema\Table; +use OCP\DB\ISchemaWrapper; +use OCP\DB\Types; +use OCP\Migration\IOutput; +use OCP\Migration\SimpleMigrationStep; + +class Version000800Date20240213123743 extends SimpleMigrationStep { + + protected const PREFIX = 'tables_contexts_'; + + /** + * @throws SchemaException + */ + public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper { + // Introduction of Contexts tables + + /** @var ISchemaWrapper $schema */ + $schema = $schemaClosure(); + + $this->haveContextTable($schema); + $this->haveContextNodeRelationTable($schema); + $this->havePageTable($schema); + $this->havePageContentTable($schema); + $this->haveNavigationTable($schema); + + return $schema; + } + + protected function shouldAddTable(string $tableName, ISchemaWrapper $schema): ?Table { + return !$schema->hasTable($tableName) ? $schema->createTable($tableName) : null; + } + + /** + * @throws SchemaException + */ + protected function haveContextTable(ISchemaWrapper $schema): void { + if ($table = $this->shouldAddTable(self::PREFIX . 'context', $schema)) { + $table->addColumn('id', Types::INTEGER, ['autoincrement' => true, 'notnull' => true]); + $table->addColumn('name', Types::STRING, ['notnull' => true, 'length' => 200]); + $table->addColumn('icon', Types::STRING, ['notnull' => true, 'length' => 64]); + $table->addColumn('description', Types::TEXT); + $table->addColumn('owner_id', Types::STRING, ['notnull' => true, 'length' => 64]); + $table->addColumn('owner_type', Types::INTEGER, ['notnull' => true]); + + $table->setPrimaryKey(['id']); + } + } + + /** + * @throws SchemaException + */ + protected function haveContextNodeRelationTable(ISchemaWrapper $schema): void { + if ($table = $this->shouldAddTable(self::PREFIX . 'rel_context_node', $schema)) { + $table->addColumn('id', Types::INTEGER, ['autoincrement' => true, 'notnull' => true]); + $table->addColumn('context_id', Types::INTEGER, ['notnull' => true]); + $table->addColumn('node_id', Types::INTEGER, ['notnull' => true]); + $table->addColumn('node_type', Types::INTEGER, ['notnull' => true]); + $table->addColumn('permissions', Types::INTEGER, ['notnull' => true]); + + $table->setPrimaryKey(['id']); + } + } + + /** + * @throws SchemaException + */ + protected function havePageTable(ISchemaWrapper $schema): void { + if ($table = $this->shouldAddTable(self::PREFIX . 'page', $schema)) { + $table->addColumn('id', Types::INTEGER, ['autoincrement' => true, 'notnull' => true]); + $table->addColumn('context_id', Types::INTEGER, ['notnull' => true]); + $table->addColumn('page_type', Types::STRING, ['notnull' => true, 'length' => 32]); + + $table->setPrimaryKey(['id']); + } + } + + /** + * @throws SchemaException + */ + protected function havePageContentTable(ISchemaWrapper $schema): void { + if ($table = $this->shouldAddTable(self::PREFIX . 'page_content', $schema)) { + $table->addColumn('id', Types::INTEGER, ['autoincrement' => true, 'notnull' => true]); + $table->addColumn('page_id', Types::INTEGER, ['notnull' => true]); + $table->addColumn('node_rel_id', Types::INTEGER, ['notnull' => true]); + $table->addColumn('order', Types::INTEGER, ['notnull' => true]); + + $table->setPrimaryKey(['id']); + } + } + + /** + * @throws SchemaException + */ + protected function haveNavigationTable(ISchemaWrapper $schema): void { + if ($table = $this->shouldAddTable(self::PREFIX . 'navigation', $schema)) { + $table->addColumn('share_id', Types::INTEGER, ['notnull' => true]); + $table->addColumn('display_mode', Types::INTEGER, ['notnull' => true]); + $table->addColumn('user_id', Types::STRING, ['notnull' => true, 'length' => 64, 'default' => '']); + + $table->setPrimaryKey(['share_id', 'user_id']); + } + } +} diff --git a/lib/ResponseDefinitions.php b/lib/ResponseDefinitions.php index 172b760a0..d738a3c0d 100644 --- a/lib/ResponseDefinitions.php +++ b/lib/ResponseDefinitions.php @@ -128,6 +128,15 @@ * errors_parsing_count: int, * errors_count: int, * } + * + * @psalm-type TablesContext = array{ + * id: int, + * name: string, + * iconName: string, + * description: string, + * owner: string, + * ownerType: int, + * } */ class ResponseDefinitions { } diff --git a/lib/Service/ContextService.php b/lib/Service/ContextService.php new file mode 100644 index 000000000..a0e247bd8 --- /dev/null +++ b/lib/Service/ContextService.php @@ -0,0 +1,439 @@ +contextMapper = $contextMapper; + $this->isCLI = $isCLI; + $this->logger = $logger; + $this->contextNodeRelMapper = $contextNodeRelationMapper; + $this->pageMapper = $pageMapper; + $this->pageContentMapper = $pageContentMapper; + $this->permissionsService = $permissionsService; + $this->userManager = $userManager; + $this->eventDispatcher = $eventDispatcher; + } + + /** + * @return Context[] + * @throws Exception + * @throws InternalError + */ + public function findAll(?string $userId): array { + if ($userId !== null && trim($userId) === '') { + $userId = null; + } + if ($userId === null && !$this->isCLI) { + $error = 'Try to set no user in context, but request is not allowed.'; + $this->logger->warning($error); + throw new InternalError($error); + } + return $this->contextMapper->findAll($userId); + } + + public function findForNavigation(string $userId): array { + return $this->contextMapper->findForNavBar($userId); + } + + /** + * @throws Exception + * @throws InternalError + * @throws NotFoundError + */ + public function findById(int $id, ?string $userId): Context { + if ($userId !== null && trim($userId) === '') { + $userId = null; + } + if ($userId === null && !$this->isCLI) { + $error = 'Try to set no user in context, but request is not allowed.'; + $this->logger->warning($error); + throw new InternalError($error); + } + + return $this->contextMapper->findById($id, $userId); + } + + /** + * @throws Exception + */ + public function create(string $name, string $iconName, string $description, array $nodes, string $ownerId, int $ownerType): Context { + $context = new Context(); + $context->setName(trim($name)); + $context->setIcon(trim($iconName)); + $context->setDescription(trim($description)); + $context->setOwnerId($ownerId); + $context->setOwnerType($ownerType); + + $this->contextMapper->insert($context); + + if (!empty($nodes)) { + $context->resetUpdatedFields(); + $this->insertNodesFromArray($context, $nodes); + $this->insertPage($context); + } + + return $context; + } + + /** + * @throws Exception + * @throws DoesNotExistException + * @throws MultipleObjectsReturnedException + */ + public function update(int $contextId, string $userId, ?string $name, ?string $iconName, ?string $description, ?array $nodes): Context { + $context = $this->contextMapper->findById($contextId, $userId); + + if ($name !== null) { + $context->setName(trim($name)); + } + if ($iconName !== null) { + $context->setIcon(trim($iconName)); + } + if ($description !== null) { + $context->setDescription(trim($description)); + } + + $hasUpdatedNodeInformation = false; + if ($nodes !== null) { + $currentNodes = $context->getNodes(); + $currentPages = $context->getPages(); + + $nodesBeingRemoved = []; + $nodesBeingAdded = []; + $nodesBeingKept = []; + + // new node relationships do not have an ID. We can recognize them + // through their nodeType and nodeIds. For this we need to transform + // the known relationships` keys to a compatible format. + $oldNodeResolvableIdMapper = []; + foreach ($currentNodes as $i => $oldNode) { + $key = sprintf('t%di%d', $oldNode['node_type'], $oldNode['node_id']); + $oldNodeResolvableIdMapper[$key] = $i; + } + + foreach ($nodes as $node) { + $key = sprintf('t%di%d', $node['type'], $node['id']); + if (isset($oldNodeResolvableIdMapper[$key])) { + unset($oldNodeResolvableIdMapper[$key]); + $nodesBeingKept[$key] = $node; + continue; + } + $nodesBeingAdded[$key] = $node; + } + + foreach (array_diff_key($oldNodeResolvableIdMapper, $nodesBeingAdded, $nodesBeingKept) as $toRemoveId) { + $nodesBeingRemoved[$toRemoveId] = $currentNodes[$toRemoveId]; + } + unset($nodesBeingKept); + + $hasUpdatedNodeInformation = !empty($nodesBeingAdded) || !empty($nodesBeingRemoved); + + foreach ($nodesBeingRemoved as $node) { + /** @var ContextNodeRelation $removedNode */ + /** @var PageContent[] $removedContents */ + [$removedNode, $removedContents] = $this->removeNodeFromContextAndPages($node['id']); + foreach ($removedContents as $removedContent) { + unset($currentPages[$removedContent->getPageId()]['content'][$removedContent->getId()]); + } + unset($currentNodes[$removedNode->getId()]); + } + unset($nodesBeingRemoved); + + foreach ($nodesBeingAdded as $node) { + /** @var ContextNodeRelation $addedNode */ + /** @var PageContent $updatedContent */ + [$addedNode, $updatedContent] = $this->addNodeToContextAndStartpage( + $contextId, + $node['id'], + $node['type'], + $node['permissions'], + $node['order'] ?? 100, + $userId + ); + $currentNodes[$addedNode->getId()] = $addedNode->jsonSerialize(); + $currentPages[$updatedContent->getPageId()]['content'][$updatedContent->getId()] = $updatedContent->jsonSerialize(); + } + unset($nodesBeingAdded); + } + + $context = $this->contextMapper->update($context); + if ($hasUpdatedNodeInformation && isset($currentNodes) && isset($currentPages)) { + $context->setNodes($currentNodes); + $context->setPages($currentPages); + } + return $context; + } + + /** + * @throws NotFoundError + * @throws Exception + */ + public function delete(int $contextId, string $userId): Context { + $context = $this->contextMapper->findById($contextId, $userId); + return $this->contextMapper->delete($context); + } + + /** + * @throws MultipleObjectsReturnedException + * @throws DoesNotExistException + * @throws Exception + * @throws BadRequestError + */ + public function transfer(int $contextId, string $newOwnerId, int $newOwnerType): Context { + $context = $this->contextMapper->findById($contextId); + + // the owner type check can be dropped as soon as NC 29 is the lowest supported version, + // as the int range as defined in the Controller will be enforced by the Http/Dispatcher. + if ($newOwnerType !== Application::OWNER_TYPE_USER) { + throw new BadRequestError('Unsupported owner type'); + } + + if (!$this->userManager->userExists($newOwnerId)) { + throw new BadRequestError('User does not exist'); + } + + $context->setOwnerId($newOwnerId); + $context->setOwnerType($newOwnerType); + + $context = $this->contextMapper->update($context); + + $auditEvent = new CriticalActionPerformedEvent( + sprintf('Tables application with ID %d was transferred to user %s', + $contextId, $newOwnerId, + ) + ); + + $this->eventDispatcher->dispatchTyped($auditEvent); + + return $context; + } + + /** + * @throws MultipleObjectsReturnedException + * @throws DoesNotExistException + * @throws Exception + */ + public function addNodeToContextById(int $contextId, int $nodeId, int $nodeType, int $permissions, ?string $userId): ContextNodeRelation { + $context = $this->contextMapper->findById($contextId, $userId); + return $this->addNodeToContext($context, $nodeId, $nodeType, $permissions); + } + + /** + * @throws Exception + */ + public function removeNodeFromContext(ContextNodeRelation $nodeRelation): ContextNodeRelation { + return $this->contextNodeRelMapper->delete($nodeRelation); + } + + /** + * @throws DoesNotExistException + * @throws MultipleObjectsReturnedException + * @throws Exception + */ + public function removeNodeFromContextById(int $nodeRelationId): ContextNodeRelation { + $nodeRelation = $this->contextNodeRelMapper->findById($nodeRelationId); + return $this->contextNodeRelMapper->delete($nodeRelation); + } + + /** + * @throws MultipleObjectsReturnedException + * @throws DoesNotExistException + * @throws Exception + */ + public function addNodeToContextAndStartpage(int $contextId, int $nodeId, int $nodeType, int $permissions, int $order, string $userId): array { + $relation = $this->addNodeToContextById($contextId, $nodeId, $nodeType, $permissions, $userId); + $pageContent = $this->addNodeRelToPage($relation, $order); + return [$relation, $pageContent]; + } + + /** + * @throws DoesNotExistException + * @throws MultipleObjectsReturnedException + * @throws Exception + */ + public function removeNodeFromContextAndPages(int $nodeRelationId): array { + $nodeRelation = $this->removeNodeFromContextById($nodeRelationId); + $contents = $this->removeNodeRelFromAllPages($nodeRelation); + return [$nodeRelation, $contents]; + } + + /** + * @throws Exception + */ + public function addNodeToContext(Context $context, int $nodeId, int $nodeType, int $permissions): ContextNodeRelation { + $contextNodeRel = new ContextNodeRelation(); + $contextNodeRel->setContextId($context->getId()); + $contextNodeRel->setNodeId($nodeId); + $contextNodeRel->setNodeType($nodeType); + $contextNodeRel->setPermissions($permissions); + + return $this->contextNodeRelMapper->insert($contextNodeRel); + } + + public function addNodeRelToPage(ContextNodeRelation $nodeRel, int $order = null, ?int $pageId = null): PageContent { + if ($pageId === null) { + // when no page is given, find the startpage to add it to + $context = $this->contextMapper->findById($nodeRel->getContextId()); + $pages = $context->getPages(); + foreach ($pages as $page) { + if ($page['page_type'] === 'startpage') { + $pageId = $page['id']; + break; + } + } + } + + $pageContent = $this->pageContentMapper->findByPageAndNodeRelation($pageId, $nodeRel->getId()); + + if ($pageContent === null) { + $pageContent = new PageContent(); + $pageContent->setPageId($pageId); + $pageContent->setNodeRelId($nodeRel->getId()); + $pageContent->setOrder($order ?? 100); //FIXME: demand or calc order + + $pageContent = $this->pageContentMapper->insert($pageContent); + } + return $pageContent; + } + + public function removeNodeRelFromAllPages(ContextNodeRelation $nodeRelation): array { + $contents = $this->pageContentMapper->findByNodeRelation($nodeRelation->getId()); + /** @var PageContent $content */ + foreach ($contents as $content) { + try { + $this->pageContentMapper->delete($content); + } catch (Exception $e) { + $this->logger->warning('Failed to delete Contexts page content with ID {pcId}', [ + 'pcId' => $content->getId(), + 'exception' => $e, + ]); + } + } + return $contents; + } + + public function updateContentOrder(int $pageId, array $contents): array { + $updated = []; + foreach ($contents as $content) { + try { + $updated[] = $this->updatePageContent($pageId, $content['id'], $content['order']); + } catch (DoesNotExistException|MultipleObjectsReturnedException|Exception|InvalidArgumentException $e) { + $this->logger->info('Could not updated order of content with ID {cID}', [ + 'cID' => $content['id'], + 'exception' => $e, + ]); + } + } + return $updated; + } + + /** + * @throws MultipleObjectsReturnedException + * @throws DoesNotExistException + * @throws Exception + * @throws InvalidArgumentException + */ + protected function updatePageContent(int $pageId, int $contentId, int $order): PageContent { + $pageContent = $this->pageContentMapper->findById($contentId); + if ($pageContent->getPageId() !== $pageId) { + throw new InvalidArgumentException('Content does not belong to given page'); + } + $pageContent->setOrder($order); + return $this->pageContentMapper->update($pageContent); + } + + protected function insertPage(Context $context): void { + $page = new Page(); + $page->setContextId($context->getId()); + $page->setPageType(Page::TYPE_STARTPAGE); + $this->pageMapper->insert($page); + + $addedPage = $page->jsonSerialize(); + + $i = 1; + foreach ($context->getNodes() as $node) { + $pageContent = new PageContent(); + $pageContent->setPageId($page->getId()); + $pageContent->setNodeRelId($node['id']); + $pageContent->setOrder(10 * $i++); + + $this->pageContentMapper->insert($pageContent); + + $addedPage['content'][$pageContent->getId()] = $pageContent->jsonSerialize(); + // the content is already embedded in the page + unset($addedPage['content'][$pageContent->getId()]['pageId']); + } + + $context->setPages($addedPage); + } + + protected function insertNodesFromArray(Context $context, array $nodes): void { + $addedNodes = []; + + $userId = $context->getOwnerType() === Application::OWNER_TYPE_USER ? $context->getOwnerId() : null; + foreach ($nodes as $node) { + try { + if (!$this->permissionsService->canManageNodeById($node['type'], $node['id'], $userId)) { + throw new PermissionError(sprintf('Owner cannot manage node %d (type %d)', $node['id'], $node['type'])); + } + $contextNodeRel = $this->addNodeToContext($context, $node['id'], $node['type'], $node['permissions'] ?? 660); + $addedNodes[] = $contextNodeRel->jsonSerialize(); + } catch (Exception $e) { + $this->logger->warning('Could not add node {ntype}/{nid} to context {cid}, skipping.', [ + 'app' => Application::APP_ID, + 'ntype' => $node['type'], + 'nid' => $node['id'], + 'cid' => $context['id'], + 'exception' => $e, + ]); + } + } + $context->setNodes($addedNodes); + } +} diff --git a/lib/Service/PermissionsService.php b/lib/Service/PermissionsService.php index 8911867bd..922bd4685 100644 --- a/lib/Service/PermissionsService.php +++ b/lib/Service/PermissionsService.php @@ -3,6 +3,7 @@ namespace OCA\Tables\Service; use OCA\Tables\AppInfo\Application; +use OCA\Tables\Db\ContextMapper; use OCA\Tables\Db\Share; use OCA\Tables\Db\ShareMapper; use OCA\Tables\Db\Table; @@ -31,8 +32,18 @@ class PermissionsService { protected ?string $userId = null; protected bool $isCli = false; - - public function __construct(LoggerInterface $logger, ?string $userId, TableMapper $tableMapper, ViewMapper $viewMapper, ShareMapper $shareMapper, UserHelper $userHelper, bool $isCLI) { + private ContextMapper $contextMapper; + + public function __construct( + LoggerInterface $logger, + ?string $userId, + TableMapper $tableMapper, + ViewMapper $viewMapper, + ShareMapper $shareMapper, + ContextMapper $contextMapper, + UserHelper $userHelper, + bool $isCLI + ) { $this->tableMapper = $tableMapper; $this->viewMapper = $viewMapper; $this->shareMapper = $shareMapper; @@ -40,6 +51,7 @@ public function __construct(LoggerInterface $logger, ?string $userId, TableMappe $this->logger = $logger; $this->userId = $userId; $this->isCli = $isCLI; + $this->contextMapper = $contextMapper; } @@ -118,6 +130,28 @@ public function canManageNodeById(int $nodeType, int $nodeId, ?string $userId = return false; } + public function canManageContextById(int $contextId, ?string $userId = null): bool { + try { + $context = $this->contextMapper->findById($contextId, $userId); + } catch (DoesNotExistException $e) { + $this->logger->warning('Context does not exist'); + return false; + } catch (MultipleObjectsReturnedException $e) { + $this->logger->warning('Multiple contexts found for this ID'); + return false; + } catch (Exception $e) { + $this->logger->warning($e->getMessage()); + return false; + } + + if ($context->getOwnerType() !== Application::OWNER_TYPE_USER) { + $this->logger->warning('Unsupported owner type'); + return false; + } + + return $context->getOwnerId() === $userId; + } + public function canAccessView(View $view, ?string $userId = null): bool { if($this->basisCheck($view, 'view', $userId)) { return true; diff --git a/openapi.json b/openapi.json index 864136c15..5a96f7ff9 100644 --- a/openapi.json +++ b/openapi.json @@ -175,6 +175,39 @@ } } }, + "Context": { + "type": "object", + "required": [ + "id", + "name", + "iconName", + "description", + "owner", + "ownerType" + ], + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "name": { + "type": "string" + }, + "iconName": { + "type": "string" + }, + "description": { + "type": "string" + }, + "owner": { + "type": "string" + }, + "ownerType": { + "type": "integer", + "format": "int64" + } + } + }, "ImportState": { "type": "object", "required": [ @@ -7852,6 +7885,1535 @@ } } } + }, + "/ocs/v2.php/apps/tables/api/2/contexts": { + "get": { + "operationId": "context-list", + "summary": "[api v3] Get all contexts available to the requesting person", + "description": "Return an empty array if no contexts were found", + "tags": [ + "context" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "reporting in available contexts", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Context" + } + } + } + } + } + } + } + } + }, + "500": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "message" + ], + "properties": { + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + } + } + }, + "post": { + "operationId": "context-create", + "summary": "[api v2] Create a new context and return it", + "tags": [ + "context" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "name", + "in": "query", + "description": "Name of the context", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "iconName", + "in": "query", + "description": "Material design icon name of the context", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "description", + "in": "query", + "description": "Descriptive text of the context", + "schema": { + "type": "string", + "default": "" + } + }, + { + "name": "nodes", + "in": "query", + "description": "optional nodes to be connected to this context", + "schema": { + "default": [], + "oneOf": [ + { + "type": "object", + "required": [ + "id", + "type", + "permissions" + ], + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "type": { + "type": "integer", + "format": "int64" + }, + "permissions": { + "type": "integer", + "format": "int64" + } + } + }, + { + "type": "array", + "maxLength": 0 + } + ] + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "returning the full context information", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "$ref": "#/components/schemas/Context" + } + } + } + } + } + } + } + }, + "500": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "message" + ], + "properties": { + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/tables/api/2/contexts/{contextId}": { + "get": { + "operationId": "context-show", + "summary": "[api v2] Get information about the requests context", + "tags": [ + "context" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "contextId", + "in": "path", + "description": "ID of the context", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "returning the full context information", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "$ref": "#/components/schemas/Context" + } + } + } + } + } + } + } + }, + "500": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "message" + ], + "properties": { + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + }, + "404": { + "description": "context not found or not available anymore", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "message" + ], + "properties": { + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + } + } + }, + "put": { + "operationId": "context-update", + "summary": "[api v2] Update an existing context and return it", + "tags": [ + "context" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "name", + "in": "query", + "description": "provide this parameter to set a new name", + "schema": { + "type": "string", + "nullable": true + } + }, + { + "name": "iconName", + "in": "query", + "description": "provide this parameter to set a new icon", + "schema": { + "type": "string", + "nullable": true + } + }, + { + "name": "description", + "in": "query", + "description": "provide this parameter to set a new description", + "schema": { + "type": "string", + "nullable": true + } + }, + { + "name": "nodes", + "in": "query", + "description": "provide this parameter to set a new list of nodes.", + "schema": { + "type": "string", + "nullable": true + } + }, + { + "name": "contextId", + "in": "path", + "description": "ID of the context", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "returning the full context information", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "$ref": "#/components/schemas/Context" + } + } + } + } + } + } + } + }, + "500": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "message" + ], + "properties": { + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "message" + ], + "properties": { + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + } + } + }, + "delete": { + "operationId": "context-destroy", + "summary": "[api v2] Delete an existing context and return it", + "tags": [ + "context" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "contextId", + "in": "path", + "description": "ID of the context", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "returning the full context information", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "$ref": "#/components/schemas/Context" + } + } + } + } + } + } + } + }, + "500": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "message" + ], + "properties": { + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "message" + ], + "properties": { + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/tables/api/2/contexts/{contextId}/transfer": { + "put": { + "operationId": "context-transfer", + "summary": "[api v2] Transfer the ownership of a context and return it", + "tags": [ + "context" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "newOwnerId", + "in": "query", + "description": "ID of the new owner", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "newOwnerType", + "in": "query", + "description": "any Application::OWNER_TYPE_* constant", + "schema": { + "type": "integer", + "format": "int64", + "default": 0, + "minimum": 0, + "maximum": 0 + } + }, + { + "name": "contextId", + "in": "path", + "description": "ID of the context", + "required": true, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Ownership transferred", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "$ref": "#/components/schemas/Context" + } + } + } + } + } + } + } + }, + "500": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "message" + ], + "properties": { + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "message" + ], + "properties": { + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + }, + "400": { + "description": "Invalid request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "message" + ], + "properties": { + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/tables/api/2/contexts/{contextId}/nodes": { + "post": { + "operationId": "context-add-node", + "summary": "[api v2] Add a node to a Context", + "tags": [ + "context" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "nodeId", + "in": "query", + "description": "ID of the node", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "nodeType", + "in": "query", + "description": "any Application::NODE_TYPE_* constant", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "permissions", + "in": "query", + "description": "bitmask of the permissions for context recipients", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "order", + "in": "query", + "description": "in which order the node should appear within the context", + "schema": { + "type": "integer", + "format": "int64", + "nullable": true + } + }, + { + "name": "contextId", + "in": "path", + "description": "ID of the context", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Node added successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "$ref": "#/components/schemas/Context" + } + } + } + } + } + } + } + }, + "500": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "message" + ], + "properties": { + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "message" + ], + "properties": { + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/tables/api/2/contexts/{contextId}/nodes/{nodeRelId}": { + "delete": { + "operationId": "context-remove-node", + "summary": "[api v2] Remove a node from a Context", + "tags": [ + "context" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "contextId", + "in": "path", + "description": "ID of the context", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "nodeRelId", + "in": "path", + "description": "ID of the node-in-context relation", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Node removed successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "$ref": "#/components/schemas/Context" + } + } + } + } + } + } + } + }, + "500": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "message" + ], + "properties": { + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "message" + ], + "properties": { + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + }, + "400": { + "description": "Invalid request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "message" + ], + "properties": { + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/tables/api/2/contexts/{contextId}/pages/{pageId}": { + "put": { + "operationId": "context-update-content-order", + "summary": "[api v2] Update the order on a page of a context", + "tags": [ + "context" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "content", + "in": "query", + "description": "content items with it and order values", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "contextId", + "in": "path", + "description": "ID of the context", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "pageId", + "in": "path", + "description": "ID of the page", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "content updated successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "$ref": "#/components/schemas/Context" + } + } + } + } + } + } + } + }, + "500": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "message" + ], + "properties": { + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "message" + ], + "properties": { + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + }, + "400": { + "description": "Invalid request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "message" + ], + "properties": { + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + } + } + } } }, "tags": [] diff --git a/psalm.xml b/psalm.xml index dc1fbe1d2..651516ea3 100644 --- a/psalm.xml +++ b/psalm.xml @@ -34,7 +34,9 @@ + + diff --git a/src/App.vue b/src/App.vue index 383b2b884..52fd243aa 100644 --- a/src/App.vue +++ b/src/App.vue @@ -38,9 +38,9 @@ export default { } }, computed: { - ...mapState(['tablesLoading']), + ...mapState(['tablesLoading', 'contextsLoading']), somethingIsLoading() { - return this.tablesLoading || this.loading + return this.tablesLoading || this.contextsLoading || this.loading }, }, watch: { @@ -50,6 +50,7 @@ export default { }, async created() { await this.$store.dispatch('loadTablesFromBE') + await this.$store.dispatch('getAllContexts') await this.$store.dispatch('loadViewsSharedWithMeFromBE') this.routing(this.$router.currentRoute) this.observeAppContent() @@ -67,6 +68,9 @@ export default { } else if (currentRoute.path.startsWith('/view/')) { this.$store.commit('setActiveViewId', parseInt(currentRoute.params.viewId)) this.setPageTitle(this.$store.getters.activeView.title) + } else if (currentRoute.path.startsWith('/application/')) { + this.$store.commit('setActiveContextId', parseInt(currentRoute.params.contextId)) + this.setPageTitle(this.$store.getters.activeContext.name) } }, setPageTitle(title) { diff --git a/src/modules/main/sections/DataTable.vue b/src/modules/main/sections/DataTable.vue index 969d86fdb..9b1ee6547 100644 --- a/src/modules/main/sections/DataTable.vue +++ b/src/modules/main/sections/DataTable.vue @@ -1,7 +1,7 @@
@@ -76,6 +76,7 @@ +