diff --git a/docker-compose.yml b/docker-compose.yml
index 06f4211..c79b452 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -8,7 +8,7 @@ services:
- "127.0.0.1:4566:4566" # LocalStack Edge Proxy
environment:
- DEBUG=${DEBUG:-0}
- - SERVICES=sns,sqs,s3,lambda,dynamodb,kinesis,kms
+ - SERVICES=sns,sqs,s3,ses,lambda,dynamodb,kinesis,kms
- DISABLE_CORS_CHECKS=1
- DISABLE_CORS_HANDLERS=1
- SKIP_CORS_PREFLIGHT=1
diff --git a/package-lock.json b/package-lock.json
index 5a165a5..c0d5cc5 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -13,6 +13,7 @@
"@aws-sdk/client-kms": "^3.400.0",
"@aws-sdk/client-lambda": "^3.400.0",
"@aws-sdk/client-s3": "^3.400.0",
+ "@aws-sdk/client-ses": "^3.839.0",
"@aws-sdk/client-sns": "^3.400.0",
"@aws-sdk/client-sqs": "^3.400.0",
"@mdi/font": "^7.4.0",
@@ -546,6 +547,378 @@
"uuid": "dist/bin/uuid"
}
},
+ "node_modules/@aws-sdk/client-ses": {
+ "version": "3.839.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/client-ses/-/client-ses-3.839.0.tgz",
+ "integrity": "sha512-y6JqloPDS1yin71nH5r9KnBBBaJRXtYC1h6WzLBm99nfHjP9qK00JBjO3gRAds+eii9U4kTN2bfT0+1jWMNEuw==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@aws-crypto/sha256-browser": "5.2.0",
+ "@aws-crypto/sha256-js": "5.2.0",
+ "@aws-sdk/core": "3.839.0",
+ "@aws-sdk/credential-provider-node": "3.839.0",
+ "@aws-sdk/middleware-host-header": "3.821.0",
+ "@aws-sdk/middleware-logger": "3.821.0",
+ "@aws-sdk/middleware-recursion-detection": "3.821.0",
+ "@aws-sdk/middleware-user-agent": "3.839.0",
+ "@aws-sdk/region-config-resolver": "3.821.0",
+ "@aws-sdk/types": "3.821.0",
+ "@aws-sdk/util-endpoints": "3.828.0",
+ "@aws-sdk/util-user-agent-browser": "3.821.0",
+ "@aws-sdk/util-user-agent-node": "3.839.0",
+ "@smithy/config-resolver": "^4.1.4",
+ "@smithy/core": "^3.6.0",
+ "@smithy/fetch-http-handler": "^5.0.4",
+ "@smithy/hash-node": "^4.0.4",
+ "@smithy/invalid-dependency": "^4.0.4",
+ "@smithy/middleware-content-length": "^4.0.4",
+ "@smithy/middleware-endpoint": "^4.1.13",
+ "@smithy/middleware-retry": "^4.1.14",
+ "@smithy/middleware-serde": "^4.0.8",
+ "@smithy/middleware-stack": "^4.0.4",
+ "@smithy/node-config-provider": "^4.1.3",
+ "@smithy/node-http-handler": "^4.0.6",
+ "@smithy/protocol-http": "^5.1.2",
+ "@smithy/smithy-client": "^4.4.5",
+ "@smithy/types": "^4.3.1",
+ "@smithy/url-parser": "^4.0.4",
+ "@smithy/util-base64": "^4.0.0",
+ "@smithy/util-body-length-browser": "^4.0.0",
+ "@smithy/util-body-length-node": "^4.0.0",
+ "@smithy/util-defaults-mode-browser": "^4.0.21",
+ "@smithy/util-defaults-mode-node": "^4.0.21",
+ "@smithy/util-endpoints": "^3.0.6",
+ "@smithy/util-middleware": "^4.0.4",
+ "@smithy/util-retry": "^4.0.6",
+ "@smithy/util-utf8": "^4.0.0",
+ "@smithy/util-waiter": "^4.0.6",
+ "tslib": "^2.6.2"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/client-sso": {
+ "version": "3.839.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.839.0.tgz",
+ "integrity": "sha512-AZABysUhbfcwXVlMo97/vwHgsfJNF81wypCAowpqAJkSjP2KrqsqHpb71/RoR2w8JGmEnBBXRD4wIxDhnmifWg==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@aws-crypto/sha256-browser": "5.2.0",
+ "@aws-crypto/sha256-js": "5.2.0",
+ "@aws-sdk/core": "3.839.0",
+ "@aws-sdk/middleware-host-header": "3.821.0",
+ "@aws-sdk/middleware-logger": "3.821.0",
+ "@aws-sdk/middleware-recursion-detection": "3.821.0",
+ "@aws-sdk/middleware-user-agent": "3.839.0",
+ "@aws-sdk/region-config-resolver": "3.821.0",
+ "@aws-sdk/types": "3.821.0",
+ "@aws-sdk/util-endpoints": "3.828.0",
+ "@aws-sdk/util-user-agent-browser": "3.821.0",
+ "@aws-sdk/util-user-agent-node": "3.839.0",
+ "@smithy/config-resolver": "^4.1.4",
+ "@smithy/core": "^3.6.0",
+ "@smithy/fetch-http-handler": "^5.0.4",
+ "@smithy/hash-node": "^4.0.4",
+ "@smithy/invalid-dependency": "^4.0.4",
+ "@smithy/middleware-content-length": "^4.0.4",
+ "@smithy/middleware-endpoint": "^4.1.13",
+ "@smithy/middleware-retry": "^4.1.14",
+ "@smithy/middleware-serde": "^4.0.8",
+ "@smithy/middleware-stack": "^4.0.4",
+ "@smithy/node-config-provider": "^4.1.3",
+ "@smithy/node-http-handler": "^4.0.6",
+ "@smithy/protocol-http": "^5.1.2",
+ "@smithy/smithy-client": "^4.4.5",
+ "@smithy/types": "^4.3.1",
+ "@smithy/url-parser": "^4.0.4",
+ "@smithy/util-base64": "^4.0.0",
+ "@smithy/util-body-length-browser": "^4.0.0",
+ "@smithy/util-body-length-node": "^4.0.0",
+ "@smithy/util-defaults-mode-browser": "^4.0.21",
+ "@smithy/util-defaults-mode-node": "^4.0.21",
+ "@smithy/util-endpoints": "^3.0.6",
+ "@smithy/util-middleware": "^4.0.4",
+ "@smithy/util-retry": "^4.0.6",
+ "@smithy/util-utf8": "^4.0.0",
+ "tslib": "^2.6.2"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/core": {
+ "version": "3.839.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.839.0.tgz",
+ "integrity": "sha512-KdwL5RaK7eUIlOpdOoZ5u+2t4X1rdX/MTZgz3IV/aBzjVUoGsp+uUnbyqXomLQSUitPHp72EE/NHDsvWW/IHvQ==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@aws-sdk/types": "3.821.0",
+ "@aws-sdk/xml-builder": "3.821.0",
+ "@smithy/core": "^3.6.0",
+ "@smithy/node-config-provider": "^4.1.3",
+ "@smithy/property-provider": "^4.0.4",
+ "@smithy/protocol-http": "^5.1.2",
+ "@smithy/signature-v4": "^5.1.2",
+ "@smithy/smithy-client": "^4.4.5",
+ "@smithy/types": "^4.3.1",
+ "@smithy/util-base64": "^4.0.0",
+ "@smithy/util-body-length-browser": "^4.0.0",
+ "@smithy/util-middleware": "^4.0.4",
+ "@smithy/util-utf8": "^4.0.0",
+ "fast-xml-parser": "4.4.1",
+ "tslib": "^2.6.2"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/credential-provider-env": {
+ "version": "3.839.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.839.0.tgz",
+ "integrity": "sha512-cWTadewPPz1OvObZJB+olrgh8VwcgIVcT293ZUT9V0CMF0UU7QaPwJP7uNXcNxltTh+sk1yhjH4UlcnJigZZbA==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@aws-sdk/core": "3.839.0",
+ "@aws-sdk/types": "3.821.0",
+ "@smithy/property-provider": "^4.0.4",
+ "@smithy/types": "^4.3.1",
+ "tslib": "^2.6.2"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/credential-provider-http": {
+ "version": "3.839.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.839.0.tgz",
+ "integrity": "sha512-fv0BZwrDhWDju4D1MCLT4I2aPjr0dVQ6P+MpqvcGNOA41Oa9UdRhYTV5iuy5NLXzIzoCmnS+XfSq5Kbsf6//xw==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@aws-sdk/core": "3.839.0",
+ "@aws-sdk/types": "3.821.0",
+ "@smithy/fetch-http-handler": "^5.0.4",
+ "@smithy/node-http-handler": "^4.0.6",
+ "@smithy/property-provider": "^4.0.4",
+ "@smithy/protocol-http": "^5.1.2",
+ "@smithy/smithy-client": "^4.4.5",
+ "@smithy/types": "^4.3.1",
+ "@smithy/util-stream": "^4.2.2",
+ "tslib": "^2.6.2"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/credential-provider-ini": {
+ "version": "3.839.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.839.0.tgz",
+ "integrity": "sha512-GHm0hF4CiDxIDR7TauMaA6iI55uuSqRxMBcqTAHaTPm6+h1A+MS+ysQMxZ+Jvwtoy8WmfTIGrJVxSCw0sK2hvA==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@aws-sdk/core": "3.839.0",
+ "@aws-sdk/credential-provider-env": "3.839.0",
+ "@aws-sdk/credential-provider-http": "3.839.0",
+ "@aws-sdk/credential-provider-process": "3.839.0",
+ "@aws-sdk/credential-provider-sso": "3.839.0",
+ "@aws-sdk/credential-provider-web-identity": "3.839.0",
+ "@aws-sdk/nested-clients": "3.839.0",
+ "@aws-sdk/types": "3.821.0",
+ "@smithy/credential-provider-imds": "^4.0.6",
+ "@smithy/property-provider": "^4.0.4",
+ "@smithy/shared-ini-file-loader": "^4.0.4",
+ "@smithy/types": "^4.3.1",
+ "tslib": "^2.6.2"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/credential-provider-node": {
+ "version": "3.839.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.839.0.tgz",
+ "integrity": "sha512-7bR+U2h+ft0V8chyeu9Bh/pvau4ZkQMeRt5f0dAULoepZQ77QQVRP4H04yJPTg9DCtqbVULQ3uf5YOp1/08vQw==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@aws-sdk/credential-provider-env": "3.839.0",
+ "@aws-sdk/credential-provider-http": "3.839.0",
+ "@aws-sdk/credential-provider-ini": "3.839.0",
+ "@aws-sdk/credential-provider-process": "3.839.0",
+ "@aws-sdk/credential-provider-sso": "3.839.0",
+ "@aws-sdk/credential-provider-web-identity": "3.839.0",
+ "@aws-sdk/types": "3.821.0",
+ "@smithy/credential-provider-imds": "^4.0.6",
+ "@smithy/property-provider": "^4.0.4",
+ "@smithy/shared-ini-file-loader": "^4.0.4",
+ "@smithy/types": "^4.3.1",
+ "tslib": "^2.6.2"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/credential-provider-process": {
+ "version": "3.839.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.839.0.tgz",
+ "integrity": "sha512-qShpekjociUZ+isyQNa0P7jo+0q3N2+0eJDg8SGyP6K6hHTcGfiqxTDps+IKl6NreCPhZCBzyI9mWkP0xSDR6g==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@aws-sdk/core": "3.839.0",
+ "@aws-sdk/types": "3.821.0",
+ "@smithy/property-provider": "^4.0.4",
+ "@smithy/shared-ini-file-loader": "^4.0.4",
+ "@smithy/types": "^4.3.1",
+ "tslib": "^2.6.2"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/credential-provider-sso": {
+ "version": "3.839.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.839.0.tgz",
+ "integrity": "sha512-w10zBLHhU8SBQcdrSPMI02haLoRGZg+gP7mH/Er8VhIXfHefbr7o4NirmB0hwdw/YAH8MLlC9jj7c2SJlsNhYA==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@aws-sdk/client-sso": "3.839.0",
+ "@aws-sdk/core": "3.839.0",
+ "@aws-sdk/token-providers": "3.839.0",
+ "@aws-sdk/types": "3.821.0",
+ "@smithy/property-provider": "^4.0.4",
+ "@smithy/shared-ini-file-loader": "^4.0.4",
+ "@smithy/types": "^4.3.1",
+ "tslib": "^2.6.2"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/credential-provider-web-identity": {
+ "version": "3.839.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.839.0.tgz",
+ "integrity": "sha512-EvqTc7J1kgmiuxknpCp1S60hyMQvmKxsI5uXzQtcogl/N55rxiXEqnCLI5q6p33q91PJegrcMCM5Q17Afhm5qA==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@aws-sdk/core": "3.839.0",
+ "@aws-sdk/nested-clients": "3.839.0",
+ "@aws-sdk/types": "3.821.0",
+ "@smithy/property-provider": "^4.0.4",
+ "@smithy/types": "^4.3.1",
+ "tslib": "^2.6.2"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/middleware-user-agent": {
+ "version": "3.839.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.839.0.tgz",
+ "integrity": "sha512-2u74uRM1JWq6Sf7+3YpjejPM9YkomGt4kWhrmooIBEq1k5r2GTbkH7pNCxBQwBueXM21jAGVDxxeClpTx+5hig==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@aws-sdk/core": "3.839.0",
+ "@aws-sdk/types": "3.821.0",
+ "@aws-sdk/util-endpoints": "3.828.0",
+ "@smithy/core": "^3.6.0",
+ "@smithy/protocol-http": "^5.1.2",
+ "@smithy/types": "^4.3.1",
+ "tslib": "^2.6.2"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/nested-clients": {
+ "version": "3.839.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.839.0.tgz",
+ "integrity": "sha512-Glic0pg2THYP3aRhJORwJJBe1JLtJoEdWV/MFZNyzCklfMwEzpWtZAyxy+tQyFmMeW50uBAnh2R0jhMMcf257w==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@aws-crypto/sha256-browser": "5.2.0",
+ "@aws-crypto/sha256-js": "5.2.0",
+ "@aws-sdk/core": "3.839.0",
+ "@aws-sdk/middleware-host-header": "3.821.0",
+ "@aws-sdk/middleware-logger": "3.821.0",
+ "@aws-sdk/middleware-recursion-detection": "3.821.0",
+ "@aws-sdk/middleware-user-agent": "3.839.0",
+ "@aws-sdk/region-config-resolver": "3.821.0",
+ "@aws-sdk/types": "3.821.0",
+ "@aws-sdk/util-endpoints": "3.828.0",
+ "@aws-sdk/util-user-agent-browser": "3.821.0",
+ "@aws-sdk/util-user-agent-node": "3.839.0",
+ "@smithy/config-resolver": "^4.1.4",
+ "@smithy/core": "^3.6.0",
+ "@smithy/fetch-http-handler": "^5.0.4",
+ "@smithy/hash-node": "^4.0.4",
+ "@smithy/invalid-dependency": "^4.0.4",
+ "@smithy/middleware-content-length": "^4.0.4",
+ "@smithy/middleware-endpoint": "^4.1.13",
+ "@smithy/middleware-retry": "^4.1.14",
+ "@smithy/middleware-serde": "^4.0.8",
+ "@smithy/middleware-stack": "^4.0.4",
+ "@smithy/node-config-provider": "^4.1.3",
+ "@smithy/node-http-handler": "^4.0.6",
+ "@smithy/protocol-http": "^5.1.2",
+ "@smithy/smithy-client": "^4.4.5",
+ "@smithy/types": "^4.3.1",
+ "@smithy/url-parser": "^4.0.4",
+ "@smithy/util-base64": "^4.0.0",
+ "@smithy/util-body-length-browser": "^4.0.0",
+ "@smithy/util-body-length-node": "^4.0.0",
+ "@smithy/util-defaults-mode-browser": "^4.0.21",
+ "@smithy/util-defaults-mode-node": "^4.0.21",
+ "@smithy/util-endpoints": "^3.0.6",
+ "@smithy/util-middleware": "^4.0.4",
+ "@smithy/util-retry": "^4.0.6",
+ "@smithy/util-utf8": "^4.0.0",
+ "tslib": "^2.6.2"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/token-providers": {
+ "version": "3.839.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.839.0.tgz",
+ "integrity": "sha512-2nlafqdSbet/2WtYIoZ7KEGFowFonPBDYlTjrUvwU2yooE10VhvzhLSCTB2aKIVzo2Z2wL5WGFQsqAY5QwK6Bw==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@aws-sdk/core": "3.839.0",
+ "@aws-sdk/nested-clients": "3.839.0",
+ "@aws-sdk/types": "3.821.0",
+ "@smithy/property-provider": "^4.0.4",
+ "@smithy/shared-ini-file-loader": "^4.0.4",
+ "@smithy/types": "^4.3.1",
+ "tslib": "^2.6.2"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/util-user-agent-node": {
+ "version": "3.839.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.839.0.tgz",
+ "integrity": "sha512-MuunkIG1bJVMtTH7MbjXOrhHleU5wjHz5eCAUc6vj7M9rwol71nqjj9b8RLnkO5gsJcKc29Qk8iV6xQuzKWNMw==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@aws-sdk/middleware-user-agent": "3.839.0",
+ "@aws-sdk/types": "3.821.0",
+ "@smithy/node-config-provider": "^4.1.3",
+ "@smithy/types": "^4.3.1",
+ "tslib": "^2.6.2"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "peerDependencies": {
+ "aws-crt": ">=1.0.0"
+ },
+ "peerDependenciesMeta": {
+ "aws-crt": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@aws-sdk/client-sns": {
"version": "3.835.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/client-sns/-/client-sns-3.835.0.tgz",
diff --git a/package.json b/package.json
index 2304d7b..70254be 100644
--- a/package.json
+++ b/package.json
@@ -11,12 +11,13 @@
},
"dependencies": {
"@aws-sdk/client-dynamodb": "^3.400.0",
+ "@aws-sdk/client-kinesis": "^3.400.0",
+ "@aws-sdk/client-kms": "^3.400.0",
+ "@aws-sdk/client-lambda": "^3.400.0",
"@aws-sdk/client-s3": "^3.400.0",
- "@aws-sdk/client-sqs": "^3.400.0",
+ "@aws-sdk/client-ses": "^3.839.0",
"@aws-sdk/client-sns": "^3.400.0",
- "@aws-sdk/client-lambda": "^3.400.0",
- "@aws-sdk/client-kms": "^3.400.0",
- "@aws-sdk/client-kinesis": "^3.400.0",
+ "@aws-sdk/client-sqs": "^3.400.0",
"@mdi/font": "^7.4.0",
"axios": "^1.6.0",
"jszip": "^3.10.1",
diff --git a/src/App.vue b/src/App.vue
index 11e7b08..c4b969e 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -170,6 +170,7 @@ const menuItems = [
{ title: 'KMS Keys', icon: 'mdi-key', to: '/kms' },
{ title: 'Lambda Functions', icon: 'mdi-function', to: '/lambda' },
{ title: 'S3 Buckets', icon: 'mdi-folder-multiple', to: '/s3' },
+ { title: 'SES Emails', icon: 'mdi-email-multiple', to: '/ses' },
{ title: 'SNS Topics', icon: 'mdi-forum', to: '/sns' },
{ title: 'SQS Queues', icon: 'mdi-format-list-bulleted', to: '/sqs' },
]
diff --git a/src/router/routes.js b/src/router/routes.js
index de25dda..dbcdecb 100644
--- a/src/router/routes.js
+++ b/src/router/routes.js
@@ -7,6 +7,7 @@ import KinesisView from '@/views/KinesisView.vue'
import SNSView from '@/views/SNSView.vue'
import KMSView from '@/views/KMSView.vue'
import AboutView from '@/views/AboutView.vue'
+import SESView from '@/views/SESView.vue'
export default [
{
@@ -19,6 +20,11 @@ export default [
name: 'S3',
component: S3View
},
+ {
+ path: '/ses',
+ name: 'SES',
+ component: SESView
+ },
{
path: '/sqs',
name: 'SQS',
diff --git a/src/stores/app.js b/src/stores/app.js
index e8defe7..a6b6249 100644
--- a/src/stores/app.js
+++ b/src/stores/app.js
@@ -1,6 +1,7 @@
import { defineStore } from 'pinia'
import { ref } from 'vue'
import { S3Client } from '@aws-sdk/client-s3'
+import { SESClient} from '@aws-sdk/client-ses'
import { SNSClient } from '@aws-sdk/client-sns'
import { SQSClient } from '@aws-sdk/client-sqs'
import { DynamoDBClient } from '@aws-sdk/client-dynamodb'
@@ -35,6 +36,7 @@ export const useAppStore = defineStore('app', () => {
// Initialize AWS services
const s3 = ref(null)
+ const ses = ref(null)
const sns = ref(null)
const sqs = ref(null)
const dynamodb = ref(null)
@@ -53,6 +55,7 @@ export const useAppStore = defineStore('app', () => {
}
s3.value = new S3Client(config)
+ ses.value = new SESClient(config)
sns.value = new SNSClient(config)
sqs.value = new SQSClient(config)
dynamodb.value = new DynamoDBClient(config)
@@ -106,6 +109,7 @@ export const useAppStore = defineStore('app', () => {
connectionStatus,
snackbar,
s3,
+ ses,
sns,
sqs,
dynamodb,
diff --git a/src/utils/api.js b/src/utils/api.js
new file mode 100644
index 0000000..27bcd49
--- /dev/null
+++ b/src/utils/api.js
@@ -0,0 +1,25 @@
+import axios from 'axios'
+
+const api = axios.create({
+ baseURL: import.meta.env.VITE_LOCALSTACK_ENDPOINT || 'http://localhost:4566',
+ timeout: 10000, // 10 seconds
+})
+
+export const getSesData = async (params = {}) => {
+ try {
+ const response = await api.get('/_aws/ses', { params })
+ return response.data
+ } catch (error) {
+ console.error('Error fetching SES data:', error);
+ throw error
+ }
+}
+
+export const deleteSesMessage = async (params = {}) => {
+ try {
+ await api.delete('/_aws/ses', { params })
+ } catch (error) {
+ console.error('Error deleting SES message:', error);
+ throw error
+ }
+}
diff --git a/src/utils/formatDate.js b/src/utils/formatDate.js
new file mode 100644
index 0000000..5d72e20
--- /dev/null
+++ b/src/utils/formatDate.js
@@ -0,0 +1,4 @@
+export const formatDate = (date) => {
+ if (!date) return 'N/A'
+ return new Date(date).toLocaleString('pt-BR')
+}
diff --git a/src/views/Dashboard.vue b/src/views/Dashboard.vue
index 1252360..efb2556 100644
--- a/src/views/Dashboard.vue
+++ b/src/views/Dashboard.vue
@@ -15,7 +15,7 @@
:color="service.status === 'active' ? 'primary' : 'grey-lighten-2'"
:variant="service.status === 'active' ? 'elevated' : 'outlined'"
class="pa-4"
- height="120"
+ height="150"
@click="service.status === 'active' ? navigateToService(service.route): null"
style="cursor: pointer"
>
@@ -127,10 +127,12 @@ import { ListFunctionsCommand } from '@aws-sdk/client-lambda'
import { ListBucketsCommand, ListObjectsV2Command, DeleteObjectsCommand, DeleteBucketCommand } from '@aws-sdk/client-s3'
import { ListTopicsCommand } from '@aws-sdk/client-sns'
import { ListQueuesCommand, DeleteQueueCommand } from '@aws-sdk/client-sqs'
+import { ListIdentitiesCommand } from '@aws-sdk/client-ses'
+import { deleteSesMessage, getSesData } from '@/utils/api.js'
const router = useRouter()
const appStore = useAppStore()
-const { s3, sns, sqs, dynamodb, lambda, kinesis, kms } = storeToRefs(appStore)
+const { s3, ses, sns, sqs, dynamodb, lambda, kinesis, kms } = storeToRefs(appStore)
const services = ref([
{
@@ -168,6 +170,13 @@ const services = ref([
status: 'inactive',
stats: null
},
+ {
+ name: 'SES',
+ icon: 'mdi-email',
+ route: '/ses',
+ status: 'inactive',
+ stats: null
+ },
{
name: 'SNS',
icon: 'mdi-forum',
@@ -206,6 +215,13 @@ const quickActions = ref([
action: 'clearDynamoDB',
loading: false
},
+ {
+ title: 'Limpar SES',
+ icon: 'mdi-email-remove',
+ color: 'error',
+ action: 'clearSES',
+ loading: false
+ },
{
title: 'Atualizar Status',
icon: 'mdi-refresh',
@@ -290,28 +306,42 @@ const loadServiceStats = async () => {
services.value[4].status = 'inactive'
}
- // SNS Stats
+ // SES Stats
try {
- const snsTopics = await sns.value.send(new ListTopicsCommand({}))
+ const sesIdentities = await ses.value.send(new ListIdentitiesCommand({ IdentityType: 'EmailAddress' }))
+ const sesData = await getSesData();
services.value[5].status = 'active'
services.value[5].stats = {
+ 'E-mails': sesData.messages ? sesData.messages.length : 0,
+ 'Identidades': sesIdentities.Identities ? sesIdentities.Identities.length : 0
+ }
+ } catch (error) {
+ console.error('SES error:', error)
+ services.value[5].status = 'inactive'
+ }
+
+ // SNS Stats
+ try {
+ const snsTopics = await sns.value.send(new ListTopicsCommand({}))
+ services.value[6].status = 'active'
+ services.value[6].stats = {
'Tópicos': snsTopics.Topics ? snsTopics.Topics.length : 0
}
} catch (error) {
console.error('SNS error:', error)
- services.value[5].status = 'inactive'
+ services.value[6].status = 'inactive'
}
// SQS Stats
try {
const sqsQueues = await sqs.value.send(new ListQueuesCommand({}))
- services.value[6].status = 'active'
- services.value[6].stats = {
+ services.value[7].status = 'active'
+ services.value[7].stats = {
'Filas': sqsQueues.QueueUrls ? sqsQueues.QueueUrls.length : 0
}
} catch (error) {
console.error('SQS error:', error)
- services.value[6].status = 'inactive'
+ services.value[7].status = 'inactive'
}
} catch (error) {
@@ -344,6 +374,11 @@ const executeQuickAction = (action) => {
text = 'Esta ação irá deletar todas as filas SQS. Deseja continuar?'
color = 'warning'
break
+ case 'clearSES':
+ title = 'Limpar todos os emails SES'
+ text = 'Esta ação irá deletar todos os emails do SES. Deseja continuar?'
+ color = 'error'
+ break
case 'clearDynamoDB':
title = 'Limpar todas as tabelas DynamoDB'
text = 'Esta ação irá deletar todas as tabelas DynamoDB. Deseja continuar?'
@@ -373,6 +408,9 @@ const performClearAction = async (action) => {
case 'clearSQS':
await clearAllSQSQueues()
break
+ case 'clearSES':
+ await clearAllSESData()
+ break
case 'clearDynamoDB':
await clearAllDynamoDBTables()
break
@@ -422,6 +460,10 @@ const clearAllSQSQueues = async () => {
}
}
+const clearAllSESData = async () => {
+ await deleteSesMessage()
+}
+
const clearAllDynamoDBTables = async () => {
const tables = await dynamodb.value.send(new ListTablesCommand({}))
diff --git a/src/views/DynamoDBView.vue b/src/views/DynamoDBView.vue
index 48000ab..b87503d 100644
--- a/src/views/DynamoDBView.vue
+++ b/src/views/DynamoDBView.vue
@@ -304,6 +304,7 @@ import {
DeleteItemCommand,
PutItemCommand
} from '@aws-sdk/client-dynamodb'
+import { formatDate } from '../utils/formatDate.js'
const appStore = useAppStore()
const { dynamodb } = storeToRefs(appStore)
@@ -622,10 +623,6 @@ const getStatusColor = (status) => {
}
}
-const formatDate = (date) => {
- return new Date(date).toLocaleString('pt-BR')
-}
-
const formatBytes = (bytes) => {
if (bytes === 0) return '0 Bytes'
const k = 1024
diff --git a/src/views/KMSView.vue b/src/views/KMSView.vue
index 2225db1..e47b3fa 100644
--- a/src/views/KMSView.vue
+++ b/src/views/KMSView.vue
@@ -308,6 +308,7 @@ import {
DecryptCommand,
ScheduleKeyDeletionCommand
} from '@aws-sdk/client-kms'
+import { formatDate } from '../utils/formatDate.js'
const appStore = useAppStore()
const { kms } = storeToRefs(appStore)
@@ -381,11 +382,6 @@ const getKeyStateColor = (state) => {
}
}
-const formatDate = (dateString) => {
- if (!dateString) return 'N/A'
- return new Date(dateString).toLocaleString('pt-BR')
-}
-
// KMS API functions
const loadKeys = async () => {
try {
diff --git a/src/views/KinesisView.vue b/src/views/KinesisView.vue
index ce68115..18e9e90 100644
--- a/src/views/KinesisView.vue
+++ b/src/views/KinesisView.vue
@@ -301,6 +301,7 @@ import {
GetShardIteratorCommand,
GetRecordsCommand
} from '@aws-sdk/client-kinesis'
+import { formatDate } from '../utils/formatDate.js'
const appStore = useAppStore()
const { kinesis } = storeToRefs(appStore)
@@ -511,10 +512,6 @@ const getStatusColor = (status) => {
}
}
-const formatDate = (date) => {
- return new Date(date).toLocaleString('pt-BR')
-}
-
const decodeData = (data) => {
try {
// Try to decode as UTF-8 string
diff --git a/src/views/LambdaView.vue b/src/views/LambdaView.vue
index 5645417..f281934 100644
--- a/src/views/LambdaView.vue
+++ b/src/views/LambdaView.vue
@@ -659,10 +659,6 @@ const getStateColor = (state) => {
}
}
-const formatDate = (date) => {
- return new Date(date).toLocaleString('pt-BR')
-}
-
const decodeLogs = (logResult) => {
try {
return atob(logResult)
diff --git a/src/views/S3View.vue b/src/views/S3View.vue
index ceb89b2..a1d3136 100644
--- a/src/views/S3View.vue
+++ b/src/views/S3View.vue
@@ -211,6 +211,7 @@ import {
DeleteObjectCommand,
PutObjectCommand
} from '@aws-sdk/client-s3'
+import { formatDate } from '../utils/formatDate.js'
const appStore = useAppStore()
const { s3 } = storeToRefs(appStore)
@@ -370,10 +371,6 @@ const uploadFile = async () => {
}
}
-const formatDate = (date) => {
- return new Date(date).toLocaleString('pt-BR')
-}
-
const formatBytes = (bytes) => {
if (bytes === 0) return '0 Bytes'
const k = 1024
diff --git a/src/views/SESView.vue b/src/views/SESView.vue
new file mode 100644
index 0000000..0638c30
--- /dev/null
+++ b/src/views/SESView.vue
@@ -0,0 +1,364 @@
+
+ Quando novos emails forem enviados, eles aparecerão aqui Nenhuma identidade Id {{ currentMessage.Id }} Enviado por {{ currentMessage.Source }} Destino(s) {{ currentMessage.Destination.ToAddresses.join(", ") }} Assunto {{ currentMessage.Subject }} Data {{ formatDate(currentMessage.Timestamp) }} Body - Texto {{ currentMessage.Body.text_part || 'Não disponível' }} Body - HTML Não disponívelSES Emails
+ Nenhum email encontrado
+