mirror of
https://github.com/czhu12/canine.git
synced 2025-12-30 15:49:54 -06:00
lots
This commit is contained in:
2
Gemfile
2
Gemfile
@@ -84,3 +84,5 @@ gem "rqrcode", "~> 2.2"
|
||||
gem "oj", "~> 3.16"
|
||||
gem "omniauth", "~> 2.1"
|
||||
gem "omniauth-rails_csrf_protection", "~> 1.0"
|
||||
|
||||
gem "annotate", "~> 3.2"
|
||||
|
||||
@@ -89,6 +89,9 @@ GEM
|
||||
tzinfo (~> 2.0, >= 2.0.5)
|
||||
addressable (2.8.7)
|
||||
public_suffix (>= 2.0.2, < 7.0)
|
||||
annotate (3.2.0)
|
||||
activerecord (>= 3.2, < 8.0)
|
||||
rake (>= 10.4, < 14.0)
|
||||
ast (2.4.2)
|
||||
base64 (0.2.0)
|
||||
bcrypt (3.1.20)
|
||||
@@ -503,6 +506,7 @@ PLATFORMS
|
||||
x86_64-linux
|
||||
|
||||
DEPENDENCIES
|
||||
annotate (~> 3.2)
|
||||
bootsnap
|
||||
brakeman
|
||||
capybara
|
||||
|
||||
98
app/controllers/add_ons_controller.rb
Normal file
98
app/controllers/add_ons_controller.rb
Normal file
@@ -0,0 +1,98 @@
|
||||
class AddOnsController < ApplicationController
|
||||
include StorageHelper
|
||||
before_action :set_add_on, only: [:show, :edit, :update, :destroy, :logs]
|
||||
|
||||
# GET /add_ons
|
||||
def index
|
||||
@pagy, @add_ons = pagy(AddOn.sort_by_params(params[:sort], sort_direction))
|
||||
|
||||
# Uncomment to authorize with Pundit
|
||||
# authorize @add_ons
|
||||
end
|
||||
|
||||
# GET /add_ons/1 or /add_ons/1.json
|
||||
def show
|
||||
end
|
||||
|
||||
# GET /add_ons/new
|
||||
def new
|
||||
@add_on = AddOn.new
|
||||
|
||||
# Uncomment to authorize with Pundit
|
||||
# authorize @add_on
|
||||
end
|
||||
|
||||
def logs
|
||||
end
|
||||
|
||||
# GET /add_ons/1/edit
|
||||
def edit
|
||||
end
|
||||
|
||||
# POST /add_ons or /add_ons.json
|
||||
def create
|
||||
@add_on = AddOn.new(add_on_params)
|
||||
# Uncomment to authorize with Pundit
|
||||
# authorize @add_on
|
||||
|
||||
respond_to do |format|
|
||||
if @add_on.save
|
||||
#AddOns::InstallJob.perform_later(@add_on)
|
||||
format.html { redirect_to @add_on, notice: "Add on was successfully created." }
|
||||
format.json { render :show, status: :created, location: @add_on }
|
||||
else
|
||||
format.html { render :new, status: :unprocessable_entity }
|
||||
format.json { render json: @add_on.errors, status: :unprocessable_entity }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# PATCH/PUT /add_ons/1 or /add_ons/1.json
|
||||
def update
|
||||
respond_to do |format|
|
||||
if @add_on.update(add_on_params)
|
||||
format.html { redirect_to @add_on, notice: "Add on was successfully updated." }
|
||||
format.json { render :show, status: :ok, location: @add_on }
|
||||
else
|
||||
format.html { render :edit, status: :unprocessable_entity }
|
||||
format.json { render json: @add_on.errors, status: :unprocessable_entity }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# DELETE /add_ons/1 or /add_ons/1.json
|
||||
def destroy
|
||||
@add_on.uninstalling!
|
||||
respond_to do |format|
|
||||
AddOns::UninstallJob.perform_later(@add_on)
|
||||
format.html { redirect_to add_ons_url, status: :see_other, notice: "Uninstalling add on #{@add_on.name}" }
|
||||
format.json { head :no_content }
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Use callbacks to share common setup or constraints between actions.
|
||||
def set_add_on
|
||||
@add_on = current_user.add_ons.find(params[:id])
|
||||
|
||||
# Uncomment to authorize with Pundit
|
||||
# authorize @add_on
|
||||
if @add_on.chart_type == "redis"
|
||||
@service = K8::Helm::Redis.new(@add_on)
|
||||
elsif @add_on.chart_type == "postgresql"
|
||||
@service = K8::Helm::Postgresql.new(@add_on)
|
||||
end
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
redirect_to add_ons_path
|
||||
end
|
||||
|
||||
# Only allow a list of trusted parameters through.
|
||||
def add_on_params
|
||||
params[:add_on][:metadata] = params[:add_on][:metadata][params[:add_on][:chart_type]]
|
||||
params.require(:add_on).permit(:cluster_id, :chart_type, :name, metadata: {})
|
||||
|
||||
# Uncomment to use Pundit permitted attributes
|
||||
# params.require(:add_on).permit(policy(@add_on).permitted_attributes)
|
||||
end
|
||||
end
|
||||
9
app/controllers/clusters/base_controller.rb
Normal file
9
app/controllers/clusters/base_controller.rb
Normal file
@@ -0,0 +1,9 @@
|
||||
class Clusters::BaseController < ApplicationController
|
||||
before_action :set_cluster
|
||||
|
||||
private
|
||||
|
||||
def set_cluster
|
||||
@cluster = Cluster.find(params[:cluster_id])
|
||||
end
|
||||
end
|
||||
8
app/controllers/clusters/metrics_controller.rb
Normal file
8
app/controllers/clusters/metrics_controller.rb
Normal file
@@ -0,0 +1,8 @@
|
||||
class Clusters::MetricsController < Clusters::BaseController
|
||||
before_action :set_cluster
|
||||
|
||||
def show
|
||||
@pod_metrics = K8::Metrics::Pods.call(@cluster)
|
||||
@node_metrics = K8::Metrics::Nodes.call(@cluster)
|
||||
end
|
||||
end
|
||||
110
app/controllers/clusters_controller.rb
Normal file
110
app/controllers/clusters_controller.rb
Normal file
@@ -0,0 +1,110 @@
|
||||
class ClustersController < ApplicationController
|
||||
before_action :set_cluster, only: [:show, :edit, :update, :destroy, :test_connection, :download_kubeconfig]
|
||||
|
||||
# GET /clusters
|
||||
def index
|
||||
@pagy, @clusters = pagy(current_user.clusters.sort_by_params(params[:sort], sort_direction))
|
||||
|
||||
# Uncomment to authorize with Pundit
|
||||
# authorize @clusters
|
||||
end
|
||||
|
||||
# GET /clusters/1 or /clusters/1.json
|
||||
def show
|
||||
end
|
||||
|
||||
# GET /clusters/new
|
||||
def new
|
||||
@cluster = Cluster.new
|
||||
|
||||
# Uncomment to authorize with Pundit
|
||||
# authorize @cluster
|
||||
end
|
||||
|
||||
# GET /clusters/1/edit
|
||||
def edit
|
||||
end
|
||||
|
||||
def restart
|
||||
K8::Kubectl.new(@cluster.kubeconfig).run("rollout restart deployment")
|
||||
redirect_to @cluster, notice: "Cluster was successfully restarted."
|
||||
end
|
||||
|
||||
def test_connection
|
||||
client = K8::Client.new(@cluster.kubeconfig)
|
||||
if client.can_connect?
|
||||
render turbo_stream: turbo_stream.replace("test_connection_frame", partial: "clusters/connection_success")
|
||||
else
|
||||
render turbo_stream: turbo_stream.replace("test_connection_frame", partial: "clusters/connection_failed")
|
||||
end
|
||||
end
|
||||
|
||||
def download_kubeconfig
|
||||
send_data @cluster.kubeconfig, filename: "#{@cluster.name}-kubeconfig.yml", type: "application/yaml"
|
||||
end
|
||||
|
||||
# POST /clusters or /clusters.json
|
||||
def create
|
||||
@cluster = current_user.clusters.new(cluster_params)
|
||||
|
||||
# Uncomment to authorize with Pundit
|
||||
# authorize @cluster
|
||||
|
||||
respond_to do |format|
|
||||
if @cluster.save
|
||||
# Kick off cluster job
|
||||
InstallClusterJob.perform_later(@cluster)
|
||||
format.html { redirect_to @cluster, notice: "Cluster was successfully created." }
|
||||
format.json { render :show, status: :created, location: @cluster }
|
||||
else
|
||||
format.html { render :new, status: :unprocessable_entity }
|
||||
format.json { render json: @cluster.errors, status: :unprocessable_entity }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# PATCH/PUT /clusters/1 or /clusters/1.json
|
||||
def update
|
||||
respond_to do |format|
|
||||
if @cluster.update(cluster_params)
|
||||
format.html { redirect_to @cluster, notice: "Cluster was successfully updated." }
|
||||
format.json { render :show, status: :ok, location: @cluster }
|
||||
else
|
||||
format.html { render :edit, status: :unprocessable_entity }
|
||||
format.json { render json: @cluster.errors, status: :unprocessable_entity }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# DELETE /clusters/1 or /clusters/1.json
|
||||
def destroy
|
||||
@cluster.destroy!
|
||||
respond_to do |format|
|
||||
format.html { redirect_to clusters_url, status: :see_other, notice: "Cluster was successfully destroyed." }
|
||||
format.json { head :no_content }
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Use callbacks to share common setup or constraints between actions.
|
||||
def set_cluster
|
||||
@cluster = current_user.clusters.find(params[:id])
|
||||
|
||||
# Uncomment to authorize with Pundit
|
||||
# authorize @cluster
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
redirect_to clusters_path
|
||||
end
|
||||
|
||||
# Only allow a list of trusted parameters through.
|
||||
def cluster_params
|
||||
if params[:cluster][:kubeconfig].present?
|
||||
kubeconfig_file = params[:cluster][:kubeconfig]
|
||||
yaml_content = kubeconfig_file.read
|
||||
params[:cluster][:kubeconfig] = YAML.safe_load(yaml_content).to_json
|
||||
end
|
||||
|
||||
params.require(:cluster).permit(:name, :kubeconfig)
|
||||
end
|
||||
end
|
||||
9
app/controllers/projects/base_controller.rb
Normal file
9
app/controllers/projects/base_controller.rb
Normal file
@@ -0,0 +1,9 @@
|
||||
class Projects::BaseController < ApplicationController
|
||||
include ProjectsHelper
|
||||
before_action :set_project
|
||||
|
||||
private
|
||||
def set_project
|
||||
@project = current_user.projects.find(params[:project_id])
|
||||
end
|
||||
end
|
||||
35
app/controllers/projects/deployments_controller.rb
Normal file
35
app/controllers/projects/deployments_controller.rb
Normal file
@@ -0,0 +1,35 @@
|
||||
class Projects::DeploymentsController < Projects::BaseController
|
||||
before_action :set_project
|
||||
before_action :set_build, only: %i[show redeploy]
|
||||
|
||||
def index
|
||||
@pagy, @builds = pagy(@project.builds.sort_by_params(params[:sort], 'desc'))
|
||||
end
|
||||
|
||||
def show; end
|
||||
|
||||
def redeploy
|
||||
new_build = @build.dup
|
||||
if new_build.save
|
||||
Projects::BuildJob.perform_later(new_build)
|
||||
redirect_to project_deployment_path(@project, new_build), notice: 'Redeploying...'
|
||||
else
|
||||
redirect_to project_deployments_url(@project), alert: 'Failed to redeploy'
|
||||
end
|
||||
end
|
||||
|
||||
def deploy
|
||||
result = Projects::DeployLatestCommit.execute(project: @project)
|
||||
if result.success?
|
||||
redirect_to @project, notice: 'Deploying project...'
|
||||
else
|
||||
redirect_to @project, alert: 'Failed to deploy project'
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_build
|
||||
@build = @project.builds.find(params[:id])
|
||||
end
|
||||
end
|
||||
34
app/controllers/projects/domains_controller.rb
Normal file
34
app/controllers/projects/domains_controller.rb
Normal file
@@ -0,0 +1,34 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class Projects::DomainsController < Projects::BaseController
|
||||
before_action :set_project
|
||||
|
||||
def create
|
||||
# TODO(chris): This is a bit of a hack, we should probably refactor this
|
||||
@domain = @project.services.web_service.first.domains.new(domain_params)
|
||||
respond_to do |format|
|
||||
if @domain.save
|
||||
Projects::AddDomainJob.perform_later(@domain.cluster)
|
||||
format.html { redirect_to project_path(@project), notice: 'Domain was successfully added.' }
|
||||
format.json { render :show, status: :created, domain: @domain }
|
||||
else
|
||||
format.html { render :new, status: :unprocessable_entity }
|
||||
format.json { render json: @domain.errors, status: :unprocessable_entity }
|
||||
end
|
||||
format.turbo_stream
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@domain = @project.domains.find(params[:id])
|
||||
@domain.destroy
|
||||
|
||||
respond_to(&:turbo_stream)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def domain_params
|
||||
params.require(:domain).permit(:domain_name)
|
||||
end
|
||||
end
|
||||
27
app/controllers/projects/environment_variables_controller.rb
Normal file
27
app/controllers/projects/environment_variables_controller.rb
Normal file
@@ -0,0 +1,27 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class Projects::EnvironmentVariablesController < Projects::BaseController
|
||||
before_action :set_project
|
||||
|
||||
def index
|
||||
@environment_variables = @project.environment_variables
|
||||
end
|
||||
|
||||
def create
|
||||
EnvironmentVariables::BulkUpdate.execute(project: @project, params:)
|
||||
if @project.current_deployment.present?
|
||||
Projects::DeploymentJob.perform_later(@project.current_deployment)
|
||||
redirect_to project_environment_variables_path(@project),
|
||||
notice: 'Deployment started to apply new environment variables.'
|
||||
else
|
||||
redirect_to project_environment_variables_path(@project),
|
||||
notice: 'Environment variables will be applied on the next deployment.'
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def environment_variable_params
|
||||
params.require(:environment_variable).permit(:name, :value)
|
||||
end
|
||||
end
|
||||
13
app/controllers/projects/metrics_controller.rb
Normal file
13
app/controllers/projects/metrics_controller.rb
Normal file
@@ -0,0 +1,13 @@
|
||||
class Projects::MetricsController < Projects::BaseController
|
||||
def index
|
||||
client = K8::Client.from_project(@project).client
|
||||
@services = client.get_services
|
||||
@service = @services.find { |service| service.metadata.name == "#{@project.name}-service" }
|
||||
@pod_metrics = if @service.present?
|
||||
selector = "app=#{@service.metadata['labels'].app}"
|
||||
K8::Metrics::Pods.call(@project.cluster, selector:)
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
end
|
||||
46
app/controllers/projects/project_add_ons_controller.rb
Normal file
46
app/controllers/projects/project_add_ons_controller.rb
Normal file
@@ -0,0 +1,46 @@
|
||||
class Projects::ProjectAddOnsController < Projects::BaseController
|
||||
before_action :set_project_add_on, only: %i[show edit update destroy]
|
||||
|
||||
def index
|
||||
@project_add_ons = @project.project_add_ons
|
||||
end
|
||||
|
||||
def new
|
||||
@project_add_on = @project.project_add_ons.build
|
||||
end
|
||||
|
||||
def create
|
||||
@project_add_on = @project.project_add_ons.build(project_add_on_params)
|
||||
|
||||
if @project_add_on.save
|
||||
redirect_to project_project_add_on_path(@project, @project_add_on),
|
||||
notice: 'Project add-on was successfully created.'
|
||||
else
|
||||
render :new
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
if @project_add_on.update(project_add_on_params)
|
||||
redirect_to project_project_add_on_path(@project, @project_add_on),
|
||||
notice: 'Project add-on was successfully updated.'
|
||||
else
|
||||
render :edit
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@project_add_on.destroy
|
||||
redirect_to project_project_add_ons_path(@project), notice: 'Project add-on was successfully destroyed.'
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_project_add_on
|
||||
@project_add_on = @project.project_add_ons.find(params[:id])
|
||||
end
|
||||
|
||||
def project_add_on_params
|
||||
params.require(:project_add_on).permit(:project_id, :add_on_id)
|
||||
end
|
||||
end
|
||||
47
app/controllers/projects/services_controller.rb
Normal file
47
app/controllers/projects/services_controller.rb
Normal file
@@ -0,0 +1,47 @@
|
||||
class Projects::ServicesController < Projects::BaseController
|
||||
before_action :set_project
|
||||
before_action :set_service, only: %i[update destroy]
|
||||
|
||||
def index
|
||||
@services = @project.services
|
||||
end
|
||||
|
||||
def new
|
||||
@service = @project.services.build
|
||||
end
|
||||
|
||||
def create
|
||||
service = @project.services.build(service_params)
|
||||
if service.save
|
||||
redirect_to project_services_path(@project), notice: 'Service was successfully created.'
|
||||
else
|
||||
redirect_to project_services_path(@project), alert: 'Service could not be created.'
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
if @service.update(service_params)
|
||||
redirect_to project_services_path(@project), notice: 'Service was successfully updated.'
|
||||
else
|
||||
redirect_to project_services_path(@project), alert: 'Service could not be updated.'
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
if @service.destroy
|
||||
redirect_to project_services_path(@project), notice: 'Service was successfully destroyed.'
|
||||
else
|
||||
redirect_to project_services_path(@project), alert: 'Service could not be destroyed.'
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_service
|
||||
@service = @project.services.find(params[:id])
|
||||
end
|
||||
|
||||
def service_params
|
||||
params.require(:service).permit(:service_type, :command, :name)
|
||||
end
|
||||
end
|
||||
89
app/controllers/projects_controller.rb
Normal file
89
app/controllers/projects_controller.rb
Normal file
@@ -0,0 +1,89 @@
|
||||
class ProjectsController < ApplicationController
|
||||
include ProjectsHelper
|
||||
before_action :set_project, only: %i[show edit update destroy]
|
||||
|
||||
# GET /projects
|
||||
def index
|
||||
@pagy, @projects = pagy(current_user.projects.sort_by_params(params[:sort], sort_direction))
|
||||
|
||||
# Uncomment to authorize with Pundit
|
||||
# authorize @projects
|
||||
end
|
||||
|
||||
# GET /projects/1 or /projects/1.json
|
||||
def show; end
|
||||
|
||||
# GET /projects/new
|
||||
def new
|
||||
@project = Project.new
|
||||
|
||||
# Uncomment to authorize with Pundit
|
||||
# authorize @project
|
||||
end
|
||||
|
||||
# GET /projects/1/edit
|
||||
def edit; end
|
||||
|
||||
# POST /projects or /projects.json
|
||||
def create
|
||||
result = Projects::Create.call(Project.new(project_params), params)
|
||||
|
||||
@project = result.project
|
||||
respond_to do |format|
|
||||
if result.success?
|
||||
format.html { redirect_to @project, notice: 'Project was successfully created.' }
|
||||
format.json { render :show, status: :created, location: @project }
|
||||
else
|
||||
format.html { render :new, status: :unprocessable_entity }
|
||||
format.json { render json: @project.errors, status: :unprocessable_entity }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# PATCH/PUT /projects/1 or /projects/1.json
|
||||
def update
|
||||
respond_to do |format|
|
||||
if @project.update(project_params)
|
||||
format.html { redirect_to @project, notice: 'Project was successfully updated.' }
|
||||
format.json { render :show, status: :ok, location: @project }
|
||||
else
|
||||
format.html { render :edit, status: :unprocessable_entity }
|
||||
format.json { render json: @project.errors, status: :unprocessable_entity }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# DELETE /projects/1 or /projects/1.json
|
||||
def destroy
|
||||
@project.destroy!
|
||||
respond_to do |format|
|
||||
format.html { redirect_to projects_url, status: :see_other, notice: 'Project was successfully destroyed.' }
|
||||
format.json { head :no_content }
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Use callbacks to share common setup or constraints between actions.
|
||||
def set_project
|
||||
@project = Project.find(params[:id])
|
||||
|
||||
# Uncomment to authorize with Pundit
|
||||
# authorize @project
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
redirect_to projects_path
|
||||
end
|
||||
|
||||
# Only allow a list of trusted parameters through.
|
||||
def project_params
|
||||
params.require(:project).permit(
|
||||
:name,
|
||||
:repository_url,
|
||||
:branch,
|
||||
:cluster_id,
|
||||
:docker_build_context_directory,
|
||||
:docker_command,
|
||||
:dockerfile_path
|
||||
)
|
||||
end
|
||||
end
|
||||
24
app/models/add_on.rb
Normal file
24
app/models/add_on.rb
Normal file
@@ -0,0 +1,24 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: add_ons
|
||||
#
|
||||
# id :bigint not null, primary key
|
||||
# chart_type :string not null
|
||||
# metadata :jsonb
|
||||
# name :string not null
|
||||
# status :integer default(0), not null
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# cluster_id :bigint not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_add_ons_on_cluster_id (cluster_id)
|
||||
# index_add_ons_on_cluster_id_and_name (cluster_id,name) UNIQUE
|
||||
#
|
||||
# Foreign Keys
|
||||
#
|
||||
# fk_rails_... (cluster_id => clusters.id)
|
||||
#
|
||||
class AddOn < ApplicationRecord
|
||||
end
|
||||
@@ -1,3 +1,15 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: announcements
|
||||
#
|
||||
# id :bigint not null, primary key
|
||||
# announcement_type :string
|
||||
# description :text
|
||||
# name :string
|
||||
# published_at :datetime
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
#
|
||||
class Announcement < ApplicationRecord
|
||||
TYPES = %w{ new fix update }
|
||||
|
||||
|
||||
24
app/models/build.rb
Normal file
24
app/models/build.rb
Normal file
@@ -0,0 +1,24 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: builds
|
||||
#
|
||||
# id :bigint not null, primary key
|
||||
# commit_message :string
|
||||
# commit_sha :string not null
|
||||
# git_sha :string
|
||||
# repository_url :string
|
||||
# status :integer default(0)
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# project_id :bigint not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_builds_on_project_id (project_id)
|
||||
#
|
||||
# Foreign Keys
|
||||
#
|
||||
# fk_rails_... (project_id => projects.id)
|
||||
#
|
||||
class Build < ApplicationRecord
|
||||
end
|
||||
22
app/models/cluster.rb
Normal file
22
app/models/cluster.rb
Normal file
@@ -0,0 +1,22 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: clusters
|
||||
#
|
||||
# id :bigint not null, primary key
|
||||
# kubeconfig :jsonb not null
|
||||
# name :string not null
|
||||
# status :integer default(0), not null
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# user_id :bigint not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_clusters_on_user_id (user_id)
|
||||
#
|
||||
# Foreign Keys
|
||||
#
|
||||
# fk_rails_... (user_id => users.id)
|
||||
#
|
||||
class Cluster < ApplicationRecord
|
||||
end
|
||||
18
app/models/cron_schedule.rb
Normal file
18
app/models/cron_schedule.rb
Normal file
@@ -0,0 +1,18 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: cron_schedules
|
||||
#
|
||||
# id :bigint not null, primary key
|
||||
# schedule :string not null
|
||||
# service_id :bigint not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_cron_schedules_on_service_id (service_id)
|
||||
#
|
||||
# Foreign Keys
|
||||
#
|
||||
# fk_rails_... (service_id => services.id)
|
||||
#
|
||||
class CronSchedule < ApplicationRecord
|
||||
end
|
||||
20
app/models/deployment.rb
Normal file
20
app/models/deployment.rb
Normal file
@@ -0,0 +1,20 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: deployments
|
||||
#
|
||||
# id :bigint not null, primary key
|
||||
# status :integer default(0), not null
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# build_id :bigint not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_deployments_on_build_id (build_id)
|
||||
#
|
||||
# Foreign Keys
|
||||
#
|
||||
# fk_rails_... (build_id => builds.id)
|
||||
#
|
||||
class Deployment < ApplicationRecord
|
||||
end
|
||||
20
app/models/domain.rb
Normal file
20
app/models/domain.rb
Normal file
@@ -0,0 +1,20 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: domains
|
||||
#
|
||||
# id :bigint not null, primary key
|
||||
# domain_name :string not null
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# service_id :bigint not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_domains_on_service_id (service_id)
|
||||
#
|
||||
# Foreign Keys
|
||||
#
|
||||
# fk_rails_... (service_id => services.id)
|
||||
#
|
||||
class Domain < ApplicationRecord
|
||||
end
|
||||
22
app/models/environment_variable.rb
Normal file
22
app/models/environment_variable.rb
Normal file
@@ -0,0 +1,22 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: environment_variables
|
||||
#
|
||||
# id :bigint not null, primary key
|
||||
# name :string not null
|
||||
# value :text
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# project_id :bigint not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_environment_variables_on_project_id (project_id)
|
||||
# index_environment_variables_on_project_id_and_name (project_id,name) UNIQUE
|
||||
#
|
||||
# Foreign Keys
|
||||
#
|
||||
# fk_rails_... (project_id => projects.id)
|
||||
#
|
||||
class EnvironmentVariable < ApplicationRecord
|
||||
end
|
||||
13
app/models/log_output.rb
Normal file
13
app/models/log_output.rb
Normal file
@@ -0,0 +1,13 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: log_outputs
|
||||
#
|
||||
# id :bigint not null, primary key
|
||||
# loggable_type :string not null
|
||||
# output :text
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# loggable_id :bigint not null
|
||||
#
|
||||
class LogOutput < ApplicationRecord
|
||||
end
|
||||
29
app/models/project.rb
Normal file
29
app/models/project.rb
Normal file
@@ -0,0 +1,29 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: projects
|
||||
#
|
||||
# id :bigint not null, primary key
|
||||
# autodeploy :boolean default(TRUE), not null
|
||||
# branch :string default("main"), not null
|
||||
# docker_build_context_directory :string default("."), not null
|
||||
# docker_command :string
|
||||
# dockerfile_path :string default("./Dockerfile"), not null
|
||||
# name :string not null
|
||||
# predeploy_command :string
|
||||
# repository_url :string not null
|
||||
# status :integer default(0), not null
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# cluster_id :bigint not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_projects_on_cluster_id (cluster_id)
|
||||
# index_projects_on_name (name) UNIQUE
|
||||
#
|
||||
# Foreign Keys
|
||||
#
|
||||
# fk_rails_... (cluster_id => clusters.id)
|
||||
#
|
||||
class Project < ApplicationRecord
|
||||
end
|
||||
22
app/models/project_add_on.rb
Normal file
22
app/models/project_add_on.rb
Normal file
@@ -0,0 +1,22 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: project_add_ons
|
||||
#
|
||||
# id :bigint not null, primary key
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# add_on_id :bigint not null
|
||||
# project_id :bigint not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_project_add_ons_on_add_on_id (add_on_id)
|
||||
# index_project_add_ons_on_project_id (project_id)
|
||||
#
|
||||
# Foreign Keys
|
||||
#
|
||||
# fk_rails_... (add_on_id => add_ons.id)
|
||||
# fk_rails_... (project_id => projects.id)
|
||||
#
|
||||
class ProjectAddOn < ApplicationRecord
|
||||
end
|
||||
@@ -1,3 +1,27 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: services
|
||||
#
|
||||
# id :bigint not null, primary key
|
||||
# access_token :string
|
||||
# access_token_secret :string
|
||||
# auth :text
|
||||
# expires_at :datetime
|
||||
# provider :string
|
||||
# refresh_token :string
|
||||
# uid :string
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# user_id :bigint not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_services_on_user_id (user_id)
|
||||
#
|
||||
# Foreign Keys
|
||||
#
|
||||
# fk_rails_... (user_id => users.id)
|
||||
#
|
||||
class Service < ApplicationRecord
|
||||
belongs_to :user
|
||||
|
||||
|
||||
@@ -1,3 +1,25 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: users
|
||||
#
|
||||
# id :bigint not null, primary key
|
||||
# admin :boolean default(FALSE)
|
||||
# announcements_last_read_at :datetime
|
||||
# email :string default(""), not null
|
||||
# encrypted_password :string default(""), not null
|
||||
# first_name :string
|
||||
# last_name :string
|
||||
# remember_created_at :datetime
|
||||
# reset_password_sent_at :datetime
|
||||
# reset_password_token :string
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_users_on_email (email) UNIQUE
|
||||
# index_users_on_reset_password_token (reset_password_token) UNIQUE
|
||||
#
|
||||
class User < ApplicationRecord
|
||||
# Include default devise modules. Others available are:
|
||||
# :confirmable, :lockable, :timeoutable and :omniauthable
|
||||
|
||||
14
app/views/add_ons/_add_on.html.erb
Normal file
14
app/views/add_ons/_add_on.html.erb
Normal file
@@ -0,0 +1,14 @@
|
||||
<!-- How to represent an add_on on other surfaces -->
|
||||
<%= link_to add_on_path(add_on) do %>
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title">
|
||||
<%= add_on.name %>
|
||||
</h2>
|
||||
<p class="card-text">
|
||||
<%= render "add_ons/status", add_on: add_on %>
|
||||
<%= add_on.chart_type.titleize %>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
2
app/views/add_ons/_add_on.json.jbuilder
Normal file
2
app/views/add_ons/_add_on.json.jbuilder
Normal file
@@ -0,0 +1,2 @@
|
||||
json.extract! add_on, :id, :cluster_id, :add_on_type, :name, :metadata, :created_at, :updated_at
|
||||
json.url add_on_url(add_on, format: :json)
|
||||
27
app/views/add_ons/_chart_form.html.erb
Normal file
27
app/views/add_ons/_chart_form.html.erb
Normal file
@@ -0,0 +1,27 @@
|
||||
<% chart['template'].each do |variable| %>
|
||||
<% next if variable['hidden'] %>
|
||||
<div class="form-group">
|
||||
<%= form.label variable['name'] %>
|
||||
<% if variable['type'] == 'string' %>
|
||||
<%= form.text_field variable['key'], name: "add_on[metadata][#{chart['name']}][template][#{variable['key']}]", class: "input input-bordered" %>
|
||||
<% elsif variable['type'] == 'size' %>
|
||||
<%= form.hidden_field(
|
||||
"metadata][#{chart['name']}][template][#{variable['key']}][type",
|
||||
value: 'size'
|
||||
) %>
|
||||
<%= form.text_field(
|
||||
variable['key'],
|
||||
name: "add_on[metadata][#{chart['name']}][template][#{variable['key']}][value]",
|
||||
class: "input input-bordered",
|
||||
type: 'number',
|
||||
value: variable['default'][..-3]
|
||||
) %>
|
||||
<%= form.select(
|
||||
"metadata][#{chart['name']}][template][#{variable['key']}][unit",
|
||||
options_for_select([['Gi', 'Gi'], ['Mi', 'Mi'], ['Ki', 'Ki']]),
|
||||
{ value: variable['default'][-2..] },
|
||||
{ class: "select select-bordered" }
|
||||
) %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
22
app/views/add_ons/_index.html.erb
Normal file
22
app/views/add_ons/_index.html.erb
Normal file
@@ -0,0 +1,22 @@
|
||||
<table class="table w-full">
|
||||
<thead class="border-b-2 border-gray-300">
|
||||
<tr>
|
||||
<th class="text-left py-2">Name</th>
|
||||
<th class="text-left py-2">Helm Chart</th>
|
||||
<th class="text-left py-2">Cluster</th>
|
||||
<th class="text-left py-2">Status</th>
|
||||
<th class="text-left py-2">Created</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% add_ons.each do |add_on| %>
|
||||
<tr class="border-b border-gray-200">
|
||||
<td class="py-4"><%= link_to add_on.name, add_on, class: "text-inherit hover:underline" %></td>
|
||||
<td class="py-4"><%= add_on.chart_type %></td>
|
||||
<td class="py-4"><%= link_to add_on.cluster.name, add_on.cluster, class: "text-inherit hover:underline" %></td>
|
||||
<td class="py-4"><%= render "add_ons/status", add_on: %></td>
|
||||
<td class="py-4"><%= time_ago_in_words(add_on.created_at) %> ago</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
29
app/views/add_ons/_installing.html.erb
Normal file
29
app/views/add_ons/_installing.html.erb
Normal file
@@ -0,0 +1,29 @@
|
||||
<div class="scene">
|
||||
<div class="objects">
|
||||
<div class="square"></div>
|
||||
<div class="circle"></div>
|
||||
<div class="triangle"></div>
|
||||
</div>
|
||||
<div class="wizard">
|
||||
<div class="body"></div>
|
||||
<div class="right-arm">
|
||||
<div class="right-hand"></div>
|
||||
</div>
|
||||
<div class="left-arm">
|
||||
<div class="left-hand"></div>
|
||||
</div>
|
||||
<div class="head">
|
||||
<div class="beard"></div>
|
||||
<div class="face">
|
||||
<div class="adds"></div>
|
||||
</div>
|
||||
<div class="hat">
|
||||
<div class="hat-of-the-hat"></div>
|
||||
<div class="four-point-star --first"></div>
|
||||
<div class="four-point-star --second"></div>
|
||||
<div class="four-point-star --third"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="progress"></div>
|
||||
35
app/views/add_ons/_layout.html.erb
Normal file
35
app/views/add_ons/_layout.html.erb
Normal file
@@ -0,0 +1,35 @@
|
||||
<% if add_on.installing? %>
|
||||
<div class="flex flex-col items-center justify-center">
|
||||
<%= render "add_ons/installing" %>
|
||||
<div class="mt-4 text-lg">
|
||||
Your add-on is installing... Go grab a coffee, this could take a while.
|
||||
</div>
|
||||
</div>
|
||||
<% else %>
|
||||
<div class="container px-4 mx-auto my-8">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<div>
|
||||
<div class="text-sm">
|
||||
<%= render "add_ons/status", add_on: @add_on %>
|
||||
</div>
|
||||
<h1 class="h3">
|
||||
<%= @add_on.name %>
|
||||
</h1>
|
||||
<div class="flex flex-row">
|
||||
<%= link_to @add_on.cluster.name, cluster_path(@add_on.cluster), class: "mr-2" %>
|
||||
<%= @add_on.chart_type %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="p-8 dark:border border-base-300 bg-gray-900 rounded-b-box rounded shadow">
|
||||
<div class="container mx-auto flex">
|
||||
<!-- Sidebar -->
|
||||
<%= render "add_ons/sidebar", add_on: add_on %>
|
||||
<div class="block w-full">
|
||||
<%= yield %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
33
app/views/add_ons/_postgresql.html.erb
Normal file
33
app/views/add_ons/_postgresql.html.erb
Normal file
@@ -0,0 +1,33 @@
|
||||
<h4>PostgreSQL</h4>
|
||||
<div class="mt-2 space-y-6">
|
||||
<div>
|
||||
<h6>Storage</h6>
|
||||
<% @service.storage_metrics.each do |metric| %>
|
||||
<div>Volume: <pre class="inline"><%= metric[:name] %></pre></div>
|
||||
<div><strong><%= metric[:usage][:use_percentage] %>%</strong> used out of <strong><%= standardize_size(metric[:usage][:available]) %>B</strong></div>
|
||||
<progress class="progress w-56" value="<%= metric[:usage][:use_percentage] %>" max="100"></progress>
|
||||
<% end %>
|
||||
</div>
|
||||
<div>
|
||||
<h6>Created</h6>
|
||||
<div><%= @add_on.created_at.to_formatted_s(:long_ordinal) %></div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h6>PostgreSQL Version</h6>
|
||||
<div><%= @service.version %></div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h6>Connection Details</h6>
|
||||
<div class="mt-2">
|
||||
<label for="redis-password" class="form-label">Connection URL</label>
|
||||
<div class="flex flex-row" data-controller="toggle-password">
|
||||
<input type="password" id="redis-password" name="redis-password" class="form-control" value="<%= @service.internal_url %>" data-toggle-password-target="input">
|
||||
<button class="btn btn-outline-secondary" type="button" data-action="click->toggle-password#toggle">
|
||||
<i class="bi bi-eye" data-toggle-password-target="icon"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
33
app/views/add_ons/_redis.html.erb
Normal file
33
app/views/add_ons/_redis.html.erb
Normal file
@@ -0,0 +1,33 @@
|
||||
<h4>Redis</h4>
|
||||
<div class="mt-2 space-y-6">
|
||||
<div>
|
||||
<h6>Storage</h6>
|
||||
<% @service.storage_metrics.each do |metric| %>
|
||||
<div>Volume: <pre class="inline"><%= metric[:name] %></pre></div>
|
||||
<div><strong><%= metric[:usage][:use_percentage] %>%</strong> used out of <strong><%= standardize_size(metric[:usage][:available]) %>B</strong></div>
|
||||
<progress class="progress w-56" value="<%= metric[:usage][:use_percentage] %>" max="100"></progress>
|
||||
<% end %>
|
||||
</div>
|
||||
<div>
|
||||
<h6>Created</h6>
|
||||
<div><%= @add_on.created_at.to_formatted_s(:long_ordinal) %></div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h6>Redis Version</h6>
|
||||
<div><%= @service.version %></div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h6>Connection Details</h6>
|
||||
<div class="mt-2">
|
||||
<label for="redis-password" class="form-label">Connection URL</label>
|
||||
<div class="flex flex-row" data-controller="toggle-password">
|
||||
<input type="password" id="redis-password" name="redis-password" class="form-control" value="<%= @service.internal_url %>" data-toggle-password-target="input">
|
||||
<button class="btn btn-outline-secondary" type="button" data-action="click->toggle-password#toggle">
|
||||
<i class="bi bi-eye" data-toggle-password-target="icon"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
7
app/views/add_ons/_sidebar.html.erb
Normal file
7
app/views/add_ons/_sidebar.html.erb
Normal file
@@ -0,0 +1,7 @@
|
||||
<nav class="w-64 p-4">
|
||||
<ul class="space-y-2 list-none">
|
||||
<li><%= link_to "Info", add_on_url(add_on), class: "block py-2 px-4 hover:bg-neutral rounded" %></li>
|
||||
<li><%= link_to "Logs", logs_add_on_url(add_on), class: "block py-2 px-4 hover:bg-neutral rounded" %></li>
|
||||
<li><%= link_to "Settings", edit_add_on_url(add_on), class: "block py-2 px-4 hover:bg-neutral rounded" %></li>
|
||||
</ul>
|
||||
</nav>
|
||||
10
app/views/add_ons/_status.html.erb
Normal file
10
app/views/add_ons/_status.html.erb
Normal file
@@ -0,0 +1,10 @@
|
||||
<% if add_on.installed? %>
|
||||
<div class="text-green-500">
|
||||
●
|
||||
<%= add_on.status.titleize.upcase %>
|
||||
</div>
|
||||
<% elsif %>
|
||||
<div class="text-danger-500">
|
||||
<%= add_on.status.titleize.upcase %>
|
||||
</div>
|
||||
<% end %>
|
||||
7
app/views/add_ons/edit.html.erb
Normal file
7
app/views/add_ons/edit.html.erb
Normal file
@@ -0,0 +1,7 @@
|
||||
<%= content_for :title, t("scaffold.edit.title", model: "Add On") %>
|
||||
<%= add_on_layout(@add_on) do %>
|
||||
<div>
|
||||
Delete Add-on
|
||||
</div>
|
||||
<%= button_to "Uninstall", add_on_path(@add_on), method: :delete, class: "btn btn-danger" %>
|
||||
<% end %>
|
||||
23
app/views/add_ons/index.html.erb
Normal file
23
app/views/add_ons/index.html.erb
Normal file
@@ -0,0 +1,23 @@
|
||||
<%= content_for :title, "Add Ons" %>
|
||||
<%= turbo_stream_from :add_ons %>
|
||||
|
||||
<div class="container px-4 mx-auto my-8">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<%= link_to t("scaffold.new.title", model: "Add On"), new_add_on_path, class: "btn btn-secondary" %>
|
||||
</div>
|
||||
|
||||
<%= tag.div id: ("add_ons" if first_page?), class: "bg-white dark:bg-gray-900 dark:border dark:border-gray-700 rounded-md shadow p-6 space-y-8" do %>
|
||||
<%= render "add_ons/index", add_ons: @add_ons, cached: true %>
|
||||
|
||||
<div class="hidden only:block text-center">
|
||||
<p class="mb-4 h3">Create your first Add On</p>
|
||||
<%= link_to t("scaffold.new.title", model: "Add On"), new_add_on_path, class: "btn btn-primary" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% if @pagy.pages > 1 %>
|
||||
<div class="my-6 text-center">
|
||||
<%== pagy_nav(@pagy) %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
1
app/views/add_ons/index.json.jbuilder
Normal file
1
app/views/add_ons/index.json.jbuilder
Normal file
@@ -0,0 +1 @@
|
||||
json.array! @add_ons, partial: "add_ons/add_on", as: :add_on
|
||||
3
app/views/add_ons/logs.html.erb
Normal file
3
app/views/add_ons/logs.html.erb
Normal file
@@ -0,0 +1,3 @@
|
||||
<%= add_on_layout(@add_on) do %>
|
||||
<%= render "log_outputs/logs", loggable: @add_on %>
|
||||
<% end %>
|
||||
74
app/views/add_ons/new.html.erb
Normal file
74
app/views/add_ons/new.html.erb
Normal file
@@ -0,0 +1,74 @@
|
||||
<%= content_for :title, t("scaffold.new.title", model: "Add On") %>
|
||||
|
||||
<div class="container px-4 mx-auto my-8">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h1 class="h3">
|
||||
<%= link_to "Add Ons", add_ons_path, class: "text-black dark:text-white" %>
|
||||
<span class="text-gray-400 font-light mx-2">\</span>
|
||||
<%= t("scaffold.new.title", model: "Add On") %>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<div class="p-8 bg-white dark:bg-gray-900 dark:border dark:border-gray-700 rounded shadow" data-controller="new-add-ons">
|
||||
<%= form_with(model: @add_on) do |form| %>
|
||||
<%= render "error_messages", resource: form.object %>
|
||||
|
||||
<div class="form-group">
|
||||
<%= form.label :name %>
|
||||
<%= form.text_field :name, class: "form-control", value: RandomNameGenerator.generate_name %>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<%= form.label :cluster_id %>
|
||||
<%= form.collection_select :cluster_id, current_user.clusters, :id, :name, {}, { class: "select select-bordered" } %>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<%= form.text_field :chart_type, class: "hidden", data: { 'new-add-ons-target': "input" } %>
|
||||
</div>
|
||||
|
||||
<h4>Select a chart</h4>
|
||||
<div class="text-sm text-gray-500">
|
||||
More charts coming soon.
|
||||
</div>
|
||||
<div class="grid grid-cols-8 gap-4 my-4">
|
||||
<% YAML.load_file(Rails.root.join('resources', 'helm', 'charts.yml'))['helm']['charts'].each do |chart| %>
|
||||
<div class="card bg-base-100 shadow-xl cursor-pointer group overflow-hidden"
|
||||
data-new-add-ons-target="card"
|
||||
data-action="click->new-add-ons#selectChart"
|
||||
data-chart-name="<%= chart['name'] %>">
|
||||
<figure class="px-12 pt-12 overflow-visible">
|
||||
<div class="w-full flex items-center justify-center">
|
||||
<img
|
||||
src="<%= chart['logo'] %>" alt="<%= chart['name'] %>"
|
||||
class="h-[50px] object-contain transition-transform duration-300 group-hover:scale-110"
|
||||
/>
|
||||
</div>
|
||||
</figure>
|
||||
<div class="card-body items-center text-center">
|
||||
<%= chart['name'].titleize %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<% YAML.load_file(Rails.root.join('resources', 'helm', 'charts.yml'))['helm']['charts'].each do |chart| %>
|
||||
<div id="chart-<%= chart['name'] %>" class="chart-form hidden">
|
||||
<h4><%= chart['name'].titleize %></h4>
|
||||
<%= render "add_ons/chart_form", chart: chart, form: form %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div>
|
||||
<%= form.button button_text(form.send(:submit_default_value)), class: "btn btn-primary" %>
|
||||
|
||||
<% if form.object.new_record? %>
|
||||
<%= link_to t("cancel"), add_ons_path, class: "btn btn-secondary" %>
|
||||
<% else %>
|
||||
<%= link_to t("cancel"), add_on_path(@add_on), class: "btn btn-secondary" %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
3
app/views/add_ons/show.html.erb
Normal file
3
app/views/add_ons/show.html.erb
Normal file
@@ -0,0 +1,3 @@
|
||||
<%= add_on_layout(@add_on) do %>
|
||||
<%= render "add_ons/#{add_on.chart_type}", service: @service %>
|
||||
<% end %>
|
||||
1
app/views/add_ons/show.json.jbuilder
Normal file
1
app/views/add_ons/show.json.jbuilder
Normal file
@@ -0,0 +1 @@
|
||||
json.partial! "add_ons/add_on", add_on: @add_on
|
||||
2
app/views/clusters/_cluster.json.jbuilder
Normal file
2
app/views/clusters/_cluster.json.jbuilder
Normal file
@@ -0,0 +1,2 @@
|
||||
json.extract! cluster, :id, :name, :user_id, :created_at, :updated_at
|
||||
json.url cluster_url(cluster, format: :json)
|
||||
1
app/views/clusters/_connection_failed.html.erb
Normal file
1
app/views/clusters/_connection_failed.html.erb
Normal file
@@ -0,0 +1 @@
|
||||
❌ Connection failed!
|
||||
1
app/views/clusters/_connection_success.html.erb
Normal file
1
app/views/clusters/_connection_success.html.erb
Normal file
@@ -0,0 +1 @@
|
||||
✅ Connection successful!
|
||||
23
app/views/clusters/_form.html.erb
Normal file
23
app/views/clusters/_form.html.erb
Normal file
@@ -0,0 +1,23 @@
|
||||
<%= form_with(model: cluster) do |form| %>
|
||||
<%= render "error_messages", resource: form.object %>
|
||||
|
||||
<div class="form-group">
|
||||
<%= form.label :name %>
|
||||
<%= form.text_field :name, class: "input input-bordered", value: RandomNameGenerator.generate_name %>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<%= form.label :kubeconfig %>
|
||||
<%= form.file_field :kubeconfig, class: "file-input w-full" %>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<%= form.button button_text(form.send(:submit_default_value)), class: "btn btn-primary" %>
|
||||
|
||||
<% if form.object.new_record? %>
|
||||
<%= link_to t("cancel"), clusters_path, class: "btn btn-secondary" %>
|
||||
<% else %>
|
||||
<%= link_to t("cancel"), cluster_path(@cluster), class: "btn btn-secondary" %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
4
app/views/clusters/_health.html.erb
Normal file
4
app/views/clusters/_health.html.erb
Normal file
@@ -0,0 +1,4 @@
|
||||
<div>
|
||||
<h4>Health check: <%= cluster.health %></h4>
|
||||
<%= render "log_outputs/logs", loggable: cluster %>
|
||||
</div>
|
||||
18
app/views/clusters/_index.html.erb
Normal file
18
app/views/clusters/_index.html.erb
Normal file
@@ -0,0 +1,18 @@
|
||||
<table class="table w-full">
|
||||
<thead class="border-b-2 border-gray-300">
|
||||
<tr>
|
||||
<th class="text-left py-2">Name</th>
|
||||
<th class="text-left py-2">Status</th>
|
||||
<th class="text-left py-2">Created</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% clusters.each do |cluster| %>
|
||||
<tr class="border-b border-gray-200">
|
||||
<td class="py-4"><%= link_to cluster.name, cluster, class: "text-inherit hover:underline" %></td>
|
||||
<td class="py-4"><%= cluster.status %></td>
|
||||
<td class="py-4"><%= time_ago_in_words(cluster.created_at) %> ago</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
16
app/views/clusters/edit.html.erb
Normal file
16
app/views/clusters/edit.html.erb
Normal file
@@ -0,0 +1,16 @@
|
||||
<%= content_for :title, t("scaffold.edit.title", model: "Cluster") %>
|
||||
|
||||
<div class="container mx-auto px-4 my-8">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h1 class="h3">
|
||||
<%= link_to "Clusters", clusters_path, class: "text-black dark:text-white" %>
|
||||
<span class="text-gray-400 font-light mx-2">\</span>
|
||||
<%= t("scaffold.edit.title", model: "Cluster") %>
|
||||
</h1>
|
||||
<%= button_to t("delete"), @cluster, method: :delete, class: "btn btn-secondary", form: { data: { turbo_confirm: t("are_you_sure") } } %>
|
||||
</div>
|
||||
|
||||
<div class="p-8 bg-white dark:bg-gray-900 dark:border dark:border-gray-700 rounded shadow">
|
||||
<%= render "form", cluster: @cluster %>
|
||||
</div>
|
||||
</div>
|
||||
23
app/views/clusters/index.html.erb
Normal file
23
app/views/clusters/index.html.erb
Normal file
@@ -0,0 +1,23 @@
|
||||
<%= content_for :title, "Clusters" %>
|
||||
<%= turbo_stream_from :clusters %>
|
||||
|
||||
<div class="container px-4 mx-auto my-8">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<%= link_to t("scaffold.new.title", model: "Cluster"), new_cluster_path, class: "btn btn-secondary" %>
|
||||
</div>
|
||||
|
||||
<%= tag.div id: ("clusters" if first_page?), class: "bg-white dark:bg-gray-900 dark:border dark:border-gray-700 rounded-md shadow p-6 space-y-8" do %>
|
||||
<%= render "clusters/index", clusters: @clusters, cached: true %>
|
||||
|
||||
<div class="hidden only:block text-center">
|
||||
<p class="mb-4 h3">Create your first Cluster</p>
|
||||
<%= link_to t("scaffold.new.title", model: "Cluster"), new_cluster_path, class: "btn btn-primary" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% if @pagy.pages > 1 %>
|
||||
<div class="my-6 text-center">
|
||||
<%== pagy_nav(@pagy) %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
1
app/views/clusters/index.json.jbuilder
Normal file
1
app/views/clusters/index.json.jbuilder
Normal file
@@ -0,0 +1 @@
|
||||
json.array! @clusters, partial: "clusters/cluster", as: :cluster
|
||||
8
app/views/clusters/kubectls/show.html.erb
Normal file
8
app/views/clusters/kubectls/show.html.erb
Normal file
@@ -0,0 +1,8 @@
|
||||
<div class="container mx-auto px-4 py-8">
|
||||
Run any kubectl command here
|
||||
|
||||
<div data-controller="shell" class="bg-white w-full" data-shell-cluster-id-value="<%= @cluster.id %>">
|
||||
<div data-shell-target="terminal" class="w-full h-full">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
62
app/views/clusters/metrics/show.html.erb
Normal file
62
app/views/clusters/metrics/show.html.erb
Normal file
@@ -0,0 +1,62 @@
|
||||
<div class="container mx-auto px-4 py-8">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h1 class="h3">
|
||||
<%= link_to "Clusters", clusters_path, class: "text-black dark:text-white" %>
|
||||
<span class="text-gray-400 font-light mx-2">\</span>
|
||||
<%= @cluster.name %> metrics
|
||||
</h1>
|
||||
<button onclick="location.reload()" class="btn btn-primary m-1">
|
||||
Refresh
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<h2 class="text-xl font-semibold mb-4">Node Metrics</h2>
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full table-auto">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="px-4 py-2 text-left">Node Name</th>
|
||||
<th class="px-4 py-2 text-left">CPU Cores</th>
|
||||
<th class="px-4 py-2 text-left">CPU %</th>
|
||||
<th class="px-4 py-2 text-left">Memory Bytes</th>
|
||||
<th class="px-4 py-2 text-left">Memory %</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% @node_metrics.each do |metric| %>
|
||||
<tr class="border-b">
|
||||
<td class="px-4 py-2"><%= metric[:name] %></td>
|
||||
<td class="px-4 py-2"><%= metric[:cpu_cores] %></td>
|
||||
<td class="px-4 py-2"><%= metric[:cpu_percent] %></td>
|
||||
<td class="px-4 py-2"><%= metric[:memory_bytes] %></td>
|
||||
<td class="px-4 py-2"><%= metric[:memory_percent] %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="overflow-x-auto mt-4">
|
||||
<table class="w-full table-auto">
|
||||
<thead class="">
|
||||
<tr>
|
||||
<th class="px-4 py-2 text-left">Pod Name</th>
|
||||
<th class="px-4 py-2 text-left">CPU</th>
|
||||
<th class="px-4 py-2 text-left">Memory</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% @pod_metrics.each do |metric| %>
|
||||
<tr class="border-b">
|
||||
<td class="px-4 py-2"><%= metric[:name] %></td>
|
||||
<td class="px-4 py-2"><%= metric[:cpu] %></td>
|
||||
<td class="px-4 py-2"><%= metric[:memory] %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
15
app/views/clusters/new.html.erb
Normal file
15
app/views/clusters/new.html.erb
Normal file
@@ -0,0 +1,15 @@
|
||||
<%= content_for :title, t("scaffold.new.title", model: "Cluster") %>
|
||||
|
||||
<div class="container px-4 mx-auto my-8">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h1 class="h3">
|
||||
<%= link_to "Clusters", clusters_path, class: "text-black dark:text-white" %>
|
||||
<span class="text-gray-400 font-light mx-2">\</span>
|
||||
<%= t("scaffold.new.title", model: "Cluster") %>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<div class="p-8 bg-white dark:bg-gray-900 dark:border dark:border-gray-700 rounded shadow">
|
||||
<%= render "form", cluster: @cluster %>
|
||||
</div>
|
||||
</div>
|
||||
42
app/views/clusters/show.html.erb
Normal file
42
app/views/clusters/show.html.erb
Normal file
@@ -0,0 +1,42 @@
|
||||
<%= content_for :title, "Clusters ##{@cluster.id}" %>
|
||||
<%= turbo_stream_from @cluster %>
|
||||
|
||||
<div class="container px-4 mx-auto my-8">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h1 class="h3">
|
||||
<%= link_to "Clusters", clusters_path, class: "text-black dark:text-white" %>
|
||||
<span class="text-gray-400 font-light mx-2">\</span>
|
||||
<%= @cluster.name %>
|
||||
</h1>
|
||||
<div class="flex">
|
||||
<%= turbo_frame_tag "test_connection_frame" do %>
|
||||
<%= button_to "Test Connection", test_connection_cluster_path(@cluster), class: "btn btn-ghost m-1" %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="p-8 bg-white dark:bg-gray-900 dark:border dark:border-gray-700 rounded shadow">
|
||||
<div id="<%= dom_id @cluster %>">
|
||||
<div class="mb-4">
|
||||
<p class="text-sm font-medium text-gray-500">Name</p>
|
||||
<%= @cluster.name %>
|
||||
<%= render "log_outputs/logs", loggable: @cluster %>
|
||||
</div>
|
||||
<h4>Projects:</h4>
|
||||
<div class="grid grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
<% @cluster.projects.each do |project| %>
|
||||
<%= render project %>
|
||||
<% end %>
|
||||
</div>
|
||||
<h4>Add Ons:</h4>
|
||||
<div class="grid grid-cols-1 lg:grid-cols-4 gap-4">
|
||||
<% @cluster.add_ons.each do |add_on| %>
|
||||
<%= render add_on %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<%= link_to "Metrics", cluster_metrics_path(@cluster) %>
|
||||
<%= link_to "Download Kubeconfig File", download_kubeconfig_cluster_path(@cluster) %>
|
||||
</div>
|
||||
1
app/views/clusters/show.json.jbuilder
Normal file
1
app/views/clusters/show.json.jbuilder
Normal file
@@ -0,0 +1 @@
|
||||
json.partial! "clusters/cluster", cluster: @cluster
|
||||
63
app/views/projects/_form.html.erb
Normal file
63
app/views/projects/_form.html.erb
Normal file
@@ -0,0 +1,63 @@
|
||||
<%= form_with(model: project) do |form| %>
|
||||
<%= render "error_messages", resource: form.object %>
|
||||
|
||||
<div class="form-group">
|
||||
<%= form.label :name %>
|
||||
<%= form.text_field :name, class: "input input-bordered w-full", value: RandomNameGenerator.generate_name %>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<%= form.label :cluster_id %>
|
||||
<%= form.collection_select :cluster_id, current_user.clusters, :id, :name, {}, { class: "select select-bordered" } %>
|
||||
</div>
|
||||
|
||||
<div data-controller="partial-select">
|
||||
<div class="mb-4 hidden" data-partial-select-target="toggleable" data-project-type="cron_job">
|
||||
<%= form.label :cron_schedule %>
|
||||
<%= form.text_field :cron_schedule, class: "input input-bordered w-full" %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<%= form.label "Repository path *" %>
|
||||
<div class="flex gap-2">
|
||||
<%= form.text_field :repository_url, class: "input input-bordered w-full", placeholder: "accountname/repo" %>
|
||||
<%= render "projects/github/connect" %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<%= form.label :branch %>
|
||||
<%= form.text_field :branch, class: "input input-bordered w-full" %>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<%= form.label :autodeploy %>
|
||||
<%= form.check_box :autodeploy, class: "checkbox" %>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<%= form.label :dockerfile_path %>
|
||||
<%= form.text_field :dockerfile_path, class: "input input-bordered w-full" %>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<%= form.label :docker_command %>
|
||||
<%= form.text_field :docker_command, class: "input input-bordered w-full" %>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<%= form.label :predeploy_command %>
|
||||
<%= form.text_field :predeploy_command, class: "input input-bordered w-full" %>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<%= form.button button_text(form.send(:submit_default_value)), class: "btn btn-primary" %>
|
||||
|
||||
<% if form.object.new_record? %>
|
||||
<%= link_to t("cancel"), projects_path, class: "btn btn-secondary" %>
|
||||
<% else %>
|
||||
<%= link_to t("cancel"), project_path(@project), class: "btn btn-secondary" %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
20
app/views/projects/_index.html.erb
Normal file
20
app/views/projects/_index.html.erb
Normal file
@@ -0,0 +1,20 @@
|
||||
<table class="table w-full">
|
||||
<thead class="border-b-2 border-gray-300">
|
||||
<tr>
|
||||
<th class="text-left py-2">Name</th>
|
||||
<th class="text-left py-2">Status</th>
|
||||
<th class="text-left py-2">Cluster Name</th>
|
||||
<th class="text-left py-2">Last Deployed At</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% projects.each do |project| %>
|
||||
<tr class="border-b border-gray-200">
|
||||
<td class="py-4"><%= link_to project.name, project, class: "text-inherit hover:underline" %></td>
|
||||
<td class="py-4"><%= project.status %></td>
|
||||
<td class="py-4"><%= project.cluster&.name %></td>
|
||||
<td class="py-4"><%= project.last_deployed_at&.strftime('%Y-%m-%d %H:%M:%S') || "Never" %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
39
app/views/projects/_layout.html.erb
Normal file
39
app/views/projects/_layout.html.erb
Normal file
@@ -0,0 +1,39 @@
|
||||
<div class="container px-4 mx-auto my-8">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<div>
|
||||
<h1 class="h3">
|
||||
<%= project.name %>
|
||||
</h1>
|
||||
<% if project.domains.any? %>
|
||||
<div class="my-3">
|
||||
<% project.domains.each do |domain| %>
|
||||
<%= link_to domain.domain_name, "https://#{domain.domain_name}", target: "_blank" %>
|
||||
<i class="bi bi-box-arrow-up-right"></i>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
<div class="text-sm">
|
||||
<%= link_to project.full_repository_url, target: "_blank" do %>
|
||||
<i class="bi bi-github"></i>
|
||||
<span class="underline"><%= project.repository_url %></span>
|
||||
<i class="bi bi-git ml-2"></i>
|
||||
<span class="underline"><%= project.branch %></span>
|
||||
<% end %>
|
||||
<span class="ml-6"><i class="bi bi-diagram-3"></i> <%= link_to project.cluster.name, project.cluster, target: "_blank", class: "underline" %></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<%= button_to "Restart", restart_cluster_url(project.cluster), class: "btn btn-ghost m-1", data: { turbo: false, disable_with: "Loading..." } %>
|
||||
<%= button_to "Deploy", deploy_project_deployments_url(project), class: "btn btn-primary m-1", data: { turbo: false, disable_with: "Loading..." } %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-8 dark:border border-base-300 bg-gray-900 rounded-b-box rounded shadow">
|
||||
<div class="container mx-auto flex">
|
||||
<!-- Sidebar -->
|
||||
<%= render "projects/sidebar", project: project %>
|
||||
<div class="block w-full">
|
||||
<%= yield %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
14
app/views/projects/_project.html.erb
Normal file
14
app/views/projects/_project.html.erb
Normal file
@@ -0,0 +1,14 @@
|
||||
<!-- How to represent a project on other surfaces -->
|
||||
<%= link_to project_path(project) do %>
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title">
|
||||
<%= project.name %>
|
||||
</h2>
|
||||
<p class="card-text">
|
||||
<%= render "projects/status", project: project %>
|
||||
<%= project.repository_url %>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
2
app/views/projects/_project.json.jbuilder
Normal file
2
app/views/projects/_project.json.jbuilder
Normal file
@@ -0,0 +1,2 @@
|
||||
json.extract! project, :id, :name, :repository_url, :branch, :cluster_id, :subfolder, :created_at, :updated_at
|
||||
json.url project_url(project, format: :json)
|
||||
10
app/views/projects/_sidebar.html.erb
Normal file
10
app/views/projects/_sidebar.html.erb
Normal file
@@ -0,0 +1,10 @@
|
||||
<nav class="w-64 p-4">
|
||||
<ul class="space-y-2 list-none">
|
||||
<li><%= link_to "Services", project_services_path(project), class: "block py-2 px-4 hover:bg-gray-200 rounded" %></li>
|
||||
<li><%= link_to "Deployments", project_deployments_path(project), class: "block py-2 px-4 hover:bg-gray-200 rounded" %></li>
|
||||
<li><%= link_to "Environment Variables", project_environment_variables_path(project), class: "block py-2 px-4 hover:bg-gray-200 rounded" %></li>
|
||||
<li><%= link_to "Logs", "#", class: "block py-2 px-4 hover:bg-gray-200 rounded" %></li>
|
||||
<li><%= link_to "Metrics", project_metrics_url(project), class: "block py-2 px-4 hover:bg-gray-200 rounded" %></li>
|
||||
<li><%= link_to "Settings", edit_project_path(project), class: "block py-2 px-4 hover:bg-gray-200 rounded" %></li>
|
||||
</ul>
|
||||
</nav>
|
||||
10
app/views/projects/_status.html.erb
Normal file
10
app/views/projects/_status.html.erb
Normal file
@@ -0,0 +1,10 @@
|
||||
<% if project.deployed? %>
|
||||
<div class="text-green-500">
|
||||
●
|
||||
<%= project.status.titleize %>
|
||||
</div>
|
||||
<% elsif %>
|
||||
<div class="text-danger-500">
|
||||
<%= project.status.titleize %>
|
||||
</div>
|
||||
<% end %>
|
||||
41
app/views/projects/deployments/index.html.erb
Normal file
41
app/views/projects/deployments/index.html.erb
Normal file
@@ -0,0 +1,41 @@
|
||||
<%= content_for :title, "Projects ##{@project.id}" %>
|
||||
<%= turbo_stream_from @project %>
|
||||
|
||||
<%= project_layout(@project) do %>
|
||||
<h1 class="text-2xl font-bold mb-6">Deployments</h1>
|
||||
|
||||
<% if @builds.empty? %>
|
||||
<div>
|
||||
<p class="text-gray-500">No deployments yet</p>
|
||||
</div>
|
||||
<% else %>
|
||||
<ul class="space-y-4">
|
||||
<% @builds.each do |build| %>
|
||||
<li class="border rounded-lg p-4">
|
||||
<div>
|
||||
<p class="font-semibold"><%= build.commit_message %></p>
|
||||
<p class="text-sm"><%= build.created_at.strftime("%B %d, %Y %H:%M") %></p>
|
||||
</div>
|
||||
<div class="mt-2 text-sm">
|
||||
Status: <%= build.deployment&.status || build.status %>
|
||||
</div>
|
||||
<div class="mt-2 text-sm">
|
||||
Commit:
|
||||
<%= link_to build.commit_sha[0..6],
|
||||
"https://github.com/#{@project.repository_url}/commit/#{build.commit_sha}",
|
||||
class: "underline",
|
||||
target: "_blank",
|
||||
rel: "noopener noreferrer" %>
|
||||
</div>
|
||||
<div class="mt-2 text-sm">
|
||||
<%= button_to "Redeploy", redeploy_project_deployment_path(@project, build), method: :post, class: "btn btn-primary" %>
|
||||
</div>
|
||||
<div class="mt-2 text-sm">
|
||||
<%= link_to "View Logs", project_deployment_path(@project, build), class: "btn btn-primary" %>
|
||||
</div>
|
||||
<!-- Add more deployment details as needed -->
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
<% end %>
|
||||
<% end %>
|
||||
18
app/views/projects/deployments/show.html.erb
Normal file
18
app/views/projects/deployments/show.html.erb
Normal file
@@ -0,0 +1,18 @@
|
||||
<%= content_for :title, "Projects ##{@project.id}" %>
|
||||
<%= turbo_stream_from @project %>
|
||||
|
||||
<%= project_layout(@project) do %>
|
||||
<h1 class="text-2xl font-bold mb-6">Deployments</h1>
|
||||
|
||||
<h2 class="text-xl font-bold mb-4">Build Logs</h2>
|
||||
<div class="my-4">
|
||||
<%= render "log_outputs/logs", loggable: @build %>
|
||||
</div>
|
||||
|
||||
<% if @build.deployment %>
|
||||
<h2 class="text-xl font-bold mb-4">Release Logs</h2>
|
||||
<div class="my-4">
|
||||
<%= render "log_outputs/logs", loggable: @build.deployment %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
16
app/views/projects/domains/_index.html.erb
Normal file
16
app/views/projects/domains/_index.html.erb
Normal file
@@ -0,0 +1,16 @@
|
||||
<%= turbo_frame_tag "domains" do %>
|
||||
<h4>Custom Domains</h4>
|
||||
|
||||
<%= form_with(model: [project, Domain.new], data: { turbo_frame: "domains" }) do |form| %>
|
||||
<%= render "error_messages", resource: form.object %>
|
||||
<div class="flex gap-2">
|
||||
<%= form.text_field :domain_name, class: "form-control" %>
|
||||
<%= form.submit "Add Domain", class: "btn btn-primary" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<h5 class="my-4">Make sure to configure domains with the following DNS records</h5>
|
||||
<div id="domain-list">
|
||||
<%= render partial: "projects/domains/list", locals: { project: project } %>
|
||||
</div>
|
||||
<% end %>
|
||||
20
app/views/projects/domains/_list.html.erb
Normal file
20
app/views/projects/domains/_list.html.erb
Normal file
@@ -0,0 +1,20 @@
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>DOMAIN</th>
|
||||
<th>A RECORD</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% project.domains.each do |domain| %>
|
||||
<tr id="<%= dom_id(domain) %>">
|
||||
<td><%= link_to domain.domain_name, "https://#{domain.domain_name}", target: "_blank" %></td>
|
||||
<td><pre class="code">128.93.3.1</pre></td>
|
||||
<td>
|
||||
<%= button_to "Remove", project_domain_path(project, domain), method: :delete, class: "btn btn-sm btn-ghost", data: { turbo_frame: "domains" } %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
9
app/views/projects/domains/create.turbo_stream.erb
Normal file
9
app/views/projects/domains/create.turbo_stream.erb
Normal file
@@ -0,0 +1,9 @@
|
||||
<%= turbo_stream.replace "domain-list" do %>
|
||||
<%= render partial: "projects/domains/list", locals: { project: @project } %>
|
||||
<% end %>
|
||||
<%= turbo_stream.update "#{dom_id(@project)}_domain_form" do %>
|
||||
<%= form_with url: project_domains_path(@project), method: :post, data: { turbo_frame: "domains" } do |form| %>
|
||||
<%= form.text_field :domain_name, class: "form-control" %>
|
||||
<%= form.submit "Add Domain", class: "btn btn-primary" %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
5
app/views/projects/domains/destroy.turbo_stream.erb
Normal file
5
app/views/projects/domains/destroy.turbo_stream.erb
Normal file
@@ -0,0 +1,5 @@
|
||||
<%= turbo_stream.remove dom_id(@domain) %>
|
||||
|
||||
<%= turbo_stream.update "domain-list" do %>
|
||||
<%= render partial: "projects/domains/list", locals: { project: @project } %>
|
||||
<% end %>
|
||||
20
app/views/projects/edit.html.erb
Normal file
20
app/views/projects/edit.html.erb
Normal file
@@ -0,0 +1,20 @@
|
||||
<%= content_for :title, t("scaffold.edit.title", model: "Project") %>
|
||||
|
||||
<%= project_layout(@project) do %>
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h1 class="h3">
|
||||
<%= link_to "Projects", projects_path, class: "text-black dark:text-white" %>
|
||||
<span class="text-gray-400 font-light mx-2">\</span>
|
||||
<%= t("scaffold.edit.title", model: "Project") %>
|
||||
</h1>
|
||||
<%= button_to t("delete"), @project, method: :delete, class: "btn btn-secondary", form: { data: { turbo_confirm: t("are_you_sure") } } %>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 p-8 bg-white dark:bg-gray-900 dark:border dark:border-gray-700 rounded shadow">
|
||||
<%= render "projects/domains/index", project: @project %>
|
||||
</div>
|
||||
|
||||
<div class="p-8 bg-white dark:bg-gray-900 dark:border dark:border-gray-700 rounded shadow">
|
||||
<%= render "form", project: @project %>
|
||||
</div>
|
||||
<% end %>
|
||||
15
app/views/projects/environment_variables/index.html.erb
Normal file
15
app/views/projects/environment_variables/index.html.erb
Normal file
@@ -0,0 +1,15 @@
|
||||
<%= project_layout(@project) do %>
|
||||
<div
|
||||
class="flex-1 p-4"
|
||||
data-controller="environment-variables"
|
||||
data-environment-variables-vars-value="<%= @project.environment_variables.map { |e| { name: e.name, value: e.value } }.to_json %>"
|
||||
>
|
||||
<h2 class="text-2xl font-bold mb-4">Environment Variables</h2>
|
||||
|
||||
<%= form_with(url: project_environment_variables_path(@project), method: :post, class: "space-y-4") do |form| %>
|
||||
<div data-environment-variables-target="container"></div>
|
||||
<button class="btn btn-neutral btn-outline" data-action="environment-variables#add">Add New Environment Variable</button>
|
||||
<%= form.submit "Save", class: "btn btn-primary" %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
3
app/views/projects/github/_connect.html.erb
Normal file
3
app/views/projects/github/_connect.html.erb
Normal file
@@ -0,0 +1,3 @@
|
||||
<% unless current_user.connected_accounts.find_by_provider(:github).present? %>
|
||||
<%= button_to "Connect Github", omniauth_authorize_path(:user, :github), class: "btn btn-github", data: { turbo: false, disable_with: "Redirecting..." } %>
|
||||
<% end %>
|
||||
23
app/views/projects/index.html.erb
Normal file
23
app/views/projects/index.html.erb
Normal file
@@ -0,0 +1,23 @@
|
||||
<%= content_for :title, "Projects" %>
|
||||
<%= turbo_stream_from :projects %>
|
||||
|
||||
<div class="container px-4 mx-auto my-8">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<%= link_to t("scaffold.new.title", model: "Project"), new_project_path, class: "btn btn-secondary" %>
|
||||
</div>
|
||||
|
||||
<%= tag.div id: ("projects" if first_page?), class: "bg-white dark:bg-gray-900 dark:border dark:border-gray-700 rounded-md shadow p-6 space-y-8" do %>
|
||||
<%= render "projects/index", projects: @projects, cached: true %>
|
||||
|
||||
<div class="hidden only:block text-center">
|
||||
<p class="mb-4 h3">Create your first Project</p>
|
||||
<%= link_to t("scaffold.new.title", model: "Project"), new_project_path, class: "btn btn-primary" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% if @pagy.pages > 1 %>
|
||||
<div class="my-6 text-center">
|
||||
<%== pagy_nav(@pagy) %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
1
app/views/projects/index.json.jbuilder
Normal file
1
app/views/projects/index.json.jbuilder
Normal file
@@ -0,0 +1 @@
|
||||
json.array! @projects, partial: "projects/project", as: :project
|
||||
33
app/views/projects/metrics/index.html.erb
Normal file
33
app/views/projects/metrics/index.html.erb
Normal file
@@ -0,0 +1,33 @@
|
||||
<%= content_for :title, t("scaffold.edit.title", model: "Project") %>
|
||||
|
||||
<%= project_layout(@project) do %>
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
Metrics
|
||||
</div>
|
||||
|
||||
<h5>Pods</h5>
|
||||
<div class="overflow-x-auto">
|
||||
<% if @pod_metrics.present? %>
|
||||
<table class="w-full table-auto">
|
||||
<thead class="">
|
||||
<tr>
|
||||
<th class="px-4 py-2 text-left text-gray-600">Pod Name</th>
|
||||
<th class="px-4 py-2 text-left text-gray-600">CPU</th>
|
||||
<th class="px-4 py-2 text-left text-gray-600">Memory</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% @pod_metrics.each do |metric| %>
|
||||
<tr class="border-b">
|
||||
<td class="px-4 py-2"><%= metric[:name] %></td>
|
||||
<td class="px-4 py-2"><%= metric[:cpu] %></td>
|
||||
<td class="px-4 py-2"><%= metric[:memory] %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
<% else %>
|
||||
<div class="text-gray-600">No metrics available</div>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
15
app/views/projects/new.html.erb
Normal file
15
app/views/projects/new.html.erb
Normal file
@@ -0,0 +1,15 @@
|
||||
<%= content_for :title, t("scaffold.new.title", model: "Project") %>
|
||||
|
||||
<div class="container px-4 mx-auto my-8">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h1 class="h3">
|
||||
<%= link_to "Projects", projects_path, class: "text-black dark:text-white" %>
|
||||
<span class="text-gray-400 font-light mx-2">\</span>
|
||||
<%= t("scaffold.new.title", model: "Project") %>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<div class="p-8 bg-white dark:bg-gray-900 dark:border dark:border-gray-700 rounded shadow">
|
||||
<%= render "form", project: @project %>
|
||||
</div>
|
||||
</div>
|
||||
4
app/views/projects/services/_service_type.html.erb
Normal file
4
app/views/projects/services/_service_type.html.erb
Normal file
@@ -0,0 +1,4 @@
|
||||
<span class="text-xs font-semibold">
|
||||
<i class="bi bi-globe"></i>
|
||||
<%= project.project_type.titleize.upcase %>
|
||||
</span>
|
||||
31
app/views/projects/services/index.html.erb
Normal file
31
app/views/projects/services/index.html.erb
Normal file
@@ -0,0 +1,31 @@
|
||||
<%= project_layout(@project) do %>
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
Services
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<%= turbo_frame_tag "new_service" do %>
|
||||
<%= link_to "New Service", new_project_service_path(@project), class: "btn btn-primary" %>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full table-auto">
|
||||
<thead class="">
|
||||
<tr>
|
||||
<th class="px-4 py-2 text-left">Name</th>
|
||||
<th class="px-4 py-2 text-left">Service Type</th>
|
||||
<th class="px-4 py-2 text-left">Command</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% @project.services.each do |service| %>
|
||||
<tr class="border-b">
|
||||
<td class="px-4 py-2"><%= service.name %></td>
|
||||
<td class="px-4 py-2"><%= service.service_type.titleize %></td>
|
||||
<td class="px-4 py-2"><%= service.command %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<% end %>
|
||||
45
app/views/projects/services/new.html.erb
Normal file
45
app/views/projects/services/new.html.erb
Normal file
@@ -0,0 +1,45 @@
|
||||
<%= turbo_frame_tag "new_service" do %>
|
||||
<div class="overflow-x-auto">
|
||||
<%= form_with(model: [@project, @service]) do |form| %>
|
||||
<%= form.label :name %>
|
||||
<%= form.text_field :name, class: "input input-bordered", required: true %>
|
||||
|
||||
<div data-controller="partial-select">
|
||||
<%= form.label :service_type %>
|
||||
<%= form.select(
|
||||
:service_type,
|
||||
Service.service_types.keys.map { |type| [type.titleize, type] },
|
||||
{},
|
||||
class: "select select-bordered",
|
||||
data: {
|
||||
"partial-select-target": "select",
|
||||
"select-attribute-value": "data-project-type",
|
||||
"action": "change->partial-select#toggle",
|
||||
}
|
||||
) %>
|
||||
</div>
|
||||
|
||||
<%= form.label :command %>
|
||||
<%= form.text_field :command, class: "input input-bordered", required: false %>
|
||||
<%= form.button button_text(form.send(:submit_default_value)), class: "btn btn-primary" %>
|
||||
<% end %>
|
||||
<div class="text-sm mb-4">
|
||||
<p>
|
||||
<b>Web service</b>: Useful for publicly accessible services like web applications.
|
||||
</p>
|
||||
<p>
|
||||
<b>Internal service</b>: Useful for services that should only be connected to within the cluster like microservices.
|
||||
</p>
|
||||
<p>
|
||||
<b>Process</b>: Useful for services that should don't need to be connected to like background workers that are continuously running.
|
||||
</p>
|
||||
<p>
|
||||
<b>Cron job</b>: Useful for running tasks at a specific time like backups.
|
||||
</p>
|
||||
<div class="mt-4 text-warning italic">
|
||||
Do not create any databases here, create an <%= link_to "add on", add_ons_path %> and then connect it to your project.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<% end %>
|
||||
6
app/views/projects/show.html.erb
Normal file
6
app/views/projects/show.html.erb
Normal file
@@ -0,0 +1,6 @@
|
||||
<%= content_for :title, "Projects ##{@project.id}" %>
|
||||
<%= turbo_stream_from @project %>
|
||||
|
||||
<%= project_layout(@project) do %>
|
||||
<%= render @project %>
|
||||
<% end %>
|
||||
1
app/views/projects/show.json.jbuilder
Normal file
1
app/views/projects/show.json.jbuilder
Normal file
@@ -0,0 +1 @@
|
||||
json.partial! "projects/project", project: @project
|
||||
12
db/migrate/20240925212703_create_clusters.rb
Normal file
12
db/migrate/20240925212703_create_clusters.rb
Normal file
@@ -0,0 +1,12 @@
|
||||
class CreateClusters < ActiveRecord::Migration[7.2]
|
||||
def change
|
||||
create_table :clusters do |t|
|
||||
t.string :name, null: false
|
||||
t.jsonb :kubeconfig, null: false, default: {}
|
||||
t.references :user, null: false, foreign_key: true
|
||||
t.integer :status, null: false, default: 0
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
end
|
||||
end
|
||||
19
db/migrate/20240925212710_create_projects.rb
Normal file
19
db/migrate/20240925212710_create_projects.rb
Normal file
@@ -0,0 +1,19 @@
|
||||
class CreateProjects < ActiveRecord::Migration[7.2]
|
||||
def change
|
||||
create_table :projects do |t|
|
||||
t.string :name, null: false
|
||||
t.string :repository_url, null: false
|
||||
t.string :branch, default: "main", null: false
|
||||
t.references :cluster, null: false, foreign_key: true
|
||||
t.boolean :autodeploy, default: true, null: false
|
||||
t.string :dockerfile_path, default: "./Dockerfile", null: false
|
||||
t.string :docker_build_context_directory, default: ".", null: false
|
||||
t.string :docker_command
|
||||
t.string :predeploy_command
|
||||
t.integer :status, default: 0, null: false
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
add_index :projects, [ :name ], unique: true
|
||||
end
|
||||
end
|
||||
12
db/migrate/20240925212823_create_environment_variables.rb
Normal file
12
db/migrate/20240925212823_create_environment_variables.rb
Normal file
@@ -0,0 +1,12 @@
|
||||
class CreateEnvironmentVariables < ActiveRecord::Migration[7.2]
|
||||
def change
|
||||
create_table :environment_variables do |t|
|
||||
t.string :name, null: false
|
||||
t.text :value
|
||||
t.references :project, null: false, foreign_key: true
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
add_index :environment_variables, [ :project_id, :name ], unique: true
|
||||
end
|
||||
end
|
||||
14
db/migrate/20240925212831_create_builds.rb
Normal file
14
db/migrate/20240925212831_create_builds.rb
Normal file
@@ -0,0 +1,14 @@
|
||||
class CreateBuilds < ActiveRecord::Migration[7.2]
|
||||
def change
|
||||
create_table :builds do |t|
|
||||
t.references :project, null: false, foreign_key: true
|
||||
t.string :repository_url
|
||||
t.string :git_sha
|
||||
t.string :commit_message
|
||||
t.integer :status, default: 0
|
||||
t.string :commit_sha, null: false
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
end
|
||||
end
|
||||
11
db/migrate/20240925212839_create_log_outputs.rb
Normal file
11
db/migrate/20240925212839_create_log_outputs.rb
Normal file
@@ -0,0 +1,11 @@
|
||||
class CreateLogOutputs < ActiveRecord::Migration[7.2]
|
||||
def change
|
||||
create_table :log_outputs do |t|
|
||||
t.bigint :loggable_id, null: false
|
||||
t.string :loggable_type, null: false
|
||||
t.text :output
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
end
|
||||
end
|
||||
14
db/migrate/20240925212846_create_add_ons.rb
Normal file
14
db/migrate/20240925212846_create_add_ons.rb
Normal file
@@ -0,0 +1,14 @@
|
||||
class CreateAddOns < ActiveRecord::Migration[7.2]
|
||||
def change
|
||||
create_table :add_ons do |t|
|
||||
t.references :cluster, null: false, foreign_key: true
|
||||
t.string :name, null: false
|
||||
t.string :chart_type, null: false
|
||||
t.integer :status, null: false, default: 0
|
||||
t.jsonb :metadata, default: {}
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
add_index :add_ons, [ :cluster_id, :name ], unique: true
|
||||
end
|
||||
end
|
||||
10
db/migrate/20240925212856_create_project_add_ons.rb
Normal file
10
db/migrate/20240925212856_create_project_add_ons.rb
Normal file
@@ -0,0 +1,10 @@
|
||||
class CreateProjectAddOns < ActiveRecord::Migration[7.2]
|
||||
def change
|
||||
create_table :project_add_ons do |t|
|
||||
t.references :project, null: false, foreign_key: true
|
||||
t.references :add_on, null: false, foreign_key: true
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
end
|
||||
end
|
||||
10
db/migrate/20240925212903_create_deployments.rb
Normal file
10
db/migrate/20240925212903_create_deployments.rb
Normal file
@@ -0,0 +1,10 @@
|
||||
class CreateDeployments < ActiveRecord::Migration[7.2]
|
||||
def change
|
||||
create_table :deployments do |t|
|
||||
t.references :build, null: false, foreign_key: true
|
||||
t.integer :status, default: 0, null: false
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
end
|
||||
end
|
||||
8
db/migrate/20240925212939_create_cron_schedules.rb
Normal file
8
db/migrate/20240925212939_create_cron_schedules.rb
Normal file
@@ -0,0 +1,8 @@
|
||||
class CreateCronSchedules < ActiveRecord::Migration[7.2]
|
||||
def change
|
||||
create_table :cron_schedules do |t|
|
||||
t.references :service, null: false, foreign_key: true
|
||||
t.string :schedule, null: false
|
||||
end
|
||||
end
|
||||
end
|
||||
10
db/migrate/20240925212945_create_domains.rb
Normal file
10
db/migrate/20240925212945_create_domains.rb
Normal file
@@ -0,0 +1,10 @@
|
||||
class CreateDomains < ActiveRecord::Migration[7.2]
|
||||
def change
|
||||
create_table :domains do |t|
|
||||
t.references :service, null: false, foreign_key: true
|
||||
t.string :domain_name, null: false
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
end
|
||||
end
|
||||
112
db/schema.rb
generated
112
db/schema.rb
generated
@@ -10,7 +10,7 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema[7.2].define(version: 2024_09_25_205204) do
|
||||
ActiveRecord::Schema[7.2].define(version: 2024_09_25_212945) do
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
|
||||
@@ -42,6 +42,18 @@ ActiveRecord::Schema[7.2].define(version: 2024_09_25_205204) do
|
||||
t.index ["blob_id", "variation_digest"], name: "index_active_storage_variant_records_uniqueness", unique: true
|
||||
end
|
||||
|
||||
create_table "add_ons", force: :cascade do |t|
|
||||
t.bigint "cluster_id", null: false
|
||||
t.string "name", null: false
|
||||
t.string "chart_type", null: false
|
||||
t.integer "status", default: 0, null: false
|
||||
t.jsonb "metadata", default: {}
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.index ["cluster_id", "name"], name: "index_add_ons_on_cluster_id_and_name", unique: true
|
||||
t.index ["cluster_id"], name: "index_add_ons_on_cluster_id"
|
||||
end
|
||||
|
||||
create_table "announcements", force: :cascade do |t|
|
||||
t.datetime "published_at"
|
||||
t.string "announcement_type"
|
||||
@@ -51,6 +63,60 @@ ActiveRecord::Schema[7.2].define(version: 2024_09_25_205204) do
|
||||
t.datetime "updated_at", null: false
|
||||
end
|
||||
|
||||
create_table "builds", force: :cascade do |t|
|
||||
t.bigint "project_id", null: false
|
||||
t.string "repository_url"
|
||||
t.string "git_sha"
|
||||
t.string "commit_message"
|
||||
t.integer "status", default: 0
|
||||
t.string "commit_sha", null: false
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.index ["project_id"], name: "index_builds_on_project_id"
|
||||
end
|
||||
|
||||
create_table "clusters", force: :cascade do |t|
|
||||
t.string "name", null: false
|
||||
t.jsonb "kubeconfig", default: {}, null: false
|
||||
t.bigint "user_id", null: false
|
||||
t.integer "status", default: 0, null: false
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.index ["user_id"], name: "index_clusters_on_user_id"
|
||||
end
|
||||
|
||||
create_table "cron_schedules", force: :cascade do |t|
|
||||
t.bigint "service_id", null: false
|
||||
t.string "schedule", null: false
|
||||
t.index ["service_id"], name: "index_cron_schedules_on_service_id"
|
||||
end
|
||||
|
||||
create_table "deployments", force: :cascade do |t|
|
||||
t.bigint "build_id", null: false
|
||||
t.integer "status", default: 0, null: false
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.index ["build_id"], name: "index_deployments_on_build_id"
|
||||
end
|
||||
|
||||
create_table "domains", force: :cascade do |t|
|
||||
t.bigint "service_id", null: false
|
||||
t.string "domain_name", null: false
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.index ["service_id"], name: "index_domains_on_service_id"
|
||||
end
|
||||
|
||||
create_table "environment_variables", force: :cascade do |t|
|
||||
t.string "name", null: false
|
||||
t.text "value"
|
||||
t.bigint "project_id", null: false
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.index ["project_id", "name"], name: "index_environment_variables_on_project_id_and_name", unique: true
|
||||
t.index ["project_id"], name: "index_environment_variables_on_project_id"
|
||||
end
|
||||
|
||||
create_table "friendly_id_slugs", force: :cascade do |t|
|
||||
t.string "slug", null: false
|
||||
t.integer "sluggable_id", null: false
|
||||
@@ -62,6 +128,14 @@ ActiveRecord::Schema[7.2].define(version: 2024_09_25_205204) do
|
||||
t.index ["sluggable_type", "sluggable_id"], name: "index_friendly_id_slugs_on_sluggable_type_and_sluggable_id"
|
||||
end
|
||||
|
||||
create_table "log_outputs", force: :cascade do |t|
|
||||
t.bigint "loggable_id", null: false
|
||||
t.string "loggable_type", null: false
|
||||
t.text "output"
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
end
|
||||
|
||||
create_table "noticed_events", force: :cascade do |t|
|
||||
t.string "type"
|
||||
t.string "record_type"
|
||||
@@ -86,6 +160,32 @@ ActiveRecord::Schema[7.2].define(version: 2024_09_25_205204) do
|
||||
t.index ["recipient_type", "recipient_id"], name: "index_noticed_notifications_on_recipient"
|
||||
end
|
||||
|
||||
create_table "project_add_ons", force: :cascade do |t|
|
||||
t.bigint "project_id", null: false
|
||||
t.bigint "add_on_id", null: false
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.index ["add_on_id"], name: "index_project_add_ons_on_add_on_id"
|
||||
t.index ["project_id"], name: "index_project_add_ons_on_project_id"
|
||||
end
|
||||
|
||||
create_table "projects", force: :cascade do |t|
|
||||
t.string "name", null: false
|
||||
t.string "repository_url", null: false
|
||||
t.string "branch", default: "main", null: false
|
||||
t.bigint "cluster_id", null: false
|
||||
t.boolean "autodeploy", default: true, null: false
|
||||
t.string "dockerfile_path", default: "./Dockerfile", null: false
|
||||
t.string "docker_build_context_directory", default: ".", null: false
|
||||
t.string "docker_command"
|
||||
t.string "predeploy_command"
|
||||
t.integer "status", default: 0, null: false
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.index ["cluster_id"], name: "index_projects_on_cluster_id"
|
||||
t.index ["name"], name: "index_projects_on_name", unique: true
|
||||
end
|
||||
|
||||
create_table "services", force: :cascade do |t|
|
||||
t.bigint "user_id", null: false
|
||||
t.string "provider"
|
||||
@@ -118,5 +218,15 @@ ActiveRecord::Schema[7.2].define(version: 2024_09_25_205204) do
|
||||
|
||||
add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id"
|
||||
add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id"
|
||||
add_foreign_key "add_ons", "clusters"
|
||||
add_foreign_key "builds", "projects"
|
||||
add_foreign_key "clusters", "users"
|
||||
add_foreign_key "cron_schedules", "services"
|
||||
add_foreign_key "deployments", "builds"
|
||||
add_foreign_key "domains", "services"
|
||||
add_foreign_key "environment_variables", "projects"
|
||||
add_foreign_key "project_add_ons", "add_ons"
|
||||
add_foreign_key "project_add_ons", "projects"
|
||||
add_foreign_key "projects", "clusters"
|
||||
add_foreign_key "services", "users"
|
||||
end
|
||||
|
||||
59
lib/tasks/auto_annotate_models.rake
Normal file
59
lib/tasks/auto_annotate_models.rake
Normal file
@@ -0,0 +1,59 @@
|
||||
# NOTE: only doing this in development as some production environments (Heroku)
|
||||
# NOTE: are sensitive to local FS writes, and besides -- it's just not proper
|
||||
# NOTE: to have a dev-mode tool do its thing in production.
|
||||
if Rails.env.development?
|
||||
require 'annotate'
|
||||
task :set_annotation_options do
|
||||
# You can override any of these by setting an environment variable of the
|
||||
# same name.
|
||||
Annotate.set_defaults(
|
||||
'active_admin' => 'false',
|
||||
'additional_file_patterns' => [],
|
||||
'routes' => 'false',
|
||||
'models' => 'true',
|
||||
'position_in_routes' => 'before',
|
||||
'position_in_class' => 'before',
|
||||
'position_in_test' => 'before',
|
||||
'position_in_fixture' => 'before',
|
||||
'position_in_factory' => 'before',
|
||||
'position_in_serializer' => 'before',
|
||||
'show_foreign_keys' => 'true',
|
||||
'show_complete_foreign_keys' => 'false',
|
||||
'show_indexes' => 'true',
|
||||
'simple_indexes' => 'false',
|
||||
'model_dir' => 'app/models',
|
||||
'root_dir' => '',
|
||||
'include_version' => 'false',
|
||||
'require' => '',
|
||||
'exclude_tests' => 'false',
|
||||
'exclude_fixtures' => 'false',
|
||||
'exclude_factories' => 'false',
|
||||
'exclude_serializers' => 'false',
|
||||
'exclude_scaffolds' => 'true',
|
||||
'exclude_controllers' => 'true',
|
||||
'exclude_helpers' => 'true',
|
||||
'exclude_sti_subclasses' => 'false',
|
||||
'ignore_model_sub_dir' => 'false',
|
||||
'ignore_columns' => nil,
|
||||
'ignore_routes' => nil,
|
||||
'ignore_unknown_models' => 'false',
|
||||
'hide_limit_column_types' => 'integer,bigint,boolean',
|
||||
'hide_default_column_types' => 'json,jsonb,hstore',
|
||||
'skip_on_db_migrate' => 'false',
|
||||
'format_bare' => 'true',
|
||||
'format_rdoc' => 'false',
|
||||
'format_yard' => 'false',
|
||||
'format_markdown' => 'false',
|
||||
'sort' => 'false',
|
||||
'force' => 'false',
|
||||
'frozen' => 'false',
|
||||
'classified_sort' => 'true',
|
||||
'trace' => 'false',
|
||||
'wrapper_open' => nil,
|
||||
'wrapper_close' => nil,
|
||||
'with_comment' => 'true'
|
||||
)
|
||||
end
|
||||
|
||||
Annotate.load_tasks
|
||||
end
|
||||
32
test/fixtures/add_ons.yml
vendored
Normal file
32
test/fixtures/add_ons.yml
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: add_ons
|
||||
#
|
||||
# id :bigint not null, primary key
|
||||
# chart_type :string not null
|
||||
# metadata :jsonb
|
||||
# name :string not null
|
||||
# status :integer default(0), not null
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# cluster_id :bigint not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_add_ons_on_cluster_id (cluster_id)
|
||||
# index_add_ons_on_cluster_id_and_name (cluster_id,name) UNIQUE
|
||||
#
|
||||
# Foreign Keys
|
||||
#
|
||||
# fk_rails_... (cluster_id => clusters.id)
|
||||
#
|
||||
|
||||
# This model initially had no columns defined. If you add columns to the
|
||||
# model remove the "{}" from the fixture names and add the columns immediately
|
||||
# below each fixture, per the syntax in the comments below
|
||||
#
|
||||
one: {}
|
||||
# column: value
|
||||
#
|
||||
two: {}
|
||||
# column: value
|
||||
13
test/fixtures/announcements.yml
vendored
13
test/fixtures/announcements.yml
vendored
@@ -1,4 +1,15 @@
|
||||
# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: announcements
|
||||
#
|
||||
# id :bigint not null, primary key
|
||||
# announcement_type :string
|
||||
# description :text
|
||||
# name :string
|
||||
# published_at :datetime
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
#
|
||||
|
||||
one:
|
||||
published_at: 2024-09-25 13:51:47
|
||||
|
||||
32
test/fixtures/builds.yml
vendored
Normal file
32
test/fixtures/builds.yml
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: builds
|
||||
#
|
||||
# id :bigint not null, primary key
|
||||
# commit_message :string
|
||||
# commit_sha :string not null
|
||||
# git_sha :string
|
||||
# repository_url :string
|
||||
# status :integer default(0)
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# project_id :bigint not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_builds_on_project_id (project_id)
|
||||
#
|
||||
# Foreign Keys
|
||||
#
|
||||
# fk_rails_... (project_id => projects.id)
|
||||
#
|
||||
|
||||
# This model initially had no columns defined. If you add columns to the
|
||||
# model remove the "{}" from the fixture names and add the columns immediately
|
||||
# below each fixture, per the syntax in the comments below
|
||||
#
|
||||
one: {}
|
||||
# column: value
|
||||
#
|
||||
two: {}
|
||||
# column: value
|
||||
30
test/fixtures/clusters.yml
vendored
Normal file
30
test/fixtures/clusters.yml
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: clusters
|
||||
#
|
||||
# id :bigint not null, primary key
|
||||
# kubeconfig :jsonb not null
|
||||
# name :string not null
|
||||
# status :integer default(0), not null
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# user_id :bigint not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_clusters_on_user_id (user_id)
|
||||
#
|
||||
# Foreign Keys
|
||||
#
|
||||
# fk_rails_... (user_id => users.id)
|
||||
#
|
||||
|
||||
# This model initially had no columns defined. If you add columns to the
|
||||
# model remove the "{}" from the fixture names and add the columns immediately
|
||||
# below each fixture, per the syntax in the comments below
|
||||
#
|
||||
one: {}
|
||||
# column: value
|
||||
#
|
||||
two: {}
|
||||
# column: value
|
||||
26
test/fixtures/cron_schedules.yml
vendored
Normal file
26
test/fixtures/cron_schedules.yml
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: cron_schedules
|
||||
#
|
||||
# id :bigint not null, primary key
|
||||
# schedule :string not null
|
||||
# service_id :bigint not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_cron_schedules_on_service_id (service_id)
|
||||
#
|
||||
# Foreign Keys
|
||||
#
|
||||
# fk_rails_... (service_id => services.id)
|
||||
#
|
||||
|
||||
# This model initially had no columns defined. If you add columns to the
|
||||
# model remove the "{}" from the fixture names and add the columns immediately
|
||||
# below each fixture, per the syntax in the comments below
|
||||
#
|
||||
one: {}
|
||||
# column: value
|
||||
#
|
||||
two: {}
|
||||
# column: value
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user