├── .gitignore ├── README.md ├── example ├── .env ├── data.db └── package.json ├── package-lock.json ├── package.json ├── pnpm-workspace.yaml ├── preview.png └── src ├── index.js └── interface.vue /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | dist 4 | .idea 5 | pnpm-lock.yaml 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Action Button interface for Directus 9 2 | 3 | ![](https://raw.githubusercontent.com/cah4a/directus-action-button/main/preview.png) 4 | 5 | ## Install 6 | 7 | ```sh 8 | npm install directus-extension-action-button 9 | ``` 10 | or 11 | 12 | ```sh 13 | yarn add directus-extension-action-button 14 | ``` 15 | 16 | Restart Directus 17 | 18 | ## Example 19 | 20 | ```sh 21 | pnpm i 22 | pnpm exec directus start 23 | ``` 24 | 25 | User: admin@example.com 26 | Password: admin 27 | 28 | 29 | ## Contribution 30 | 31 | PRs or Issues are welcome! 32 | -------------------------------------------------------------------------------- /example/.env: -------------------------------------------------------------------------------- 1 | #################################################################################################### 2 | # 3 | # These values set environment variables which modify core settings of Directus. 4 | # 5 | # Values in square brackets are the default values. 6 | # 7 | # The following options are not all possible options. For more, see 8 | # https://docs.directus.io/self-hosted/config-options/ 9 | # 10 | #################################################################################################### 11 | #################################################################################################### 12 | 13 | ### General 14 | 15 | # IP or host the API listens on ["0.0.0.0"] 16 | HOST="0.0.0.0" 17 | 18 | # The port Directus will run on [8055] 19 | PORT=8055 20 | 21 | # The URL where your API can be reached on the web. It is also used for things like OAuth redirects, 22 | # forgot-password emails, and logos that needs to be publicly available on the internet. ["/"] 23 | PUBLIC_URL="/" 24 | # PUBLIC_URL="http://localhost:8055" 25 | 26 | # What level of detail to log. [info] 27 | # "fatal", "error", "warn", "info", "debug", "trace", "silent" 28 | # LOG_LEVEL="info" 29 | 30 | # Render the logs human readable (pretty) or as JSON (raw), [pretty] 31 | # "pretty", "raw" 32 | # LOG_STYLE="pretty" 33 | 34 | # Controls the maximum request body size. Accepts number of bytes, or human readable string ["100kb"] 35 | # MAX_PAYLOAD_SIZE="100kb" 36 | 37 | # Where to redirect to when navigating to /. Accepts a relative path, absolute URL, or false to disable ["./admin"] 38 | # ROOT_REDIRECT="./admin" 39 | 40 | # Whether or not to serve the Admin App under /admin. [true] 41 | # SERVE_APP=true 42 | 43 | # Whether or not to enable GraphQL Introspection [true] 44 | # GRAPHQL_INTROSPECTION=true 45 | 46 | #################################################################################################### 47 | ### Database 48 | 49 | # All DB_* environment variables are passed to the connection configuration of a Knex instance. 50 | # Based on your project's needs, you can extend the DB_* environment variables with any config 51 | # you need to pass to the database instance. 52 | 53 | DB_CLIENT="sqlite3" 54 | DB_FILENAME="./data.db" 55 | 56 | 57 | 58 | # These match the databases defined in the docker-compose file in the root of this repo 59 | 60 | ## Postgres 61 | # DB_CLIENT="pg" 62 | # DB_HOST="localhost" 63 | # DB_PORT=5432 64 | # DB_DATABASE="directus" 65 | # DB_USER="postgres" 66 | # DB_PASSWORD="secret" 67 | 68 | ## CockroachDB 69 | # DB_CLIENT="cockroachdb" 70 | # DB_HOST="localhost" 71 | # DB_PORT=26257 72 | # DB_DATABASE="directus" 73 | # DB_USER="root" 74 | # DB_PASSWORD="" 75 | 76 | ## MySQL 8 77 | # DB_CLIENT="mysql" 78 | # DB_HOST="localhost" 79 | # DB_PORT=3306 80 | # DB_DATABASE="directus" 81 | # DB_USER="root" 82 | # DB_PASSWORD="secret" 83 | 84 | ## MariaDB 85 | # DB_CLIENT="mysql" 86 | # DB_HOST="localhost" 87 | # DB_PORT=3306 88 | # DB_DATABASE="directus" 89 | # DB_USER="root" 90 | # DB_PASSWORD="secret" 91 | 92 | ## MS SQL 93 | # DB_CLIENT="mssql" 94 | # DB_HOST="localhost" 95 | # DB_PORT=1343 96 | # DB_DATABASE="directus" 97 | # DB_USER="sa" 98 | # DB_PASSWORD="Test@123" 99 | 100 | ## OracleDB 101 | # DB_CLIENT="oracledb" 102 | # DB_CONNECT_STRING="localhost:1521/XE" 103 | # DB_USER="secretsysuser" 104 | # DB_PASSWORD="secretpassword" 105 | 106 | ## SQLite Example 107 | # DB_CLIENT="sqlite3" 108 | # DB_FILENAME="./data.db" 109 | 110 | ## MySQL 5.7 111 | # DB_CLIENT="mysql" 112 | # DB_HOST="localhost" 113 | # DB_PORT=3306 114 | # DB_DATABASE="directus" 115 | # DB_USER="root" 116 | # DB_PASSWORD="secret" 117 | 118 | #################################################################################################### 119 | ### Rate Limiting 120 | 121 | # Whether or not to enable rate limiting on the API [false] 122 | RATE_LIMITER_ENABLED=false 123 | 124 | # Where to store the rate limiter counts [memory] 125 | # memory, redis, memcache 126 | RATE_LIMITER_STORE=memory 127 | # RATE_LIMITER_REDIS="redis://@127.0.0.1:5105" 128 | # RATE_LIMITER_MEMCACHE="localhost:5109" 129 | 130 | # The amount of allowed hits per duration [50] 131 | RATE_LIMITER_POINTS=25 132 | 133 | # The time window in seconds in which the hits are counted [1] 134 | RATE_LIMITER_DURATION=1 135 | 136 | #################################################################################################### 137 | ### Caching 138 | 139 | # Whether or not caching is enabled. [false] 140 | CACHE_ENABLED=false 141 | 142 | # How long the cache is persisted ["5m"] 143 | # CACHE_TTL="30m" 144 | 145 | # How to scope the cache data ["directus-cache"] 146 | # CACHE_NAMESPACE="directus-cache" 147 | 148 | # Automatically purge the cache on create, update, and delete actions. [false] 149 | # CACHE_AUTO_PURGE=true 150 | 151 | # memory | redis | memcache 152 | CACHE_STORE=memory 153 | 154 | # How long assets will be cached for in the browser. Sets the max-age value of the Cache-Control header ["30m"] 155 | ASSETS_CACHE_TTL="30m" 156 | 157 | # CACHE_REDIS="redis://@127.0.0.1:5105" 158 | # CACHE_MEMCACHE="localhost:5109" 159 | 160 | #################################################################################################### 161 | ### File Storage 162 | 163 | # A CSV of storage locations (eg: local,digitalocean,amazon) to use. You can use any names you'd like for these keys ["local"] 164 | STORAGE_LOCATIONS="local" 165 | STORAGE_LOCAL_DRIVER="local" 166 | STORAGE_LOCAL_ROOT="./uploads" 167 | 168 | ## S3 Example (location name: DigitalOcean) 169 | # STORAGE_DIGITALOCEAN_DRIVER="s3" 170 | # STORAGE_DIGITALOCEAN_KEY="abcdef" 171 | # STORAGE_DIGITALOCEAN_SECRET="ghijkl" 172 | # STORAGE_DIGITALOCEAN_ENDPOINT="ams3.digitaloceanspaces.com" 173 | # STORAGE_DIGITALOCEAN_BUCKET="my-files" 174 | # STORAGE_DIGITALOCEAN_REGION="ams3" 175 | 176 | ## Google Cloud Storage Example (location name: Google) 177 | # STORAGE_GOOGLE_DRIVER="gcs" 178 | # STORAGE_GOOGLE_KEY_FILENAME="abcdef" 179 | # STORAGE_GOOGLE_BUCKET="my-files" 180 | 181 | 182 | ## A comma-separated list of metadata keys to collect during file upload. Use * for all 183 | # Extracting all metadata might cause memory issues when the file has an unusually large set of metadata 184 | # [ifd0.Make,ifd0.Model,exif.FNumber,exif.ExposureTime,exif.FocalLength,exif.ISO] 185 | # FILE_METADATA_ALLOW_LIST= 186 | 187 | #################################################################################################### 188 | ### Security 189 | 190 | KEY="8620cba0-f0c5-4460-b1bc-604d0c34dc26" 191 | SECRET="ONYKPNhudp5kst3J9C-AReFw_A4wRZSJ" 192 | 193 | 194 | # Unique identifier for the project 195 | # KEY="xxxxxxx-xxxxxx-xxxxxxxx-xxxxxxxxxx" 196 | 197 | # Secret string for the project 198 | # SECRET="abcdef" 199 | 200 | # The duration that the access token is valid ["15m"] 201 | ACCESS_TOKEN_TTL="15m" 202 | 203 | # The duration that the refresh token is valid, and also how long users stay logged-in to the App ["7d"] 204 | REFRESH_TOKEN_TTL="7d" 205 | 206 | # Whether or not to use a secure cookie for the refresh token in cookie mode [false] 207 | REFRESH_TOKEN_COOKIE_SECURE=false 208 | 209 | # Value for sameSite in the refresh token cookie when in cookie mode ["lax"] 210 | REFRESH_TOKEN_COOKIE_SAME_SITE="lax" 211 | 212 | # Name of refresh token cookie ["directus_refresh_token"] 213 | REFRESH_TOKEN_COOKIE_NAME="directus_refresh_token" 214 | 215 | # Which domain to use for the refresh cookie. Useful for development mode. 216 | # REFRESH_TOKEN_COOKIE_DOMAIN 217 | 218 | # The duration in milliseconds that a login request will be stalled for, 219 | # and it should be greater than the time taken for a login request with an invalid password [500] 220 | # LOGIN_STALL_TIME=500 221 | 222 | # Whether or not to enable the CORS headers [false] 223 | CORS_ENABLED=true 224 | 225 | # Value for the Access-Control-Allow-Origin header. Use true to match the Origin header, or provide a domain or a CSV of domains for specific access [false] 226 | CORS_ORIGIN=true 227 | 228 | # Value for the Access-Control-Allow-Methods header [GET,POST,PATCH,DELETE] 229 | CORS_METHODS=GET,POST,PATCH,DELETE 230 | 231 | # Value for the Access-Control-Allow-Headers header [Content-Type,Authorization] 232 | CORS_ALLOWED_HEADERS=Content-Type,Authorization 233 | 234 | # Value for the Access-Control-Expose-Headers header [Content-R 235 | CORS_EXPOSED_HEADERS=Content-Range 236 | 237 | # Whether or not to send the Access-Control-Allow-Credentials header [true] 238 | CORS_CREDENTIALS=true 239 | 240 | # Value for the Access-Control-Max-Age header [18000] 241 | CORS_MAX_AGE=18000 242 | 243 | #################################################################################################### 244 | ### Argon2 245 | 246 | # How much memory to use when generating hashes, in KiB [4096] 247 | # HASH_MEMORY_COST=81920 248 | 249 | # The length of the hash function output in bytes [32] 250 | # HASH_HASH_LENGTH=32 251 | 252 | # The amount of passes (iterations) used by the hash function. It increases hash strength at the cost of time required to compute [3] 253 | # HASH_TIME_COST=10 254 | 255 | # The amount of threads to compute the hash on. Each thread has a memory pool with HASH_MEMORY_COST size [1] 256 | # HASH_PARALLELISM=2 257 | 258 | # The variant of the hash function (0: argon2d, 1: argon2i, or 2: argon2id) [2] 259 | # HASH_TYPE=2 260 | 261 | # An extra and optional non-secret value. The value will be included B64 encoded in the parameters portion of the digest [] 262 | # HASH_ASSOCIATED_DATA=foo 263 | 264 | #################################################################################################### 265 | ### Auth Providers 266 | 267 | # A comma-separated list of auth providers [] 268 | AUTH_PROVIDERS="" 269 | # AUTH_PROVIDERS="github" 270 | 271 | # AUTH_GITHUB_DRIVER="oauth2" 272 | # AUTH_GITHUB_CLIENT_ID="73e...4b" 273 | # AUTH_GITHUB_CLIENT_SECRET="b9...98" 274 | # AUTH_GITHUB_AUTHORIZE_URL="https://github.com/login/oauth/authorize" 275 | # AUTH_GITHUB_ACCESS_URL="https://github.com/login/oauth/access_token" 276 | # AUTH_GITHUB_PROFILE_URL="https://api.github.com/user" 277 | # AUTH_GITHUB_ALLOW_PUBLIC_REGISTRATION=true 278 | # AUTH_GITHUB_DEFAULT_ROLE_ID="82424427-c9d4-4289-8bc5-ed1bf8422c90" 279 | # AUTH_GITHUB_ICON="github" 280 | # AUTH_GITHUB_EMAIL_KEY="email" 281 | # AUTH_GITHUB_IDENTIFIER_KEY="login" 282 | 283 | #################################################################################################### 284 | ### Extensions 285 | 286 | # Path to your local extensions folder ["./extensions"] 287 | EXTENSIONS_PATH="./extensions" 288 | 289 | # Automatically reload extensions when they have changed [false] 290 | EXTENSIONS_AUTO_RELOAD=false 291 | 292 | #################################################################################################### 293 | ### Email 294 | 295 | # Email address from which emails are sent ["no-reply@directus.io"] 296 | EMAIL_FROM="no-reply@directus.io" 297 | 298 | # What to use to send emails. One of 299 | # sendmail, smtp, mailgun, sendgrid, ses. 300 | EMAIL_TRANSPORT="sendmail" 301 | EMAIL_SENDMAIL_NEW_LINE="unix" 302 | EMAIL_SENDMAIL_PATH="/usr/sbin/sendmail" 303 | 304 | ## Email (Sendmail Transport) 305 | 306 | # What new line style to use in sendmail ["unix"] 307 | # EMAIL_SENDMAIL_NEW_LINE="unix" 308 | 309 | # Path to your sendmail executable ["/usr/sbin/sendmail"] 310 | # EMAIL_SENDMAIL_PATH="/usr/sbin/sendmail" 311 | 312 | ## Email (SMTP Transport) 313 | # EMAIL_SMTP_HOST="localhost" 314 | 315 | # Use SMTP pooling 316 | # EMAIL_SMTP_POOL=true 317 | # EMAIL_SMTP_PORT=465 318 | # EMAIL_SMTP_SECURE=false # Use TLS 319 | # EMAIL_SMTP_IGNORE_TLS=false 320 | # EMAIL_SMTP_USER="username" 321 | # EMAIL_SMTP_PASSWORD="password" 322 | 323 | ## Email (Mailgun Transport) 324 | # EMAIL_MAILGUN_API_KEY="key-1234123412341234" 325 | # EMAIL_MAILGUN_DOMAIN="a domain name from https://app.mailgun.com/app/sending/domains" 326 | 327 | ## Email (SendGrid Transport) 328 | # EMAIL_SENDGRID_API_KEY="key-1234123412341234" 329 | -------------------------------------------------------------------------------- /example/data.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cah4a/directus-action-button/b0b5305725dfa3801a5ffbe9fb867718cb9c5005/example/data.db -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "Sancha ", 11 | "license": "ISC", 12 | "dependencies": { 13 | "directus": "^9.18.1", 14 | "sqlite3": "^5.1.1", 15 | "directus-extension-action-button-interface": "workspace:*" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "directus-extension-action-button", 3 | "description": "Action button interface that allows sending any HTTP request for Directus 9", 4 | "version": "1.0.1", 5 | "author": "Oleksand Kozlov ", 6 | "keywords": [ 7 | "directus", 8 | "directus-extension", 9 | "directus-custom-interface", 10 | "button", 11 | "http", 12 | "request" 13 | ], 14 | "files": [ 15 | "dist/index.js", 16 | "package.json", 17 | "README.md" 18 | ], 19 | "directus:extension": { 20 | "type": "interface", 21 | "path": "dist/index.js", 22 | "source": "src/index.js", 23 | "host": "^9.18.1" 24 | }, 25 | "bugs": { 26 | "url": "https://github.com/cah4a/directus-action-button/issues" 27 | }, 28 | "repository": { 29 | "type": "git", 30 | "url": "https://github.com/cah4a/directus-action-button.git" 31 | }, 32 | "license": "ISC", 33 | "scripts": { 34 | "build": "directus-extension build", 35 | "dev": "directus-extension build -w --no-minify", 36 | "prepublish": "npm run build" 37 | }, 38 | "devDependencies": { 39 | "@directus/extensions-sdk": "9.18.1", 40 | "vue": "^3.2.39" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - . 3 | - example/ 4 | -------------------------------------------------------------------------------- /preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cah4a/directus-action-button/b0b5305725dfa3801a5ffbe9fb867718cb9c5005/preview.png -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import InterfaceComponent from "./interface.vue"; 2 | 3 | export default { 4 | id: "action-button", 5 | name: "Action Button", 6 | description: "Send HTTP requests", 7 | icon: "smart_button", 8 | component: InterfaceComponent, 9 | hideLabel: true, 10 | hideLoader: true, 11 | types: ["alias"], 12 | localTypes: ["presentation"], 13 | group: "presentation", 14 | options: ({ collection }) => [ 15 | { 16 | field: "icon", 17 | name: "$t:icon", 18 | type: "string", 19 | meta: { 20 | width: "half", 21 | interface: "select-icon", 22 | }, 23 | }, 24 | { 25 | field: "buttonType", 26 | name: "$t:type", 27 | type: "string", 28 | meta: { 29 | width: "half", 30 | interface: "select-dropdown", 31 | default_value: "normal", 32 | options: { 33 | choices: [ 34 | { text: "$t:primary", value: "primary" }, 35 | { text: "$t:normal", value: "normal" }, 36 | { text: "$t:info", value: "info" }, 37 | { text: "$t:success", value: "success" }, 38 | { text: "$t:warning", value: "warning" }, 39 | { text: "$t:danger", value: "danger" }, 40 | ], 41 | }, 42 | }, 43 | schema: { 44 | default_value: "normal", 45 | }, 46 | }, 47 | { 48 | field: "label", 49 | type: "full", 50 | name: "$t:label", 51 | meta: { 52 | width: "full", 53 | interface: "system-display-template", 54 | options: { 55 | collectionName: collection, 56 | font: "monospace", 57 | placeholder: "/items/collection/{{ id }}", 58 | }, 59 | }, 60 | }, 61 | { 62 | field: "method", 63 | name: "Method", 64 | type: "string", 65 | meta: { 66 | width: "half", 67 | interface: "select-dropdown", 68 | options: { 69 | choices: [ 70 | { text: "GET", value: "GET" }, 71 | { text: "POST", value: "POST" }, 72 | { text: "PUT", value: "PUT" }, 73 | { text: "PATCH", value: "PATCH" }, 74 | { text: "DELETE", value: "DELETE" }, 75 | ], 76 | }, 77 | }, 78 | }, 79 | { 80 | field: "url", 81 | type: "string", 82 | name: "$t:url", 83 | meta: { 84 | width: "full", 85 | interface: "system-display-template", 86 | options: { 87 | collectionName: collection, 88 | font: "monospace", 89 | placeholder: "/items/collection/{{ id }}", 90 | }, 91 | }, 92 | }, 93 | { 94 | field: "headers", 95 | type: "json", 96 | name: "Headers", 97 | meta: { 98 | width: "full", 99 | interface: "list", 100 | options: { 101 | template: "{{ key }}: {{ value }}", 102 | fields: [ 103 | { 104 | field: "key", 105 | type: "string", 106 | name: "$t:name", 107 | meta: { 108 | interface: "text", 109 | width: "full", 110 | options: { 111 | font: "monospace", 112 | placeholder: "Header", 113 | }, 114 | }, 115 | }, 116 | { 117 | field: "value", 118 | type: "string", 119 | name: "$t:value", 120 | meta: { 121 | width: "full", 122 | interface: "system-display-template", 123 | options: { 124 | collectionName: collection, 125 | font: "monospace", 126 | }, 127 | }, 128 | }, 129 | ], 130 | }, 131 | }, 132 | }, 133 | { 134 | field: "body", 135 | type: "text", 136 | name: "Body", 137 | meta: { 138 | width: "full", 139 | interface: "input-code", 140 | }, 141 | }, 142 | { 143 | field: "result", 144 | name: "On success", 145 | type: "string", 146 | meta: { 147 | width: "full", 148 | interface: "select-dropdown", 149 | default_value: "popup", 150 | options: { 151 | choices: [ 152 | { text: "Show popup", value: "popup" }, 153 | { text: "Go to list", value: "list" }, 154 | { text: "Reload current item", value: "reload" }, 155 | ], 156 | }, 157 | }, 158 | schema: { 159 | default_value: "popup", 160 | }, 161 | }, 162 | ], 163 | }; 164 | -------------------------------------------------------------------------------- /src/interface.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 167 | 168 | 198 | --------------------------------------------------------------------------------