Skip to content
This repository was archived by the owner on Aug 30, 2023. It is now read-only.

Commit 9478150

Browse files
authored
Merge pull request #487 from threefoldtech/development_discourse_weblet
discourse weblet
2 parents 447e49d + 234eefd commit 9478150

File tree

15 files changed

+480
-1
lines changed

15 files changed

+480
-1
lines changed

easy-docs/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"dependencies": {
1212
"axios": "^0.24.0",
1313
"bip39": "^3.0.4",
14+
"buffer": "^6.0.3",
1415
"core-js": "^3.6.5",
1516
"front-matter": "^4.0.2",
1617
"grid3_client": "1.1.0",

easy-docs/public/build/elements/discourse.wc.js

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

easy-docs/src/App.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ export default class App extends Vue {
3838
"kubernetes",
3939
"deployedlist",
4040
"caprover",
41+
"discourse",
4142
"farmingcalculator",
4243
"funkwhale",
4344
"peertube",

easy-docs/src/configs.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import * as client from "ts-rmb-http-client/dist/es6";
22
import * as grid3_client from "grid3_client/dist/es6";
3+
import * as buffer from "buffer";
34

45
(window as any).configs = (window as any).configs || {};
56
(window as any).configs = {
67
...(window as any).configs,
78
client,
89
grid3_client,
10+
buffer,
911
};

easy-docs/src/views/Editor.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ export default class Editor extends Vue {
107107
public sections = ["deployment", "my account", "calculator"];
108108
public weblets: Weblet[] = [
109109
new Weblet("CapRover", "caprover", "caprover", "deployment"),
110+
new Weblet("Discourse", "discourse", "discourse", "deployment"),
110111
new Weblet("Virtual Machine", "vm", "vm", "deployment"),
111112
new Weblet("Kubernetes", `kubernetes`, "k8s", "deployment"),
112113
new Weblet("Contracts", "contractslist", "", "my account"),

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
"@polkadot/extension-dapp": "^0.41.1",
5252
"add": "^2.0.6",
5353
"bip39": "^3.0.4",
54+
"buffer": "^6.0.3",
5455
"bulma": "^0.9.3",
5556
"chart.js": "^3.6.0",
5657
"crypto-js": "^4.1.1",

src/components/FormatData.svelte

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,17 @@
9494
}}
9595
/>
9696
{/if}
97+
{#if vm.env.DISCOURSE_HOSTNAME}
98+
<Input
99+
data={"https://" + vm.env.DISCOURSE_HOSTNAME}
100+
field={{
101+
label: "Domain",
102+
symbol: "domain",
103+
type: "text",
104+
disabled: true,
105+
}}
106+
/>
107+
{/if}
97108
{#if vm.env.PEERTUBE_WEBSERVER_HOSTNAME}
98109
<Input
99110
data={"https://" + vm.env.PEERTUBE_WEBSERVER_HOSTNAME}
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
<svelte:options tag="tf-discourse" />
2+
3+
<script lang="ts">
4+
import type { IFormField, ITab } from "../../types";
5+
import { default as Discourse } from "../../types/discourse";
6+
import deployDiscourse from "../../utils/deployDiscourse";
7+
import type { IProfile } from "../../types/Profile";
8+
import rootFs from "../../utils/rootFs";
9+
// Components
10+
import SelectProfile from "../../components/SelectProfile.svelte";
11+
import Input from "../../components/Input.svelte";
12+
import Tabs from "../../components/Tabs.svelte";
13+
import DeployBtn from "../../components/DeployBtn.svelte";
14+
import Alert from "../../components/Alert.svelte";
15+
import SelectNodeId from "../../components/SelectNodeId.svelte";
16+
import Modal from "../../components/DeploymentModal.svelte";
17+
import hasEnoughBalance from "../../utils/hasEnoughBalance";
18+
import validateName, {
19+
isInvalid,
20+
validateCpu,
21+
validateDisk,
22+
validateEmail,
23+
validateMemory,
24+
} from "../../utils/validateName";
25+
import { noActiveProfile } from "../../utils/message";
26+
27+
28+
const data = new Discourse();
29+
30+
let loading = false;
31+
let success = false;
32+
let failed = false;
33+
34+
let status: "valid" | "invalid";
35+
let profile: IProfile;
36+
37+
const deploymentStore = window.configs?.deploymentStore;
38+
const currentDeployment = window.configs?.currentDeploymentStore;
39+
40+
// prettier-ignore
41+
const tabs: ITab[] = [
42+
{ label: "Config", value: "config" },
43+
{ label: "Mail Server", value: "mail" },
44+
45+
];
46+
let active = "config";
47+
48+
// prettier-ignore
49+
const fields: IFormField[] = [
50+
{ label: "Name", symbol: "name", placeholder: "Discourse Instance Name", type: "text", validator: validateName, invalid: false },
51+
{ label: "CPU", symbol: "cpu", placeholder: "CPU", type: "number", validator: validateCpu, invalid: false },
52+
{ label: "Memory (MB)", symbol: 'memory', placeholder: "Memory in MB", type: "number", validator: validateMemory, invalid: false },
53+
{ label: "Disk Size (GB)", symbol: "diskSize", placeholder: "Disk Size in GB", type: "number", validator: validateDisk, invalid: false },
54+
{ label: "Email", symbol: "developerEmail", placeholder: "Admin Email", type: "text", validator: validateEmail, invalid: false },
55+
{ label: "Public IP", symbol: "publicIp", type: 'checkbox' },
56+
{ label: "Planetary Network", symbol: "planetary", placeholder: "Enable planetary network", type: 'checkbox' },
57+
];
58+
59+
$: disabled = ((loading || !data.valid) && !(success || failed)) || !profile || status !== "valid" || isInvalid(fields); // prettier-ignore
60+
61+
let message: string;
62+
let modalData: Object;
63+
64+
async function deployDiscourseHandler() {
65+
loading = true;
66+
67+
if (!hasEnoughBalance()) {
68+
failed = true;
69+
loading = false;
70+
message =
71+
"No enough balance to execute! Transaction requires 2 TFT at least in your wallet.";
72+
return;
73+
}
74+
75+
success = false;
76+
failed = false;
77+
message = undefined;
78+
79+
deployDiscourse(data, profile)
80+
.then((data: any) => {
81+
modalData = data;
82+
deploymentStore.set(0);
83+
success = true;
84+
})
85+
.catch((err: string) => {
86+
failed = true;
87+
message = err;
88+
})
89+
.finally(() => {
90+
loading = false;
91+
});
92+
}
93+
94+
$: logs = $currentDeployment;
95+
</script>
96+
97+
<SelectProfile
98+
on:profile={({ detail }) => {
99+
profile = detail;
100+
}}
101+
/>
102+
103+
<div style="padding: 15px;">
104+
<form class="box" on:submit|preventDefault={deployDiscourseHandler}>
105+
<h4 class="is-size-4 mb-4">Deploy a Discourse Instance</h4>
106+
107+
<hr />
108+
109+
{#if loading || (logs !== null && logs.type === "Discourse")}
110+
<Alert type="info" message={logs?.message ?? "Loading..."} />
111+
{:else if !profile}
112+
<Alert type="info" message={noActiveProfile} />
113+
{:else if success}
114+
<Alert
115+
type="success"
116+
message="Successfully Deployed Discourse."
117+
deployed={true}
118+
/>
119+
{:else if failed}
120+
<Alert type="danger" message={message || "Failed to Deploy Discourse."} />
121+
{:else}
122+
<Tabs bind:active {tabs} />
123+
124+
{#if active === "config"}
125+
{#each fields as field (field.symbol)}
126+
{#if field.invalid !== undefined}
127+
<Input
128+
bind:data={data[field.symbol]}
129+
bind:invalid={field.invalid}
130+
{field}
131+
/>
132+
{:else}
133+
<Input bind:data={data[field.symbol]} {field} />
134+
{/if}
135+
{/each}
136+
137+
<SelectNodeId
138+
cpu={data.cpu}
139+
memory={data.memory}
140+
publicIp={data.publicIp}
141+
ssd={data.diskSize + rootFs(data.cpu, data.memory)}
142+
bind:data={data.nodeId}
143+
bind:nodeSelection={data.selection.type}
144+
bind:status
145+
filters={data.selection.filters}
146+
{profile}
147+
on:fetch={({ detail }) => (data.selection.nodes = detail)}
148+
nodes={data.selection.nodes}
149+
/>
150+
151+
<!-- SMTP fields -->
152+
{:else if active === "mail"}
153+
<div class="notification is-warning is-light">
154+
<p>
155+
Discourse needs SMTP service so please configure these settings properly.
156+
</p>
157+
</div>
158+
{#each data.smtp.fields as field (field.symbol)}
159+
{#if field.invalid !== undefined}
160+
<Input
161+
bind:data={data.smtp[field.symbol]}
162+
bind:invalid={field.invalid}
163+
{field}
164+
/>
165+
{:else}
166+
<Input bind:data={data.smtp[field.symbol]} {field} />
167+
{/if}
168+
{/each}
169+
{/if}
170+
{/if}
171+
172+
<DeployBtn
173+
{disabled}
174+
{loading}
175+
{success}
176+
{failed}
177+
on:click={(e) => {
178+
if (success || failed) {
179+
e.preventDefault();
180+
success = false;
181+
failed = false;
182+
loading = false;
183+
}
184+
}}
185+
/>
186+
</form>
187+
</div>
188+
189+
{#if modalData}
190+
<Modal data={modalData} on:closed={() => (modalData = null)} />
191+
{/if}
192+
193+
<style lang="scss" scoped>
194+
@import url("https://cdn.jsdelivr.net/npm/[email protected]/css/bulma.min.css");
195+
</style>

src/elements/discourse/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
import "./Discourse.wc.svelte";

src/global.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import * as client from "ts-rmb-http-client";
44
import * as grid3_client from "grid3_client";
5+
import * as buffer from "buffer";
56

67
// stores
78
import baseConfigStore from "./stores/baseConfig";
@@ -18,6 +19,7 @@ interface AppConfigs {
1819
notificationStore: typeof notificationStore;
1920
currentDeploymentStore: typeof currentDeploymentStore;
2021
balanceStore: typeof balanceStore;
22+
buffer: typeof buffer;
2123
}
2224

2325
declare global {

0 commit comments

Comments
 (0)