mirror of
https://github.com/fleetbase/fleetbase.git
synced 2026-01-06 14:40:12 +00:00
Compare commits
70 Commits
dev-v0.2.4
...
deploy/sta
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dd65ee619b | ||
|
|
4f4fdeaafc | ||
|
|
39747601d0 | ||
|
|
321ef64229 | ||
|
|
1b8f7a663d | ||
|
|
e790a0e123 | ||
|
|
2a5a68f620 | ||
|
|
3033f6f4cf | ||
|
|
9fbc3252c6 | ||
|
|
25ce216e3b | ||
|
|
6bf3dbad2d | ||
|
|
9a8c67a1b7 | ||
|
|
eabd83c8ad | ||
|
|
e4f64021d7 | ||
|
|
941c6d03d9 | ||
|
|
2331c6902e | ||
|
|
be9faea3bc | ||
|
|
e8d7c021f5 | ||
|
|
8c86eed5fc | ||
|
|
a2ce7b5a65 | ||
|
|
48069177df | ||
|
|
c5574a25ae | ||
|
|
0a3ad2f0a6 | ||
|
|
d60760104d | ||
|
|
88b4acff67 | ||
|
|
4d2179129d | ||
|
|
5c7e0a1c56 | ||
|
|
65a6894d4b | ||
|
|
723e3ca3d1 | ||
|
|
4eb706d33e | ||
|
|
e3acd28c18 | ||
|
|
313b6e63a8 | ||
|
|
a7ed7ee935 | ||
|
|
1e28d9d8d8 | ||
|
|
0c31b54fde | ||
|
|
f6b83e5638 | ||
|
|
b30ee818fc | ||
|
|
6ec9ad59d3 | ||
|
|
10ff2e066b | ||
|
|
f56db88ad6 | ||
|
|
033cf5cfe0 | ||
|
|
4a4dc76e60 | ||
|
|
a52af94b00 | ||
|
|
9c4daf7a68 | ||
|
|
a8904ba112 | ||
|
|
6880664d9e | ||
|
|
99b30d7f58 | ||
|
|
c8539fd2a0 | ||
|
|
cb1aec40fd | ||
|
|
b728b366a0 | ||
|
|
5cfc3f1cc7 | ||
|
|
e7b5282aa3 | ||
|
|
7ffb7ac24a | ||
|
|
6e4a9edd7d | ||
|
|
d9d01c8bbc | ||
|
|
c54d75fa0f | ||
|
|
91904c3836 | ||
|
|
0e075e3b24 | ||
|
|
c56bea95d0 | ||
|
|
f1cec329bc | ||
|
|
34dc365dd2 | ||
|
|
74a782f4ea | ||
|
|
a8b2042d85 | ||
|
|
cc52a40660 | ||
|
|
4fb2dec8c3 | ||
|
|
0db3634ab3 | ||
|
|
1c0d324ba9 | ||
|
|
096cc1097a | ||
|
|
eca881156a | ||
|
|
40b499bcb2 |
2
.github/workflows/cd.yml
vendored
2
.github/workflows/cd.yml
vendored
@@ -35,7 +35,7 @@ jobs:
|
||||
echo "STACK=$(basename $GITHUB_REF)" >> $GITHUB_ENV
|
||||
|
||||
- name: Configure AWS Credentials
|
||||
uses: aws-actions/configure-aws-credentials@v2
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
with:
|
||||
role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_NUMBER }}:role/${{ env.PROJECT }}-${{ env.STACK }}-deployer
|
||||
role-session-name: github
|
||||
|
||||
185
.github/workflows/gcp-cd.yml
vendored
Normal file
185
.github/workflows/gcp-cd.yml
vendored
Normal file
@@ -0,0 +1,185 @@
|
||||
name: Fleetbase CI/CD
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "gcpdeploy/*" ]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
PROJECT: ${{ vars.PROJECT }}
|
||||
REGISTRY: ${{ vars.REGISTRY }}
|
||||
SOCKETCLUSTER_HOST: ${{ vars.SOCKETCLUSTER_HOST }}
|
||||
API_HOST: ${{ vars.API_HOST }}
|
||||
K8S_CLUSTER_NAME: ${{ vars.K8S_CLUSTER_NAME }}
|
||||
K8S_CLUSTER_LOCATION: ${{ vars.K8S_CLUSTER_LOCATION }}
|
||||
GCP_WORKLOAD_IDENTITY_PROVIDER: ${{ vars.GCP_WORKLOAD_IDENTITY_PROVIDER }}
|
||||
GCP_SERVICE_ACCOUNT: ${{ vars.GCP_SERVICE_ACCOUNT }}
|
||||
GCP: "True" # switches docker builds to GCP-style registry
|
||||
|
||||
jobs:
|
||||
build_service:
|
||||
name: Build and Deploy the Service
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
id-token: write # This is required for requesting the JWT
|
||||
contents: read # This is required for actions/checkout
|
||||
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Set Dynamic ENV Vars
|
||||
run: |
|
||||
SHORT_COMMIT=$(echo $GITHUB_SHA | cut -c -8)
|
||||
echo "VERSION=${SHORT_COMMIT}" >> $GITHUB_ENV
|
||||
echo "STACK=$(basename $GITHUB_REF)" >> $GITHUB_ENV
|
||||
echo "REGISTRY_HOST=$(dirname $(dirname $REGISTRY))" >> $GITHUB_ENV
|
||||
|
||||
- id: 'auth'
|
||||
name: 'Authenticate to Google Cloud'
|
||||
uses: 'google-github-actions/auth@v1'
|
||||
with:
|
||||
token_format: "access_token"
|
||||
create_credentials_file: true
|
||||
workload_identity_provider: ${{ env.GCP_WORKLOAD_IDENTITY_PROVIDER }}
|
||||
service_account: ${{ env.GCP_SERVICE_ACCOUNT }}
|
||||
|
||||
- name: 'Set up Cloud SDK'
|
||||
uses: 'google-github-actions/setup-gcloud@v1'
|
||||
|
||||
- id: 'get-credentials'
|
||||
uses: 'google-github-actions/get-gke-credentials@v1'
|
||||
with:
|
||||
cluster_name: ${{ env.K8S_CLUSTER_NAME }}
|
||||
location: ${{ env.K8S_CLUSTER_LOCATION }}
|
||||
|
||||
- uses: 'docker/login-action@v3'
|
||||
with:
|
||||
registry: ${{ env.REGISTRY_HOST }}
|
||||
username: 'oauth2accesstoken'
|
||||
password: '${{ steps.auth.outputs.access_token }}'
|
||||
|
||||
- name: Prepare Composer Auth Secret
|
||||
run: |
|
||||
if [[ -n "${{ secrets._GITHUB_AUTH_TOKEN }}" ]]; then
|
||||
echo '{"github-oauth": {"github.com": "'${{ secrets._GITHUB_AUTH_TOKEN }}'"}}' > composer-auth.json
|
||||
else
|
||||
echo '{}' > composer-auth.json
|
||||
fi
|
||||
|
||||
- name: nullify ssm-parent config
|
||||
run: |
|
||||
# this is needed to disable ssm-parent, which is used on AWS
|
||||
echo > api/.ssm-parent.yaml
|
||||
|
||||
- name: Build and Release
|
||||
uses: docker/bake-action@v2
|
||||
env:
|
||||
REGISTRY: ${{ env.REGISTRY }}
|
||||
VERSION: ${{ env.VERSION }}
|
||||
CACHE: type=gha
|
||||
with:
|
||||
push: true
|
||||
files: |
|
||||
./docker-bake.hcl
|
||||
|
||||
- name: deploy with helm
|
||||
run: |
|
||||
helm upgrade -i fleetbase infra/helm -n ${{ env.PROJECT }}-${{ env.STACK }} --set image.repository=${{ env.REGISTRY }} --set image.tag=${{ env.VERSION }} --set 'api_host=${{ env.API_HOST }}' --set 'socketcluster_host=${{ env.SOCKETCLUSTER_HOST }}' --set 'ingress.annotations.kubernetes\.io/ingress\.global-static-ip-name=${{ env.PROJECT }}-${{ env.STACK }}'
|
||||
|
||||
build_frontend:
|
||||
name: Build and Deploy the Console
|
||||
needs: [build_service]
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
id-token: write # This is required for requesting the JWT
|
||||
contents: read # This is required for actions/checkout
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Set Dynamic ENV Vars
|
||||
run: |
|
||||
SHORT_COMMIT=$(echo $GITHUB_SHA | cut -c -8)
|
||||
echo "VERSION=${SHORT_COMMIT}" >> $GITHUB_ENV
|
||||
echo "STACK=$(basename $GITHUB_REF)" >> $GITHUB_ENV
|
||||
|
||||
- id: 'auth'
|
||||
name: 'Authenticate to Google Cloud'
|
||||
uses: 'google-github-actions/auth@v1'
|
||||
with:
|
||||
token_format: "access_token"
|
||||
create_credentials_file: true
|
||||
workload_identity_provider: ${{ env.GCP_WORKLOAD_IDENTITY_PROVIDER }}
|
||||
service_account: ${{ env.GCP_SERVICE_ACCOUNT }}
|
||||
|
||||
- name: 'Set up Cloud SDK'
|
||||
uses: 'google-github-actions/setup-gcloud@v1'
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- uses: pnpm/action-setup@v2
|
||||
name: Install pnpm
|
||||
id: pnpm-install
|
||||
with:
|
||||
version: 8
|
||||
run_install: false
|
||||
|
||||
- name: Get pnpm Store Directory
|
||||
id: pnpm-cache
|
||||
shell: bash
|
||||
run: |
|
||||
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/cache@v3
|
||||
name: Setup pnpm Cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
|
||||
- name: Check for _GITHUB_AUTH_TOKEN and create .npmrc
|
||||
run: |
|
||||
if [[ -n "${{ secrets._GITHUB_AUTH_TOKEN }}" ]]; then
|
||||
echo "//npm.pkg.github.com/:_authToken=${{ secrets._GITHUB_AUTH_TOKEN }}" > .npmrc
|
||||
fi
|
||||
working-directory: ./console
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
working-directory: ./console
|
||||
|
||||
- name: Build
|
||||
env:
|
||||
SOCKETCLUSTER_HOST: ${{ env.SOCKETCLUSTER_HOST }}
|
||||
SOCKETCLUSTER_SECURE: "true"
|
||||
SOCKETCLUSTER_PORT: "443"
|
||||
API_HOST: ${{ env.API_HOST }}
|
||||
run: |
|
||||
set -eu
|
||||
|
||||
pnpm build
|
||||
working-directory: ./console
|
||||
|
||||
- name: Deploy Console 🚀
|
||||
run: |
|
||||
set -eu
|
||||
|
||||
gcloud app deploy --appyaml console/app.yaml console/dist
|
||||
# leave 2 versions
|
||||
gcloud app versions list --filter="traffic_split=0" --sort-by '~version' --format 'value(version.id)' | sed '1d' | xargs -r gcloud app versions delete
|
||||
21
.gitignore
vendored
21
.gitignore
vendored
@@ -14,12 +14,21 @@ api/storage/public
|
||||
api/vendor
|
||||
api/composer.dev.json
|
||||
api/composer-install-dev.sh
|
||||
api/auth.json
|
||||
act.sh
|
||||
composer-auth.json
|
||||
packages/billing-api
|
||||
packages/billing-engine
|
||||
packages/flespi-engine
|
||||
packages/flespi-integration
|
||||
packages/projectargus-engine
|
||||
docker/database/*
|
||||
docker/database/mysql/*
|
||||
docker/database/mysql/*
|
||||
.talismanrc
|
||||
verdaccio/minio
|
||||
verdaccio/config/htpasswd
|
||||
verdaccio/storage
|
||||
# private packages
|
||||
packages/billing
|
||||
packages/flespi
|
||||
packages/loconav
|
||||
packages/projectargus-engine
|
||||
# wip
|
||||
packages/solid
|
||||
solid
|
||||
verdaccio
|
||||
@@ -10,6 +10,9 @@
|
||||
<a href="https://fleetbase.github.io/guides" rel="nofollow">Fleetbase Documentation →</a>
|
||||
<br>
|
||||
<br>
|
||||
<a href="https://meetings.hubspot.com/shiv-thakker" rel="nofollow">Book a Demo</a>
|
||||
<br>
|
||||
<br>
|
||||
<a href="https://github.com/fleetbase/fleetbase/issues">Report an Issue</a>
|
||||
·
|
||||
<a href="https://fleetbase.github.io/api-reference">API Reference</a>
|
||||
|
||||
@@ -9,9 +9,10 @@
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"php": "^7.3|^8.0",
|
||||
"fleetbase/core-api": "^1.3.1",
|
||||
"fleetbase/fleetops-api": "^0.2.8",
|
||||
"fleetbase/storefront-api": "^0.2.0",
|
||||
"fleetbase/core-api": "^1.3.5",
|
||||
"fleetbase/fleetops-api": "^0.3.7",
|
||||
"fleetbase/storefront-api": "^0.2.5",
|
||||
"fleetbase/billing-api": "^0.0.5",
|
||||
"fruitcake/laravel-cors": "^2.0",
|
||||
"guzzlehttp/guzzle": "^7.0.1",
|
||||
"laravel/framework": "^8.75",
|
||||
@@ -32,6 +33,12 @@
|
||||
"nunomaduro/collision": "^5.10",
|
||||
"phpunit/phpunit": "^9.5.10"
|
||||
},
|
||||
"repositories": [
|
||||
{
|
||||
"type": "vcs",
|
||||
"url": "git@github.com:fleetbase/billing.git"
|
||||
}
|
||||
],
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"App\\": "app/",
|
||||
|
||||
1571
api/composer.lock
generated
1571
api/composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -13,7 +13,7 @@ return [
|
||||
|
|
||||
*/
|
||||
|
||||
'name' => env('APP_NAME', 'Laravel'),
|
||||
'name' => env('APP_NAME', 'Fleetbase'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
use Fleetbase\Support\Utils;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
@@ -19,7 +21,7 @@ return [
|
||||
|
||||
'allowed_methods' => ['*'],
|
||||
|
||||
'allowed_origins' => ['http://localhost:4200', env('CONSOLE_HOST')],
|
||||
'allowed_origins' => array_filter(['http://localhost:4200', env('CONSOLE_HOST'), Utils::addWwwToUrl(env('CONSOLE_URL'))]),
|
||||
|
||||
'allowed_origins_patterns' => [],
|
||||
|
||||
|
||||
@@ -32,13 +32,13 @@ return [
|
||||
|
||||
'local' => [
|
||||
'driver' => 'local',
|
||||
'root' => storage_path('app'),
|
||||
'root' => storage_path('app')
|
||||
],
|
||||
|
||||
'public' => [
|
||||
'driver' => 'local',
|
||||
'root' => storage_path('app/public'),
|
||||
'url' => env('APP_URL').'/storage',
|
||||
'url' => env('APP_URL') . '/storage',
|
||||
],
|
||||
|
||||
's3' => [
|
||||
@@ -51,6 +51,14 @@ return [
|
||||
'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false),
|
||||
],
|
||||
|
||||
'gcs' => [
|
||||
'driver' => 'gcs',
|
||||
'project_id' => env('GOOGLE_CLOUD_PROJECT_ID', 'your-project-id'),
|
||||
'key_file' => env('GOOGLE_CLOUD_KEY_FILE', null),
|
||||
'bucket' => env('GOOGLE_CLOUD_STORAGE_BUCKET', env('AWS_BUCKET')),
|
||||
'path_prefix' => env('GOOGLE_CLOUD_STORAGE_PATH_PREFIX', null),
|
||||
'storage_api_uri' => env('GOOGLE_CLOUD_STORAGE_API_URI', env('AWS_URL')),
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
@@ -65,8 +73,7 @@ return [
|
||||
*/
|
||||
|
||||
'links' => [
|
||||
public_path('storage') => storage_path('app/public'),
|
||||
public_path('uploads') => storage_path('app/uploads'),
|
||||
public_path('storage') => storage_path('app/public')
|
||||
],
|
||||
|
||||
];
|
||||
|
||||
@@ -60,6 +60,10 @@ return [
|
||||
'transport' => 'postmark',
|
||||
],
|
||||
|
||||
'sendgrid' => [
|
||||
'transport' => 'sendgrid',
|
||||
],
|
||||
|
||||
'sendmail' => [
|
||||
'transport' => 'sendmail',
|
||||
'path' => env('MAIL_SENDMAIL_PATH', '/usr/sbin/sendmail -t -i'),
|
||||
@@ -96,7 +100,7 @@ return [
|
||||
|
||||
'from' => [
|
||||
'address' => env('MAIL_FROM_ADDRESS', 'hello@fleetbase.io'),
|
||||
'name' => env('MAIL_FROM_NAME', 'Fleetbase'),
|
||||
'name' => env('MAIL_FROM_NAME', env('APP_NAME', 'Fleetbase')),
|
||||
],
|
||||
|
||||
/*
|
||||
|
||||
@@ -30,4 +30,8 @@ return [
|
||||
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
|
||||
],
|
||||
|
||||
'sendgrid' => [
|
||||
'api_key' => env('SENDGRID_API_KEY'),
|
||||
],
|
||||
|
||||
];
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
/var/www/html/api/storage/app/uploads
|
||||
@@ -1,15 +1,7 @@
|
||||
{
|
||||
/**
|
||||
Ember CLI sends analytics information by default. The data is completely
|
||||
anonymous, but there are times when you might want to disable this behavior.
|
||||
|
||||
Setting `disableAnalytics` to true will prevent any data from being sent.
|
||||
*/
|
||||
"disableAnalytics": false,
|
||||
|
||||
/**
|
||||
Setting `isTypeScriptProject` to true will force the blueprint generators to generate TypeScript
|
||||
rather than JavaScript by default, when a TypeScript version of a given blueprint is available.
|
||||
Setting `isTypeScriptProject` to true will force the blueprint generators to generate TypeScript
|
||||
rather than JavaScript by default, when a TypeScript version of a given blueprint is available.
|
||||
*/
|
||||
"isTypeScriptProject": false
|
||||
}
|
||||
|
||||
@@ -1,25 +1,13 @@
|
||||
# unconventional js
|
||||
/blueprints/*/files/
|
||||
/vendor/
|
||||
|
||||
# compiled output
|
||||
/dist/
|
||||
/tmp/
|
||||
|
||||
# dependencies
|
||||
/bower_components/
|
||||
/node_modules/
|
||||
|
||||
# misc
|
||||
/coverage/
|
||||
!.*
|
||||
.*/
|
||||
.eslintcache
|
||||
|
||||
# ember-try
|
||||
/.node_modules.ember-try/
|
||||
/bower.json.ember-try
|
||||
/npm-shrinkwrap.json.ember-try
|
||||
/package.json.ember-try
|
||||
/package-lock.json.ember-try
|
||||
/yarn.lock.ember-try
|
||||
|
||||
@@ -2,12 +2,13 @@
|
||||
|
||||
module.exports = {
|
||||
root: true,
|
||||
parser: 'babel-eslint',
|
||||
parser: '@babel/eslint-parser',
|
||||
parserOptions: {
|
||||
ecmaVersion: 2018,
|
||||
ecmaVersion: 'latest',
|
||||
sourceType: 'module',
|
||||
ecmaFeatures: {
|
||||
legacyDecorators: true,
|
||||
requireConfigFile: false,
|
||||
babelOptions: {
|
||||
plugins: [['@babel/plugin-proposal-decorators', { decoratorsBeforeExport: true }]],
|
||||
},
|
||||
},
|
||||
plugins: ['ember'],
|
||||
@@ -50,18 +51,18 @@ module.exports = {
|
||||
'no-prototype-builtins': 'off',
|
||||
},
|
||||
overrides: [
|
||||
// node files
|
||||
{
|
||||
files: [
|
||||
'./.eslintrc.js',
|
||||
'./.prettierrc.js',
|
||||
'./.stylelintrc.js',
|
||||
'./.template-lintrc.js',
|
||||
'./ember-cli-build.js',
|
||||
'./index.js',
|
||||
'./testem.js',
|
||||
'./blueprints/*/index.js',
|
||||
'./config/**/*.js',
|
||||
'./tests/dummy/config/**/*.js',
|
||||
'./lib/*/index.js',
|
||||
'./server/**/*.js',
|
||||
],
|
||||
parserOptions: {
|
||||
sourceType: 'script',
|
||||
@@ -70,13 +71,7 @@ module.exports = {
|
||||
browser: false,
|
||||
node: true,
|
||||
},
|
||||
plugins: ['node'],
|
||||
extends: ['plugin:node/recommended'],
|
||||
},
|
||||
{
|
||||
// test files
|
||||
files: ['tests/**/*-test.{js,ts}'],
|
||||
extends: ['plugin:qunit/recommended'],
|
||||
extends: ['plugin:n/recommended'],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
4
console/.github/workflows/ci.yml
vendored
4
console/.github/workflows/ci.yml
vendored
@@ -14,7 +14,7 @@ jobs:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [16.x] # Build on Node.js 16
|
||||
node-version: [18.x] # Build on Node.js 18
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
@@ -57,4 +57,4 @@ jobs:
|
||||
run: pnpm run lint
|
||||
|
||||
- name: Build
|
||||
run: npx ember build --environment production
|
||||
run: npx ember build --environment production
|
||||
10
console/.gitignore
vendored
10
console/.gitignore
vendored
@@ -1,31 +1,23 @@
|
||||
# See https://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# compiled output
|
||||
/dist/
|
||||
/tmp/
|
||||
/declarations/
|
||||
|
||||
# dependencies
|
||||
/bower_components/
|
||||
/node_modules/
|
||||
|
||||
# misc
|
||||
/.env*
|
||||
/environments/.env*
|
||||
/.pnp*
|
||||
/.sass-cache
|
||||
/.eslintcache
|
||||
/connect.lock
|
||||
/coverage/
|
||||
/libpeerconnection.log
|
||||
/npm-debug.log*
|
||||
/testem.log
|
||||
/yarn-error.log
|
||||
/.npmrc
|
||||
/pnpm-lock.yaml
|
||||
|
||||
# ember-try
|
||||
/.node_modules.ember-try/
|
||||
/bower.json.ember-try
|
||||
/npm-shrinkwrap.json.ember-try
|
||||
/package.json.ember-try
|
||||
/package-lock.json.ember-try
|
||||
|
||||
@@ -1,25 +1,13 @@
|
||||
# unconventional js
|
||||
/blueprints/*/files/
|
||||
/vendor/
|
||||
|
||||
# compiled output
|
||||
/dist/
|
||||
/tmp/
|
||||
|
||||
# dependencies
|
||||
/bower_components/
|
||||
/node_modules/
|
||||
|
||||
# misc
|
||||
/coverage/
|
||||
!.*
|
||||
.eslintcache
|
||||
.lint-todo/
|
||||
.*/
|
||||
|
||||
# ember-try
|
||||
/.node_modules.ember-try/
|
||||
/bower.json.ember-try
|
||||
/npm-shrinkwrap.json.ember-try
|
||||
/package.json.ember-try
|
||||
/package-lock.json.ember-try
|
||||
/yarn.lock.ember-try
|
||||
|
||||
@@ -8,7 +8,7 @@ module.exports = {
|
||||
printWidth: 190,
|
||||
overrides: [
|
||||
{
|
||||
files: '*.hbs',
|
||||
files: '*.{hbs,js,ts}',
|
||||
options: {
|
||||
singleQuote: false,
|
||||
},
|
||||
|
||||
8
console/.stylelintignore
Normal file
8
console/.stylelintignore
Normal file
@@ -0,0 +1,8 @@
|
||||
# unconventional files
|
||||
/blueprints/*/files/
|
||||
|
||||
# compiled output
|
||||
/dist/
|
||||
|
||||
# addons
|
||||
/.node_modules.ember-try/
|
||||
5
console/.stylelintrc.js
Normal file
5
console/.stylelintrc.js
Normal file
@@ -0,0 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
extends: ['stylelint-config-standard', 'stylelint-prettier/recommended'],
|
||||
};
|
||||
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"ignore_dirs": ["tmp", "dist"]
|
||||
"ignore_dirs": ["dist"]
|
||||
}
|
||||
|
||||
12
console/app.yaml
Normal file
12
console/app.yaml
Normal file
@@ -0,0 +1,12 @@
|
||||
runtime: python312
|
||||
|
||||
handlers:
|
||||
- url: /(.*\..+)$
|
||||
static_files: \1
|
||||
upload: (.+)
|
||||
secure: always
|
||||
expiration: 1h
|
||||
- url: /.*
|
||||
static_files: index.html
|
||||
upload: index.html
|
||||
secure: always
|
||||
@@ -14,7 +14,7 @@ export default class App extends Application {
|
||||
|
||||
async ready() {
|
||||
const extensions = await loadExtensions();
|
||||
|
||||
|
||||
this.extensions = extensions;
|
||||
this.engines = mapEngines(extensions);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,6 @@
|
||||
<Button @wrapperClass="mt-3" @icon="plug" @text="Test Config" @onClick={{this.test}} @isLoading={{this.isLoading}} />
|
||||
</ContentPanel>
|
||||
|
||||
<div class="mt-3 flex items-center justify-end">
|
||||
<Button @type="primary" @size="lg" @icon="save" @text="Save Changes" @onClick={{this.save}} @disabled={{this.isLoading}} @isLoading={{this.isLoading}} />
|
||||
</div>
|
||||
<EmberWormhole @to="next-view-section-subheader-actions">
|
||||
<Button @type="primary" @size="sm" @icon="save" @text="Save Changes" @onClick={{this.save}} @disabled={{this.isLoading}} @isLoading={{this.isLoading}} />
|
||||
</EmberWormhole>
|
||||
@@ -22,6 +22,6 @@
|
||||
<Button @wrapperClass="mt-3" @icon="plug" @text="Test Config" @onClick={{this.test}} @isLoading={{this.isLoading}} />
|
||||
</ContentPanel>
|
||||
|
||||
<div class="mt-3 flex items-center justify-end">
|
||||
<Button @type="primary" @size="lg" @icon="save" @text="Save Changes" @onClick={{this.save}} @disabled={{this.isLoading}} @isLoading={{this.isLoading}} />
|
||||
</div>
|
||||
<EmberWormhole @to="next-view-section-subheader-actions">
|
||||
<Button @type="primary" @size="sm" @icon="save" @text="Save Changes" @onClick={{this.save}} @disabled={{this.isLoading}} @isLoading={{this.isLoading}} />
|
||||
</EmberWormhole>
|
||||
@@ -47,6 +47,6 @@
|
||||
</div>
|
||||
</ContentPanel>
|
||||
|
||||
<div class="mt-3 flex items-center justify-end">
|
||||
<Button @type="primary" @size="lg" @icon="save" @text="Save Changes" @onClick={{this.save}} @disabled={{this.isLoading}} @isLoading={{this.isLoading}} />
|
||||
</div>
|
||||
<EmberWormhole @to="next-view-section-subheader-actions">
|
||||
<Button @type="primary" @size="sm" @icon="save" @text="Save Changes" @onClick={{this.save}} @disabled={{this.isLoading}} @isLoading={{this.isLoading}} />
|
||||
</EmberWormhole>
|
||||
@@ -20,6 +20,6 @@
|
||||
<Button @wrapperClass="mt-3" @icon="plug" @text="Test Config" @onClick={{this.test}} @isLoading={{this.isLoading}} />
|
||||
</ContentPanel>
|
||||
|
||||
<div class="mt-3 flex items-center justify-end">
|
||||
<Button @type="primary" @size="lg" @icon="save" @text="Save Changes" @onClick={{this.save}} @disabled={{this.isLoading}} @isLoading={{this.isLoading}} />
|
||||
</div>
|
||||
<EmberWormhole @to="next-view-section-subheader-actions">
|
||||
<Button @type="primary" @size="sm" @icon="save" @text="Save Changes" @onClick={{this.save}} @disabled={{this.isLoading}} @isLoading={{this.isLoading}} />
|
||||
</EmberWormhole>
|
||||
@@ -40,6 +40,6 @@
|
||||
<InputGroup @name="IP Info API Key" @value={{this.ipinfoApiKey}} disabled={{this.isLoading}} />
|
||||
</ContentPanel>
|
||||
|
||||
<div class="mt-3 flex items-center justify-end">
|
||||
<Button @type="primary" @size="lg" @icon="save" @text="Save Changes" @onClick={{this.save}} @disabled={{this.isLoading}} @isLoading={{this.isLoading}} />
|
||||
</div>
|
||||
<EmberWormhole @to="next-view-section-subheader-actions">
|
||||
<Button @type="primary" @size="sm" @icon="save" @text="Save Changes" @onClick={{this.save}} @disabled={{this.isLoading}} @isLoading={{this.isLoading}} />
|
||||
</EmberWormhole>
|
||||
@@ -5,14 +5,14 @@
|
||||
<Spinner />
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="flex flex-row p-4 border-b dark:border-gray-700 border-gray-200">
|
||||
<div class="flex flex-row p-3 border-b dark:border-gray-700 border-gray-200">
|
||||
<div class="w-12 flex-shrink-0"><img src={{this.data.owner.avatar_url}} alt="fleetbase/fleetbase" class="rounded-full w-8 h-8" width="32" height="32" /></div>
|
||||
<div class="flex-1 -mt-2">
|
||||
<div class="flex flex-1 flex-row items-center justify-between mb-2">
|
||||
<a href={{this.data.html_url}} target="_github" class="dark:text-gray-100 text-black text-lg font-semibold">{{this.data.full_name}}</a>
|
||||
<a href={{this.data.html_url}} target="_github" class="dark:text-gray-100 text-black text-base font-semibold">{{this.data.full_name}}</a>
|
||||
<a href={{this.data.html_url}} target="_github" class="btn btn-xs btn-default">
|
||||
<FaIcon @icon="star" class="text-yellow-400" />
|
||||
<span class="hidden lg:flex ml-2.5">Star on Github</span>
|
||||
<span class="hidden truncate lg:flex ml-2.5">Star on Github</span>
|
||||
</a>
|
||||
</div>
|
||||
<p class="dark:text-gray-100 text-black text-sm">{{this.data.description}}</p>
|
||||
@@ -40,7 +40,7 @@
|
||||
</div>
|
||||
<div class="col-span-3 dark:text-gray-100 text-black text-xs flex flex-row">
|
||||
<span class="font-bold mr-1">{{this.data.open_issues_count}}</span>
|
||||
<span><span class="hidden lg:inline-flex">Open</span> Issues</span>
|
||||
<span class="truncate"><span class="hidden lg:inline-flex">Open</span> Issues</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -33,6 +33,14 @@ export default class AuthLoginController extends Controller {
|
||||
*/
|
||||
@service session;
|
||||
|
||||
|
||||
/**
|
||||
* Inject the `router` service
|
||||
*
|
||||
* @var {Service}
|
||||
*/
|
||||
@service router;
|
||||
|
||||
/**
|
||||
* Whether or not to remember the users session
|
||||
*
|
||||
@@ -124,14 +132,14 @@ export default class AuthLoginController extends Controller {
|
||||
* Transition user to onboarding screen
|
||||
*/
|
||||
@action transitionToOnboard() {
|
||||
return this.transitionToRoute('onboard');
|
||||
return this.router.transitionTo('onboard');
|
||||
}
|
||||
|
||||
/**
|
||||
* Transition to forgot password screen, if email is set - set it.
|
||||
*/
|
||||
@action forgotPassword() {
|
||||
return this.transitionToRoute('auth.forgot-password').then(() => {
|
||||
return this.router.transitionTo('auth.forgot-password').then(() => {
|
||||
if (this.email) {
|
||||
this.forgotPasswordController.email = this.email;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,13 @@ export default class AuthResetPasswordController extends Controller {
|
||||
*/
|
||||
@service notifications;
|
||||
|
||||
/**
|
||||
* Inject the `router` service
|
||||
*
|
||||
* @memberof AuthResetPasswordController
|
||||
*/
|
||||
@service router;
|
||||
|
||||
/**
|
||||
* The code param.
|
||||
*
|
||||
@@ -65,7 +72,7 @@ export default class AuthResetPasswordController extends Controller {
|
||||
.then(() => {
|
||||
this.notifications.success('Your password has been reset! Login to continue.');
|
||||
|
||||
return this.transitionToRoute('auth.login');
|
||||
return this.router.transitionTo('auth.login');
|
||||
})
|
||||
.catch((error) => {
|
||||
this.notifications.serverError(error);
|
||||
|
||||
@@ -65,13 +65,6 @@ export default class ConsoleController extends Controller {
|
||||
*/
|
||||
@tracked organizations = [];
|
||||
|
||||
/**
|
||||
* Whether or not to hide the sidebar.
|
||||
*
|
||||
* @var {Boolean}
|
||||
*/
|
||||
@tracked hideSidebar = true;
|
||||
|
||||
/**
|
||||
* Sidebar Context Controls
|
||||
*
|
||||
@@ -79,6 +72,27 @@ export default class ConsoleController extends Controller {
|
||||
*/
|
||||
@tracked sidebarContext;
|
||||
|
||||
/**
|
||||
* State of sidebar toggle icon
|
||||
*
|
||||
* @var {SidebarContext}
|
||||
*/
|
||||
@tracked sidebarToggleEnabled = true;
|
||||
|
||||
/**
|
||||
* The sidebar toggle state.
|
||||
*
|
||||
* @var {SidebarContext}
|
||||
*/
|
||||
@tracked sidebarToggleState = {};
|
||||
|
||||
/**
|
||||
* Routes which should hide the sidebar menu.
|
||||
*
|
||||
* @var {Array}
|
||||
*/
|
||||
@tracked hiddenSidebarRoutes = ['console.home', 'console.extensions', 'console.notifications'];
|
||||
|
||||
/**
|
||||
* Installed extensions.
|
||||
*
|
||||
@@ -104,15 +118,47 @@ export default class ConsoleController extends Controller {
|
||||
|
||||
this.router.on('routeDidChange', (transition) => {
|
||||
if (this.sidebarContext) {
|
||||
if (transition.to.name === 'console.home' || transition.to.name === 'console.extensions') {
|
||||
// Determine if the new route should hide the sidebar
|
||||
const shouldHideSidebar = this.hiddenSidebarRoutes.includes(transition.to.name);
|
||||
|
||||
// Check if the sidebar was manually toggled and is currently closed
|
||||
const isSidebarManuallyClosed = this.sidebarToggleState.clicked && !this.sidebarToggleState.isOpen;
|
||||
|
||||
// Hide the sidebar if the current route is in hiddenSidebarRoutes
|
||||
if (shouldHideSidebar) {
|
||||
this.sidebarContext.hideNow();
|
||||
this.sidebarToggleEnabled = false;
|
||||
return; // Exit early as no further action is required
|
||||
}
|
||||
|
||||
// If the sidebar was manually closed and not on a hidden route, keep it closed
|
||||
if (isSidebarManuallyClosed) {
|
||||
this.sidebarContext.hideNow();
|
||||
} else {
|
||||
// Otherwise, show the sidebar
|
||||
this.sidebarContext.show();
|
||||
}
|
||||
|
||||
// Ensure toggle is enabled unless on a hidden route
|
||||
this.sidebarToggleEnabled = !shouldHideSidebar;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* When sidebar is manually toggled
|
||||
*
|
||||
* @param {SidebarContext} sidebar
|
||||
* @param {boolean} isOpen
|
||||
* @memberof ConsoleController
|
||||
*/
|
||||
@action onSidebarToggle(sidebar, isOpen) {
|
||||
this.sidebarToggleState = {
|
||||
clicked: true,
|
||||
isOpen
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the sidebar context
|
||||
*
|
||||
@@ -123,8 +169,9 @@ export default class ConsoleController extends Controller {
|
||||
this.sidebarContext = sidebarContext;
|
||||
this.universe.sidebarContext = sidebarContext;
|
||||
|
||||
if (this.router.currentRouteName === 'console.home' || this.router.currentRouteName === 'console.extensions') {
|
||||
if (this.hiddenSidebarRoutes.includes(this.router.currentRouteName)) {
|
||||
this.sidebarContext.hideNow();
|
||||
this.sidebarToggleEnabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,5 +2,10 @@ import Controller from '@ember/controller';
|
||||
import { inject as service } from '@ember/service';
|
||||
|
||||
export default class ConsoleAccountController extends Controller {
|
||||
/**
|
||||
* Inject the `universe` service.
|
||||
*
|
||||
* @memberof ConsoleAdminController
|
||||
*/
|
||||
@service universe;
|
||||
}
|
||||
|
||||
@@ -2,5 +2,10 @@ import Controller from '@ember/controller';
|
||||
import { inject as service } from '@ember/service';
|
||||
|
||||
export default class ConsoleAdminController extends Controller {
|
||||
/**
|
||||
* Inject the `universe` service.
|
||||
*
|
||||
* @memberof ConsoleAdminController
|
||||
*/
|
||||
@service universe;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import Controller from '@ember/controller';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { action } from '@ember/object';
|
||||
import { isArray } from '@ember/array';
|
||||
|
||||
export default class ConsoleAdminBrandingController extends Controller {
|
||||
/**
|
||||
@@ -51,13 +52,43 @@ export default class ConsoleAdminBrandingController extends Controller {
|
||||
}
|
||||
|
||||
/**
|
||||
* Unset a branding settings
|
||||
* Unsets the value of a given key or array of keys on the model.
|
||||
*
|
||||
* @param {String} key
|
||||
* @action
|
||||
* @param {string | string[]} key - The key or keys to unset on the model.
|
||||
* @param {*} [newValue=null] - The new value to set for the given key or keys. Defaults to null.
|
||||
* @memberof ConsoleAdminBrandingController
|
||||
*/
|
||||
@action unset(key, newValue = null) {
|
||||
this.model[key] = newValue;
|
||||
if (isArray(key)) {
|
||||
return key.forEach((k) => this.unset(k, undefined));
|
||||
}
|
||||
|
||||
this.model.set(key, newValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsets the icon properties on the model.
|
||||
*
|
||||
* @action
|
||||
* @returns {void} - No return value.
|
||||
* @memberof ConsoleAdminBrandingController
|
||||
*/
|
||||
@action unsetIcon() {
|
||||
this.unset(['icon_uuid', 'icon_url']);
|
||||
this.model.set('icon_url', '/images/icon.png');
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsets the logo properties on the model.
|
||||
*
|
||||
* @action
|
||||
* @returns {void} - No return value.
|
||||
* @memberof ConsoleAdminBrandingController
|
||||
*/
|
||||
@action unsetLogo() {
|
||||
this.unset(['logo_uuid', 'logo_url']);
|
||||
this.model.set('logo_url', '/images/fleetbase-logo-svg.svg');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -73,6 +104,16 @@ export default class ConsoleAdminBrandingController extends Controller {
|
||||
.save()
|
||||
.then(() => {
|
||||
this.notifications.success('Branding settings saved.');
|
||||
|
||||
// if logo url is null
|
||||
if (this.model.logo_url === null) {
|
||||
this.model.set('logo_url', '/images/fleetbase-logo-svg.svg');
|
||||
}
|
||||
|
||||
// if icon url is null
|
||||
if (this.model.icon_url === null) {
|
||||
this.model.set('icon_url', '/images/icon.png');
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false;
|
||||
|
||||
136
console/app/controllers/console/admin/notifications.js
Normal file
136
console/app/controllers/console/admin/notifications.js
Normal file
@@ -0,0 +1,136 @@
|
||||
import Controller from '@ember/controller';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
import { action } from '@ember/object';
|
||||
import { inject as service } from '@ember/service';
|
||||
import createNotificationKey from '../../../utils/create-notification-key';
|
||||
|
||||
export default class ConsoleAdminNotificationsController extends Controller {
|
||||
/**
|
||||
* Inject the notifications service.
|
||||
*
|
||||
* @memberof ConsoleAdminNotificationsController
|
||||
*/
|
||||
@service notifications;
|
||||
|
||||
/**
|
||||
* Inject the fetch service.
|
||||
*
|
||||
* @memberof ConsoleAdminNotificationsController
|
||||
*/
|
||||
@service fetch;
|
||||
|
||||
/**
|
||||
* The notification settings value JSON.
|
||||
*
|
||||
* @memberof ConsoleAdminNotificationsController
|
||||
* @var {Object}
|
||||
*/
|
||||
@tracked notificationSettings = {};
|
||||
|
||||
/**
|
||||
* Notification transport methods enabled.
|
||||
*
|
||||
* @memberof ConsoleAdminNotificationsController
|
||||
* @var {Array}
|
||||
*/
|
||||
@tracked notificationTransportMethods = ['email', 'sms'];
|
||||
|
||||
/**
|
||||
* Tracked property for the loading state
|
||||
*
|
||||
* @memberof ConsoleAdminNotificationsController
|
||||
* @var {Boolean}
|
||||
*/
|
||||
@tracked isLoading = false;
|
||||
|
||||
/**
|
||||
* Creates an instance of ConsoleAdminNotificationsController.
|
||||
* @memberof ConsoleAdminNotificationsController
|
||||
*/
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
this.getSettings();
|
||||
}
|
||||
|
||||
/**
|
||||
* Selectes notifiables for settings.
|
||||
*
|
||||
* @param {Object} notification
|
||||
* @param {Array} notifiables
|
||||
* @memberof ConsoleAdminNotificationsController
|
||||
*/
|
||||
@action onSelectNotifiable(notification, notifiables) {
|
||||
const notificationKey = createNotificationKey(notification.definition, notification.name);
|
||||
const _notificationSettings = { ...this.notificationSettings };
|
||||
|
||||
if (!_notificationSettings[notificationKey]) {
|
||||
_notificationSettings[notificationKey] = {};
|
||||
}
|
||||
|
||||
_notificationSettings[notificationKey].notifiables = notifiables;
|
||||
_notificationSettings[notificationKey].definition = notification.definition;
|
||||
_notificationSettings[notificationKey].via = notifiables.map((notifiable) => {
|
||||
return {
|
||||
identifier: notifiable.value,
|
||||
methods: this.notificationTransportMethods,
|
||||
};
|
||||
});
|
||||
|
||||
this.mutateNotificationSettings(_notificationSettings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mutates the notification settings property.
|
||||
*
|
||||
* @param {Object} [_notificationSettings={}]
|
||||
* @memberof ConsoleAdminNotificationsController
|
||||
*/
|
||||
mutateNotificationSettings(_notificationSettings = {}) {
|
||||
this.notificationSettings = {
|
||||
...this.notificationSettings,
|
||||
..._notificationSettings,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Save notification settings to the server.
|
||||
*
|
||||
* @action
|
||||
* @method saveSettings
|
||||
* @returns {Promise}
|
||||
* @memberof ConsoleAdminNotificationsController
|
||||
*/
|
||||
@action saveSettings() {
|
||||
const { notificationSettings } = this;
|
||||
|
||||
this.isLoading = true;
|
||||
|
||||
return this.fetch
|
||||
.post('notifications/save-settings', { notificationSettings })
|
||||
.then(() => {
|
||||
this.notifications.success('Notification settings successfully saved.');
|
||||
})
|
||||
.catch((error) => {
|
||||
this.notifications.serverError(error);
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches and updates notification settings asynchronously.
|
||||
*
|
||||
* @returns {Promise<void>} A promise for successful retrieval and update, or an error on failure.
|
||||
*/
|
||||
getSettings() {
|
||||
return this.fetch
|
||||
.get('notifications/get-settings')
|
||||
.then(({ notificationSettings }) => {
|
||||
this.notificationSettings = notificationSettings;
|
||||
})
|
||||
.catch((error) => {
|
||||
this.notifications.serverError(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
188
console/app/controllers/console/notifications.js
Normal file
188
console/app/controllers/console/notifications.js
Normal file
@@ -0,0 +1,188 @@
|
||||
import Controller from '@ember/controller';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
import { action } from '@ember/object';
|
||||
import { inject as service } from '@ember/service';
|
||||
|
||||
/**
|
||||
* Controller for managing notifications.
|
||||
*/
|
||||
export default class NotificationsController extends Controller {
|
||||
/**
|
||||
* Inject the `socket` service
|
||||
*
|
||||
* @memberof NotificationsController
|
||||
*/
|
||||
@service socket;
|
||||
|
||||
/**
|
||||
* Inject the `store` service
|
||||
*
|
||||
* @memberof NotificationsController
|
||||
*/
|
||||
@service store;
|
||||
|
||||
/**
|
||||
* Inject the `fetch` service
|
||||
*
|
||||
* @memberof NotificationsController
|
||||
*/
|
||||
@service fetch;
|
||||
|
||||
/**
|
||||
* Inject the `notifications` service
|
||||
*
|
||||
* @memberof NotificationsController
|
||||
*/
|
||||
@service notifications;
|
||||
|
||||
/**
|
||||
* Inject the `universe` service
|
||||
*
|
||||
* @memberof NotificationsController
|
||||
*/
|
||||
@service universe;
|
||||
|
||||
/**
|
||||
* Inject the `router` service
|
||||
*
|
||||
* @memberof NotificationsController
|
||||
*/
|
||||
@service router;
|
||||
|
||||
/**
|
||||
* Queryable parameters for this controller's model
|
||||
*
|
||||
* @var {Array}
|
||||
*/
|
||||
queryParams = ['page', 'limit', 'sort', 'query', 'created_at'];
|
||||
|
||||
/**
|
||||
* The current page of data being viewed
|
||||
*
|
||||
* @var {Integer}
|
||||
*/
|
||||
@tracked page = 1;
|
||||
|
||||
/**
|
||||
* The maximum number of items to show per page
|
||||
*
|
||||
* @var {Integer}
|
||||
*/
|
||||
@tracked limit = 20;
|
||||
|
||||
/**
|
||||
* The param to sort the data on, the param with prepended `-` is descending
|
||||
*
|
||||
* @var {String}
|
||||
*/
|
||||
@tracked sort = '-created_at';
|
||||
|
||||
/**
|
||||
* The selected notifications.
|
||||
*
|
||||
* @tracked
|
||||
* @var {Array}
|
||||
* @memberof NotificationsController
|
||||
*/
|
||||
@tracked selected = [];
|
||||
|
||||
/**
|
||||
* Creates an instance of NotificationsController.
|
||||
* @memberof NotificationsController
|
||||
*/
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
|
||||
// listen for received notifications
|
||||
this.universe.on('notification.received', () => {
|
||||
this.router.refresh();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Action to select or deselect a notification.
|
||||
*
|
||||
* @param {NotificationModel} notification - The notification to select or deselect.
|
||||
* @memberof NotificationsController
|
||||
*/
|
||||
@action selectNotification(notification) {
|
||||
if (this.selected.includes(notification)) {
|
||||
this.selected.removeObject(notification);
|
||||
} else {
|
||||
this.selected.pushObject(notification);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Action to delete selected notifications.
|
||||
*
|
||||
* @memberof NotificationsController
|
||||
*/
|
||||
@action delete() {
|
||||
return this.fetch
|
||||
.delete('notifications/bulk-delete', {
|
||||
notifications: this.selected.map(({ id }) => id),
|
||||
})
|
||||
.then(() => {
|
||||
this.notifications.success(`${this.selected.length} notifications deleted`);
|
||||
this.universe.trigger('notifications.deleted', [...this.selected]);
|
||||
this.selected.clear();
|
||||
|
||||
return this.router.refresh();
|
||||
})
|
||||
.catch((error) => {
|
||||
this.notifications.serverError(error);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Action to mark selected notifications as read.
|
||||
*
|
||||
* @memberof NotificationsController
|
||||
*/
|
||||
@action read() {
|
||||
const unreadSelectedNotifications = this.selected.filter((notification) => notification.unread);
|
||||
|
||||
return this.fetch
|
||||
.put('notifications/mark-as-read', {
|
||||
notifications: unreadSelectedNotifications.map(({ id }) => id),
|
||||
})
|
||||
.then(() => {
|
||||
this.notifications.success(`${unreadSelectedNotifications.length} notifications marked as read`);
|
||||
this.universe.trigger('notifications.read', [...unreadSelectedNotifications]);
|
||||
this.selected.clear();
|
||||
|
||||
return this.router.refresh();
|
||||
})
|
||||
.catch((error) => {
|
||||
this.notifications.serverError(error);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Action to select all notifications.
|
||||
*
|
||||
* @memberof NotificationsController
|
||||
*/
|
||||
@action selectAll() {
|
||||
if (this.selected.length === this.model.length) {
|
||||
this.selected.clear();
|
||||
} else {
|
||||
this.selected = this.model.toArray();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Action to mark a notification as read.
|
||||
*
|
||||
* @param {NotificationModel} notification
|
||||
* @return {Promise}
|
||||
* @memberof NotificationsController
|
||||
*/
|
||||
@action markNotificationAsRead(notification) {
|
||||
return notification.markAsRead().then(() => {
|
||||
this.notifications.info('Notification marked as read.');
|
||||
this.universe.trigger('notifications.read', [notification]);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -2,5 +2,10 @@ import Controller from '@ember/controller';
|
||||
import { inject as service } from '@ember/service';
|
||||
|
||||
export default class ConsoleSettingsController extends Controller {
|
||||
/**
|
||||
* INject the `universe` service
|
||||
*
|
||||
* @memberof ConsoleSettingsController
|
||||
*/
|
||||
@service universe;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import { task } from 'ember-concurrency-decorators';
|
||||
export default class InstallController extends Controller {
|
||||
@service fetch;
|
||||
@service notifications;
|
||||
@service router;
|
||||
@tracked error;
|
||||
@tracked steps = [
|
||||
{ task: 'createdb', name: 'Create Database', status: 'pending' },
|
||||
@@ -46,7 +47,7 @@ export default class InstallController extends Controller {
|
||||
|
||||
if (isCompleted) {
|
||||
this.notifications.success('Install completed successfully!');
|
||||
return this.transitionToRoute('onboard');
|
||||
return this.router.transitionTo('onboard');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ export default class InviteForUserController extends Controller {
|
||||
@service session;
|
||||
@service notifications;
|
||||
@service modalsManager;
|
||||
@service router;
|
||||
@tracked code;
|
||||
@tracked isLoading;
|
||||
|
||||
@@ -24,7 +25,7 @@ export default class InviteForUserController extends Controller {
|
||||
|
||||
this.isLoading = false;
|
||||
|
||||
return this.transitionToRoute('console').then(() => {
|
||||
return this.router.transitionTo('console').then(() => {
|
||||
if (response.needs_password && response.needs_password === true) {
|
||||
this.setPassword();
|
||||
}
|
||||
|
||||
@@ -21,6 +21,13 @@ export default class OnboardIndexController extends Controller {
|
||||
*/
|
||||
@service session;
|
||||
|
||||
/**
|
||||
* Inject the `router` service
|
||||
*
|
||||
* @memberof OnboardIndexController
|
||||
*/
|
||||
@service router;
|
||||
|
||||
/**
|
||||
* Inject the `notifications` service
|
||||
*
|
||||
@@ -122,12 +129,12 @@ export default class OnboardIndexController extends Controller {
|
||||
this.session.isOnboarding().manuallyAuthenticate(response.token);
|
||||
|
||||
if (response.skipVerification === true) {
|
||||
return this.transitionToRoute('console').then(() => {
|
||||
return this.router.transitionTo('console').then(() => {
|
||||
this.notifications.success('Welcome to Fleetbase!');
|
||||
});
|
||||
}
|
||||
|
||||
return this.transitionToRoute('onboard.verify-email', { queryParams: { hello: response.session } });
|
||||
return this.router.transitionTo('onboard.verify-email', { queryParams: { hello: response.session } });
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
|
||||
@@ -34,6 +34,14 @@ export default class OnboardVerifyEmailController extends Controller {
|
||||
*/
|
||||
@service currentUser;
|
||||
|
||||
|
||||
/**
|
||||
* Inject the `router` service
|
||||
*
|
||||
* @memberof OnboardIndexController
|
||||
*/
|
||||
@service router;
|
||||
|
||||
/**
|
||||
* The session paramerer.
|
||||
*
|
||||
@@ -139,7 +147,7 @@ export default class OnboardVerifyEmailController extends Controller {
|
||||
this.notifications.success('Email successfully verified!');
|
||||
this.notifications.info('Welcome to Fleetbase!');
|
||||
|
||||
return this.transitionToRoute('console');
|
||||
return this.router.transitionTo('console');
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
|
||||
6
console/app/helpers/get-notification-key.js
Normal file
6
console/app/helpers/get-notification-key.js
Normal file
@@ -0,0 +1,6 @@
|
||||
import { helper } from '@ember/component/helper';
|
||||
import createNotificationKey from '../utils/create-notification-key';
|
||||
|
||||
export default helper(function getNotificationKey([definition, name]) {
|
||||
return createNotificationKey(definition, name);
|
||||
});
|
||||
@@ -10,7 +10,7 @@ export default class Company extends Model {
|
||||
@attr('string') owner_uuid;
|
||||
@attr('string') logo_uuid;
|
||||
@attr('string') backdrop_uuid;
|
||||
@attr('string') address_uuid;
|
||||
@attr('string') place_uuid;
|
||||
|
||||
/** @relationships */
|
||||
@belongsTo('file') logo;
|
||||
|
||||
53
console/app/models/notification.js
Normal file
53
console/app/models/notification.js
Normal file
@@ -0,0 +1,53 @@
|
||||
import Model, { attr } from '@ember-data/model';
|
||||
import { computed } from '@ember/object';
|
||||
|
||||
import { format, formatDistanceToNow } from 'date-fns';
|
||||
|
||||
export default class NotificationModel extends Model {
|
||||
@attr('string') notifiable_id;
|
||||
@attr('string') notifiable_type;
|
||||
|
||||
/** @attributes */
|
||||
@attr('string') type;
|
||||
@attr('raw') data;
|
||||
@attr('raw') meta;
|
||||
|
||||
/** @dates */
|
||||
@attr('date') read_at;
|
||||
@attr('date') created_at;
|
||||
|
||||
/** @computed */
|
||||
@computed('created_at') get createdAgo() {
|
||||
return formatDistanceToNow(this.created_at);
|
||||
}
|
||||
|
||||
@computed('created_at') get createdAt() {
|
||||
return format(this.created_at, 'PPP p');
|
||||
}
|
||||
|
||||
@computed('read_at') get readAt() {
|
||||
return format(this.read_at, 'PPP p');
|
||||
}
|
||||
|
||||
@computed('read_at') get isRead() {
|
||||
return this.read_at instanceof Date;
|
||||
}
|
||||
|
||||
@computed('read_at') get read() {
|
||||
return this.read_at instanceof Date;
|
||||
}
|
||||
|
||||
@computed('isRead') get unread() {
|
||||
return !this.get('isRead');
|
||||
}
|
||||
|
||||
/** @actions */
|
||||
markAsRead() {
|
||||
if (this.isRead) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.set('read_at', new Date());
|
||||
return this.save();
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@ Router.map(function () {
|
||||
this.route('console', { path: '/' }, function () {
|
||||
this.route('home', { path: '/' });
|
||||
this.route('extensions');
|
||||
this.route('notifications');
|
||||
this.route('account', function () {
|
||||
this.route('virtual', { path: '/:slug/:view' });
|
||||
});
|
||||
@@ -41,9 +42,15 @@ Router.map(function () {
|
||||
this.route('socket');
|
||||
});
|
||||
this.route('branding');
|
||||
this.route('notifications');
|
||||
this.route('virtual', { path: '/:slug/:view' });
|
||||
});
|
||||
|
||||
this.mount('@fleetbase/billing-engine', {
|
||||
as: 'billing',
|
||||
path: 'billing'
|
||||
});
|
||||
|
||||
this.mount('@fleetbase/dev-engine', {
|
||||
as: 'developers',
|
||||
path: 'developers'
|
||||
|
||||
@@ -11,6 +11,7 @@ export default class ApplicationRoute extends Route {
|
||||
@service urlSearchParams;
|
||||
@service modalsManager;
|
||||
@service intl;
|
||||
@service router;
|
||||
@tracked defaultTheme;
|
||||
|
||||
/**
|
||||
@@ -27,11 +28,11 @@ export default class ApplicationRoute extends Route {
|
||||
this.defaultTheme = defaultTheme;
|
||||
|
||||
if (shouldInstall) {
|
||||
return this.transitionTo('install');
|
||||
return this.router.transitionTo('install');
|
||||
}
|
||||
|
||||
if (shouldOnboard) {
|
||||
return this.transitionTo('onboard');
|
||||
return this.router.transitionTo('onboard');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +50,7 @@ export default class ApplicationRoute extends Route {
|
||||
const shift = this.urlSearchParams.get('shift');
|
||||
|
||||
if (isAuthenticated && shift) {
|
||||
return this.transitionTo(pathToRoute(shift));
|
||||
return this.router.transitionTo(pathToRoute(shift));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,11 +4,12 @@ import { inject as service } from '@ember/service';
|
||||
export default class ConsoleAdminRoute extends Route {
|
||||
@service currentUser;
|
||||
@service notifications;
|
||||
@service router;
|
||||
|
||||
beforeModel() {
|
||||
// USER MUST BE ADMIN
|
||||
if (!this.currentUser.user.is_admin) {
|
||||
return this.transitionTo('console').then(() => {
|
||||
return this.router.transitionTo('console').then(() => {
|
||||
this.notifications.error('You do not have authorization to access admin!');
|
||||
});
|
||||
}
|
||||
|
||||
20
console/app/routes/console/admin/notifications.js
Normal file
20
console/app/routes/console/admin/notifications.js
Normal file
@@ -0,0 +1,20 @@
|
||||
import Route from '@ember/routing/route';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { hash } from 'rsvp';
|
||||
import groupBy from '@fleetbase/ember-core/utils/group-by';
|
||||
|
||||
export default class ConsoleAdminNotificationsRoute extends Route {
|
||||
@service fetch;
|
||||
|
||||
model() {
|
||||
return hash({
|
||||
registry: this.fetch.get('notifications/registry'),
|
||||
notifiables: this.fetch.get('notifications/notifiables'),
|
||||
});
|
||||
}
|
||||
|
||||
setupController(controller, { registry, notifiables }) {
|
||||
controller.groupedNotifications = groupBy(registry, 'package');
|
||||
controller.notifiables = notifiables;
|
||||
}
|
||||
}
|
||||
27
console/app/routes/console/notifications.js
Normal file
27
console/app/routes/console/notifications.js
Normal file
@@ -0,0 +1,27 @@
|
||||
import Route from '@ember/routing/route';
|
||||
import { inject as service } from '@ember/service';
|
||||
|
||||
/**
|
||||
* Route for managing console notifications.
|
||||
*/
|
||||
export default class ConsoleNotificationsRoute extends Route {
|
||||
@service store;
|
||||
|
||||
queryParams = {
|
||||
page: { refreshModel: true },
|
||||
limit: { refreshModel: true },
|
||||
sort: { refreshModel: true },
|
||||
query: { refreshModel: true },
|
||||
created_at: { refreshModel: true },
|
||||
};
|
||||
|
||||
/**
|
||||
* Fetch the model data based on the specified parameters.
|
||||
*
|
||||
* @param {Object} params - Query parameters for fetching notifications.
|
||||
* @returns {Promise} - A promise that resolves with the notification data.
|
||||
*/
|
||||
model(params = {}) {
|
||||
return this.store.query('notification', params);
|
||||
}
|
||||
}
|
||||
5
console/app/serializers/notification.js
Normal file
5
console/app/serializers/notification.js
Normal file
@@ -0,0 +1,5 @@
|
||||
import ApplicationSerializer from '@fleetbase/ember-core/serializers/application';
|
||||
|
||||
export default class NotificationSerializer extends ApplicationSerializer {
|
||||
primaryKey = 'id';
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
@import 'tailwindcss/base';
|
||||
@import 'tailwindcss/components';
|
||||
@import 'tailwindcss/utilities';
|
||||
@import 'inter-ui/inter.css';
|
||||
@import 'inter-ui/inter.css';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{{page-title "Console"}}
|
||||
<Layout::Container>
|
||||
<Layout::Header @brand={{@model}} @user={{this.user}} @organizations={{this.organizations}} @menuItems={{this.universe.headerMenuItems}} @extensions={{this.extensions}} @onAction={{this.onAction}} />
|
||||
<Layout::Header @brand={{@model}} @user={{this.user}} @organizations={{this.organizations}} @menuItems={{this.universe.headerMenuItems}} @extensions={{this.extensions}} @onAction={{this.onAction}} @showSidebarToggle={{true}} @sidebarToggleEnabled={{this.sidebarToggleEnabled}} @onSidebarToggle={{this.onSidebarToggle}} />
|
||||
<Layout::Main>
|
||||
<Layout::Sidebar @onSetup={{this.setSidebarContext}}>
|
||||
<div class="next-sidebar-content-inner">
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
<EmberWormhole @to="sidebar-menu-items">
|
||||
<Layout::Sidebar::Item @route="console.admin.index" @icon="rectangle-list">Overview</Layout::Sidebar::Item>
|
||||
<Layout::Sidebar::Item @route="console.admin.branding" @icon="palette">Branding</Layout::Sidebar::Item>
|
||||
<Layout::Sidebar::Item @route="console.admin.notifications" @icon="bell">Notifications</Layout::Sidebar::Item>
|
||||
{{#each this.universe.adminMenuItems as |menuItem|}}
|
||||
<Layout::Sidebar::Item @onClick={{fn this.universe.transitionMenuItem "console.admin.virtual" menuItem}} @item={{menuItem}} @icon={{menuItem.icon}}>{{menuItem.title}}</Layout::Sidebar::Item>
|
||||
{{/each}}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
{{page-title "Branding"}}
|
||||
<Layout::Section::Header @title="Branding" />
|
||||
<Layout::Section::Header @title="Branding">
|
||||
<Button @type="primary" @size="sm" @icon="save" @text="Save Changes" @onClick={{this.save}} @disabled={{this.isLoading}} @isLoading={{this.isLoading}} />
|
||||
</Layout::Section::Header>
|
||||
|
||||
<Layout::Section::Body class="overflow-y-scroll h-full">
|
||||
<div class="container mx-auto h-screen" {{increase-height-by 300}}>
|
||||
@@ -28,7 +30,7 @@
|
||||
</a>
|
||||
</FileUpload>
|
||||
</div>
|
||||
<a href="javascript:;" class="text-danger text-xs mt-1" {{on "click" (fn this.unset "icon_url" "/images/icon.png")}}>Reset to default</a>
|
||||
<a href="javascript:;" class="text-danger text-xs mt-1" {{on "click" this.unsetIcon}}>Reset to default</a>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<label>Logo</label>
|
||||
@@ -52,17 +54,13 @@
|
||||
</a>
|
||||
</FileUpload>
|
||||
</div>
|
||||
<a href="javascript:;" class="text-danger text-xs mt-1" {{on "click" (fn this.unset "logo_url" "/images/fleetbase-logo-svg.svg")}}>Reset to default</a>
|
||||
<a href="javascript:;" class="text-danger text-xs mt-1" {{on "click" this.unsetLogo}}>Reset to default</a>
|
||||
</div>
|
||||
<InputGroup @name="Default Theme">
|
||||
<Select @value={{@model.default_theme}} @onSelect={{this.setTheme}} @options={{this.themeOptions}} />
|
||||
</InputGroup>
|
||||
</form>
|
||||
</ContentPanel>
|
||||
|
||||
<div class="mt-3 flex items-center justify-end">
|
||||
<Button @type="primary" @size="lg" @icon="save" @text="Save Changes" @onClick={{this.save}} @disabled={{this.isLoading}} @isLoading={{this.isLoading}} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Layout::Section::Body>
|
||||
32
console/app/templates/console/admin/notifications.hbs
Normal file
32
console/app/templates/console/admin/notifications.hbs
Normal file
@@ -0,0 +1,32 @@
|
||||
{{page-title "Notifications"}}
|
||||
<Layout::Section::Header @title="Notifications">
|
||||
<Button @type="primary" @size="sm" @icon="save" @text="Save Changes" @onClick={{this.saveSettings}} @disabled={{this.isLoading}} @isLoading={{this.isLoading}} />
|
||||
</Layout::Section::Header>
|
||||
|
||||
<Layout::Section::Body class="overflow-y-scroll h-full">
|
||||
<div class="container mx-auto h-screen" {{increase-height-by 1200}}>
|
||||
<div class="max-w-3xl my-10 mx-auto space-y-4">
|
||||
{{#each-in this.groupedNotifications as |groupName notifications|}}
|
||||
<ContentPanel @title={{concat (smart-humanize groupName) " Notification Settings"}} @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
|
||||
{{#each notifications as |notification|}}
|
||||
<InputGroup @name={{notification.name}} @helpText={{notification.description}}>
|
||||
<div class="fleetbase-model-select fleetbase-power-select ember-model-select">
|
||||
<PowerSelectMultiple
|
||||
@searchEnabled={{true}}
|
||||
@options={{this.notifiables}}
|
||||
@selected={{get this.notificationSettings (concat (get-notification-key notification.definition notification.name) ".notifiables")}}
|
||||
@onChange={{fn this.onSelectNotifiable notification}}
|
||||
@placeholder="Select notifiables..."
|
||||
@triggerClass="form-select form-input form-input-sm flex-1"
|
||||
as |notifiable|
|
||||
>
|
||||
{{notifiable.label}}
|
||||
</PowerSelectMultiple>
|
||||
</div>
|
||||
</InputGroup>
|
||||
{{/each}}
|
||||
</ContentPanel>
|
||||
{{/each-in}}
|
||||
</div>
|
||||
</div>
|
||||
</Layout::Section::Body>
|
||||
@@ -1,6 +1,6 @@
|
||||
{{page-title "Dashboard"}}
|
||||
<Layout::Section::Body class="overflow-y-scroll h-full pt-6">
|
||||
<div class="container mx-auto h-screen space-y-4" {{increase-height-by 300}}>
|
||||
<div class="console-home-container mx-auto h-screen space-y-4" {{increase-height-by 300}}>
|
||||
<div class="grid grid-cols-1 md:grid-cols-12 gap-4">
|
||||
<GithubCard class="lg:col-span-4" />
|
||||
<FleetbaseBlog class="lg:col-span-8" />
|
||||
|
||||
51
console/app/templates/console/notifications.hbs
Normal file
51
console/app/templates/console/notifications.hbs
Normal file
@@ -0,0 +1,51 @@
|
||||
<Layout::Section::Header @title="Notifications">
|
||||
<Button @icon="check-square" @type="default" @text="Select All" {{on "click" this.selectAll}} class="mr-2" />
|
||||
<Button @icon="envelope" @type="primary" @text="Mark as Read" {{on "click" this.read}} class="mr-2" />
|
||||
<Button @icon="trash" @type="danger" @text="Delete" {{on "click" this.delete}} />
|
||||
</Layout::Section::Header>
|
||||
|
||||
<Layout::Section::Body class="h-full w-full">
|
||||
<div class="max-h-[calc(100vh-10rem)] h-full w-full overflow-y-scroll">
|
||||
<div class="h-full w-full">
|
||||
{{#each @model as |notification|}}
|
||||
<div class="flex flex-row justify-between px-4 py-3 text-black dark:text-white border-b dark:border-gray-800 border-gray-200 text-sm hover:opacity-60 {{if notification.read_at 'bg-gray-100 dark:bg-gray-900' 'bg-white dark:bg-gray-800'}}">
|
||||
<div class="flex flex-row flex-1">
|
||||
<div class="flex items-center justify-center mr-6">
|
||||
<Checkbox @value={{includes notification this.selected}} @onToggle={{fn this.selectNotification notification}} />
|
||||
</div>
|
||||
<a href="javascript:;" class="flex-1 flex flex-row" {{on "click" (fn this.markNotificationAsRead notification)}}>
|
||||
<div class="mr-4 flex items-center justify-center">
|
||||
{{#if notification.read_at}}
|
||||
<FaIcon @icon="envelope-open" class="text-gray-200" />
|
||||
{{else}}
|
||||
<FaIcon @icon="envelope" class="text-gray-200" />
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<div class="flex flex-row space-x-2">
|
||||
<h1 class="text-sm font-semibold antialiased leading-4">{{notification.data.subject}}</h1>
|
||||
<div class="text-xs antialiased text-gray-900 dark:text-gray-200">- {{notification.data.message}}</div>
|
||||
</div>
|
||||
<div class="text-gray-300 text-xs antialiased mt-1">Received: {{notification.createdAgo}}</div>
|
||||
</div>
|
||||
</a>
|
||||
<div>
|
||||
<FaIcon @icon="clock" class="text-gray-400 dark:text-gray-700" @size="sm" />
|
||||
<span class="text-gray-400 dark:text-gray-600 text-xs">{{notification.createdAt}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="flex items-center justify-center h-full w-full">
|
||||
<p class="text-base text-gray-800 dark:text-gray-300 italic">No notifications to display.</p>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
</Layout::Section::Body>
|
||||
|
||||
<div class="fixed bottom-0 w-full">
|
||||
<Layout::Section::Footer>
|
||||
<Pagination @meta={{@model.meta}} @currentPage={{this.page}} @onPageChange={{fn (mut this.page)}} @tfootVerticalOffset="53" @tfootVerticalOffsetElements=".next-view-section-subheader" />
|
||||
</Layout::Section::Footer>
|
||||
</div>
|
||||
8
console/app/utils/create-notification-key.js
Normal file
8
console/app/utils/create-notification-key.js
Normal file
@@ -0,0 +1,8 @@
|
||||
import { camelize } from '@ember/string';
|
||||
|
||||
export default function createNotificationKey(definition, name) {
|
||||
const withoutSlashes = definition.replace(/[\W_]+/g, '');
|
||||
const key = `${camelize(withoutSlashes)}__${camelize(name)}`;
|
||||
|
||||
return key;
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
"packages": [
|
||||
{
|
||||
"name": "ember-cli",
|
||||
"version": "4.6.0",
|
||||
"version": "5.4.1",
|
||||
"blueprints": [
|
||||
{
|
||||
"name": "app",
|
||||
|
||||
@@ -4,12 +4,13 @@ const getenv = require('./utils/getenv');
|
||||
const fixApiHost = require('./utils/fix-api-host');
|
||||
|
||||
module.exports = function (environment) {
|
||||
let ENV = {
|
||||
const ENV = {
|
||||
modulePrefix: '@fleetbase/console',
|
||||
environment,
|
||||
rootURL: '/',
|
||||
locationType: 'history',
|
||||
EmberENV: {
|
||||
EXTEND_PROTOTYPES: true,
|
||||
FEATURES: {
|
||||
// Here you can enable experimental features on an ember canary build
|
||||
// e.g. EMBER_NATIVE_DECORATOR_SUPPORT: true
|
||||
@@ -21,7 +22,7 @@ module.exports = function (environment) {
|
||||
},
|
||||
|
||||
API: {
|
||||
host: fixApiHost(getenv('API_HOST'), getenv('API_SECURE')),
|
||||
host: fixApiHost(getenv('API_HOST'), toBoolean(getenv('API_SECURE'))),
|
||||
namespace: getenv('API_NAMESPACE', 'int/v1'),
|
||||
},
|
||||
|
||||
@@ -43,7 +44,8 @@ module.exports = function (environment) {
|
||||
driverImage: getenv('DEFAULT_DRIVER_IMAGE', 'https://s3.ap-southeast-1.amazonaws.com/flb-assets/static/no-avatar.png'),
|
||||
userImage: getenv('DEFAULT_USER_IMAGE', 'https://s3.ap-southeast-1.amazonaws.com/flb-assets/static/no-avatar.png'),
|
||||
contactImage: getenv('DEFAULT_CONTACT_IMAGE', 'https://s3.ap-southeast-1.amazonaws.com/flb-assets/static/no-avatar.png'),
|
||||
vehicleImage: getenv('DEFAULT_VEHICLE_IMAGE', 'https://flb-assets.s3.ap-southeast-1.amazonaws.com/static/vehicle-icons/light_commercial_van.svg'),
|
||||
vendorImage: getenv('DEFAULT_VENDOR_IMAGE', 'https://s3.ap-southeast-1.amazonaws.com/flb-assets/static/no-avatar.png'),
|
||||
vehicleImage: getenv('DEFAULT_VEHICLE_IMAGE', 'https://s3.ap-southeast-1.amazonaws.com/flb-assets/static/vehicle-placeholder.png'),
|
||||
vehicleAvatar: getenv('DEFAUL_VEHICLE_AVATAR', 'https://flb-assets.s3-ap-southeast-1.amazonaws.com/static/vehicle-icons/mini_bus.svg'),
|
||||
},
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ const autoprefixer = require('autoprefixer');
|
||||
const tailwind = require('tailwindcss');
|
||||
|
||||
module.exports = function (defaults) {
|
||||
let app = new EmberApp(defaults, {
|
||||
const app = new EmberApp(defaults, {
|
||||
storeConfigInMeta: false,
|
||||
|
||||
fingerprint: {
|
||||
@@ -43,7 +43,7 @@ module.exports = function (defaults) {
|
||||
postcssMixins,
|
||||
postcssPresetEnv({ stage: 1 }),
|
||||
postcssEach,
|
||||
tailwind('./tailwind.js'),
|
||||
tailwind('./tailwind.config.js'),
|
||||
autoprefixer,
|
||||
],
|
||||
},
|
||||
|
||||
8
console/environments/.env.development
Normal file
8
console/environments/.env.development
Normal file
@@ -0,0 +1,8 @@
|
||||
API_HOST=http://localhost:8000
|
||||
API_NAMESPACE=int/v1
|
||||
SOCKETCLUSTER_PATH=/socketcluster/
|
||||
SOCKETCLUSTER_HOST=localhost
|
||||
SOCKETCLUSTER_SECURE=false
|
||||
SOCKETCLUSTER_PORT=38000
|
||||
OSRM_HOST=https://bundle.routing.fleetbase.io
|
||||
OSRM_SERVERS=https://canada.routing.fleetbase.io,https://us.routing.fleetbase.io
|
||||
9
console/environments/.env.production
Normal file
9
console/environments/.env.production
Normal file
@@ -0,0 +1,9 @@
|
||||
API_HOST=
|
||||
API_NAMESPACE=int/v1
|
||||
API_SECURE=true
|
||||
SOCKETCLUSTER_PATH=/socketcluster/
|
||||
SOCKETCLUSTER_HOST=
|
||||
SOCKETCLUSTER_SECURE=true
|
||||
SOCKETCLUSTER_PORT=38000
|
||||
OSRM_HOST=https://bundle.routing.fleetbase.io
|
||||
OSRM_SERVERS=https://canada.routing.fleetbase.io,https://us.routing.fleetbase.io
|
||||
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"name": "@fleetbase/console",
|
||||
"version": "0.2.5",
|
||||
"version": "0.3.3",
|
||||
"private": true,
|
||||
"description": "Fleetbase Console",
|
||||
"repository": "",
|
||||
"repository": "https://github.com/fleetbase/fleetbase",
|
||||
"license": "MIT",
|
||||
"author": "",
|
||||
"author": "Fleetbase Pte Ltd <hello@fleetbase.io>",
|
||||
"directories": {
|
||||
"doc": "doc",
|
||||
"test": "tests"
|
||||
@@ -13,37 +13,40 @@
|
||||
"scripts": {
|
||||
"prebuild": "node prebuild.js",
|
||||
"build": "pnpm run prebuild && ember build --environment=production",
|
||||
"lint": "npm-run-all --aggregate-output --continue-on-error --parallel \"lint:!(fix)\"",
|
||||
"lint:fix": "npm-run-all --aggregate-output --continue-on-error --parallel lint:*:fix",
|
||||
"lint": "concurrently \"npm:lint:*(!fix)\" --names \"lint:\"",
|
||||
"lint:css": "stylelint \"**/*.css\"",
|
||||
"lint:css:fix": "concurrently \"npm:lint:css -- --fix\"",
|
||||
"lint:fix": "concurrently \"npm:lint:*:fix\" --names \"fix:\"",
|
||||
"lint:hbs": "ember-template-lint .",
|
||||
"lint:hbs:fix": "ember-template-lint . --fix",
|
||||
"lint:js": "eslint . --cache",
|
||||
"lint:js:fix": "eslint . --fix",
|
||||
"start": "pnpm run prebuild && ember serve",
|
||||
"test": "npm-run-all lint test:*",
|
||||
"test": "concurrently \"npm:lint\" \"npm:test:*\" --names \"lint,test:\"",
|
||||
"test:ember": "ember test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ember/legacy-built-in-components": "^0.4.1",
|
||||
"@fleetbase/ember-core": "^0.1.4",
|
||||
"@fleetbase/ember-ui": "^0.2.0",
|
||||
"@fleetbase/dev-engine": "^0.1.8",
|
||||
"@fleetbase/iam-engine": "^0.0.6",
|
||||
"@fleetbase/fleetops-engine": "^0.2.8",
|
||||
"@fleetbase/fleetops-data": "^0.1.1",
|
||||
"@fleetbase/storefront-engine": "^0.2.0",
|
||||
"@fleetbase/ember-core": "^0.1.9",
|
||||
"@fleetbase/ember-ui": "^0.2.8",
|
||||
"@fleetbase/storefront-engine": "^0.2.5",
|
||||
"@fleetbase/fleetops-engine": "^0.3.7",
|
||||
"@fleetbase/fleetops-data": "^0.1.6",
|
||||
"@fleetbase/dev-engine": "^0.2.0",
|
||||
"@fleetbase/iam-engine": "^0.0.8",
|
||||
"@fleetbase/billing-engine": "^0.0.5",
|
||||
"@fleetbase/leaflet-routing-machine": "^3.2.16",
|
||||
"@ember/legacy-built-in-components": "^0.4.1",
|
||||
"@fortawesome/ember-fontawesome": "^0.4.1",
|
||||
"ember-intl": "^6.0.0-beta.6",
|
||||
"ember-changeset": "^4.1.2",
|
||||
"ember-changeset-validations": "^4.1.1",
|
||||
"ember-composable-helpers": "^5.0.0",
|
||||
"ember-concurrency": "^3.0.0",
|
||||
"ember-concurrency-decorators": "^2.0.3",
|
||||
"ember-intl": "6.3.2",
|
||||
"ember-math-helpers": "^2.18.2",
|
||||
"ember-power-select": "^6.0.1",
|
||||
"ember-prism": "^0.13.0",
|
||||
"ember-radio-button": "^3.0.0-beta.1",
|
||||
"ember-radio-button": "3.0.0-beta.1",
|
||||
"ember-tag-input": "^3.1.0",
|
||||
"fleetbase-extensions-indexer": "^0.0.4",
|
||||
"postcss-at-rules-variables": "^0.3.0",
|
||||
@@ -51,8 +54,12 @@
|
||||
"postcss-nth-list": "^1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.23.2",
|
||||
"@babel/eslint-parser": "^7.22.15",
|
||||
"@babel/plugin-proposal-decorators": "^7.23.2",
|
||||
"@ember/optional-features": "^2.0.0",
|
||||
"@ember/test-helpers": "^2.8.1",
|
||||
"@ember/string": "^3.1.1",
|
||||
"@ember/test-helpers": "^3.2.0",
|
||||
"@fortawesome/fontawesome-svg-core": "^6.4.0",
|
||||
"@fortawesome/free-brands-svg-icons": "^6.4.0",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.4.0",
|
||||
@@ -60,49 +67,49 @@
|
||||
"@glimmer/tracking": "^1.1.2",
|
||||
"@tailwindcss/forms": "^0.5.3",
|
||||
"autoprefixer": "^10.4.8",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"broccoli-asset-rev": "^3.0.0",
|
||||
"broccoli-funnel": "^3.0.8",
|
||||
"concurrently": "^8.2.2",
|
||||
"date-fns": "^2.30.0",
|
||||
"dragula": "^3.7.3",
|
||||
"ember-auto-import": "^2.4.2",
|
||||
"ember-cli": "~4.6.0",
|
||||
"ember-cli-app-version": "^5.0.0",
|
||||
"ember-cli-babel": "^7.26.11",
|
||||
"ember-cli-dependency-checker": "^3.3.1",
|
||||
"ember-auto-import": "^2.6.3",
|
||||
"ember-cli": "~5.4.1",
|
||||
"ember-cli-app-version": "^6.0.1",
|
||||
"ember-cli-babel": "^8.2.0",
|
||||
"ember-cli-clean-css": "^3.0.0",
|
||||
"ember-cli-dependency-checker": "^3.3.2",
|
||||
"ember-cli-dotenv": "^3.1.0",
|
||||
"ember-cli-es6-transform": "^1.0.0",
|
||||
"ember-cli-htmlbars": "^6.1.0",
|
||||
"ember-cli-htmlbars": "^6.3.0",
|
||||
"ember-cli-inject-live-reload": "^2.1.0",
|
||||
"ember-cli-postcss": "^8.2.0",
|
||||
"ember-cli-sri": "^2.1.1",
|
||||
"ember-cli-string-helpers": "^6.1.0",
|
||||
"ember-cli-terser": "^4.0.2",
|
||||
"ember-data": "^4.6.1",
|
||||
"ember-data": "^4.12.5",
|
||||
"ember-engines": "^0.8.23",
|
||||
"ember-fetch": "^8.1.1",
|
||||
"ember-fetch": "^8.1.2",
|
||||
"ember-leaflet": "^5.1.1",
|
||||
"ember-load-initializers": "^2.1.2",
|
||||
"ember-page-title": "^7.0.0",
|
||||
"ember-qunit": "^5.1.5",
|
||||
"ember-resolver": "^8.0.3",
|
||||
"ember-modifier": "^4.1.0",
|
||||
"ember-page-title": "^8.0.0",
|
||||
"ember-qunit": "^8.0.1",
|
||||
"ember-resolver": "^11.0.1",
|
||||
"ember-responsive": "^5.0.0",
|
||||
"ember-source": "~4.6.0",
|
||||
"ember-template-lint": "^4.10.1",
|
||||
"ember-source": "~5.4.0",
|
||||
"ember-template-lint": "^5.11.2",
|
||||
"ember-wormhole": "^0.6.0",
|
||||
"eslint": "^7.32.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-ember": "^11.0.2",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"eslint-plugin-qunit": "^7.3.1",
|
||||
"eslint": "^8.52.0",
|
||||
"eslint-config-prettier": "^9.0.0",
|
||||
"eslint-plugin-ember": "^11.11.1",
|
||||
"eslint-plugin-n": "^16.2.0",
|
||||
"eslint-plugin-prettier": "^5.0.1",
|
||||
"eslint-plugin-qunit": "^8.0.1",
|
||||
"fast-glob": "^3.3.0",
|
||||
"fs": "0.0.1-security",
|
||||
"inter-ui": "^3.19.3",
|
||||
"leaflet": "^1.9.4",
|
||||
"loader.js": "^4.7.0",
|
||||
"normalize.css": "^8.0.1",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"postcss": "^8.4.21",
|
||||
"postcss-conditionals-renewed": "^1.0.0",
|
||||
"postcss-each": "^1.1.0",
|
||||
@@ -110,24 +117,28 @@
|
||||
"postcss-mixins": "^9.0.4",
|
||||
"postcss-preset-env": "^7.8.2",
|
||||
"postcss-simple-vars": "^7.0.0",
|
||||
"prettier": "^2.7.1",
|
||||
"qunit": "^2.19.1",
|
||||
"prettier": "^3.0.3",
|
||||
"qunit": "^2.20.0",
|
||||
"qunit-dom": "^2.0.0",
|
||||
"recast": "^0.23.3",
|
||||
"stylelint": "^15.11.0",
|
||||
"stylelint-config-standard": "^34.0.0",
|
||||
"stylelint-prettier": "^4.0.2",
|
||||
"tailwindcss": "^3.1.8",
|
||||
"webpack": "^5.74.0"
|
||||
"tracked-built-ins": "^3.3.0",
|
||||
"webpack": "^5.89.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "14.* || >= 16"
|
||||
"node": ">= 18"
|
||||
},
|
||||
"ember": {
|
||||
"edition": "octane"
|
||||
},
|
||||
"pnpm": {
|
||||
"overrides": {
|
||||
"@fleetbase/fleetops-data": "^0.1.1",
|
||||
"@fleetbase/ember-core": "^0.1.4",
|
||||
"@fleetbase/ember-ui": "^0.2.0"
|
||||
"@fleetbase/fleetops-data": "^0.1.6",
|
||||
"@fleetbase/ember-core": "^0.1.9",
|
||||
"@fleetbase/ember-ui": "^0.2.8"
|
||||
}
|
||||
},
|
||||
"prettier": {
|
||||
|
||||
16804
console/pnpm-lock.yaml
generated
Normal file
16804
console/pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -5,6 +5,17 @@ const recast = require('recast');
|
||||
const babelParser = require('recast/parsers/babel');
|
||||
const builders = recast.types.builders;
|
||||
|
||||
function getExtensionMountPath(extensionName) {
|
||||
let extensionNameSegments = extensionName.split('/');
|
||||
let mountName = extensionNameSegments[1];
|
||||
|
||||
if (typeof mountName !== 'string') {
|
||||
mountName = extensionNameSegments[0];
|
||||
}
|
||||
|
||||
return mountName.replace('-engine', '');
|
||||
}
|
||||
|
||||
function only(subject, props = []) {
|
||||
const keys = Object.keys(subject);
|
||||
const result = {};
|
||||
@@ -85,8 +96,7 @@ function getRouterFileContents() {
|
||||
if (functionExpression) {
|
||||
// Check and add the new engine mounts
|
||||
extensions.forEach((extension) => {
|
||||
const mountName = extension.name.split('/')[1];
|
||||
const mountPath = mountName.replace('-engine', '');
|
||||
const mountPath = getExtensionMountPath(extension.name);
|
||||
let route = mountPath;
|
||||
|
||||
if (extension.fleetbase && extension.fleetbase.route) {
|
||||
|
||||
@@ -22,6 +22,7 @@ Router.map(function () {
|
||||
this.route('console', { path: '/' }, function () {
|
||||
this.route('home', { path: '/' });
|
||||
this.route('extensions');
|
||||
this.route('notifications');
|
||||
this.route('account', function () {
|
||||
this.route('virtual', { path: '/:slug/:view' });
|
||||
});
|
||||
@@ -41,6 +42,7 @@ Router.map(function () {
|
||||
this.route('socket');
|
||||
});
|
||||
this.route('branding');
|
||||
this.route('notifications');
|
||||
this.route('virtual', { path: '/:slug/:view' });
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { setupApplicationTest as upstreamSetupApplicationTest, setupRenderingTest as upstreamSetupRenderingTest, setupTest as upstreamSetupTest } from 'ember-qunit';
|
||||
|
||||
// This file exists to provide wrappers around ember-qunit's / ember-mocha's
|
||||
// This file exists to provide wrappers around ember-qunit's
|
||||
// test setup functions. This way, you can easily extend the setup that is
|
||||
// needed per test type.
|
||||
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import { module, test } from 'qunit';
|
||||
import { setupRenderingTest } from '@fleetbase/console/tests/helpers';
|
||||
import { render } from '@ember/test-helpers';
|
||||
import { hbs } from 'ember-cli-htmlbars';
|
||||
|
||||
module('Integration | Component | notification-list', function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
test('it renders', async function (assert) {
|
||||
// Set any properties with this.set('myProperty', 'value');
|
||||
// Handle any actions with this.set('myAction', function(val) { ... });
|
||||
|
||||
await render(hbs`<NotificationList />`);
|
||||
|
||||
assert.dom(this.element).hasText('');
|
||||
|
||||
// Template block usage:
|
||||
await render(hbs`
|
||||
<NotificationList>
|
||||
template block text
|
||||
</NotificationList>
|
||||
`);
|
||||
|
||||
assert.dom(this.element).hasText('template block text');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,26 @@
|
||||
import { module, test } from 'qunit';
|
||||
import { setupRenderingTest } from '@fleetbase/console/tests/helpers';
|
||||
import { render } from '@ember/test-helpers';
|
||||
import { hbs } from 'ember-cli-htmlbars';
|
||||
|
||||
module('Integration | Component | notifications-list', function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
test('it renders', async function (assert) {
|
||||
// Set any properties with this.set('myProperty', 'value');
|
||||
// Handle any actions with this.set('myAction', function(val) { ... });
|
||||
|
||||
await render(hbs`<NotificationsList />`);
|
||||
|
||||
assert.dom(this.element).hasText('');
|
||||
|
||||
// Template block usage:
|
||||
await render(hbs`
|
||||
<NotificationsList>
|
||||
template block text
|
||||
</NotificationsList>
|
||||
`);
|
||||
|
||||
assert.dom(this.element).hasText('template block text');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,17 @@
|
||||
import { module, test } from 'qunit';
|
||||
import { setupRenderingTest } from '@fleetbase/console/tests/helpers';
|
||||
import { render } from '@ember/test-helpers';
|
||||
import { hbs } from 'ember-cli-htmlbars';
|
||||
|
||||
module('Integration | Helper | get-notification-key', function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
// TODO: Replace this with your real tests.
|
||||
test('it renders', async function (assert) {
|
||||
this.set('inputValue', '1234');
|
||||
|
||||
await render(hbs`{{get-notification-key this.inputValue}}`);
|
||||
|
||||
assert.dom(this.element).hasText('1234');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,12 @@
|
||||
import { module, test } from 'qunit';
|
||||
import { setupTest } from '@fleetbase/console/tests/helpers';
|
||||
|
||||
module('Unit | Controller | console/admin/notifications', function (hooks) {
|
||||
setupTest(hooks);
|
||||
|
||||
// TODO: Replace this with your real tests.
|
||||
test('it exists', function (assert) {
|
||||
let controller = this.owner.lookup('controller:console/admin/notifications');
|
||||
assert.ok(controller);
|
||||
});
|
||||
});
|
||||
12
console/tests/unit/controllers/console/notifications-test.js
Normal file
12
console/tests/unit/controllers/console/notifications-test.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import { module, test } from 'qunit';
|
||||
import { setupTest } from '@fleetbase/console/tests/helpers';
|
||||
|
||||
module('Unit | Controller | console/notifications', function (hooks) {
|
||||
setupTest(hooks);
|
||||
|
||||
// TODO: Replace this with your real tests.
|
||||
test('it exists', function (assert) {
|
||||
let controller = this.owner.lookup('controller:console/notifications');
|
||||
assert.ok(controller);
|
||||
});
|
||||
});
|
||||
14
console/tests/unit/models/notification-test.js
Normal file
14
console/tests/unit/models/notification-test.js
Normal file
@@ -0,0 +1,14 @@
|
||||
import { module, test } from 'qunit';
|
||||
|
||||
import { setupTest } from '@fleetbase/console/tests/helpers';
|
||||
|
||||
module('Unit | Model | notification', function (hooks) {
|
||||
setupTest(hooks);
|
||||
|
||||
// Replace this with your real tests.
|
||||
test('it exists', function (assert) {
|
||||
let store = this.owner.lookup('service:store');
|
||||
let model = store.createRecord('notification', {});
|
||||
assert.ok(model);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,11 @@
|
||||
import { module, test } from 'qunit';
|
||||
import { setupTest } from '@fleetbase/console/tests/helpers';
|
||||
|
||||
module('Unit | Route | console/admin/notifications', function (hooks) {
|
||||
setupTest(hooks);
|
||||
|
||||
test('it exists', function (assert) {
|
||||
let route = this.owner.lookup('route:console/admin/notifications');
|
||||
assert.ok(route);
|
||||
});
|
||||
});
|
||||
11
console/tests/unit/routes/console/notifications-test.js
Normal file
11
console/tests/unit/routes/console/notifications-test.js
Normal file
@@ -0,0 +1,11 @@
|
||||
import { module, test } from 'qunit';
|
||||
import { setupTest } from '@fleetbase/console/tests/helpers';
|
||||
|
||||
module('Unit | Route | console/notifications', function (hooks) {
|
||||
setupTest(hooks);
|
||||
|
||||
test('it exists', function (assert) {
|
||||
let route = this.owner.lookup('route:console/notifications');
|
||||
assert.ok(route);
|
||||
});
|
||||
});
|
||||
24
console/tests/unit/serializers/notification-test.js
Normal file
24
console/tests/unit/serializers/notification-test.js
Normal file
@@ -0,0 +1,24 @@
|
||||
import { module, test } from 'qunit';
|
||||
|
||||
import { setupTest } from '@fleetbase/console/tests/helpers';
|
||||
|
||||
module('Unit | Serializer | notification', function (hooks) {
|
||||
setupTest(hooks);
|
||||
|
||||
// Replace this with your real tests.
|
||||
test('it exists', function (assert) {
|
||||
let store = this.owner.lookup('service:store');
|
||||
let serializer = store.serializerFor('notification');
|
||||
|
||||
assert.ok(serializer);
|
||||
});
|
||||
|
||||
test('it serializes records', function (assert) {
|
||||
let store = this.owner.lookup('service:store');
|
||||
let record = store.createRecord('notification', {});
|
||||
|
||||
let serializedRecord = record.serialize();
|
||||
|
||||
assert.ok(serializedRecord);
|
||||
});
|
||||
});
|
||||
10
console/tests/unit/utils/create-notification-key-test.js
Normal file
10
console/tests/unit/utils/create-notification-key-test.js
Normal file
@@ -0,0 +1,10 @@
|
||||
import createNotificationKey from '@fleetbase/console/utils/create-notification-key';
|
||||
import { module, test } from 'qunit';
|
||||
|
||||
module('Unit | Utility | create-notification-key', function () {
|
||||
// TODO: Replace this with your real tests.
|
||||
test('it works', function (assert) {
|
||||
let result = createNotificationKey();
|
||||
assert.ok(result);
|
||||
});
|
||||
});
|
||||
@@ -2,6 +2,7 @@
|
||||
variable "REGISTRY" { default = "" }
|
||||
variable "VERSION" { default = "latest" }
|
||||
variable "CACHE" { default = "" }
|
||||
variable "GCP" { default = false }
|
||||
|
||||
group "default" {
|
||||
targets = ["app", "app-httpd"]
|
||||
@@ -23,7 +24,7 @@ target "app" {
|
||||
]
|
||||
|
||||
tags = notequal("", REGISTRY) ? formatlist(
|
||||
"${REGISTRY}:${tgt}-%s",
|
||||
GCP ? "${REGISTRY}/${tgt}:%s" : "${REGISTRY}:${tgt}-%s",
|
||||
compact(["latest", VERSION])
|
||||
) : []
|
||||
|
||||
@@ -43,7 +44,7 @@ target "app-httpd" {
|
||||
]
|
||||
|
||||
tags = notequal("", REGISTRY) ? formatlist(
|
||||
"${REGISTRY}:app-httpd-%s",
|
||||
GCP ? "${REGISTRY}/app-httpd:%s" : "${REGISTRY}:app-httpd-%s",
|
||||
compact(["latest", VERSION])
|
||||
) : []
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ services:
|
||||
SESSION_DOMAIN: localhost
|
||||
BROADCAST_DRIVER: socketcluster
|
||||
MAIL_FROM_NAME: Fleetbase
|
||||
APP_NAME: Fleetbase
|
||||
LOG_CHANNEL: daily
|
||||
depends_on:
|
||||
- database
|
||||
|
||||
23
infra/helm/.helmignore
Normal file
23
infra/helm/.helmignore
Normal file
@@ -0,0 +1,23 @@
|
||||
# Patterns to ignore when building packages.
|
||||
# This supports shell glob matching, relative path matching, and
|
||||
# negation (prefixed with !). Only one pattern per line.
|
||||
.DS_Store
|
||||
# Common VCS dirs
|
||||
.git/
|
||||
.gitignore
|
||||
.bzr/
|
||||
.bzrignore
|
||||
.hg/
|
||||
.hgignore
|
||||
.svn/
|
||||
# Common backup files
|
||||
*.swp
|
||||
*.bak
|
||||
*.tmp
|
||||
*.orig
|
||||
*~
|
||||
# Various IDEs
|
||||
.project
|
||||
.idea/
|
||||
*.tmproj
|
||||
.vscode/
|
||||
24
infra/helm/Chart.yaml
Normal file
24
infra/helm/Chart.yaml
Normal file
@@ -0,0 +1,24 @@
|
||||
apiVersion: v2
|
||||
name: app
|
||||
description: A Helm chart for Kubernetes
|
||||
|
||||
# A chart can be either an 'application' or a 'library' chart.
|
||||
#
|
||||
# Application charts are a collection of templates that can be packaged into versioned archives
|
||||
# to be deployed.
|
||||
#
|
||||
# Library charts provide useful utilities or functions for the chart developer. They're included as
|
||||
# a dependency of application charts to inject those utilities and functions into the rendering
|
||||
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
|
||||
type: application
|
||||
|
||||
# This is the chart version. This version number should be incremented each time you make changes
|
||||
# to the chart and its templates, including the app version.
|
||||
# Versions are expected to follow Semantic Versioning (https://semver.org/)
|
||||
version: 0.1.0
|
||||
|
||||
# This is the version number of the application being deployed. This version number should be
|
||||
# incremented each time you make changes to the application. Versions are not expected to
|
||||
# follow Semantic Versioning. They should reflect the version the application is using.
|
||||
# It is recommended to use it with quotes.
|
||||
appVersion: "1.16.0"
|
||||
1
infra/helm/mysql.txt
Normal file
1
infra/helm/mysql.txt
Normal file
@@ -0,0 +1 @@
|
||||
Oyster-Upstart-Acronym6
|
||||
1
infra/helm/secrets.env
Normal file
1
infra/helm/secrets.env
Normal file
@@ -0,0 +1 @@
|
||||
DATABASE_URL=mysql://root:Oyster-Upstart-Acronym6@10.87.32.3/fleetbase
|
||||
3
infra/helm/templates/NOTES.txt
Normal file
3
infra/helm/templates/NOTES.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
1. Get the application URL by running these commands:
|
||||
|
||||
https://{{ .Values.api_host }}
|
||||
62
infra/helm/templates/_helpers.tpl
Normal file
62
infra/helm/templates/_helpers.tpl
Normal file
@@ -0,0 +1,62 @@
|
||||
{{/*
|
||||
Expand the name of the chart.
|
||||
*/}}
|
||||
{{- define "helm.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create a default fully qualified app name.
|
||||
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||
If release name contains chart name it will be used as a full name.
|
||||
*/}}
|
||||
{{- define "helm.fullname" -}}
|
||||
{{- if .Values.fullnameOverride }}
|
||||
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- $name := default .Chart.Name .Values.nameOverride }}
|
||||
{{- if contains $name .Release.Name }}
|
||||
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create chart name and version as used by the chart label.
|
||||
*/}}
|
||||
{{- define "helm.chart" -}}
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Common labels
|
||||
*/}}
|
||||
{{- define "helm.labels" -}}
|
||||
helm.sh/chart: {{ include "helm.chart" . }}
|
||||
{{ include "helm.selectorLabels" . }}
|
||||
{{- if .Chart.AppVersion }}
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||
{{- end }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Selector labels
|
||||
*/}}
|
||||
{{- define "helm.selectorLabels" -}}
|
||||
app.kubernetes.io/name: {{ include "helm.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create the name of the service account to use
|
||||
*/}}
|
||||
{{- define "helm.serviceAccountName" -}}
|
||||
{{- if .Values.serviceAccount.create }}
|
||||
{{- default (include "helm.fullname" .) .Values.serviceAccount.name }}
|
||||
{{- else }}
|
||||
{{- default "default" .Values.serviceAccount.name }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
17
infra/helm/templates/certificate.yaml
Normal file
17
infra/helm/templates/certificate.yaml
Normal file
@@ -0,0 +1,17 @@
|
||||
apiVersion: networking.gke.io/v1
|
||||
kind: ManagedCertificate
|
||||
metadata:
|
||||
name: managed-cert
|
||||
spec:
|
||||
domains:
|
||||
- {{ .Values.api_host }}
|
||||
- {{ .Values.socketcluster_host }}
|
||||
---
|
||||
apiVersion: networking.gke.io/v1beta1
|
||||
kind: FrontendConfig
|
||||
metadata:
|
||||
name: httpsredirect
|
||||
spec:
|
||||
redirectToHttps:
|
||||
enabled: true
|
||||
responseCodeName: MOVED_PERMANENTLY_DEFAULT
|
||||
81
infra/helm/templates/deployment.yaml
Normal file
81
infra/helm/templates/deployment.yaml
Normal file
@@ -0,0 +1,81 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "helm.fullname" . }}
|
||||
labels:
|
||||
{{- include "helm.labels" . | nindent 4 }}
|
||||
spec:
|
||||
{{- if not .Values.autoscaling.enabled }}
|
||||
replicas: {{ .Values.replicaCount }}
|
||||
{{- end }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "helm.selectorLabels" . | nindent 6 }}
|
||||
template:
|
||||
metadata:
|
||||
{{- with .Values.podAnnotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "helm.selectorLabels" . | nindent 8 }}
|
||||
spec:
|
||||
{{- with .Values.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
serviceAccountName: {{ include "helm.serviceAccountName" . }}
|
||||
securityContext:
|
||||
{{- toYaml .Values.podSecurityContext | nindent 8 }}
|
||||
containers:
|
||||
- name: {{ .Chart.Name }}-httpd
|
||||
securityContext:
|
||||
{{- toYaml .Values.securityContext | nindent 12 }}
|
||||
image: "{{ .Values.image.repository }}/app-httpd:{{ .Values.image.tag | default .Chart.AppVersion }}"
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
env:
|
||||
- name: NGINX_APPLICATION_HOSTNAME
|
||||
value: localhost
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: {{ .Values.service.port }}
|
||||
protocol: TCP
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: http
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: http
|
||||
resources:
|
||||
{{- toYaml .Values.resources | nindent 12 }}
|
||||
- name: {{ .Chart.Name }}
|
||||
securityContext:
|
||||
{{- toYaml .Values.securityContext | nindent 12 }}
|
||||
image: "{{ .Values.image.repository }}/app:{{ .Values.image.tag | default .Chart.AppVersion }}"
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: infra-provided-secret
|
||||
env:
|
||||
- name: CACHE_URL
|
||||
value: $(REDIS_SERVICE_PORT)/1
|
||||
- name: SOCKETCLUSTER_PORT
|
||||
value: "8000"
|
||||
- name: SOCKETCLUSTER_HOST
|
||||
value: $(SOCKETCLUSTER_SERVICE_HOST)
|
||||
resources:
|
||||
{{- toYaml .Values.resources | nindent 12 }}
|
||||
{{- with .Values.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.affinity }}
|
||||
affinity:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
28
infra/helm/templates/hpa.yaml
Normal file
28
infra/helm/templates/hpa.yaml
Normal file
@@ -0,0 +1,28 @@
|
||||
{{- if .Values.autoscaling.enabled }}
|
||||
apiVersion: autoscaling/v2beta1
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: {{ include "helm.fullname" . }}
|
||||
labels:
|
||||
{{- include "helm.labels" . | nindent 4 }}
|
||||
spec:
|
||||
scaleTargetRef:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
name: {{ include "helm.fullname" . }}
|
||||
minReplicas: {{ .Values.autoscaling.minReplicas }}
|
||||
maxReplicas: {{ .Values.autoscaling.maxReplicas }}
|
||||
metrics:
|
||||
{{- if .Values.autoscaling.targetCPUUtilizationPercentage }}
|
||||
- type: Resource
|
||||
resource:
|
||||
name: cpu
|
||||
targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
|
||||
{{- end }}
|
||||
{{- if .Values.autoscaling.targetMemoryUtilizationPercentage }}
|
||||
- type: Resource
|
||||
resource:
|
||||
name: memory
|
||||
targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
60
infra/helm/templates/ingress.yaml
Normal file
60
infra/helm/templates/ingress.yaml
Normal file
@@ -0,0 +1,60 @@
|
||||
{{- if .Values.ingress.enabled -}}
|
||||
{{- $fullName := include "helm.fullname" . -}}
|
||||
{{- $svcPort := .Values.service.port -}}
|
||||
{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }}
|
||||
{{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }}
|
||||
{{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
|
||||
apiVersion: networking.k8s.io/v1beta1
|
||||
{{- else -}}
|
||||
apiVersion: extensions/v1beta1
|
||||
{{- end }}
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: {{ $fullName }}
|
||||
labels:
|
||||
{{- include "helm.labels" . | nindent 4 }}
|
||||
{{- with .Values.ingress.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }}
|
||||
ingressClassName: {{ .Values.ingress.className }}
|
||||
{{- end }}
|
||||
{{- if .Values.ingress.tls }}
|
||||
tls:
|
||||
{{- range .Values.ingress.tls }}
|
||||
- hosts:
|
||||
{{- range .hosts }}
|
||||
- {{ . | quote }}
|
||||
{{- end }}
|
||||
secretName: {{ .secretName }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
rules:
|
||||
- host: {{ .Values.api_host }}
|
||||
http:
|
||||
paths:
|
||||
- path: /*
|
||||
pathType: ImplementationSpecific
|
||||
backend:
|
||||
service:
|
||||
name: fleetbase-app
|
||||
port:
|
||||
number: {{ $svcPort }}
|
||||
- host: {{ .Values.socketcluster_host }}
|
||||
http:
|
||||
paths:
|
||||
- path: /*
|
||||
pathType: ImplementationSpecific
|
||||
backend:
|
||||
service:
|
||||
name: socketcluster
|
||||
port:
|
||||
number: {{ $svcPort }}
|
||||
{{- end }}
|
||||
33
infra/helm/templates/redis.yaml
Normal file
33
infra/helm/templates/redis.yaml
Normal file
@@ -0,0 +1,33 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: redis
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: redis
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: redis
|
||||
spec:
|
||||
containers:
|
||||
- name: redis
|
||||
image: redis:6-alpine # Use the Redis Docker image
|
||||
ports:
|
||||
- containerPort: 6379
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: redis-service
|
||||
spec:
|
||||
selector:
|
||||
app: redis
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 6379
|
||||
targetPort: 6379
|
||||
type: ClusterIP
|
||||
|
||||
15
infra/helm/templates/service.yaml
Normal file
15
infra/helm/templates/service.yaml
Normal file
@@ -0,0 +1,15 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "helm.fullname" . }}
|
||||
labels:
|
||||
{{- include "helm.labels" . | nindent 4 }}
|
||||
spec:
|
||||
type: {{ .Values.service.type }}
|
||||
ports:
|
||||
- port: {{ .Values.service.port }}
|
||||
targetPort: http
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
{{- include "helm.selectorLabels" . | nindent 4 }}
|
||||
12
infra/helm/templates/serviceaccount.yaml
Normal file
12
infra/helm/templates/serviceaccount.yaml
Normal file
@@ -0,0 +1,12 @@
|
||||
{{- if .Values.serviceAccount.create -}}
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: {{ include "helm.serviceAccountName" . }}
|
||||
labels:
|
||||
{{- include "helm.labels" . | nindent 4 }}
|
||||
{{- with .Values.serviceAccount.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
36
infra/helm/templates/socketcluster.yaml
Normal file
36
infra/helm/templates/socketcluster.yaml
Normal file
@@ -0,0 +1,36 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: socketcluster
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: socketcluster
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: socketcluster
|
||||
spec:
|
||||
containers:
|
||||
- name: socketcluster
|
||||
image: socketcluster/socketcluster:v19.1.2
|
||||
ports:
|
||||
- containerPort: 8000
|
||||
env:
|
||||
- name: SOCKETCLUSTER_PORT
|
||||
value: "8000"
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: socketcluster
|
||||
spec:
|
||||
selector:
|
||||
app: socketcluster
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 80
|
||||
targetPort: 8000
|
||||
type: ClusterIP
|
||||
|
||||
15
infra/helm/templates/tests/test-connection.yaml
Normal file
15
infra/helm/templates/tests/test-connection.yaml
Normal file
@@ -0,0 +1,15 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: "{{ include "helm.fullname" . }}-test-connection"
|
||||
labels:
|
||||
{{- include "helm.labels" . | nindent 4 }}
|
||||
annotations:
|
||||
"helm.sh/hook": test
|
||||
spec:
|
||||
containers:
|
||||
- name: wget
|
||||
image: busybox
|
||||
command: ['wget']
|
||||
args: ['{{ include "helm.fullname" . }}:{{ .Values.service.port }}']
|
||||
restartPolicy: Never
|
||||
80
infra/helm/values.yaml
Normal file
80
infra/helm/values.yaml
Normal file
@@ -0,0 +1,80 @@
|
||||
# Default values for helm.
|
||||
# This is a YAML-formatted file.
|
||||
# Declare variables to be passed into your templates.
|
||||
|
||||
replicaCount: 1
|
||||
|
||||
image:
|
||||
repository: OVERRIDE
|
||||
pullPolicy: IfNotPresent
|
||||
# Overrides the image tag whose default is the chart appVersion.
|
||||
tag: "latest"
|
||||
|
||||
imagePullSecrets: []
|
||||
nameOverride: ""
|
||||
fullnameOverride: ""
|
||||
|
||||
serviceAccount:
|
||||
# Specifies whether a service account should be created
|
||||
create: true
|
||||
# Annotations to add to the service account
|
||||
annotations: {}
|
||||
# The name of the service account to use.
|
||||
# If not set and create is true, a name is generated using the fullname template
|
||||
name: ""
|
||||
|
||||
podAnnotations: {}
|
||||
|
||||
podSecurityContext: {}
|
||||
# fsGroup: 2000
|
||||
|
||||
securityContext: {}
|
||||
# capabilities:
|
||||
# drop:
|
||||
# - ALL
|
||||
# readOnlyRootFilesystem: true
|
||||
# runAsNonRoot: true
|
||||
# runAsUser: 1000
|
||||
|
||||
service:
|
||||
type: ClusterIP
|
||||
port: 80
|
||||
|
||||
ingress:
|
||||
enabled: true
|
||||
className: ""
|
||||
annotations:
|
||||
kubernetes.io/ingress.class: gce
|
||||
kubernetes.io/ingress.global-static-ip-name: OVERRIDE
|
||||
networking.gke.io/managed-certificates: managed-cert
|
||||
networking.gke.io/v1beta1.FrontendConfig: "httpsredirect"
|
||||
|
||||
tls: {}
|
||||
# - secretName: chart-example-tls
|
||||
# hosts:
|
||||
# - chart-example.local
|
||||
|
||||
resources: {}
|
||||
# We usually recommend not to specify default resources and to leave this as a conscious
|
||||
# choice for the user. This also increases chances charts run on environments with little
|
||||
# resources, such as Minikube. If you do want to specify resources, uncomment the following
|
||||
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
|
||||
# limits:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
# requests:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
|
||||
autoscaling:
|
||||
enabled: false
|
||||
minReplicas: 1
|
||||
maxReplicas: 100
|
||||
targetCPUUtilizationPercentage: 80
|
||||
# targetMemoryUtilizationPercentage: 80
|
||||
|
||||
nodeSelector: {}
|
||||
|
||||
tolerations: []
|
||||
|
||||
affinity: {}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user