v1.0.17 (#59)
This commit is contained in:
parent
04a5b1bd4f
commit
9d14b03eb1
26
package.json
26
package.json
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "coolify",
|
||||
"description": "An open-source, hassle-free, self-hostable Heroku & Netlify alternative.",
|
||||
"version": "1.0.16",
|
||||
"version": "1.0.17",
|
||||
"license": "AGPL-3.0",
|
||||
"scripts": {
|
||||
"dev:docker:start": "docker-compose -f docker-compose-dev.yml up -d",
|
||||
@ -17,24 +17,24 @@
|
||||
"@sveltejs/adapter-node": "^1.0.0-next.24",
|
||||
"@sveltejs/kit": "1.0.0-next.113",
|
||||
"@types/dockerode": "^3.2.3",
|
||||
"@typescript-eslint/eslint-plugin": "^4.23.0",
|
||||
"@typescript-eslint/parser": "^4.23.0",
|
||||
"autoprefixer": "^10.2.5",
|
||||
"cssnano": "^5.0.2",
|
||||
"@typescript-eslint/eslint-plugin": "^4.26.1",
|
||||
"@typescript-eslint/parser": "^4.26.1",
|
||||
"autoprefixer": "^10.2.6",
|
||||
"cssnano": "^5.0.5",
|
||||
"dotenv-extended": "^2.9.0",
|
||||
"eslint": "^7.26.0",
|
||||
"eslint": "^7.28.0",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-plugin-svelte3": "^3.2.0",
|
||||
"postcss": "^8.2.15",
|
||||
"postcss": "^8.3.0",
|
||||
"postcss-load-config": "^3.0.1",
|
||||
"prettier": "~2.3.0",
|
||||
"prettier": "~2.3.1",
|
||||
"prettier-plugin-svelte": "^2.3.0",
|
||||
"svelte": "^3.38.2",
|
||||
"svelte-preprocess": "^4.7.3",
|
||||
"tailwindcss": "2.2.0-canary.8",
|
||||
"tslib": "^2.2.0",
|
||||
"typescript": "^4.2.4",
|
||||
"vite": "^2.3.2"
|
||||
"typescript": "^4.3.2",
|
||||
"vite": "^2.3.6"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
@ -44,14 +44,14 @@
|
||||
"compare-versions": "^3.6.0",
|
||||
"cookie": "^0.4.1",
|
||||
"cuid": "^2.1.8",
|
||||
"dayjs": "^1.10.4",
|
||||
"dayjs": "^1.10.5",
|
||||
"dockerode": "^3.3.0",
|
||||
"generate-password": "^1.6.0",
|
||||
"js-yaml": "^4.1.0",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"mongoose": "^5.12.9",
|
||||
"mongoose": "^5.12.13",
|
||||
"shelljs": "^0.8.4",
|
||||
"svelte-kit-cookie-session": "^0.4.3",
|
||||
"svelte-kit-cookie-session": "^1.0.6",
|
||||
"svelte-select": "^3.17.0",
|
||||
"unique-names-generator": "^4.5.0"
|
||||
}
|
||||
|
2903
pnpm-lock.yaml
generated
2903
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -92,7 +92,9 @@ body {
|
||||
input {
|
||||
@apply text-sm rounded py-2 px-6 font-bold bg-warmGray-800 text-white transition duration-150 outline-none border border-transparent !important;
|
||||
}
|
||||
input:hover {
|
||||
input:hover,
|
||||
input:focus-visible,
|
||||
input:focus {
|
||||
@apply bg-warmGray-700 !important;
|
||||
}
|
||||
textarea {
|
||||
@ -107,6 +109,7 @@ select {
|
||||
select:hover {
|
||||
@apply bg-warmGray-700 !important;
|
||||
}
|
||||
|
||||
label {
|
||||
@apply text-left text-base font-bold text-warmGray-400 !important;
|
||||
}
|
||||
@ -116,6 +119,11 @@ button {
|
||||
.button {
|
||||
@apply rounded text-sm font-bold transition-all duration-100 !important;
|
||||
}
|
||||
|
||||
.button:focus-visible,
|
||||
.button:focus {
|
||||
@apply bg-warmGray-700 !important;
|
||||
}
|
||||
.h-271 {
|
||||
min-height: 271px !important;
|
||||
}
|
||||
|
3
src/global.d.ts
vendored
3
src/global.d.ts
vendored
@ -49,8 +49,7 @@ export type Application = {
|
||||
python: {
|
||||
module?: string;
|
||||
instance?: string;
|
||||
}
|
||||
|
||||
};
|
||||
};
|
||||
container: {
|
||||
name: string;
|
||||
|
@ -31,11 +31,9 @@ async function connectMongoDB() {
|
||||
);
|
||||
}
|
||||
console.log('Connected to mongodb.');
|
||||
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
(async () => {
|
||||
@ -48,7 +46,7 @@ async function connectMongoDB() {
|
||||
try {
|
||||
await cleanupStuckedDeploymentsInDB();
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
console.log(error);
|
||||
}
|
||||
try {
|
||||
const dockerServices = await docker.engine.listServices();
|
||||
@ -76,20 +74,23 @@ async function connectMongoDB() {
|
||||
).values()
|
||||
];
|
||||
for (const application of applications) {
|
||||
await Configuration.findOneAndUpdate({
|
||||
'repository.name': application.configuration.repository.name,
|
||||
'repository.organization': application.configuration.repository.organization,
|
||||
'repository.branch': application.configuration.repository.branch,
|
||||
'publish.domain': application.configuration.publish.domain
|
||||
}, {
|
||||
...application.configuration
|
||||
}, { upsert: true, new: true })
|
||||
await Configuration.findOneAndUpdate(
|
||||
{
|
||||
'repository.name': application.configuration.repository.name,
|
||||
'repository.organization': application.configuration.repository.organization,
|
||||
'repository.branch': application.configuration.repository.branch,
|
||||
'publish.domain': application.configuration.publish.domain
|
||||
},
|
||||
{
|
||||
...application.configuration
|
||||
},
|
||||
{ upsert: true, new: true }
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
console.log(error);
|
||||
}
|
||||
})()
|
||||
|
||||
})();
|
||||
|
||||
export async function handle({ request, resolve }) {
|
||||
const { SECRETS_ENCRYPTION_KEY } = process.env;
|
||||
@ -99,7 +100,7 @@ export async function handle({ request, resolve }) {
|
||||
secret: SECRETS_ENCRYPTION_KEY,
|
||||
cookie: { path: '/' }
|
||||
});
|
||||
} catch(error) {
|
||||
} catch (error) {
|
||||
return {
|
||||
status: 302,
|
||||
headers: {
|
||||
|
@ -11,7 +11,7 @@ export async function deleteSameDeployments(configuration) {
|
||||
const running = JSON.parse(s.Spec.Labels.configuration);
|
||||
if (
|
||||
running.repository.id === configuration.repository.id &&
|
||||
running.repository.branch === configuration.repository.branch &&
|
||||
running.repository.branch === configuration.repository.branch &&
|
||||
running.publish.domain === configuration.publish.domain
|
||||
) {
|
||||
await execShellAsync(`docker stack rm ${s.Spec.Labels['com.docker.stack.namespace']}`);
|
||||
@ -55,7 +55,6 @@ export async function purgeImagesContainers(configuration, deleteAll = false) {
|
||||
.split('\n');
|
||||
if (IDsToDelete.length > 1) await execShellAsync(`docker rmi -f ${IDsToDelete.join(' ')}`);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
@ -39,7 +39,9 @@ export default async function (configuration) {
|
||||
);
|
||||
|
||||
if (isPreviewDeploymentEnabled && pullRequest && pullRequest !== 0) {
|
||||
await execShellAsync(`cd ${workdir} && git fetch origin pull/${pullRequest}/head:pull_${pullRequest} && git checkout pull_${pullRequest}`)
|
||||
await execShellAsync(
|
||||
`cd ${workdir} && git fetch origin pull/${pullRequest}/head:pull_${pullRequest} && git checkout pull_${pullRequest}`
|
||||
);
|
||||
}
|
||||
configuration.build.container.tag = (
|
||||
await execShellAsync(`cd ${workdir}/ && git rev-parse HEAD`)
|
||||
|
@ -21,8 +21,11 @@ export function setDefaultConfiguration(configuration) {
|
||||
configuration.general.deployId = deployId;
|
||||
configuration.general.workdir = `/tmp/${deployId}`;
|
||||
if (configuration.general.isPreviewDeploymentEnabled && configuration.general.pullRequest !== 0) {
|
||||
configuration.build.container.name = `pr${configuration.general.pullRequest}-${sha256.slice(0, 8)}`
|
||||
configuration.publish.domain = `pr${configuration.general.pullRequest}.${configuration.publish.domain}`
|
||||
configuration.build.container.name = `pr${configuration.general.pullRequest}-${sha256.slice(
|
||||
0,
|
||||
8
|
||||
)}`;
|
||||
configuration.publish.domain = `pr${configuration.general.pullRequest}.${configuration.publish.domain}`;
|
||||
}
|
||||
if (!configuration.publish.path) configuration.publish.path = '/';
|
||||
if (!configuration.publish.port) {
|
||||
@ -59,11 +62,13 @@ export function setDefaultConfiguration(configuration) {
|
||||
configuration.build.pack === 'nextjs' ||
|
||||
configuration.build.pack === 'nestjs'
|
||||
) {
|
||||
if (!configuration.build.command.start) configuration.build.command.start = 'yarn start'
|
||||
if (!configuration.build.command.start) configuration.build.command.start = 'yarn start';
|
||||
}
|
||||
if (configuration.build.pack === 'python') {
|
||||
if (!configuration.build.command.python.module) configuration.build.command.python.module = 'main'
|
||||
if (!configuration.build.command.python.instance) configuration.build.command.python.instance = 'app'
|
||||
if (!configuration.build.command.python.module)
|
||||
configuration.build.command.python.module = 'main';
|
||||
if (!configuration.build.command.python.instance)
|
||||
configuration.build.command.python.instance = 'app';
|
||||
}
|
||||
|
||||
configuration.build.container.baseSHA = crypto
|
||||
@ -77,7 +82,10 @@ export function setDefaultConfiguration(configuration) {
|
||||
|
||||
export async function precheckDeployment(configuration) {
|
||||
const services = (await docker.engine.listServices()).filter(
|
||||
(r) => r.Spec.Labels.managedBy === 'coolify' && r.Spec.Labels.type === 'application' && JSON.parse(r.Spec.Labels.configuration).publish.domain === configuration.publish.domain
|
||||
(r) =>
|
||||
r.Spec.Labels.managedBy === 'coolify' &&
|
||||
r.Spec.Labels.type === 'application' &&
|
||||
JSON.parse(r.Spec.Labels.configuration).publish.domain === configuration.publish.domain
|
||||
);
|
||||
let foundService = false;
|
||||
let configChanged = false;
|
||||
@ -86,7 +94,6 @@ export async function precheckDeployment(configuration) {
|
||||
for (const service of services) {
|
||||
const running = JSON.parse(service.Spec.Labels.configuration);
|
||||
if (running) {
|
||||
|
||||
if (
|
||||
running.repository.id === configuration.repository.id &&
|
||||
running.repository.branch === configuration.repository.branch
|
||||
@ -117,26 +124,27 @@ export async function precheckDeployment(configuration) {
|
||||
|
||||
const compareObjects = (a, b) => {
|
||||
if (a === b) return true;
|
||||
|
||||
|
||||
if (typeof a != 'object' || typeof b != 'object' || a == null || b == null) return false;
|
||||
|
||||
let keysA = Object.keys(a), keysB = Object.keys(b);
|
||||
|
||||
|
||||
const keysA = Object.keys(a),
|
||||
keysB = Object.keys(b);
|
||||
|
||||
if (keysA.length != keysB.length) return false;
|
||||
|
||||
for (let key of keysA) {
|
||||
if (!keysB.includes(key)) return false;
|
||||
|
||||
if (typeof a[key] === 'function' || typeof b[key] === 'function') {
|
||||
if (a[key].toString() != b[key].toString()) return false;
|
||||
} else {
|
||||
if (!compareObjects(a[key], b[key])) return false;
|
||||
}
|
||||
|
||||
for (const key of keysA) {
|
||||
if (!keysB.includes(key)) return false;
|
||||
|
||||
if (typeof a[key] === 'function' || typeof b[key] === 'function') {
|
||||
if (a[key].toString() != b[key].toString()) return false;
|
||||
} else {
|
||||
if (!compareObjects(a[key], b[key])) return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
const runningWithoutContainer = JSON.parse(JSON.stringify(running));
|
||||
delete runningWithoutContainer.build.container;
|
||||
|
||||
@ -145,19 +153,23 @@ export async function precheckDeployment(configuration) {
|
||||
|
||||
// If only the configuration changed
|
||||
if (
|
||||
!compareObjects(runningWithoutContainer.build,configurationWithoutContainer.build) ||
|
||||
!compareObjects(runningWithoutContainer.publish,configurationWithoutContainer.publish) ||
|
||||
!compareObjects(runningWithoutContainer.build, configurationWithoutContainer.build) ||
|
||||
!compareObjects(runningWithoutContainer.publish, configurationWithoutContainer.publish) ||
|
||||
runningWithoutContainer.general.isPreviewDeploymentEnabled !==
|
||||
configurationWithoutContainer.general.isPreviewDeploymentEnabled
|
||||
){
|
||||
configurationWithoutContainer.general.isPreviewDeploymentEnabled
|
||||
) {
|
||||
configChanged = true;
|
||||
}
|
||||
|
||||
|
||||
// If only the image changed
|
||||
if (running.build.container.tag !== configuration.build.container.tag) imageChanged = true;
|
||||
// If build pack changed, forceUpdate the service
|
||||
if (running.build.pack !== configuration.build.pack) forceUpdate = true;
|
||||
if (configuration.general.isPreviewDeploymentEnabled && configuration.general.pullRequest !== 0) forceUpdate = true
|
||||
if (
|
||||
configuration.general.isPreviewDeploymentEnabled &&
|
||||
configuration.general.pullRequest !== 0
|
||||
)
|
||||
forceUpdate = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -174,5 +186,9 @@ export async function precheckDeployment(configuration) {
|
||||
}
|
||||
|
||||
export async function updateServiceLabels(configuration) {
|
||||
return await execShellAsync(`docker service update --label-add configuration='${JSON.stringify(configuration)}' ${configuration.build.container.name}_${configuration.build.container.name}`)
|
||||
return await execShellAsync(
|
||||
`docker service update --label-add configuration='${JSON.stringify(configuration)}' ${
|
||||
configuration.build.container.name
|
||||
}_${configuration.build.container.name}`
|
||||
);
|
||||
}
|
||||
|
@ -42,12 +42,8 @@ export default async function (configuration, imageChanged) {
|
||||
'`) && PathPrefix(`' +
|
||||
configuration.publish.path +
|
||||
'`)',
|
||||
'traefik.http.routers.' +
|
||||
containerName +
|
||||
'.tls.certresolver=letsencrypt',
|
||||
'traefik.http.routers.' +
|
||||
containerName +
|
||||
'.middlewares=global-compress'
|
||||
'traefik.http.routers.' + containerName + '.tls.certresolver=letsencrypt',
|
||||
'traefik.http.routers.' + containerName + '.middlewares=global-compress'
|
||||
]
|
||||
}
|
||||
}
|
||||
@ -76,7 +72,7 @@ export default async function (configuration, imageChanged) {
|
||||
await delay(10000);
|
||||
await purgeImagesContainers(found, true);
|
||||
}
|
||||
purgeImagesAsync(configuration)
|
||||
purgeImagesAsync(configuration);
|
||||
|
||||
await saveAppLog('### Published done!', configuration);
|
||||
}
|
||||
|
@ -4,7 +4,6 @@ import ApplicationLog from '$models/ApplicationLog';
|
||||
import dayjs from 'dayjs';
|
||||
import { version } from '../../../../package.json';
|
||||
|
||||
|
||||
function generateTimestamp() {
|
||||
return `${dayjs().format('YYYY-MM-DD HH:mm:ss.SSS')} `;
|
||||
}
|
||||
|
@ -15,10 +15,7 @@ const publishPython = (configuration) => {
|
||||
};
|
||||
|
||||
export default async function (configuration) {
|
||||
await fs.writeFile(
|
||||
`${configuration.general.workdir}/Dockerfile`,
|
||||
publishPython(configuration)
|
||||
);
|
||||
await fs.writeFile(`${configuration.general.workdir}/Dockerfile`, publishPython(configuration));
|
||||
const stream = await docker.engine.buildImage(
|
||||
{ src: ['.'], context: configuration.general.workdir },
|
||||
{ t: `${configuration.build.container.name}:${configuration.build.container.tag}` }
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
import Deployment from '$models/Deployment';
|
||||
import dayjs from 'dayjs';
|
||||
import buildContainer from './buildContainer';
|
||||
|
@ -9,7 +9,7 @@ export function execShellAsync(cmd, opts = {}) {
|
||||
shell.config.silent = true;
|
||||
shell.exec(cmd, opts, async function (code, stdout, stderr) {
|
||||
if (code !== 0) {
|
||||
await saveServerLog({ message: JSON.stringify({ cmd, opts, code, stdout, stderr }) })
|
||||
await saveServerLog({ message: JSON.stringify({ cmd, opts, code, stdout, stderr }) });
|
||||
return reject(new Error(stderr));
|
||||
}
|
||||
return resolve(stdout);
|
||||
|
@ -1,2 +1,2 @@
|
||||
export const publicPages = ['/', '/api/v1/login/github/app', '/api/v1/webhooks/deploy', '/success'];
|
||||
export const VITE_GITHUB_APP_NAME = import.meta.env.VITE_GITHUB_APP_NAME
|
||||
export const VITE_GITHUB_APP_NAME = import.meta.env.VITE_GITHUB_APP_NAME;
|
||||
|
@ -8,4 +8,5 @@ const ApplicationLogsSchema = new Schema({
|
||||
|
||||
ApplicationLogsSchema.set('timestamps', true);
|
||||
|
||||
export default mongoose.models['logs-application'] || mongoose.model('logs-application', ApplicationLogsSchema);
|
||||
export default mongoose.models['logs-application'] ||
|
||||
mongoose.model('logs-application', ApplicationLogsSchema);
|
||||
|
@ -20,7 +20,7 @@ const ConfigurationSchema = new Schema({
|
||||
nickname: { type: String, required: true },
|
||||
workdir: { type: String, required: true },
|
||||
isPreviewDeploymentEnabled: { type: Boolean, required: true, default: false },
|
||||
pullRequest: { type: Number, required: true, default: 0 },
|
||||
pullRequest: { type: Number, required: true, default: 0 }
|
||||
},
|
||||
build: {
|
||||
pack: { type: String, required: true },
|
||||
@ -31,25 +31,25 @@ const ConfigurationSchema = new Schema({
|
||||
start: { type: String },
|
||||
python: {
|
||||
module: { type: String },
|
||||
instance: { type: String },
|
||||
instance: { type: String }
|
||||
}
|
||||
|
||||
},
|
||||
container: {
|
||||
name: { type: String, required: true },
|
||||
tag: { type: String, required: true },
|
||||
baseSHA: { type: String, required: true },
|
||||
},
|
||||
baseSHA: { type: String, required: true }
|
||||
}
|
||||
},
|
||||
publish: {
|
||||
directory: { type: String },
|
||||
domain: { type: String, required: true },
|
||||
path: { type: String },
|
||||
port: { type: Number },
|
||||
secrets: { type: Array },
|
||||
secrets: { type: Array }
|
||||
}
|
||||
});
|
||||
|
||||
ConfigurationSchema.set('timestamps', true);
|
||||
|
||||
export default mongoose.models['configuration'] || mongoose.model('configuration', ConfigurationSchema);
|
||||
export default mongoose.models['configuration'] ||
|
||||
mongoose.model('configuration', ConfigurationSchema);
|
||||
|
@ -1,5 +1,5 @@
|
||||
import mongoose from 'mongoose';
|
||||
import { version } from '../../package.json'
|
||||
import { version } from '../../package.json';
|
||||
const { Schema, Document } = mongoose;
|
||||
|
||||
// export interface ILogsServer extends Document {
|
||||
|
@ -9,9 +9,9 @@ export async function post(request: Request) {
|
||||
const { DOMAIN } = process.env;
|
||||
const configuration = setDefaultConfiguration(request.body);
|
||||
const configurationFound = await Configuration.find({
|
||||
'repository.id': { '$ne': configuration.repository.id },
|
||||
'repository.id': { $ne: configuration.repository.id },
|
||||
'publish.domain': configuration.publish.domain
|
||||
}).select('-_id -__v -createdAt -updatedAt')
|
||||
}).select('-_id -__v -createdAt -updatedAt');
|
||||
if (configurationFound.length > 0 || configuration.publish.domain === DOMAIN) {
|
||||
return {
|
||||
status: 200,
|
||||
@ -24,7 +24,7 @@ export async function post(request: Request) {
|
||||
return {
|
||||
status: 200,
|
||||
body: { success: true, message: 'OK' }
|
||||
}
|
||||
};
|
||||
} catch (error) {
|
||||
await saveServerLog(error);
|
||||
return {
|
||||
|
@ -9,7 +9,7 @@ export async function post(request: Request) {
|
||||
'repository.name': name,
|
||||
'repository.organization': organization,
|
||||
'repository.branch': branch
|
||||
}).select('-_id -__v -createdAt -updatedAt')
|
||||
}).select('-_id -__v -createdAt -updatedAt');
|
||||
|
||||
if (configurationFound) {
|
||||
return {
|
||||
|
@ -9,26 +9,40 @@ import type { Request } from '@sveltejs/kit';
|
||||
export async function post(request: Request) {
|
||||
const { name, organization, branch, isPreviewDeploymentEnabled }: any = request.body || {};
|
||||
if (name && organization && branch) {
|
||||
const configuration = await Configuration.findOneAndUpdate({
|
||||
'repository.name': name,
|
||||
'repository.organization': organization,
|
||||
'repository.branch': branch
|
||||
}, { $set: { 'general.isPreviewDeploymentEnabled': isPreviewDeploymentEnabled, 'general.pullRequest': 0 } }, { new: true }).select('-_id -__v -createdAt -updatedAt')
|
||||
const configuration = await Configuration.findOneAndUpdate(
|
||||
{
|
||||
'repository.name': name,
|
||||
'repository.organization': organization,
|
||||
'repository.branch': branch
|
||||
},
|
||||
{
|
||||
$set: {
|
||||
'general.isPreviewDeploymentEnabled': isPreviewDeploymentEnabled,
|
||||
'general.pullRequest': 0
|
||||
}
|
||||
},
|
||||
{ new: true }
|
||||
).select('-_id -__v -createdAt -updatedAt');
|
||||
if (!isPreviewDeploymentEnabled) {
|
||||
const found = await Configuration.find({
|
||||
'repository.name': name,
|
||||
'repository.organization': organization,
|
||||
'repository.branch': branch,
|
||||
'general.pullRequest': { '$ne': 0 }
|
||||
})
|
||||
'general.pullRequest': { $ne: 0 }
|
||||
});
|
||||
for (const prDeployment of found) {
|
||||
await Configuration.findOneAndRemove({
|
||||
'repository.name': name,
|
||||
'repository.organization': organization,
|
||||
'repository.branch': branch,
|
||||
'publish.domain': prDeployment.publish.domain
|
||||
})
|
||||
const deploys = await Deployment.find({ organization, branch, name, domain: prDeployment.publish.domain });
|
||||
});
|
||||
const deploys = await Deployment.find({
|
||||
organization,
|
||||
branch,
|
||||
name,
|
||||
domain: prDeployment.publish.domain
|
||||
});
|
||||
for (const deploy of deploys) {
|
||||
await ApplicationLog.deleteMany({ deployId: deploy.deployId });
|
||||
await Deployment.deleteMany({ deployId: deploy.deployId });
|
||||
@ -51,7 +65,6 @@ export async function post(request: Request) {
|
||||
success: true
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
return {
|
||||
status: 500,
|
||||
|
@ -18,7 +18,9 @@ export async function post(request: Request) {
|
||||
}
|
||||
try {
|
||||
await cloneRepository(configuration);
|
||||
const { foundService, imageChanged, configChanged, forceUpdate } = await precheckDeployment(configuration);
|
||||
const { foundService, imageChanged, configChanged, forceUpdate } = await precheckDeployment(
|
||||
configuration
|
||||
);
|
||||
if (foundService && !forceUpdate && !imageChanged && !configChanged) {
|
||||
cleanupTmp(configuration.general.workdir);
|
||||
return {
|
||||
@ -60,15 +62,17 @@ export async function post(request: Request) {
|
||||
nickname
|
||||
}).save();
|
||||
|
||||
await Configuration.findOneAndUpdate({
|
||||
'repository.id': id,
|
||||
'repository.organization': organization,
|
||||
'repository.name': name,
|
||||
'repository.branch': branch,
|
||||
'general.pullRequest': { '$in': [null, 0] },
|
||||
},
|
||||
await Configuration.findOneAndUpdate(
|
||||
{
|
||||
'repository.id': id,
|
||||
'repository.organization': organization,
|
||||
'repository.name': name,
|
||||
'repository.branch': branch,
|
||||
'general.pullRequest': { $in: [null, 0] }
|
||||
},
|
||||
{ ...configuration },
|
||||
{ upsert: true, new: true })
|
||||
{ upsert: true, new: true }
|
||||
);
|
||||
|
||||
queueAndBuild(configuration, imageChanged);
|
||||
return {
|
||||
@ -81,7 +85,7 @@ export async function post(request: Request) {
|
||||
}
|
||||
};
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
console.log(error);
|
||||
await Deployment.findOneAndUpdate(
|
||||
{
|
||||
repoId: configuration.repository.id,
|
||||
|
@ -10,8 +10,7 @@ export async function get(request: Request) {
|
||||
.select('-_id -__v')
|
||||
.sort({ createdAt: 'asc' });
|
||||
|
||||
const deploy: any = await Deployment.findOne({ deployId })
|
||||
.select('-_id -__v')
|
||||
const deploy: any = await Deployment.findOne({ deployId }).select('-_id -__v');
|
||||
const finalLogs: any = {};
|
||||
finalLogs.progress = deploy.progress;
|
||||
finalLogs.events = logs.map((log) => log.event);
|
||||
|
@ -21,7 +21,7 @@ export async function get(request: Request) {
|
||||
const updatedAt = dayjs(d.updatedAt).utc();
|
||||
finalLogs.took = updatedAt.diff(dayjs(d.createdAt)) / 1000;
|
||||
finalLogs.since = updatedAt.fromNow();
|
||||
finalLogs.isPr = d.domain.startsWith('pr')
|
||||
finalLogs.isPr = d.domain.startsWith('pr');
|
||||
return finalLogs;
|
||||
});
|
||||
return {
|
||||
|
@ -16,7 +16,7 @@ export async function get(request: Request) {
|
||||
body: { success: true, logs }
|
||||
};
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
console.log(error);
|
||||
await saveServerLog(error);
|
||||
return {
|
||||
status: 500,
|
||||
|
@ -16,25 +16,25 @@ export async function post(request: Request) {
|
||||
'repository.name': name,
|
||||
'repository.branch': branch,
|
||||
'publish.domain': domain
|
||||
})
|
||||
});
|
||||
if (configurationFound) {
|
||||
const id = configurationFound._id
|
||||
const id = configurationFound._id;
|
||||
if (configurationFound?.general?.pullRequest === 0) {
|
||||
// Main deployment deletion request; deleting main + PRs
|
||||
const allConfiguration = await Configuration.find({
|
||||
'repository.name': name,
|
||||
'repository.organization': organization,
|
||||
'repository.branch': branch,
|
||||
})
|
||||
'repository.branch': branch
|
||||
});
|
||||
for (const config of allConfiguration) {
|
||||
await Configuration.findOneAndRemove({
|
||||
'repository.name': config.repository.name,
|
||||
'repository.organization': config.repository.organization,
|
||||
'repository.branch': config.repository.branch,
|
||||
})
|
||||
'repository.branch': config.repository.branch
|
||||
});
|
||||
await execShellAsync(`docker stack rm ${config.build.container.name}`);
|
||||
}
|
||||
const deploys = await Deployment.find({ organization, branch, name })
|
||||
const deploys = await Deployment.find({ organization, branch, name });
|
||||
for (const deploy of deploys) {
|
||||
await ApplicationLog.deleteMany({ deployId: deploy.deployId });
|
||||
await Deployment.deleteMany({ deployId: deploy.deployId });
|
||||
@ -43,9 +43,9 @@ export async function post(request: Request) {
|
||||
purgeImagesAsync(configurationFound);
|
||||
} else {
|
||||
// Delete only PRs
|
||||
await Configuration.findByIdAndRemove(id)
|
||||
await Configuration.findByIdAndRemove(id);
|
||||
await execShellAsync(`docker stack rm ${configurationFound.build.container.name}`);
|
||||
const deploys = await Deployment.find({ organization, branch, name, domain })
|
||||
const deploys = await Deployment.find({ organization, branch, name, domain });
|
||||
for (const deploy of deploys) {
|
||||
await ApplicationLog.deleteMany({ deployId: deploy.deployId });
|
||||
await Deployment.deleteMany({ deployId: deploy.deployId });
|
||||
@ -63,7 +63,7 @@ export async function post(request: Request) {
|
||||
}
|
||||
};
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
console.log(error);
|
||||
return {
|
||||
status: 500,
|
||||
error: {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { docker } from '$lib/api/docker';
|
||||
import type { Request } from '@sveltejs/kit';
|
||||
import Configuration from '$models/Configuration'
|
||||
import Configuration from '$models/Configuration';
|
||||
export async function get(request: Request) {
|
||||
// Should update this to get data from mongodb and update db with the currently running services on start!
|
||||
const dockerServices = await docker.engine.listServices();
|
||||
@ -34,21 +34,21 @@ export async function get(request: Request) {
|
||||
return {};
|
||||
});
|
||||
const configurations = await Configuration.find({
|
||||
'general.pullRequest': { '$in': [null, 0] }
|
||||
}).select('-_id -__v -createdAt')
|
||||
const applications = []
|
||||
'general.pullRequest': { $in: [null, 0] }
|
||||
}).select('-_id -__v -createdAt');
|
||||
const applications = [];
|
||||
for (const configuration of configurations) {
|
||||
const foundPRDeployments = await Configuration.find({
|
||||
'repository.id': configuration.repository.id,
|
||||
'repository.branch': configuration.repository.branch,
|
||||
'general.pullRequest': { '$ne': 0 }
|
||||
}).select('-_id -__v -createdAt')
|
||||
'general.pullRequest': { $ne: 0 }
|
||||
}).select('-_id -__v -createdAt');
|
||||
const payload = {
|
||||
configuration,
|
||||
UpdatedAt: configuration.updatedAt,
|
||||
prBuilds: foundPRDeployments.length > 0 ? true : false,
|
||||
}
|
||||
applications.push(payload)
|
||||
prBuilds: foundPRDeployments.length > 0 ? true : false
|
||||
};
|
||||
applications.push(payload);
|
||||
}
|
||||
return {
|
||||
status: 200,
|
||||
|
@ -4,6 +4,7 @@ import type { Request } from '@sveltejs/kit';
|
||||
|
||||
export async function get(request: Request) {
|
||||
const { serviceName } = request.params;
|
||||
|
||||
try {
|
||||
const service = (await docker.engine.listServices()).find(
|
||||
(r) =>
|
||||
|
59
src/routes/api/v1/services/deploy/nocodb/index.ts
Normal file
59
src/routes/api/v1/services/deploy/nocodb/index.ts
Normal file
@ -0,0 +1,59 @@
|
||||
import type { Request } from '@sveltejs/kit';
|
||||
import yaml from 'js-yaml';
|
||||
import { promises as fs } from 'fs';
|
||||
import { docker } from '$lib/api/docker';
|
||||
import { baseServiceConfiguration } from '$lib/api/applications/common';
|
||||
import { cleanupTmp, execShellAsync } from '$lib/api/common';
|
||||
|
||||
export async function post(request: Request) {
|
||||
let { baseURL } = request.body;
|
||||
const traefikURL = baseURL;
|
||||
baseURL = `https://${baseURL}`;
|
||||
const workdir = '/tmp/nocodb';
|
||||
const deployId = 'nocodb';
|
||||
const stack = {
|
||||
version: '3.8',
|
||||
services: {
|
||||
[deployId]: {
|
||||
image: 'nocodb/nocodb',
|
||||
networks: [`${docker.network}`],
|
||||
deploy: {
|
||||
...baseServiceConfiguration,
|
||||
labels: [
|
||||
'managedBy=coolify',
|
||||
'type=service',
|
||||
'serviceName=nocodb',
|
||||
'configuration=' +
|
||||
JSON.stringify({
|
||||
baseURL
|
||||
}),
|
||||
'traefik.enable=true',
|
||||
'traefik.http.services.' + deployId + '.loadbalancer.server.port=8080',
|
||||
'traefik.http.routers.' + deployId + '.entrypoints=websecure',
|
||||
'traefik.http.routers.' +
|
||||
deployId +
|
||||
'.rule=Host(`' +
|
||||
traefikURL +
|
||||
'`) && PathPrefix(`/`)',
|
||||
'traefik.http.routers.' + deployId + '.tls.certresolver=letsencrypt',
|
||||
'traefik.http.routers.' + deployId + '.middlewares=global-compress'
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
networks: {
|
||||
[`${docker.network}`]: {
|
||||
external: true
|
||||
}
|
||||
}
|
||||
};
|
||||
await execShellAsync(`mkdir -p ${workdir}`);
|
||||
await fs.writeFile(`${workdir}/stack.yml`, yaml.dump(stack));
|
||||
await execShellAsync('docker stack rm nocodb');
|
||||
await execShellAsync(`cat ${workdir}/stack.yml | docker stack deploy --prune -c - ${deployId}`);
|
||||
cleanupTmp(workdir);
|
||||
return {
|
||||
status: 200,
|
||||
body: { message: 'OK' }
|
||||
};
|
||||
}
|
@ -11,9 +11,9 @@ import ApplicationLog from '$models/ApplicationLog';
|
||||
import { cleanupStuckedDeploymentsInDB } from '$lib/api/applications/cleanup';
|
||||
export async function post(request: Request) {
|
||||
let configuration;
|
||||
const allowedGithubEvents = ['push', 'pull_request']
|
||||
const allowedPRActions = ['opened', , 'reopened', 'synchronize', 'closed']
|
||||
const githubEvent = request.headers['x-github-event']
|
||||
const allowedGithubEvents = ['push', 'pull_request'];
|
||||
const allowedPRActions = ['opened', 'reopened', 'synchronize', 'closed'];
|
||||
const githubEvent = request.headers['x-github-event'];
|
||||
const { GITHUP_APP_WEBHOOK_SECRET } = process.env;
|
||||
const hmac = crypto.createHmac('sha256', GITHUP_APP_WEBHOOK_SECRET);
|
||||
const digest = Buffer.from(
|
||||
@ -41,8 +41,8 @@ export async function post(request: Request) {
|
||||
|
||||
try {
|
||||
const applications = await Configuration.find({
|
||||
'repository.id': request.body.repository.id,
|
||||
}).select('-_id -__v -createdAt -updatedAt')
|
||||
'repository.id': request.body.repository.id
|
||||
}).select('-_id -__v -createdAt -updatedAt');
|
||||
if (githubEvent === 'push') {
|
||||
configuration = applications.find((r) => {
|
||||
if (request.body.ref.startsWith('refs')) {
|
||||
@ -61,7 +61,9 @@ export async function post(request: Request) {
|
||||
}
|
||||
};
|
||||
}
|
||||
configuration = applications.find((r) => r.repository.branch === request.body['pull_request'].base.ref);
|
||||
configuration = applications.find(
|
||||
(r) => r.repository.branch === request.body['pull_request'].base.ref
|
||||
);
|
||||
if (configuration) {
|
||||
if (!configuration.general.isPreviewDeploymentEnabled) {
|
||||
return {
|
||||
@ -71,7 +73,7 @@ export async function post(request: Request) {
|
||||
}
|
||||
};
|
||||
}
|
||||
configuration.general.pullRequest = request.body.number
|
||||
configuration.general.pullRequest = request.body.number;
|
||||
}
|
||||
}
|
||||
if (!configuration) {
|
||||
@ -99,7 +101,7 @@ export async function post(request: Request) {
|
||||
'repository.name': name,
|
||||
'repository.branch': branch,
|
||||
'general.pullRequest': pullRequest
|
||||
})
|
||||
});
|
||||
await execShellAsync(`docker stack rm ${configuration.build.container.name}`);
|
||||
return {
|
||||
status: 200,
|
||||
@ -110,7 +112,9 @@ export async function post(request: Request) {
|
||||
};
|
||||
}
|
||||
await cloneRepository(configuration);
|
||||
const { foundService, imageChanged, configChanged, forceUpdate } = await precheckDeployment(configuration);
|
||||
const { foundService, imageChanged, configChanged, forceUpdate } = await precheckDeployment(
|
||||
configuration
|
||||
);
|
||||
if (foundService && !forceUpdate && !imageChanged && !configChanged) {
|
||||
cleanupTmp(configuration.general.workdir);
|
||||
return {
|
||||
@ -149,27 +153,30 @@ export async function post(request: Request) {
|
||||
nickname
|
||||
}).save();
|
||||
|
||||
|
||||
if (githubEvent === 'pull_request') {
|
||||
await Configuration.findOneAndUpdate({
|
||||
'repository.id': id,
|
||||
'repository.organization': organization,
|
||||
'repository.name': name,
|
||||
'repository.branch': branch,
|
||||
'general.pullRequest': pullRequest
|
||||
},
|
||||
await Configuration.findOneAndUpdate(
|
||||
{
|
||||
'repository.id': id,
|
||||
'repository.organization': organization,
|
||||
'repository.name': name,
|
||||
'repository.branch': branch,
|
||||
'general.pullRequest': pullRequest
|
||||
},
|
||||
{ ...configuration },
|
||||
{ upsert: true, new: true })
|
||||
{ upsert: true, new: true }
|
||||
);
|
||||
} else {
|
||||
await Configuration.findOneAndUpdate({
|
||||
'repository.id': id,
|
||||
'repository.organization': organization,
|
||||
'repository.name': name,
|
||||
'repository.branch': branch,
|
||||
'general.pullRequest': { '$in': [null, 0] }
|
||||
},
|
||||
await Configuration.findOneAndUpdate(
|
||||
{
|
||||
'repository.id': id,
|
||||
'repository.organization': organization,
|
||||
'repository.name': name,
|
||||
'repository.branch': branch,
|
||||
'general.pullRequest': { $in: [null, 0] }
|
||||
},
|
||||
{ ...configuration },
|
||||
{ upsert: true, new: true })
|
||||
{ upsert: true, new: true }
|
||||
);
|
||||
}
|
||||
|
||||
queueAndBuild(configuration, imageChanged);
|
||||
@ -183,7 +190,7 @@ export async function post(request: Request) {
|
||||
}
|
||||
};
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
console.log(error);
|
||||
// console.log(configuration)
|
||||
if (configuration) {
|
||||
cleanupTmp(configuration.general.workdir);
|
||||
@ -216,7 +223,7 @@ export async function post(request: Request) {
|
||||
try {
|
||||
await cleanupStuckedDeploymentsInDB();
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -49,6 +49,15 @@
|
||||
/>
|
||||
<div class="text-white font-bold">Plausible Analytics</div>
|
||||
</div>
|
||||
{:else if service.serviceName == 'nocodb'}
|
||||
<div>
|
||||
<img
|
||||
alt="nocodedb"
|
||||
class="w-10 absolute top-0 left-0 -m-6"
|
||||
src="https://cdn.coollabs.io/assets/coolify/services/nocodb/nocodb.png"
|
||||
/>
|
||||
<div class="text-white font-bold">NocoDB</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -14,23 +14,14 @@
|
||||
try {
|
||||
service = await request(`/api/v1/services/${$page.params.name}`, $session);
|
||||
} catch (error) {
|
||||
browser && toast.push(`Cannot find service ${$page.params.name}?!`);
|
||||
goto(`/dashboard/services`, { replaceState: true });
|
||||
if (browser) {
|
||||
toast.push(`Cannot find service ${$page.params.name}?!`);
|
||||
goto(`/dashboard/services`, { replaceState: true });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
async function activate() {
|
||||
try {
|
||||
await request(`/api/v1/services/deploy/${$page.params.name}/activate`, $session, {
|
||||
method: 'PATCH',
|
||||
body: {}
|
||||
});
|
||||
browser && toast.push(`All users are activated for Plausible.`);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
browser && toast.push(`Ooops, there was an error activating users for Plausible?!`);
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
{#await loadServiceConfig()}
|
||||
@ -38,7 +29,12 @@
|
||||
{:then}
|
||||
<div class="min-h-full text-white">
|
||||
<div class="py-5 text-left px-6 text-3xl tracking-tight font-bold flex items-center">
|
||||
<div>{$page.params.name === 'plausible' ? 'Plausible Analytics' : $page.params.name}</div>
|
||||
{#if $page.params.name === 'plausible'}
|
||||
<div>Plausible Analytics</div>
|
||||
{:else if $page.params.name === 'nocodb'}
|
||||
<div>NocoDB</div>
|
||||
{/if}
|
||||
|
||||
<div class="px-4">
|
||||
{#if $page.params.name === 'plausible'}
|
||||
<img
|
||||
@ -46,37 +42,38 @@
|
||||
class="w-6 mx-auto"
|
||||
src="https://cdn.coollabs.io/assets/coolify/services/plausible/logo_sm.png"
|
||||
/>
|
||||
{:else if $page.params.name === 'nocodb'}
|
||||
<img
|
||||
alt="nocodb logo"
|
||||
class="w-8 mx-auto"
|
||||
src="https://cdn.coollabs.io/assets/coolify/services/nocodb/nocodb.png"
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
<a
|
||||
target="_blank"
|
||||
class="icon mx-2"
|
||||
href={service.config.baseURL}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-6 w-6"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
<a target="_blank" class="icon mx-2" href={service.config.baseURL}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-6 w-6"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
|
||||
/>
|
||||
</svg></a
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
|
||||
/>
|
||||
</svg></a
|
||||
>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="space-y-2 max-w-4xl mx-auto px-6" in:fade={{ duration: 100 }}>
|
||||
<div class="block text-center py-4">
|
||||
{#if $page.params.name === 'plausible'}
|
||||
<Plausible {service} />
|
||||
{:else if $page.params.name === 'nocodb'}
|
||||
<div class="font-bold">Nothing to show here. Enjoy using NocoDB!</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -14,13 +14,11 @@
|
||||
async function checkService() {
|
||||
try {
|
||||
const data = await request(`/api/v1/services/${$page.params.type}`, $session);
|
||||
if (!data?.success) {
|
||||
if (data?.success) {
|
||||
if (browser) {
|
||||
goto(`/dashboard/services`, { replaceState: true });
|
||||
goto(`/service/${$page.params.type}/configuration`, { replaceState: true });
|
||||
toast.push(
|
||||
`${
|
||||
$page.params.type === 'plausible' ? 'Plausible Analytics' : $page.params.type
|
||||
} already deployed.`
|
||||
`Service already deployed.`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@
|
||||
import TooltipInfo from '$components/TooltipInfo.svelte';
|
||||
import { browser } from '$app/env';
|
||||
|
||||
$: deployable =
|
||||
$: deployablePlausible =
|
||||
$newService.baseURL === '' ||
|
||||
$newService.baseURL === null ||
|
||||
$newService.email === '' ||
|
||||
@ -22,7 +22,7 @@
|
||||
$newService.userPassword.length <= 6 ||
|
||||
$newService.userPassword !== $newService.userPasswordAgain;
|
||||
let loading = false;
|
||||
async function deploy() {
|
||||
async function deployPlausible() {
|
||||
try {
|
||||
loading = true;
|
||||
const payload = $newService;
|
||||
@ -44,6 +44,30 @@
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
async function deployNocodb() {
|
||||
|
||||
try {
|
||||
loading = true;
|
||||
await request(`/api/v1/services/deploy/${$page.params.type}`, $session, {
|
||||
body: {
|
||||
baseURL: $newService.baseURL
|
||||
}
|
||||
});
|
||||
if (browser) {
|
||||
toast.push(
|
||||
'Service deployment queued.<br><br><br>It could take 2-5 minutes to be ready, be patient and grab a coffee/tea!',
|
||||
{ duration: 4000 }
|
||||
);
|
||||
goto(`/dashboard/services`, { replaceState: true });
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
browser && toast.push('Oops something went wrong. See console.log.');
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<div class="min-h-full text-white">
|
||||
@ -51,18 +75,20 @@
|
||||
Deploy new
|
||||
{#if $page.params.type === 'plausible'}
|
||||
<span class="text-blue-500 px-2 capitalize">Plausible Analytics</span>
|
||||
{:else if $page.params.type === 'nocodb'}
|
||||
<span class="text-blue-500 px-2 capitalize">NocoDB</span>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{#if loading}
|
||||
<Loading />
|
||||
{:else}
|
||||
{:else if $page.params.type === 'plausible'}
|
||||
<div class="space-y-2 max-w-4xl mx-auto px-6 flex-col text-center" in:fade={{ duration: 100 }}>
|
||||
<div class="grid grid-flow-row">
|
||||
<label for="Domain"
|
||||
>Domain <TooltipInfo
|
||||
position="right"
|
||||
label={`You will have your Plausible instance at here.`}
|
||||
label={`You could reach your Plausible Analytics instance here.`}
|
||||
/></label
|
||||
>
|
||||
<input
|
||||
@ -114,15 +140,39 @@
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
disabled={deployable}
|
||||
class:cursor-not-allowed={deployable}
|
||||
class:bg-blue-500={!deployable}
|
||||
class:hover:bg-blue-400={!deployable}
|
||||
class:hover:bg-transparent={deployable}
|
||||
class:text-warmGray-700={deployable}
|
||||
class:text-white={!deployable}
|
||||
disabled={deployablePlausible}
|
||||
class:cursor-not-allowed={deployablePlausible}
|
||||
class:bg-blue-500={!deployablePlausible}
|
||||
class:hover:bg-blue-400={!deployablePlausible}
|
||||
class:hover:bg-transparent={deployablePlausible}
|
||||
class:text-warmGray-700={deployablePlausible}
|
||||
class:text-white={!deployablePlausible}
|
||||
class="button p-2"
|
||||
on:click={deploy}
|
||||
on:click={deployPlausible}
|
||||
>
|
||||
Deploy
|
||||
</button>
|
||||
</div>
|
||||
{:else if $page.params.type === 'nocodb'}
|
||||
<div class="space-y-2 max-w-xl mx-auto px-6 flex-col text-center" in:fade={{ duration: 100 }}>
|
||||
<div class="grid grid-flow-row pb-5">
|
||||
<label for="Domain"
|
||||
>Domain <TooltipInfo
|
||||
position="right"
|
||||
label={`You could reach your NocoDB instance here.`}
|
||||
/></label
|
||||
>
|
||||
<input
|
||||
id="Domain"
|
||||
class:border-red-500={$newService.baseURL == null || $newService.baseURL == ''}
|
||||
bind:value={$newService.baseURL}
|
||||
placeholder="nocodb.coollabs.io"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<button
|
||||
class="button p-2 w-64 bg-blue-500 hover:bg-blue-400 text-white"
|
||||
on:click={deployNocodb}
|
||||
>
|
||||
Deploy
|
||||
</button>
|
||||
|
@ -1,7 +1,6 @@
|
||||
<script>
|
||||
import { goto } from '$app/navigation';
|
||||
import { page } from '$app/stores';
|
||||
|
||||
import { fade } from 'svelte/transition';
|
||||
</script>
|
||||
|
||||
@ -14,7 +13,7 @@
|
||||
{#if $page.path === '/service/new'}
|
||||
<div class="flex justify-center space-x-4 font-bold pb-6">
|
||||
<div
|
||||
class="text-center flex-col items-center cursor-pointer ease-in-out transform hover:scale-105 duration-100 border-2 border-dashed border-transparent hover:border-blue-500 p-2 rounded bg-warmGray-800"
|
||||
class="text-center flex-col items-center cursor-pointer ease-in-out transform hover:scale-105 duration-100 border-2 border-dashed border-transparent hover:border-blue-500 p-2 rounded bg-warmGray-800 w-48"
|
||||
on:click={() => goto('/service/new/plausible')}
|
||||
>
|
||||
<img
|
||||
@ -24,6 +23,18 @@
|
||||
/>
|
||||
<div class="text-white">Plausible Analytics</div>
|
||||
</div>
|
||||
<div
|
||||
class="text-center flex-col items-center cursor-pointer ease-in-out transform hover:scale-105 duration-100 border-2 border-dashed border-transparent hover:border-white p-2 rounded bg-warmGray-800 w-48"
|
||||
on:click={() => goto('/service/new/nocodb')}
|
||||
>
|
||||
<img
|
||||
alt="nocodb logo"
|
||||
class="w-14 mx-auto pb-2"
|
||||
src="https://cdn.coollabs.io/assets/coolify/services/nocodb/nocodb.png"
|
||||
/>
|
||||
<div class="flex-1" />
|
||||
<div class="text-white">NocoDB</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
@ -78,7 +78,7 @@ export const application = writable<Application>({
|
||||
secrets: []
|
||||
}
|
||||
});
|
||||
export const prApplication = writable([])
|
||||
export const prApplication = writable([]);
|
||||
|
||||
export const initConf = writable({});
|
||||
|
||||
@ -168,4 +168,4 @@ export const initialNewService = {
|
||||
baseURL: null
|
||||
};
|
||||
|
||||
export const isPullRequestPermissionsGranted = writable(false)
|
||||
export const isPullRequestPermissionsGranted = writable(false);
|
||||
|
BIN
static/nocodb.png
Normal file
BIN
static/nocodb.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
Loading…
x
Reference in New Issue
Block a user