Compare commits

...

77 Commits

Author SHA1 Message Date
a10a6d6507 bump version to 1.0.15 2025-02-25 10:22:29 -07:00
fff14183a4 .... 2025-02-24 06:34:38 -07:00
6a2e143b98 ... 2025-02-24 02:47:59 -07:00
6820a7e9c8 ... 2025-02-23 10:34:18 +00:00
1c7621f20a docusaurus 2025-02-23 07:42:16 +03:00
timurgordon
88fe8f503f rename example output dir 2025-02-20 08:15:49 +03:00
timurgordon
a26bb56b15 create missing dir 2025-02-20 08:12:48 +03:00
timurgordon
2f54f05cfd fix bizmodel docs export 2025-02-20 08:10:49 +03:00
timurgordon
f61d6808e8 fix compilation 2025-02-20 06:59:08 +03:00
timurgordon
4719876feb get example to work with echarts 2025-02-20 06:43:26 +03:00
timurgordon
975cca77b1 decouple charts from wiki representation 2025-02-20 06:41:17 +03:00
timurgordon
eb80294b0a improve echart exporting 2025-02-20 06:40:19 +03:00
timurgordon
0704c9421d make getters immutable 2025-02-20 06:38:42 +03:00
timurgordon
814b61f25e Merge branch 'development_installers' into development_bizmodel 2025-02-19 13:30:34 +03:00
timurgordon
1c264815c3 update example 2025-02-19 13:28:38 +03:00
ff45beac09 ... 2025-02-19 09:46:41 +03:00
24eb709293 fixes docusaurus 2025-02-19 09:44:03 +03:00
49e2146152 Merge branch 'development_bizmodel' into development_installers 2025-02-19 07:15:28 +03:00
cdaf64b3cf git print better 2025-02-19 07:15:14 +03:00
49af31776e gitools 2025-02-19 05:53:29 +03:00
0880823576 Merge branch 'development_installers' of github.com:freeflowuniverse/herolib into development_installers 2025-02-19 05:10:45 +03:00
1fa1ecb8ec Merge branch 'development_fix' into development_installers 2025-02-19 05:09:56 +03:00
d6108c9836 Merge branch 'development' into development_installers 2025-02-19 05:08:41 +03:00
timurgordon
cc344fa60e bizmodel example report export wip 2025-02-18 23:23:26 +03:00
timurgordon
5e468359a1 start implementing docusaurus bizmodel exporting 2025-02-18 05:09:56 +03:00
timurgordon
2317dd2d4c tidy up action processing & playing 2025-02-18 05:09:06 +03:00
timurgordon
b92647c52e fix sheet processing issues 2025-02-18 05:07:56 +03:00
timurgordon
54024ee222 bizmodel example wip 2025-02-17 18:40:11 +03:00
60d6474a42 ... 2025-02-17 08:29:57 +03:00
8c52326550 ... 2025-02-17 06:41:19 +03:00
52aba347a8 ... 2025-02-17 06:40:06 +03:00
Mahmoud Emad
61a0fd2aa6 chore: Change the factories 2025-02-16 11:12:59 +00:00
Mahmoud Emad
d604d739e3 feat: Support garage_s3 installer
- Added a new config template file to be loaded when starting the server
- Run the server in zinit as a service
- Fix the install, destroy, installed, and running functions
2025-02-16 11:10:27 +00:00
Mahmoud Emad
a57f53fdb4 feat: Improved rclone installer 2025-02-16 08:56:28 +00:00
Mahmoud Emad
f276cdf697 feat: Improved tailwind installer 2025-02-16 08:15:43 +00:00
Mahmoud Emad
7fb46a4c0b feat: Improved b2 installer 2025-02-16 07:48:11 +00:00
Mahmoud Emad
fc993a95d7 feat: simplify actrunner installer
- Remove unnecessary dependencies and simplify the actrunner installation process.
2025-02-16 07:19:03 +00:00
c6ff7e7ba5 Merge branch 'development' of github.com:freeflowuniverse/herolib into development 2025-02-16 10:05:41 +03:00
3f9a3fb1cd caldav... 2025-02-16 10:05:35 +03:00
7ae4f7dbd0 mail/contacts... 2025-02-16 09:30:51 +03:00
dbb44ec30a mail 2025-02-16 08:25:25 +03:00
7f4fc42a7a mail 2025-02-16 07:49:06 +03:00
01db4540b1 imap 2025-02-16 06:44:43 +03:00
5c0c096a79 Merge pull request #64 from freeflowuniverse/development_coredns
Development coredns
2025-02-13 19:19:09 +02:00
c1719a057a Merge pull request #62 from freeflowuniverse/development_coredns
coredns
2025-02-13 19:10:13 +02:00
e969eacd06 fix(golang): add go path to env 2025-02-13 16:56:45 +00:00
8ed3439cdc fix(coredns): comment getting machine public ip 2025-02-13 16:13:15 +00:00
Mahmoud Emad
5241dfddd4 refactor: rename mycelium to mycelium_installer
- Renamed the `mycelium` module to `mycelium_installer` to improve clarity and avoid naming conflicts.
- Updated all related files and references to reflect the name change.
2025-02-13 13:29:16 +00:00
Mahmoud Emad
6e0572b48a chore: restructure the installers for organize the installers 2025-02-13 13:11:49 +00:00
Mahmoud Emad
9a4a39b19a feat: add screen installer
- Add a new screen installer to the project.
2025-02-13 13:01:48 +00:00
Mahmoud Emad
8abf113715 feat: improve LiveKit installer
- Implement key generation for LiveKit.
- Improve health check for LiveKit server.
- Add support for different startup managers.
- Simplify installation process.
- Remove unnecessary code.
- Update dependencies.
2025-02-13 12:52:03 +00:00
25c997fec5 fix(coredns): fixes in coredns installer and client 2025-02-12 17:55:36 +02:00
Mahmoud Emad
1546bf7f87 chore: Format the installers 2025-02-12 14:29:07 +00:00
Mahmoud Emad
02d4adcff0 refactor: improve gitea installer
- Simplify gitea installer logic.
- Remove unnecessary variables and functions.
- Improve code readability and maintainability.
- Update gitea version to 1.23.3.
- Add default values for GiteaServer fields.
- Remove redundant installer.v and server.v files.
2025-02-12 14:27:18 +00:00
Mahmoud Emad
147c889b53 feat: Add ZeroDB installer
- Add a new ZeroDB installer to the installers.
2025-02-12 13:44:52 +00:00
Mahmoud Emad
f6e7644284 refactor: Improve dagu, meilisearch, and postgres installers
- Remove redundant code and improve the overall structure of the installer actions.
- Add more robust error handling and logging.
- Update the postgres and dagu `destroy` function to properly remove all related services.
- Improve the `install` function to ensure all necessary components are installed.
2025-02-12 12:07:38 +00:00
Mahmoud Emad
582da6d7f0 feat: add wireguard installer
- Add a new wireguard installer to the installers.
2025-02-12 11:24:16 +00:00
Mahmoud Emad
3a337b7b0a refactor: fix meilisearch installler and rename meilisearchinstaller to meilisearch_installer
- Renamed the `meilisearchinstaller` module and related files to  `meilisearch_installer` for consistency.
- Updated import statements and references accordingly.
- Added functionality to install, start, and destroy the  Meilisearch service.
- Improved code readability and organization.
2025-02-12 11:06:08 +00:00
Mahmoud Emad
2953dd0172 fix: simplify meilisearch destroy action
- Remove unnecessary code from the `destroy` function in the `meilisearchinstaller_actions.v` file.
- NOTE: Couldn't test it due to the new hero update, don't know how even send the configs, WIP.
2025-02-12 09:31:39 +00:00
Mahmoud Emad
08f0620305 feat: add rust installer
- Add a new Rust installer.
- Fix some issues with the rust installer.
- better organize the language-specific installers.
2025-02-12 09:28:10 +00:00
Mahmoud Emad
ec22a8e0ec refactor: improve installer code
- Refactor installer code for better readability and maintainability.
- Move `dagu_server.vsh` to `examples/virt/daguserver/dagu_server.vsh`.
- Remove unnecessary `println` statements.
- Improve error handling in `zinit_installer_actions.v`.
- Update `zinit_installer_actions.v` startup type to systemd.
- Refactor several factory functions.
2025-02-12 09:02:33 +00:00
Mahmoud Emad
be4d2547e4 refactor: Improved the hero generator, removed unneeded lines 2025-02-11 11:18:04 +00:00
Mahmoud Emad
a7f8893399 feat: Improved the zinit installer, 2025-02-11 11:11:21 +00:00
Mahmoud-Emad
d0b52f40b7 feat: Improved the pacman installer, added an example 2025-02-11 10:32:15 +00:00
3117d288b1 WIP(osal.coredns): add example for coredns usage
- added openssl and iproute2 installation to install_v.sh since they're
  needed in coredns installation and usage.
- fixed bug in coredns build process.
- fixed bug in getting own public ip.
- fixed bugs in json encoding dns records before pushing to redis
2025-02-10 17:07:49 +00:00
Mahmoud-Emad
6ecd190de8 feat: Improved the docker installer, added an example 2025-02-10 13:53:53 +00:00
Mahmoud-Emad
dacd6d5afb feat: Improved the nodejs installer, added an example 2025-02-10 13:49:27 +00:00
Mahmoud-Emad
de0e66a94a feat: Improved the python installer, added an example 2025-02-10 12:08:49 +00:00
Mahmoud-Emad
e86504ecd5 feat: Improved the griddriver installer, added an example 2025-02-10 11:51:39 +00:00
Mahmoud-Emad
1b192328b2 feat: Add an example for golang usage 2025-02-10 11:39:53 +00:00
Mahmoud-Emad
77a77ff87e fix: Rename zinit files to zinit_installer 2025-02-10 11:35:21 +00:00
Mahmoud-Emad
439dff4a64 fix: Updated the golang installer 2025-02-10 11:34:45 +00:00
Mahmoud-Emad
f8cb6f25f7 fix: Rename zinit files to zinit_installer 2025-02-10 11:23:38 +00:00
Mahmoud-Emad
c157c86600 refactor: move zinit installer to infra
- Move the zinit installer from `sysadmintools` to `infra`.
- This change improves the organization of the codebase and
- makes it easier to find and manage installers.  The old
- `zinit` module was a factory only and is removed.  The
- `zinit_installer` is now a normal installer.  The code is
- significantly refactored.
2025-02-10 09:00:49 +00:00
cb0110ed20 ... 2025-02-09 17:53:16 +01:00
2bbf814003 ... 2025-02-09 17:44:40 +01:00
86e3fdb910 WIP(osal.coredns): add example for coredns usage
- create an example to use coredns module for adding dns records
- fix module errors
2025-02-09 18:06:16 +02:00
283 changed files with 8703 additions and 4894 deletions

View File

@@ -51,7 +51,7 @@ fn do() ! {
mut cmd := Command{
name: 'hero'
description: 'Your HERO toolset.'
version: '1.0.13'
version: '1.0.15'
}
// herocmds.cmd_run_add_flags(mut cmd)
@@ -102,6 +102,7 @@ fn do() ! {
// herocmds.cmd_juggler(mut cmd)
herocmds.cmd_generator(mut cmd)
herocmds.cmd_docusaurus(mut cmd)
herocmds.cmd_starlight(mut cmd)
// herocmds.cmd_docsorter(mut cmd)
// cmd.add_command(publishing.cmd_publisher(pre_func))
cmd.setup()

View File

@@ -0,0 +1,11 @@
#!/usr/bin/env -S v -gc none -no-retry-compilation -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.biz.investortool
import freeflowuniverse.herolib.core.playbook
import os
mut plbook := playbook.new(
path: '${os.home_dir()}/code/git.ourworld.tf/ourworld_holding/investorstool/output'
)!
mut it := investortool.play(mut plbook)!
it.check()!

View File

@@ -0,0 +1,48 @@
#!/usr/bin/env -S v -cg -gc none -no-retry-compilation -cc tcc -d use_openssl -enable-globals run
// #!/usr/bin/env -S v -cg -enable-globals run
import freeflowuniverse.herolib.data.doctree
import freeflowuniverse.herolib.ui.console
import freeflowuniverse.herolib.biz.bizmodel
import freeflowuniverse.herolib.core.playbook
import freeflowuniverse.herolib.core.playcmds
import freeflowuniverse.herolib.web.mdbook
import freeflowuniverse.herolib.biz.spreadsheet
import os
const name = 'tf9_budget'
const wikipath = '${os.home_dir()}/code/git.ourworld.tf/ourworld_holding/info_ourworld/collections/${name}'
const summarypath = '${wikipath}/summary.md'
// mut sh := spreadsheet.sheet_new(name: 'test2') or { panic(err) }
// println(sh)
// sh.row_new(descr: 'this is a description', name: 'something', growth: '0:100aed,55:1000eur')!
// println(sh)
// println(sh.wiki()!)
// exit(0)
// execute the actions so we have the info populated
// mut plb:=playbook.new(path: wikipath)!
// playcmds.run(mut plb,false)!
buildpath := '${os.home_dir()}/hero/var/mdbuild/bizmodel'
// just run the doctree & mdbook and it should
// load the doctree, these are all collections
mut tree := doctree.new(name: name)!
tree.scan(path: wikipath)!
tree.export(dest: buildpath, reset: true)!
// mut bm:=bizmodel.get("test")!
// println(bm)
mut mdbooks := mdbook.get()!
mdbooks.generate(
name: 'bizmodel'
summary_path: summarypath
doctree_path: buildpath
title: 'bizmodel ${name}'
)!
mdbook.book_open('bizmodel')!

View File

@@ -0,0 +1,12 @@
need to find where the manual is
- [manual](bizmodel_example/configuration.md)
- [widgets](bizmodel_example/widgets.md)
- [graph_bar_row](bizmodel_example/graph_bar_row.md)
- [sheet_tables](bizmodel_example/sheet_tables.md)
- [widget_args](bizmodel_example/widget_args.md)
- [params](bizmodel_example/configuration.md)
- [revenue params](bizmodel_example/revenue_params.md)
- [funding params](bizmodel_example/funding_params.md)
- [hr params](bizmodel_example/hr_params.md)
- [costs params](bizmodel_example/costs_params.md)

25
examples/biztools/bizmodel.vsh Executable file
View File

@@ -0,0 +1,25 @@
#!/usr/bin/env -S v -n -w -cg -gc none -no-retry-compilation -cc tcc -d use_openssl -enable-globals run
//#!/usr/bin/env -S v -cg -enable-globals run
import freeflowuniverse.herolib.biz.bizmodel
import freeflowuniverse.herolib.core.playbook
import freeflowuniverse.herolib.core.playcmds
import os
const playbook_path = os.dir(@FILE) + '/playbook'
const build_path = os.join_path(os.dir(@FILE), '/docusaurus')
buildpath := '${os.home_dir()}/hero/var/mdbuild/bizmodel'
mut model := bizmodel.getset("example")!
model.workdir = build_path
model.play(mut playbook.new(path: playbook_path)!)!
println(model.sheet)
println(model.sheet.export()!)
model.sheet.export(path:"~/Downloads/test.csv")!
model.sheet.export(path:"~/code/github/freeflowuniverse/starlight_template/src/content/test.csv")!

View File

@@ -0,0 +1,4 @@
bizmodel
dest
wiki
build

View File

@@ -0,0 +1 @@
ms1bmodel.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

View File

@@ -0,0 +1,13 @@
## Revenue
Overview of achieved revenue.
Unit is in Million USD.
!!bizmodel.sheet_wiki title:'REVENUE' includefilter:rev sheetname:'bizmodel_test'
!!bizmodel.graph_bar_row rowname:revenue_total unit:million sheetname:'bizmodel_test'
!!bizmodel.graph_line_row rowname:revenue_total unit:million sheetname:'bizmodel_test'
!!bizmodel.graph_pie_row rowname:revenue_total unit:million size:'80%' sheetname:'bizmodel_test'

View File

@@ -0,0 +1,13 @@
- [bizmodel](bizmodel_example/bizmodel.md)
- [Revenue](bizmodel_example/revenue.md)
- [Result](bizmodel_example/overview.md)
- [parameters](bizmodel_example/params.md)
- [revenue_params](bizmodel_example/params/revenue_params.md)
- [funding_params](bizmodel_example/params/funding_params.md)
- [hr_params](bizmodel_example/params/hr_params.md)
- [costs_params](bizmodel_example/params/costs_params.md)
- [rows overview](bizmodel_example/rows_overview.md)
- [employees](bizmodel_example/employees.md)
- [debug](bizmodel_example/debug.md)
- [worksheet](bizmodel_example/worksheet.md)

View File

@@ -0,0 +1,4 @@
# Overview of the rows in the biz model sheet
!!bizmodel.sheet_wiki sheetname:'bizmodel_test'

View File

@@ -0,0 +1,37 @@
#!/usr/bin/env -S v -n -w -cg -gc none -no-retry-compilation -cc tcc -d use_openssl -enable-globals run
//#!/usr/bin/env -S v -cg -enable-globals run
import freeflowuniverse.herolib.biz.bizmodel
import freeflowuniverse.herolib.core.playbook
import freeflowuniverse.herolib.core.playcmds
import os
//TODO: need to fix wrong location
const playbook_path = os.dir(@FILE) + '/playbook'
const build_path = os.join_path(os.dir(@FILE), '/docusaurus')
buildpath := '${os.home_dir()}/hero/var/mdbuild/bizmodel'
mut model := bizmodel.getset("example")!
model.workdir = build_path
model.play(mut playbook.new(path: playbook_path)!)!
println(model.sheet)
println(model.sheet.export()!)
// model.sheet.export(path:"~/Downloads/test.csv")!
// model.sheet.export(path:"~/code/github/freeflowuniverse/starlight_template/src/content/test.csv")!
report := model.new_report(
name: 'example_report'
title: 'Example Business Model'
)!
report.export(
path: build_path
overwrite: true
format: .docusaurus
)!

View File

@@ -0,0 +1 @@
output dir of example

View File

@@ -0,0 +1,22 @@
#!/bin/bash
set -ex
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "${script_dir}"
echo "Docs directory: $script_dir"
cd "${HOME}/hero/var/docusaurus"
export PATH=/tmp/docusaurus_build/node_modules/.bin:${HOME}/.bun/bin/:$PATH
rm -rf /Users/despiegk/hero/var/docusaurus/build/
. ${HOME}/.zprofile
bun docusaurus build
mkdir -p /Users/despiegk/code/github/freeflowuniverse/herolib/examples/biztools/bizmodel/example/docusaurus
echo SYNC TO /Users/despiegk/code/github/freeflowuniverse/herolib/examples/biztools/bizmodel/example/docusaurus
rsync -rv --delete /Users/despiegk/hero/var/docusaurus/build/ /Users/despiegk/code/github/freeflowuniverse/herolib/examples/biztools/bizmodel/example/docusaurus/

View File

@@ -0,0 +1 @@
{"style":"dark","links":[]}

View File

@@ -0,0 +1 @@
{"name":"","title":"Docusaurus","tagline":"","favicon":"img/favicon.png","url":"http://localhost","url_home":"docs/introduction","baseUrl":"/","image":"img/tf_graph.png","metadata":{"description":"Docusaurus","image":"Docusaurus","title":"Docusaurus"},"buildDest":[],"buildDestDev":[]}

View File

@@ -0,0 +1 @@
{"title":"Business Model","items":[{"href":"https://threefold.info/kristof/","label":"ThreeFold Technology","position":"right"},{"href":"https://threefold.io","label":"Operational Plan","position":"left"}]}

View File

@@ -0,0 +1,16 @@
#!/bin/bash
set -e
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "${script_dir}"
echo "Docs directory: $script_dir"
cd "${HOME}/hero/var/docusaurus"
export PATH=/tmp/docusaurus_build/node_modules/.bin:${HOME}/.bun/bin/:$PATH
. ${HOME}/.zprofile
bun run start -p 3100

View File

@@ -0,0 +1,10 @@
## Loader instructions
this will make sure we load the appropriate biz model
```js
!!bizmodel.load name:'default' url:'https://github.com/freeflowuniverse/herolib/tree/development/bizmodel/example/data'
```

View File

@@ -0,0 +1 @@
name:bizmodel_example

View File

@@ -0,0 +1,10 @@
![](img/ms1bmodel.png)
# bizmodel
OurWorld has developed a tool to generate and keep business models up to date.
Our aim is to make it easy for ourworld to track changes in planning over the multiple projects and even be able to aggregated them. Because the input for such a plan is text (as you can see in this ebook) its easy to see how the modelling and parameters change over time.
This is a very flexible tool which will be extended for budgetting, cashflow management, shareholder tables, ...

View File

@@ -0,0 +1,31 @@
# HR Params
## Engineering
Costs can be grouped in cost centers which can then be used to futher process e.g. transcactions between companies.
```js
!!bizmodel.costcenter_define bizname:'test'
name:'tfdmcc'
descr:'TFDMCC executes on near source agreement for TFTech'
min_month:'10000USD'
max_month:'100000USD'
end_date:'1/1/2026' //when does agreement stop
!!bizmodel.costcenter_define bizname:'test'
name:'cs_tftech'
descr:'Nearsource agreement for TFTech towards Codescalers'
min_month:'10000USD'
max_month:'100000USD'
end_date:'1/1/2026'
!!bizmodel.costcenter_define bizname:'test'
name:'cs_tfcloud'
descr:'Nearsource agreement for TFCloud towards Codescalers'
min_month:'10000USD'
max_month:'100000USD'
end_date:'1/1/2026'
```

View File

@@ -0,0 +1,39 @@
# Generic Overhead Costs
possible parameters
- name
- descr: description of the cost
- cost: is 'month:amount,month:amount, ...', no extrapolation
- cost_growth: is 'month:amount,month:amount, ..., or just a nr', will extrapolate
- type: travel, admin, legal, varia, office
- cost_percent_revenue e.g. 4%, will make sure the cost will be at least 4% of revenue
- indexation, e.g. 2%
Other financial flows can be mentioned here as well.
```js
!!bizmodel.cost_define bizname:'test'
name:'rental'
descr:'Office Rental in BE.'
cost:'5000'
indexation:'2%'
type:'office'
!!bizmodel.cost_define bizname:'test'
name:'oneoff'
descr:'Event in Z.'
cost_one:'3:50000'
type:'event'
!!bizmodel.cost_define bizname:'test'
name:'cloud'
descr:'Datacenter and Cloud Costs'
cost:'2000eur'
cost_percent_revenue:'2%'
type:'cloud'
```

View File

@@ -0,0 +1,4 @@
# Debug
Some tools and info to help debug the bizmodel simulator.

View File

@@ -0,0 +1,20 @@
# Department Params
```js
!!bizmodel.department_define bizname:'test'
name:'ops'
title:'Operations'
order:5
!!bizmodel.department_define bizname:'test'
name:'coordination'
title:'Coordination'
order:1
!!bizmodel.department_define bizname:'test'
name:'engineering'
title:'Engineering'
order:4
```

View File

@@ -0,0 +1,29 @@
# Funding Params
possible parameters
- name, e.g. for a specific person
- descr: description of the funding
- investment is month:amount,month:amount, ...
- type: loan or capital
Other financial flows can be mentioned here as well.
```js
!!bizmodel.funding_define bizname:'test'
name:'our_investor'
descr:'A fantastic super investor.'
investment:'3:1000000EUR'
type:'capital'
!!bizmodel.funding_define bizname:'test'
name:'a_founder'
descr:'Together Are Strong'
investment:'2000000'
type:'loan'
```

View File

@@ -0,0 +1,73 @@
# HR Params
## Engineering
possible parameters
- descr, description of the function (e.g. master architect)
- cost, any currency eg. 1000usd
- in case cost changes over time e.g. 1:10000USD,20:20000USD,60:30000USD
- indexation, e.g. 2%
- department
- name, e.g. for a specific person
- nrpeople: how many people per month, growth over time notation e.g. 1:10,60:20 means 10 in month 1 growing to 20 month 60
- cost_percent_revenue e.g. 4%, will make sure the cost will be at least 4% of revenue
```js
!!bizmodel.employee_define bizname:'test'
sid:2
descr:'Senior Engineer'
cost:'1:12000,12:14000' //cost is always per person
department:'engineering'
nrpeople:'0:5,20:5'
!!bizmodel.employee_define bizname:'test'
name:'despiegk'
title: 'CTO and crazy inventor.'
sid:3
descr:'CTO'
cost:'12000EUR' //the salary is the cost independent of the fulltime status
indexation:'10%'
department:'coordination'
page:'cto.md'
fulltime: "50%" //100% means yes
!!bizmodel.employee_define bizname:'test'
descr:'Senior Architect'
cost:'10000USD' indexation:'5%'
department:'engineering'
nrpeople:'0:5,20:10'
!!bizmodel.employee_define bizname:'test'
descr:'Junior Engineer'
cost:'4000USD' indexation:'5%'
department:'engineering'
nrpeople:'0:5,20:10'
```
## Operations
```js
!!bizmodel.employee_define bizname:'test'
descr:'Ops Manager'
cost:'1:8000,12:14000'
department:'ops'
!!bizmodel.employee_define bizname:'test'
descr:'Support Junior'
cost:'2000EUR' indexation:'5%'
department:'ops'
nrpeople:'7:5,18:10'
cost_percent_revenue:'1%'
!!bizmodel.employee_define bizname:'test'
descr:'Support Senior'
cost:'5000EUR' indexation:'5%'
department:'ops'
nrpeople:'3:5,20:10'
cost_percent_revenue:'1%'
costcenter:'tfdmcc:25,cs_tfcloud:75'
generate_page:'../employees/support_senior.md'
```

View File

@@ -0,0 +1,14 @@
# Bizmodel Params
In this section we can find all the parameters for the bizmodel.
## how to use and read
The params are defined in the different instruction files e.g. revenue_params.md
Often you will see something like `revenue_growth:'10:1000,20:1100'` this can be read as month 10 it 1000, month 20 its 1100.
The software will extrapolate.

View File

@@ -0,0 +1,85 @@
# HR Params
## Revenue Items (non recurring)
This company is a cloud company ...
- name, e.g. for a specific project
- descr, description of the revenue line item
- revenue_items: does one of revenue, is not exterpolated
- revenue_growth: is a revenue stream which is being extrapolated
- revenue_setup, revenue for 1 item '1000usd'
- revenue_setup_delay
- revenue_monthly, revenue per month for 1 item
- revenue_monthly_delay, how many months before monthly revenue starts
- maintenance_month_perc, how much percent of revenue_setup will come back over months
- cogs_setup, cost of good for 1 item at setup
- cogs_setup_delay, how many months before setup cogs starts, after sales
- cogs_setup_perc: what is percentage of the cogs (can change over time) for setup e.g. 0:50%
- cogs_monthly, cost of goods for the monthly per 1 item
- cogs_monthly_delay, how many months before monthly cogs starts, after sales
- cogs_monthly_perc: what is percentage of the cogs (can change over time) for monthly e.g. 0:5%,12:10%
- nr_sold: how many do we sell per month (is in growth format e.g. 10:100,20:200, default is 1)
- nr_months_recurring: how many months is recurring, if 0 then no recurring
```js
!!bizmodel.revenue_define bizname:'test'
descr:'OEM Deals'
revenue_items:'10:1000000EUR,15:3333,20:1200000'
cogs_setup_perc: '1:5%,20:10%'
!!bizmodel.revenue_define bizname:'test'
descr:'License Deals'
revenue_growth:'10:1000,20:1100'
cogs_perc: '10%'
rev_delay_month: 1
!!bizmodel.revenue_define bizname:'test'
descr:'3NODE License Sales 1 Time'
//means revenue is 100 month 1, 200 month 60
revenue_item:'1:100,60:200'
revenue_nr:'10:1000,24:2000,60:40000'
cogs_perc: '10%'
rev_delay_month: 1
```
## Revenue Items Recurring
possible parameters
- name, e.g. for a specific project
- descr, description of the revenue line item
- revenue_setup, revenue for 1 item '1000usd'
- revenue_monthly, revenue per month for 1 item
- revenue_setup_delay, how many months before revenue comes in after sales
- revenue_monthly_delay, how many months before monthly revenue starts
- cogs_setup, cost of good for 1 item at setup
- cogs_setup_perc: what is percentage of the cogs (can change over time) for setup e.g. 0:50%
- cogs_monthly, cost of goods for the monthly per 1 item
- cogs_monthly_perc: what is percentage of the cogs (can change over time) for monthly e.g. 0:5%,12:10%
- nr_sold: how many do we sell per month (is in growth format e.g. 10:100,20:200)
- nr_months: how many months is recurring
if currency not specified then is always in USD
```js
!!bizmodel.revenue_recurring_define bizname:'test'
name: '3node_lic'
descr:'3NODE License Sales Recurring Basic'
revenue_setup:'1:100,60:50'
// revenue_setup:'5'
revenue_monthly_delay:3
revenue_monthly:'1:1,60:1'
// cogs_setup:'1:0'
cogs_setup_perc:'50%'
revenue_setup_delay:1
cogs_monthly_perc:'50%'
nr_sold:'10:1000,24:2000,60:40000'
60 is the default
nr_months:60
```

View File

@@ -1 +0,0 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run

View File

@@ -1 +0,0 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run

View File

@@ -1,15 +0,0 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.sysadmintools.daguserver
import freeflowuniverse.herolib.installers.infra.zinit
// make sure zinit is there and running, will restart it if needed
mut z := zinit.get()!
z.destroy()!
z.start()!
// mut ds := daguserver.get()!
// ds.destroy()!
// ds.start()!
// println(ds)

View File

@@ -0,0 +1,8 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.db.meilisearch_installer
mut meilisearch := meilisearch_installer.get()!
meilisearch.install()!
meilisearch.start()!
meilisearch.destroy()!

View File

@@ -0,0 +1,9 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.db.postgresql as postgresql_installer
mut db := postgresql_installer.get()!
db.install()!
db.start()!
db.destroy()!

View File

@@ -0,0 +1,9 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.db.zerodb as zerodb_installer
mut db := zerodb_installer.get()!
db.install()!
db.start()!
db.destroy()!

View File

@@ -1,16 +0,0 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.infra.gitea as gitea_installer
mut installer := gitea_installer.get(name: 'test')!
// if you want to configure using heroscript
gitea_installer.play(
heroscript: "
!!gitea.configure name:test
passwd:'something'
domain: 'docs.info.com'
"
)!
installer.start()!

View File

@@ -0,0 +1,8 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.infra.gitea as gitea_installer
mut gitea := gitea_installer.get()!
gitea.install()!
gitea.start()!
gitea.destroy()!

View File

@@ -0,0 +1,8 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.infra.livekit as livekit_installer
mut livekit := livekit_installer.get()!
livekit.install()!
livekit.start()!
livekit.destroy()!

View File

@@ -0,0 +1,8 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.infra.screen as screen_installer
mut screen := screen_installer.get()!
screen.install()!
screen.destroy()!

View File

@@ -1,6 +1,8 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.sysadmintools.zinit as zinit_installer
import freeflowuniverse.herolib.installers.infra.zinit_installer
mut installer := zinit_installer.get()!
installer.install()!
installer.start()!
// installer.destroy()!

View File

@@ -0,0 +1,6 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.lang.golang
mut golang_installer := golang.get()!
golang_installer.install()!

View File

@@ -0,0 +1,7 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.lang.nodejs
mut nodejs_installer := nodejs.get()!
// nodejs_installer.install()!
nodejs_installer.destroy()!

View File

@@ -0,0 +1,7 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.lang.python as python_module
mut python_installer := python_module.get()!
// python_installer.install()!
python_installer.destroy()!

View File

@@ -0,0 +1,7 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.lang.rust as rust_module
mut rust_installer := rust_module.get()!
// rust_installer.install()!
rust_installer.destroy()!

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.net.mycelium as mycelium_installer
import freeflowuniverse.herolib.installers.net.mycelium_installer
import freeflowuniverse.herolib.clients.mycelium
mut installer := mycelium_installer.get()!
@@ -13,25 +13,27 @@ mut client := mycelium.get()!
// Send a message to a node by public key
// Parameters: public_key, payload, topic, wait_for_reply
msg := client.send_msg('abc123...', // destination public key
'Hello World', // message payload
'greetings', // optional topic
true // wait for reply
)!
msg := client.send_msg(
public_key: 'abc123...' // destination public key
payload: 'Hello World' // message payload
topic: 'greetings' // optional topic
wait: true // wait for reply
)!
println('Sent message ID: ${msg.id}')
// Receive messages
// Parameters: wait_for_message, peek_only, topic_filter
received := client.receive_msg(true, false, 'greetings')!
received := client.receive_msg(wait: true, peek: false, topic: 'greetings')!
println('Received message from: ${received.src_pk}')
println('Message payload: ${received.payload}')
// Reply to a message
client.reply_msg(received.id, // original message ID
received.src_pk, // sender's public key
'Got your message!', // reply payload
'greetings' // topic
)!
client.reply_msg(
id: received.id // original message ID
public_key: received.src_pk // sender's public key
payload: 'Got your message!' // reply payload
topic: 'greetings' // topic
)!
// Check message status
status := client.get_msg_status(msg.id)!

View File

@@ -0,0 +1,7 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.net.wireguard_installer as wireguard
mut wireguard_installer := wireguard.get()!
wireguard_installer.install()!
wireguard_installer.destroy()!

View File

@@ -1,13 +0,0 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import time
import freeflowuniverse.herolib.installers.db.postgresql
mut db := postgresql.get()!
// db.destroy()!
db.start()!
// db.db_create('my_new_db')!
// db.stop()!
// db.start()!

View File

@@ -1,7 +1,8 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.sysadmintools.actrunner
import freeflowuniverse.herolib.installers.virt.herocontainers
// import freeflowuniverse.herolib.installers.virt.herocontainers
actrunner.install()!
mut actrunner_ := actrunner.get()!
actrunner_.install()!
// herocontainers.start()!

View File

@@ -0,0 +1,8 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.sysadmintools.garage_s3 as garage_s3_installer
mut garage_s3 := garage_s3_installer.get()!
garage_s3.install()!
garage_s3.start()!
garage_s3.destroy()!

View File

@@ -0,0 +1,7 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.sysadmintools.rclone as rclone_installer
mut rclone := rclone_installer.get()!
rclone.install()!
rclone.destroy()!

View File

@@ -4,3 +4,4 @@ import freeflowuniverse.herolib.installers.threefold.griddriver
mut griddriver_installer := griddriver.get()!
griddriver_installer.install()!
griddriver_installer.destroy()!

View File

@@ -0,0 +1,9 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.sysadmintools.daguserver
import freeflowuniverse.herolib.installers.infra.zinit_installer
mut ds := daguserver.get()!
ds.install()!
ds.start()!
ds.destroy()!

View File

@@ -0,0 +1,11 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.virt.pacman as pacman_installer
mut pacman := pacman_installer.get()!
// To install
pacman.install()!
// To remove
pacman.destroy()!

View File

@@ -0,0 +1,60 @@
#!/usr/bin/env -S v -n -w -cg -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.infra.coredns as coredns_installer
import freeflowuniverse.herolib.osal.coredns
import freeflowuniverse.herolib.core.playbook
// coredns_installer.delete()!
mut installer := coredns_installer.get()!
// coredns_installer.fix()!
installer.start()!
mut script := "
!!dns.a_record
sub_domain: 'host1'
ip: '1.2.3.4'
ttl: 300
!!dns.aaaa_record
sub_domain: 'host1'
ip: '2001:db8::1'
ttl: 300
!!dns.mx_record
sub_domain: '*'
host: 'mail.example.com'
preference: 10
ttl: 300
!!dns.txt_record
sub_domain: '*'
text: 'v=spf1 mx ~all'
ttl: 300
!!dns.srv_record
service: 'ssh'
protocol: 'tcp'
host: 'host1'
target: 'sip.example.com'
port: 5060
priority: 10
weight: 100
ttl: 300
!!dns.ns_record
host: 'ns1.example.com'
ttl: 300
!!dns.soa_record
mbox: 'hostmaster.example.com'
ns: 'ns1.example.com'
refresh: 44
retry: 55
expire: 66
minttl: 100
ttl: 300
"
mut plbook := playbook.new(text: script)!
mut set := coredns.play_dns(mut plbook)!
set.set(key_prefix: 'dns:', domain: 'heroexample.com')!

View File

@@ -1,42 +0,0 @@
#!/usr/bin/env -S v -n -w -gc none -cg -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.web.docusaurus
// import freeflowuniverse.herolib.data.doctree
// Create a new docusaurus factory
mut docs := docusaurus.new(
build_path: '/tmp/docusaurus_build'
)!
// Create a new docusaurus site
mut site := docs.dev(
url: 'https://git.ourworld.tf/despiegk/docs_kristof'
)!
// FOR FUTURE TO ADD CONTENT FROM DOCTREE
// Create a doctree for content
// mut tree := doctree.new(name: 'content')!
// // Add some content from a git repository
// tree.scan(
// git_url: 'https://github.com/yourusername/your-docs-repo'
// git_pull: true
// )!
// // Export the content to the docusaurus site
// tree.export(
// destination: '${site.path_build.path}/docs'
// reset: true
// keep_structure: true
// exclude_errors: false
// )!
// Build the docusaurus site
// site.build()!
// Generate the static site
// site.generate()!
// Optionally open the site in a browser
// site.open()!

View File

@@ -0,0 +1,17 @@
#!/usr/bin/env -S v -n -w -gc none -cg -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.web.starlight
// import freeflowuniverse.herolib.data.doctree
// Create a new starlight factory
mut docs := starlight.new(
build_path: '/tmp/starlight_build'
)!
// Create a new starlight site
mut site := docs.get(
url: 'https://git.ourworld.tf/tfgrid/docs_aibox'
init:true //init means we put config files if not there
)!
site.dev()!

View File

@@ -4,7 +4,7 @@ set -e
os_name="$(uname -s)"
arch_name="$(uname -m)"
version='1.0.13'
version='1.0.15'
# Base URL for GitHub releases

View File

@@ -181,7 +181,7 @@ function os_update {
fi
#apt install apt-transport-https ca-certificates curl software-properties-common -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" --force-yes
package_install "apt-transport-https ca-certificates curl wget software-properties-common tmux"
package_install "rclone rsync mc redis-server screen net-tools git dnsutils htop ca-certificates screen lsb-release binutils pkg-config"
package_install "rclone rsync mc redis-server screen net-tools git dnsutils htop ca-certificates screen lsb-release binutils pkg-config libssl-dev iproute2"
elif [[ "${OSNAME}" == "darwin"* ]]; then
if command -v brew >/dev/null 2>&1; then

1
lib/biz/bizmodel/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
testdata

155
lib/biz/bizmodel/act.v Normal file
View File

@@ -0,0 +1,155 @@
module bizmodel
import os
import freeflowuniverse.herolib.core.texttools
import freeflowuniverse.herolib.core.pathlib
import freeflowuniverse.herolib.core.playbook { PlayBook, Action }
import freeflowuniverse.herolib.ui.console
// import freeflowuniverse.herolib.core.texttools
import freeflowuniverse.herolib.data.paramsparser {Params}
import freeflowuniverse.herolib.biz.spreadsheet {RowGetArgs, UnitType, PeriodType}
pub fn (mut m BizModel) act(action Action) !Action {
return match texttools.snake_case(action.name) {
'funding_define' {
m.funding_define_action(action)!
}
'revenue_define' {
m.revenue_action(action)!
}
'costcenter_define' {
m.costcenter_define_action(action)!
}
'cost_define' {
m.cost_define_action(action)!
}
'department_define' {
m.department_define_action(action)!
}
'employee_define' {
m.employee_define_action(action)!
}
'export_report' {
m.new_report_action(action)!
}
'sheet_wiki' {
m.export_sheet_action(action)!
}
'graph_bar_row' {
m.export_graph_bar_action(action)!
}
'graph_pie_row' {
m.export_graph_pie_action(action)!
}
'graph_line_row' {
m.export_graph_line_action(action)!
}
'row_overview' {
m.export_overview_action(action)!
}
else {
return error('Unknown operation: ${action.name}')
}
}
}
fn (mut m BizModel) export_sheet_action(action Action) !Action {
return m.export_action(m.sheet.wiki(row_args_from_params(action.params)!)!, action)
}
fn (mut m BizModel) export_graph_title_action(action Action) !Action {
return m.export_action(m.sheet.wiki_title_chart(row_args_from_params(action.params)!)!, action)
}
fn (mut m BizModel) export_graph_line_action(action Action) !Action {
return m.export_action(m.sheet.wiki_line_chart(row_args_from_params(action.params)!)!, action)
}
fn (mut m BizModel) export_graph_bar_action(action Action) !Action {
return m.export_action(m.sheet.wiki_bar_chart(row_args_from_params(action.params)!)!, action)
}
pub fn (mut m BizModel) export_graph_pie_action(action Action) !Action {
return m.export_action(m.sheet.wiki_pie_chart(row_args_from_params(action.params)!)!, action)
}
pub fn (mut m BizModel) export_overview_action(action Action) !Action {
return m.export_action(m.sheet.wiki_row_overview(row_args_from_params(action.params)!)!, action)
}
fn (mut m BizModel) new_report_action(action Action) !Action {
m.new_report(action.params.decode[Report]()!)!
return action
}
// fetches args for getting row from params
pub fn row_args_from_params(p Params) !RowGetArgs {
rowname := p.get_default('rowname', '')!
namefilter := p.get_list_default('namefilter', [])!
includefilter := p.get_list_default('includefilter', [])!
excludefilter := p.get_list_default('excludefilter', [])!
size := p.get_default('size', '')!
title_sub := p.get_default('title_sub', '')!
title := p.get_default('title', '')!
unit := p.get_default('unit', 'normal')!
unit_e := match unit {
'thousand' { UnitType.thousand }
'million' { UnitType.million }
'billion' { UnitType.billion }
else { UnitType.normal }
}
period_type := p.get_default('period_type', 'year')!
if period_type !in ['year', 'month', 'quarter'] {
return error('period type needs to be in year,month,quarter')
}
period_type_e := match period_type {
'year' { PeriodType.year }
'month' { PeriodType.month }
'quarter' { PeriodType.quarter }
else { PeriodType.error }
}
if period_type_e == .error {
return error('period type needs to be in year,month,quarter')
}
rowname_show := p.get_default_true('rowname_show')
descr_show := p.get_default_true('descr_show')
return RowGetArgs{
rowname: rowname
namefilter: namefilter
includefilter: includefilter
excludefilter: excludefilter
period_type: period_type_e
unit: unit_e
title_sub: title_sub
title: title
size: size
rowname_show: rowname_show
descr_show: descr_show
}
}
// creates the name for a file being exported given the params of the export action
fn (m BizModel) export_action(content string, action Action) !Action {
// determine name of file being exported
name := if action.params.exists('name') { action.params.get('name')! } else {
if action.params.exists('title') { action.params.get('title')! } else {
// if no name or title, name is ex: revenue_total_graph_bar_row
rowname := action.params.get_default('rowname', '')!
'${rowname}_${action.name}'
}
}
// by default exports to working dir of bizmodel
destination := action.params.get_default('destination', m.workdir)!
mut path := pathlib.get_file(
path: os.join_path(destination, name)
increment: true
empty: action.params.get_default_false('overwrite')
)!
path.write(content)!
return action
}

151
lib/biz/bizmodel/export.v Normal file
View File

@@ -0,0 +1,151 @@
module bizmodel
import os
import freeflowuniverse.herolib.web.docusaurus
import freeflowuniverse.herolib.core.texttools
import freeflowuniverse.herolib.core.pathlib
pub struct Report {
pub:
name string
title string
description string
path string
sections []ReportSection
}
pub enum ReportSection {
revenue_model
cost_structure
human_resources
}
pub fn (b BizModel) new_report(report Report) !Report {
name := if report.name != '' {report.name} else { texttools.snake_case(report.title) }
path := pathlib.get_dir(
path: os.join_path(os.home_dir(), '/hero/var/bizmodel/reports/${name}')
create: true
empty: true
)!
b.write_introduction(path.path)!
b.write_operational_plan(path.path)!
b.write_revenue_model(path.path)!
b.write_cost_structure(path.path)!
return Report {
...report,
name: name
path: path.path
}
// b.export_summary()
// b.export_business_description()
// b.export_market_analysis()
// b.export_business_model()
// b.export_revenue_model(export)!
// b.export_cost_structure(export)
// b.export_operational_plan(export)!
// b.export_fundraising(export)
}
pub struct Export {
pub:
path string
overwrite bool
format ExportFormat
}
pub enum ExportFormat {
docusaurus
mdbook
}
pub fn (r Report) export(export Export) ! {
match export.format {
.docusaurus {
mut dir := pathlib.get_dir(path: r.path)!
dir.copy(dest: '${export.path}/docs', delete: true)!
mut factory := docusaurus.new()!
mut site := factory.get(
name: r.name
path: export.path
publish_path: export.path
init: true
config: docusaurus.Config {
navbar: docusaurus.Navbar {
title: "Business Model",
items: [
docusaurus.NavbarItem{
"href": "https://threefold.info/kristof/",
"label": "ThreeFold Technology",
"position": "right"
},
docusaurus.NavbarItem{
"href": "https://threefold.io",
"label": "Operational Plan",
"position": "left"
}
]
}
main: docusaurus.Main {
url_home: 'docs/introduction'
}
} //TODO: is this needed
)!
site.generate()!
}
.mdbook {panic('MDBook export not fully implemented')}
}
}
pub fn (model BizModel) write_introduction(path string) ! {
mut index_page := pathlib.get_file(path: '${path}/introduction.md')!
// mut tmpl_index := $tmpl('templates/index.md')
index_page.template_write($tmpl('templates/introduction.md'), true)!
}
pub fn (model BizModel) write_operational_plan(path string) ! {
mut dir := pathlib.get_dir(path: '${path}/operational_plan')!
mut ops_page := pathlib.get_file(path: '${dir.path}/operational_plan.md')!
ops_page.write('# Operational Plan')!
mut hr_dir := pathlib.get_dir(path: '${dir.path}/human_resources')!
mut hr_page := pathlib.get_file(path: '${hr_dir.path}/human_resources.md')!
hr_page.template_write($tmpl('./templates/human_resources.md'), true)!
for key, employee in model.employees {
mut employee_page := pathlib.get_file(path: '${hr_dir.path}/${texttools.snake_case(employee.name)}.md')!
employee_cost_chart := model.sheet.line_chart(rowname:'hr_cost_${employee.name}', unit: .million)!.mdx()
employee_page.template_write($tmpl('./templates/employee.md'), true)!
}
mut depts_dir := pathlib.get_dir(path: '${dir.path}/departments')!
for key, department in model.departments {
mut dept_page := pathlib.get_file(path: '${depts_dir.path}/${texttools.snake_case(department.name)}.md')!
// dept_cost_chart := model.sheet.line_chart(rowname:'hr_cost_${employee.name}', unit: .million)!.mdx()
// println(employee_cost_chart)
dept_page.template_write($tmpl('./templates/department.md'), true)!
}
}
pub fn (model BizModel) write_revenue_model(path string) ! {
mut dir := pathlib.get_dir(path: '${path}/revenue_model')!
mut rm_page := pathlib.get_file(path: '${dir.path}/revenue_model.md')!
rm_page.write('# Revenue Model')!
mut products_dir := pathlib.get_dir(path: '${dir.path}/products')!
mut products_page := pathlib.get_file(path: '${products_dir.path}/products.md')!
products_page.template_write('# Products', true)!
name1 := 'example'
for key, product in model.products {
mut product_page := pathlib.get_file(path: '${products_dir.path}/${texttools.snake_case(product.name)}.md')!
product_page.template_write($tmpl('./templates/product.md'), true)!
}
}
pub fn (model BizModel) write_cost_structure(path string) ! {
mut dir := pathlib.get_dir(path: '${path}/cost_structure')!
mut cs_page := pathlib.get_file(path: '${dir.path}/cost_structure.md')!
cs_page.write('# Cost Structure')!
}

View File

@@ -0,0 +1,14 @@
module bizmodel
import os
import freeflowuniverse.herolib.web.docusaurus
const bizmodel_name = 'test'
const export_path = os.join_path(os.dir(@FILE), 'testdata')
pub fn test_export_report() ! {
model := getset(bizmodel_name)!
model.export_report(Report{
title: 'My Business Model'
}, path: export_path)!
}

View File

@@ -11,8 +11,8 @@ pub fn get(name string) !&BizModel {
if name in bizmodels {
return bizmodels[name] or { panic('bug') }
}
return error("cann't find biz model:'${name}' in global bizmodels ${bizmodels.keys()}")
}
return error("cann't find biz model:'${name}' in global bizmodels")
}
// get bizmodel from global

View File

@@ -62,7 +62,7 @@ fn employee_wiki(p paramsparser.Params, sim BizModel) !string {
// theme := 'light'
// theme := 'dark' // Removed unused variable
mut t := $tmpl('./templates/employee.md')
mut t := $tmpl('./templates/employee_old.md')
return t
}

View File

@@ -1,10 +1,13 @@
module bizmodel
import os
import freeflowuniverse.herolib.biz.spreadsheet
pub struct BizModel {
pub mut:
name string
description string
workdir string = '${os.home_dir()}/hero/var/bizmodel'
sheet &spreadsheet.Sheet
employees map[string]&Employee
departments map[string]&Department

View File

@@ -1,89 +1,51 @@
module bizmodel
import freeflowuniverse.herolib.core.playbook { PlayBook }
import arrays
import freeflowuniverse.herolib.core.texttools
import freeflowuniverse.herolib.core.playbook { PlayBook, Action }
import freeflowuniverse.herolib.ui.console
// import freeflowuniverse.herolib.core.texttools
// import freeflowuniverse.herolib.ui.console
import freeflowuniverse.herolib.biz.spreadsheet
pub fn play(mut plbook PlayBook) ! {
// first make sure we find a run action to know the name
mut actions4 := plbook.actions_find(actor: 'bizmodel')!
if actions4.len == 0 {
return
}
knownactions := ['revenue_define', 'employee_define', 'department_define', 'funding_define',
'costcenter_define', 'cost_define']
for action in actions4 {
// biz name needs to be specified in the the bizmodel hero actions
bizname := action.params.get('bizname') or {
return error("Can't find param: 'bizname' for ${action.actor}.${action.name} macro, is a requirement argument.")
}
mut sim := getset(bizname)!
if action.name !in knownactions {
return error("Can't find macro with name: ${action.name} for macro's for bizmodel.")
}
console.print_debug(action.name)
match action.name {
'revenue_define' {
sim.revenue_action(action)!
}
'funding_define' {
sim.funding_define_action(action)!
}
'costcenter_define' {
sim.costcenter_define_action(action)!
}
else {}
}
}
console.print_debug('TOTALS for bizmodel play')
// now we have processed the macro's, we can calculate the totals
rlock bizmodels {
for _, mut sim in bizmodels {
// sim.hr_total()!
sim.cost_total()!
sim.revenue_total()!
sim.funding_total()!
}
}
for action in actions4 {
console.print_debug(action.name)
// biz name needs to be specified in the the bizmodel hero actions
bizname := action.params.get('bizname') or {
return error("Can't find param: 'bizname' for bizmodel macro, is a requirement argument.")
}
mut sim := get(bizname)!
if action.name !in knownactions {
return error("Can't find macro with name: ${action.name} for macro's for bizmodel.")
}
match action.name {
'cost_define' {
sim.cost_define_action(action)!
}
'department_define' {
sim.department_define_action(action)!
}
'employee_define' {
sim.employee_define_action(action)!
}
else {}
}
}
// mut sim:=get("test")!
// //println(sim.sheet.rows.keys())
// //println(spreadsheet.sheets_keys())
// println(spreadsheet.sheet_get('bizmodel_test')!)
// if true{panic("sss")}
const action_priorities = {
0: ['revenue_define', 'costcenter_define', 'funding_define']
1: ['cost_define', 'department_define', 'employee_define']
2: ['sheet_wiki', 'graph_bar_row', 'graph_pie_row', 'graph_line_row', 'row_overview']
}
pub fn play(mut plbook PlayBook) ! {
// group actions by which bizmodel they belong to
actions_by_biz := arrays.group_by[string, &Action](
plbook.actions_find(actor: 'bizmodel')!,
fn (a &Action) string {
return a.params.get('bizname') or {'default'}
}
)
// play actions for each biz in playbook
for biz, actions in actions_by_biz {
mut model := getset(biz)!
model.play(mut plbook)!
}
}
pub fn (mut m BizModel) play(mut plbook PlayBook) ! {
mut actions := plbook.actions_find(actor: 'bizmodel')!
for action in actions.filter(it.name in action_priorities[0]) {
m.act(*action)!
}
m.cost_total()!
m.revenue_total()!
m.funding_total()!
for action in actions.filter(it.name in action_priorities[1]) {
m.act(*action)!
}
for action in actions.filter(it.name in action_priorities[2]) {
m.act(*action)!
}
}

View File

@@ -3,7 +3,7 @@ module bizmodel
import freeflowuniverse.herolib.core.playbook { Action }
import freeflowuniverse.herolib.core.texttools
fn (mut m BizModel) cost_define_action(action Action) ! {
fn (mut m BizModel) cost_define_action(action Action) !Action {
mut name := action.params.get_default('name', '')!
mut descr := action.params.get_default('descr', '')!
if descr.len == 0 {
@@ -73,6 +73,7 @@ fn (mut m BizModel) cost_define_action(action Action) ! {
)!
m.sheet.row_delete('tmp3')
}
return action
}
fn (mut sim BizModel) cost_total() ! {

View File

@@ -3,7 +3,7 @@ module bizmodel
import freeflowuniverse.herolib.core.playbook { Action }
import freeflowuniverse.herolib.core.texttools
fn (mut m BizModel) costcenter_define_action(action Action) ! {
fn (mut m BizModel) costcenter_define_action(action Action) !Action {
mut name := action.params.get_default('name', '')!
mut descr := action.params.get_default('descr', '')!
if descr.len == 0 {
@@ -20,4 +20,5 @@ fn (mut m BizModel) costcenter_define_action(action Action) ! {
department: department
}
m.costcenters[name] = &cc
return action
}

View File

@@ -9,7 +9,7 @@ import freeflowuniverse.herolib.core.texttools
// - descr: description of the funding .
// - investment is month:amount,month:amount, ... .
// - type: loan or capital .
fn (mut m BizModel) funding_define_action(action Action) ! {
fn (mut m BizModel) funding_define_action(action Action) !Action {
mut name := action.params.get_default('name', '')!
mut descr := action.params.get_default('descr', '')!
if descr.len == 0 {
@@ -29,6 +29,7 @@ fn (mut m BizModel) funding_define_action(action Action) ! {
descr: descr
extrapolate: false
)!
return action
}
fn (mut sim BizModel) funding_total() ! {

View File

@@ -15,7 +15,7 @@ import freeflowuniverse.herolib.core.texttools
// department:'engineering'
// cost_percent_revenue e.g. 4%, will make sure the cost will be at least 4% of revenue
fn (mut m BizModel) employee_define_action(action Action) ! {
fn (mut m BizModel) employee_define_action(action Action) !Action {
mut name := action.params.get_default('name', '')!
mut descr := action.params.get_default('descr', '')!
if descr.len == 0 {
@@ -107,10 +107,7 @@ fn (mut m BizModel) employee_define_action(action Action) ! {
fulltime_perc: action.params.get_percentage_default('fulltime', '100%')!
}
// println(employee)
// todo: use existing id gen
if name != '' {
// sid = smartid.sid_new('')!
// // TODO: this isn't necessary if sid_new works correctly
@@ -120,9 +117,10 @@ fn (mut m BizModel) employee_define_action(action Action) ! {
// }
m.employees[name] = &employee
}
return action
}
fn (mut m BizModel) department_define_action(action Action) ! {
fn (mut m BizModel) department_define_action(action Action) !Action {
mut name := action.params.get_default('name', '')!
mut descr := action.params.get_default('descr', '')!
if descr.len == 0 {
@@ -141,6 +139,8 @@ fn (mut m BizModel) department_define_action(action Action) ! {
if name != '' {
m.departments[name] = &department
}
return action
}
// fn (mut sim BizModel) hr_total() ! {

View File

@@ -13,15 +13,13 @@ import freeflowuniverse.herolib.core.texttools
// - cogs_setup, cost of good for 1 item at setup
// - cogs_setup_delay, how many months before setup cogs starts, after sales
// - cogs_setup_perc: what is percentage of the cogs (can change over time) for setup e.g. 0:50%
// - cogs_monthly, cost of goods for the monthly per 1 item
// - cogs_monthly_delay, how many months before monthly cogs starts, after sales
// - cogs_monthly_perc: what is percentage of the cogs (can change over time) for monthly e.g. 0:5%,12:10%
// - nr_sold: how many do we sell per month (is in growth format e.g. 10:100,20:200)
// - nr_sold: how many do we sell per month (is in growth format e.g. 10:100,20:200, default is 1)
// - nr_months_recurring: how many months is recurring, if 0 then no recurring
//
fn (mut m BizModel) revenue_action(action Action) ! {
fn (mut m BizModel) revenue_action(action Action) !Action {
mut name := action.params.get_default('name', '')!
mut descr := action.params.get_default('descr', '')!
if descr.len == 0 {
@@ -62,6 +60,10 @@ fn (mut m BizModel) revenue_action(action Action) ! {
extrapolate: false
)!
println(action)
println(revenue)
exit(0)
mut revenue_setup := m.sheet.row_new(
name: '${name}_revenue_setup'
growth: action.params.get_default('revenue_setup', '0:0')!
@@ -139,11 +141,6 @@ fn (mut m BizModel) revenue_action(action Action) ! {
aggregatetype: .avg
)!
// if true{
// println(cogs_setup_perc)
// println(cogs_monthly_perc)
// panic("sdsd")
// }
mut nr_sold := m.sheet.row_new(
name: '${name}_nr_sold'
@@ -211,10 +208,6 @@ fn (mut m BizModel) revenue_action(action Action) ! {
nrmonths: nr_months_recurring
aggregatetype: .max
)!
// if true{
// println(nr_sold_recurring)
// panic('sd')
// }
}
// cogs as percentage of revenue
@@ -229,16 +222,17 @@ fn (mut m BizModel) revenue_action(action Action) ! {
name: '${name}_cogs_monthly_from_perc'
)!
// if true{
// println(revenue_setup_total)
// println(cogs_setup_perc)
// println(cogs_setup_from_perc)
// println("montlhy")
// println(revenue_monthly_total)
// println(cogs_monthly_perc)
// println(cogs_monthly_from_perc)
// panic("sdsd")
// }
println(action)
println(nr_sold)
println(revenue)
println(revenue_setup_total)
println(revenue_monthly_total)
println(cogs_setup_perc)
println(cogs_setup_from_perc)
println(cogs_monthly_perc)
println(cogs_monthly_from_perc)
exit(0)
// mut cogs_from_perc:=cogs_perc.action(action:.multiply,rows:[revenue],name:"cogs_from_perc")!
@@ -312,6 +306,7 @@ fn (mut m BizModel) revenue_action(action Action) ! {
// panic("sdsd")
// }
return action
}
// revenue_total calculates and aggregates the total revenue and cost of goods sold (COGS) for the business model

View File

@@ -0,0 +1,6 @@
# @{department.name}
`@{department.description}`
**Cost To The Company:**

View File

@@ -9,6 +9,7 @@
`@{employee.cost}`
@{employee_cost_chart}
@if employee.cost_percent_revenue > 0.0

View File

@@ -0,0 +1,27 @@
# @{employee.name}
`@{employee.description}`
> department: `@{employee.department}`
**Cost To The Company:**
`@{employee.cost}`
@if employee.cost_percent_revenue > 0.0
**Cost Percent Revenue:**
`@{employee.cost_percent_revenue}%`
@end
@if employee.nrpeople.len > 1
**Number of People in this group**
`@{employee.nrpeople}`
@end

View File

@@ -0,0 +1,7 @@
# Human Resources
| Name | Title | Nr People |
|------|-------|-------|
@for employee in model.employees.values()
| @{employee.name} | @{employee.title} | @{employee.nrpeople} |
@end

View File

@@ -2,53 +2,48 @@
## FUNDING
!!bizmodel.sheet_wiki includefilter:'funding'
@{bizmodel.sheet.wiki(includefilter:'funding')!}
## REVENUE vs COGS
!!bizmodel.sheet_wiki includefilter:rev
@{bizmodel.sheet.wiki(includefilter:'rev')!}
#### Revenue Lines
!!bizmodel.sheet_wiki title:'Revenue Total' includefilter:'revtotal'
@{bizmodel.sheet.wiki(title:'Revenue Total', includefilter:'revtotal')!}
#### COGS Lines
!!bizmodel.sheet_wiki title:'COGS' includefilter:'cogstotal'
@{bizmodel.sheet.wiki(title:'COGS', includefilter:'cogstotal')!}
## HR
!!bizmodel.sheet_wiki title:'HR Teams' includefilter:'hrnr'
!!bizmodel.sheet_wiki title:'HR Costs' includefilter:'hrcost'
@{bizmodel.sheet.wiki(title:'HR Teams', includefilter:'hrnr')!}
@{bizmodel.sheet.wiki(title:'HR Costs', includefilter:'hrcost')!}
## Operational Costs
!!bizmodel.sheet_wiki title:'COSTS' includefilter:'ocost'
@{bizmodel.sheet.wiki(title:'COSTS', includefilter:'ocost')!}
## P&L Overview
<!-- period is in months, 3 means every quarter -->
!!bizmodel.sheet_wiki title:'P&L Overview' includefilter:'pl'
@{bizmodel.sheet.wiki(title:'P&L Overview', includefilter:'pl')!}
!!bizmodel.graph_bar_row rowname:revenue_total unit:million title:'A Title' title_sub:'Sub'
@{bizmodel.graph_bar_row(rowname:'revenue_total', unit:'million', title:'A Title', title_sub:'Sub')!}
Unit is in Million USD.
!!bizmodel.graph_bar_row rowname:revenue_total unit:million
@{bizmodel.graph_bar_row(rowname:'revenue_total', unit:'million')!}
!!bizmodel.graph_line_row rowname:revenue_total unit:million
!!bizmodel.graph_pie_row rowname:revenue_total unit:million size:'80%'
@{bizmodel.graph_line_row(rowname:'revenue_total', unit:'million')!}
@{bizmodel.graph_pie_row(rowname:'revenue_total', unit:'million', size:'80%')!}
## Some Details
> show how we can do per month
!!bizmodel.sheet_wiki includefilter:'pl' period_months:1
@{bizmodel.sheet_wiki(includefilter:'pl', period_months:1)!}

View File

@@ -0,0 +1,49 @@
# @{model.name}
@{model.description}
## FUNDING
@{model.sheet.wiki(includefilter:['funding']) or {panic(err)}}
## REVENUE vs COGS
@{model.sheet.wiki(includefilter:['rev']) or {panic(err)}}
#### Revenue Lines
@{model.sheet.wiki(title:'Revenue Total', includefilter:['revtotal']) or {panic(err)}}
#### COGS Lines
@{model.sheet.wiki(title:'COGS', includefilter:['cogstotal']) or {panic(err)}}
## HR
@{model.sheet.wiki(title:'HR Teams', includefilter:['hrnr']) or {panic(err)}}
@{model.sheet.wiki(title:'HR Costs', includefilter:['hrcost']) or {panic(err)}}
## Operational Costs
@{model.sheet.wiki(title:'COSTS', includefilter:['ocost']) or {panic(err)}}
## P&L Overview
<!-- period is in months, 3 means every quarter -->
@{model.sheet.wiki(title:'P&L Overview', includefilter:['pl']) or {panic(err)}}
@{model.sheet.bar_chart(rowname:'revenue_total', unit: .million, title:'A Title', title_sub:'Sub') or {panic(err)}.mdx()}
Unit is in Million USD.
@{model.sheet.line_chart(rowname:'revenue_total', unit: .million) or {panic(err)}.mdx()}
@{model.sheet.pie_chart(rowname:'revenue_total', unit: .million, size:'80%') or {panic(err)}.mdx()}
## Some Details
> show how we can do per month
@{model.sheet.wiki(includefilter:['pl'], period_type:.month) or {panic(err)}}

View File

@@ -0,0 +1,62 @@
# @{product.title}
@{product.description}
#### parameters for the product
@if product.has_oneoffs
Product ${name1} has revenue events (one offs)
@{model.sheet.wiki() or {''}}
namefilter:'${name1}_revenue,${name1}_cogs,${name1}_cogs_perc,${name1}_maintenance_month_perc' sheetname:'bizmodel_tf9
- COGS = Cost of Goods Sold (is our cost to deliver the product/service)
- maintenance is fee we charge to the customer per month in relation to the revenue we charged e.g. 1% of a product which was sold for 1m EUR means we charge 1% of 1 m EUR per month.
@end //one offs
@if product.has_items
Product sold and its revenue/cost of goods
@{model.sheet.wiki() or {''}}
namefilter:'${name1}_nr_sold,${name1}_revenue_setup,${name1}_revenue_monthly,${name1}_cogs_setup,${name1}_cogs_setup_perc,${name1}_cogs_monthly,${name1}_cogs_monthly_perc'
sheetname:'bizmodel_tf9
- nr sold, is the nr sold per month of ${name1}
- revenue setup is setup per item for ${name1}, this is the money we receive. Similar there is a revenue monthly.
- cogs = Cost of Goods Sold (is our cost to deliver the product)
- can we as a setup per item, or per month per item
@if product.nr_months_recurring>1
This product ${name1} is recurring, means customer pays per month ongoing, the period customer is paying for in months is: **${product.nr_months_recurring}**
@end //recurring
@end
#### the revenue/cogs calculated
@{model.sheet.wiki() or {''}}
namefilter:'${name1}_nr_sold_recurring'
sheetname:'bizmodel_tf9
This results in following revenues and cogs:
@{model.sheet.wiki() or {''}}
namefilter:'${name1}_revenue_setup_total,${name1}_revenue_monthly_total,${name1}_cogs_setup_total,${name1}_cogs_monthly_total,${name1}_cogs_setup_from_perc,${name1}_cogs_monthly_from_perc,${name1}_maintenance_month,
${name1}_revenue_monthly_recurring,${name1}_cogs_monthly_recurring'
sheetname:'bizmodel_tf9
resulting revenues:
@{model.sheet.wiki() or {''}}
namefilter:'${name1}_revenue_total,${name1}_cogs_total'
sheetname:'bizmodel_tf9
!!!spreadsheet.graph_line_row rowname:'${name1}_cogs_total' unit:million sheetname:'bizmodel_tf9'
!!!spreadsheet.graph_line_row rowname:'${name1}_revenue_total' unit:million sheetname:'bizmodel_tf9'

View File

@@ -0,0 +1,68 @@
# @{product.title}
@{product.description}
#### parameters for the product
@if product.has_oneoffs
Product ${name1} has revenue events (one offs)
!!!spreadsheet.sheet_wiki
namefilter:'${name1}_revenue,${name1}_cogs,${name1}_cogs_perc,${name1}_maintenance_month_perc' sheetname:'bizmodel_tf9
- COGS = Cost of Goods Sold (is our cost to deliver the product/service)
- maintenance is fee we charge to the customer per month in relation to the revenue we charged e.g. 1% of a product which was sold for 1m EUR means we charge 1% of 1 m EUR per month.
@end //one offs
@if product.has_items
Product sold and its revenue/cost of goods
!!!spreadsheet.sheet_wiki
namefilter:'${name1}_nr_sold,${name1}_revenue_setup,${name1}_revenue_monthly,${name1}_cogs_setup,${name1}_cogs_setup_perc,${name1}_cogs_monthly,${name1}_cogs_monthly_perc'
sheetname:'bizmodel_tf9
- nr sold, is the nr sold per month of ${name1}
- revenue setup is setup per item for ${name1}, this is the money we receive. Similar there is a revenue monthly.
- cogs = Cost of Goods Sold (is our cost to deliver the product)
- can we as a setup per item, or per month per item
@if product.nr_months_recurring>1
This product ${name1} is recurring, means customer pays per month ongoing, the period customer is paying for in months is: **${product.nr_months_recurring}**
@end //recurring
@end
#### the revenue/cogs calculated
!!!spreadsheet.sheet_wiki
namefilter:'${name1}_nr_sold_recurring'
sheetname:'bizmodel_tf9
This results in following revenues and cogs:
!!!spreadsheet.sheet_wiki
namefilter:'${name1}_revenue_setup_total,${name1}_revenue_monthly_total,${name1}_cogs_setup_total,${name1}_cogs_monthly_total,${name1}_cogs_setup_from_perc,${name1}_cogs_monthly_from_perc,${name1}_maintenance_month,
${name1}_revenue_monthly_recurring,${name1}_cogs_monthly_recurring'
sheetname:'bizmodel_tf9
resulting revenues:
!!!spreadsheet.sheet_wiki
namefilter:'${name1}_revenue_total,${name1}_cogs_total'
sheetname:'bizmodel_tf9
!!!spreadsheet.graph_line_row rowname:'${name1}_cogs_total' unit:million sheetname:'bizmodel_tf9'
!!!spreadsheet.graph_line_row rowname:'${name1}_revenue_total' unit:million sheetname:'bizmodel_tf9'
@end //product has_revenue
@end //loop

View File

@@ -124,9 +124,4 @@ fn test_curr() {
console.print_debug(sh.rows['something'].cells[0])
assert sh.rows['something']!.cells[0].val == 25.0
assert sh.rows['something']!.cells[60 - 1].val == 900.0
// TODO: we need to create tests for it
console.print_debug(sh)
panic('test1')
}

View File

@@ -0,0 +1,138 @@
module spreadsheet
import freeflowuniverse.herolib.data.markdownparser.elements
import freeflowuniverse.herolib.ui.console
import freeflowuniverse.herolib.web.echarts
pub fn (s Sheet) title_chart(args RowGetArgs) echarts.EChartsOption {
return echarts.EChartsOption{
title: echarts.Title{
text: args.title
subtext: args.title_sub
left: 'center'
}
}
}
pub fn (s Sheet) line_chart(args_ RowGetArgs) !echarts.EChartsOption {
mut args := args_
rownames := s.rownames_get(args)!
header := s.header_get_as_string(args.period_type)!
mut series := []echarts.Series{}
for rowname in rownames {
data := s.data_get_as_string(RowGetArgs{
...args
rowname: rowname
})!
series << echarts.Series{
name: rowname
type_: 'line'
stack: 'Total'
data: data.split(',')
}
}
return echarts.EChartsOption{
title: s.title_chart(args).title
tooltip: echarts.Tooltip{
trigger: 'axis'
}
legend: echarts.Legend{
data: rownames
}
grid: echarts.Grid{
left: '3%'
right: '4%'
bottom: '3%'
contain_label: true
}
toolbox: echarts.Toolbox{
feature: echarts.ToolboxFeature{
save_as_image: {}
}
}
x_axis: echarts.XAxis{
type_: 'category'
boundary_gap: false
data: header.split(',')
}
y_axis: echarts.YAxis{
type_: 'value'
}
series: series
}
}
pub fn (s Sheet) bar_chart(args_ RowGetArgs) !echarts.EChartsOption {
mut args := args_
args.rowname = s.rowname_get(args)!
header := s.header_get_as_list(args.period_type)!
data := s.data_get_as_list(args)!
return echarts.EChartsOption{
title: s.title_chart(args).title
x_axis: echarts.XAxis{
type_: 'category'
data: header
}
y_axis: echarts.YAxis{
type_: 'value'
}
series: [
echarts.Series{
name: args.rowname
type_: 'bar'
data: data
stack: ''
},
]
}
}
pub fn (s Sheet) pie_chart(args_ RowGetArgs) !echarts.EChartsOption {
mut args := args_
args.rowname = s.rowname_get(args)!
header := s.header_get_as_list(args.period_type)!
data := s.data_get_as_list(args)!
if header.len != data.len {
return error('Data and header lengths must match.')
}
mut pie_data := []map[string]string{}
for i, _ in data {
pie_data << {
'value': data[i].trim_space().trim("'")
'name': header[i].trim_space().trim("'")
}
}
return echarts.EChartsOption{
title: s.title_chart(args).title
tooltip: echarts.Tooltip{
trigger: 'item'
}
legend: echarts.Legend{
data: header
orient: 'vertical'
left: 'left'
}
series: [
echarts.Series{
name: 'Data'
type_: 'pie'
radius: args.size.int()
data: pie_data.map(it.str())
emphasis: echarts.Emphasis{
item_style: echarts.ItemStyle{
shadow_blur: 10
shadow_offset_x: 0
shadow_color: 'rgba(0, 0, 0, 0.5)'
}
}
},
]
}
}

View File

@@ -0,0 +1,77 @@
module spreadsheet
import freeflowuniverse.herolib.data.markdownparser.elements
import freeflowuniverse.herolib.ui.console
import freeflowuniverse.herolib.web.echarts
fn test_title_chart() {
mut s := sheet_new() or { panic(err) }
mut nrnodes := s.row_new(
name: 'nrnodes'
growth: '5:100,55:1000'
tags: 'cat:nodes color:yellow urgent'
)!
args := RowGetArgs{
rowname: 'nrnodes'
title: 'Main Title'
title_sub: 'Subtitle'
}
title := s.title_chart(args).title
assert title.text == 'Main Title'
assert title.subtext == 'Subtitle'
assert title.left == 'center'
}
fn test_line_chart() {
mut s := sheet_new() or { panic(err) }
mut nrnodes := s.row_new(
name: 'nrnodes'
growth: '5:100,55:1000'
tags: 'cat:nodes color:yellow urgent'
)!
args := RowGetArgs{
rowname: 'nrnodes'
title: 'Line Chart'
period_type: .month
}
option := s.line_chart(args) or { panic(err) }
assert option.title.text == 'Line Chart'
assert option.tooltip.trigger == 'axis'
assert option.grid.contain_label == true
}
fn test_bar_chart() {
mut s := sheet_new() or { panic(err) }
mut nrnodes := s.row_new(
name: 'nrnodes'
growth: '5:100,55:1000'
tags: 'cat:nodes color:yellow urgent'
)!
args := RowGetArgs{
rowname: 'nrnodes'
title: 'Bar Chart'
period_type: .year
}
option := s.bar_chart(args) or { panic(err) }
assert option.title.text == 'Bar Chart'
assert option.x_axis.type_ == 'category'
assert option.y_axis.type_ == 'value'
}
fn test_pie_chart() {
mut s := sheet_new() or { panic(err) }
mut nrnodes := s.row_new(
name: 'nrnodes'
growth: '5:100,55:1000'
tags: 'cat:nodes color:yellow urgent'
)!
args := RowGetArgs{
rowname: 'nrnodes'
title: 'Pie Chart'
period_type: .quarter
}
option := s.pie_chart(args) or { panic(err) }
assert option.title.text == 'Pie Chart'
assert option.tooltip.trigger == 'item'
assert option.legend.data.len > 0
}

View File

@@ -92,7 +92,7 @@ pub fn playmacro(action Action) !string {
content = sh.wiki(args) or { panic(err) }
}
'graph_title_row' {
content = sh.wiki_title_chart(args)
content = sh.wiki_title_chart(args)!
}
'graph_line_row' {
content = sh.wiki_line_chart(args)!

View File

@@ -95,7 +95,7 @@ pub fn (mut r Row) cell_get(colnr int) !&Cell {
return &r.cells[colnr]
}
pub fn (mut r Row) values_get() []f64 {
pub fn (r Row) values_get() []f64 {
mut out := []f64{}
for cell in r.cells {
out << cell.val

View File

@@ -202,7 +202,7 @@ pub fn (s Sheet) tosmaller(args_ ToYearQuarterArgs) !&Sheet {
// tagsfilter []string
// tags if set will see that there is at least one corresponding tag per row
// rawsfilter is list of names of rows which will be included
pub fn (mut s Sheet) toyear(args ToYearQuarterArgs) !&Sheet {
pub fn (s Sheet) toyear(args ToYearQuarterArgs) !&Sheet {
mut args2 := args
args2.period_months = 12
return s.tosmaller(args2)
@@ -215,7 +215,7 @@ pub fn (mut s Sheet) toyear(args ToYearQuarterArgs) !&Sheet {
// tagsfilter []string
// tags if set will see that there is at least one corresponding tag per row
// rawsfilter is list of names of rows which will be included
pub fn (mut s Sheet) toquarter(args ToYearQuarterArgs) !&Sheet {
pub fn (s Sheet) toquarter(args ToYearQuarterArgs) !&Sheet {
mut args2 := args
args2.period_months = 3
return s.tosmaller(args2)
@@ -259,13 +259,15 @@ pub fn (mut s Sheet) json() string {
}
// find row, report error if not found
pub fn (mut s Sheet) row_get(name string) !&Row {
mut row := s.rows[name] or { return error('could not find row with name: ${name}') }
pub fn (s Sheet) row_get(name string) !&Row {
row := s.rows[name] or {
return error('could not find row with name: ${name}, available rows: ${s.rows.keys()}')
}
return row
}
pub fn (mut s Sheet) values_get(name string) ![]f64 {
mut r := s.row_get(name)!
pub fn (s Sheet) values_get(name string) ![]f64 {
r := s.row_get(name)!
vs := r.values_get()
return vs
}

View File

@@ -0,0 +1,49 @@
module spreadsheet
import os
import freeflowuniverse.herolib.core.pathlib
@[params]
pub struct ExportArgs{
pub mut:
path string
}
fn format_number(val f64) string {
if val < 0.001 && val > -0.001 {
return '0'
}
if val >= 1000.0 || val <= -1000.0 {
return int(val).str()
}
// Format small numbers with 3 decimal places to handle floating point precision
return '${val:.3f}'
}
pub fn (mut s Sheet) export(args ExportArgs) !string {
mut result := []string{}
// Add headers
mut header_row := ['Name', 'Description', 'AggregateType', 'Tags', 'Subgroup']
header_row << s.header()!
result << header_row.join('|')
// Add rows
for _, row in s.rows {
mut row_data := [row.name, row.description, row.aggregatetype.str(), row.tags, row.subgroup]
for cell in row.cells {
if cell.empty {
row_data << '-'
} else {
row_data << format_number(cell.val)
}
}
result << row_data.join('|')
}
if args.path.len>0{
mut p:=pathlib.get_file(path:args.path.replace("~",os.home_dir()), create:true, delete:true)!
p.write(result.join('\n'))!
}
return result.join('\n')
}

View File

@@ -71,19 +71,19 @@ pub fn (s Sheet) rowname_get(args RowGetArgs) !string {
}
// return e.g. "'Y1', 'Y2', 'Y3', 'Y4', 'Y5', 'Y6'" if year, is for header
pub fn (mut s Sheet) header_get_as_list(period_type PeriodType) ![]string {
pub fn (s Sheet) header_get_as_list(period_type PeriodType) ![]string {
str := s.header_get_as_string(period_type)!
return str.split(',')
}
// return e.g. "'Y1', 'Y2', 'Y3', 'Y4', 'Y5', 'Y6'" if year, is for header
pub fn (mut s Sheet) data_get_as_list(args RowGetArgs) ![]string {
pub fn (s Sheet) data_get_as_list(args RowGetArgs) ![]string {
str := s.data_get_as_string(args)!
return str.split(',')
}
// return e.g. "'Y1', 'Y2', 'Y3', 'Y4', 'Y5', 'Y6'" if year, is for header
pub fn (mut s Sheet) header_get_as_string(period_type PeriodType) !string {
pub fn (s Sheet) header_get_as_string(period_type PeriodType) !string {
err_pre := "Can't get header for sheet:${s.name}\n"
nryears := int(s.nrcol / 12)
mut out := ''
@@ -112,7 +112,7 @@ pub fn (mut s Sheet) header_get_as_string(period_type PeriodType) !string {
}
// return the values
pub fn (mut s Sheet) data_get_as_string(args RowGetArgs) !string {
pub fn (s Sheet) data_get_as_string(args RowGetArgs) !string {
if args.rowname == '' {
return error('rowname needs to be specified')
}
@@ -121,7 +121,7 @@ pub fn (mut s Sheet) data_get_as_string(args RowGetArgs) !string {
mut s2 := s
if args.period_type == .year {
s.toyear(
s2 = s.toyear(
name: args.rowname
namefilter: args.namefilter
includefilter: args.includefilter
@@ -129,7 +129,7 @@ pub fn (mut s Sheet) data_get_as_string(args RowGetArgs) !string {
)!
}
if args.period_type == .quarter {
s.toquarter(
s2 = s.toquarter(
name: args.rowname
namefilter: args.namefilter
includefilter: args.includefilter
@@ -141,13 +141,13 @@ pub fn (mut s Sheet) data_get_as_string(args RowGetArgs) !string {
// console.print_debug(s2.row_get(args.rowname)!)
mut vals := s2.values_get(args.rowname)!
if args.period_type == .year && vals.len != nryears {
return error('${err_pre}Vals.len need to be 6, for year.\nhere:\n${vals}')
return error('${err_pre}Vals.len need to be ${nryears}, for year.\nhere:\n${vals}')
}
if args.period_type == .quarter && vals.len != nryears * 4 {
return error('${err_pre}vals.len need to be 6*4, for quarter.\nhere:\n${vals}')
return error('${err_pre}vals.len need to be ${nryears}*4, for quarter.\nhere:\n${vals}')
}
if args.period_type == .month && vals.len != nryears * 12 {
return error('${err_pre}vals.len need to be 6*12, for month.\nhere:\n${vals}')
return error('${err_pre}vals.len need to be ${nryears}*12, for month.\nhere:\n${vals}')
}
for mut val in vals {
@@ -166,7 +166,7 @@ pub fn (mut s Sheet) data_get_as_string(args RowGetArgs) !string {
}
// use RowGetArgs to get to smaller version of sheet
pub fn (mut s Sheet) filter(args RowGetArgs) !&Sheet {
pub fn (s Sheet) filter(args RowGetArgs) !&Sheet {
period_months := match args.period_type {
.year { 12 }
.month { 1 }

View File

@@ -4,7 +4,7 @@ import freeflowuniverse.herolib.core.texttools
import freeflowuniverse.herolib.ui.console
// format a sheet properly in wiki format
pub fn (mut s Sheet) wiki(args_ RowGetArgs) !string {
pub fn (s Sheet) wiki(args_ RowGetArgs) !string {
mut args := args_
_ := match args.period_type {

View File

@@ -3,22 +3,12 @@ module spreadsheet
import freeflowuniverse.herolib.data.markdownparser.elements
import freeflowuniverse.herolib.ui.console
pub fn (mut s Sheet) wiki_title_chart(args RowGetArgs) string {
if args.title.len > 0 {
titletxt := "
title: {
text: '${args.title}',
subtext: '${args.title_sub}',
left: 'center'
},
"
return titletxt
}
return ''
pub fn (s Sheet) wiki_title_chart(args RowGetArgs) !string {
return s.title_chart(args).markdown()
}
pub fn (mut s_ Sheet) wiki_row_overview(args RowGetArgs) !string {
mut s := s_.filter(args)!
pub fn (s_ Sheet) wiki_row_overview(args RowGetArgs) !string {
s := s_.filter(args)!
rows_values := s.rows.values().map([it.name, it.description, it.tags])
mut rows := []elements.Row{}
@@ -43,146 +33,18 @@ pub fn (mut s_ Sheet) wiki_row_overview(args RowGetArgs) !string {
// produce a nice looking bar chart see
// https://echarts.apache.org/examples/en/editor.html?c=line-stack
pub fn (mut s Sheet) wiki_line_chart(args_ RowGetArgs) !string {
mut args := args_
rownames := s.rownames_get(args)!
header := s.header_get_as_string(args.period_type)!
mut series_lines := []string{}
for rowname in rownames {
data := s.data_get_as_string(RowGetArgs{
...args
rowname: rowname
})!
series_lines << '{
name: \'${rowname}\',
type: \'line\',
stack: \'Total\',
data: [${data}]
}'
}
// TODO: need to implement the multiple results which can come back from the args, can be more than 1
// header := s.header_get_as_string(args.period_type)!
// data := s.data_get_as_string(args)!
// console.print_debug('HERE! ${header}')
// console.print_debug('HERE!! ${data}')
template := "
${s.wiki_title_chart(args)}
tooltip: {
trigger: 'axis'
},
legend: {
data: ${rownames}
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
toolbox: {
feature: {
saveAsImage: {}
}
},
xAxis: {
type: 'category',
boundaryGap: false,
data: [${header}]
},
yAxis: {
type: 'value'
},
series: [${series_lines.join(',')}]
"
out := remove_empty_line('```echarts\n{${template}\n};\n```\n')
return out
pub fn (s Sheet) wiki_line_chart(args_ RowGetArgs) !string {
return s.line_chart(args_)!.markdown()
}
// produce a nice looking bar chart see
// https://echarts.apache.org/examples/en/index.html#chart-type-bar
pub fn (mut s Sheet) wiki_bar_chart(args_ RowGetArgs) !string {
mut args := args_
args.rowname = s.rowname_get(args)!
header := s.header_get_as_string(args.period_type)!
data := s.data_get_as_string(args)!
bar1 := "
${s.wiki_title_chart(args)}
xAxis: {
type: 'category',
data: [${header}]
},
yAxis: {
type: 'value'
},
series: [
{
data: [${data}],
type: 'bar',
showBackground: true,
backgroundStyle: {
color: 'rgba(180, 180, 180, 0.2)'
}
}
]
"
out := remove_empty_line('```echarts\n{${bar1}\n};\n```\n')
return out
pub fn (s Sheet) wiki_bar_chart(args_ RowGetArgs) !string {
return s.bar_chart(args_)!.markdown()
}
// produce a nice looking bar chart see
// https://echarts.apache.org/examples/en/index.html#chart-type-bar
pub fn (mut s Sheet) wiki_pie_chart(args_ RowGetArgs) !string {
mut args := args_
args.rowname = s.rowname_get(args)!
header := s.header_get_as_list(args.period_type)!
data := s.data_get_as_list(args)!
mut radius := ''
if args.size.len > 0 {
radius = "radius: '${args.size}',"
}
if header.len != data.len {
return error('data and header lengths must match.\n${header}\n${data}')
}
mut data_lines := []string{}
for i, _ in data {
data_lines << '{ value: ${data[i]}, name: ${header[i]}}'
}
data_str := '[${data_lines.join(',')}]'
bar1 := "
${s.wiki_title_chart(args)}
tooltip: {
trigger: 'item'
},
legend: {
orient: 'vertical',
left: 'left'
},
series: [
{
name: 'Access From',
type: 'pie',
${radius}
data: ${data_str},
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
"
out := remove_empty_line('```echarts\n{${bar1}\n};\n```\n')
return out
pub fn (s Sheet) wiki_pie_chart(args_ RowGetArgs) !string {
return s.pie_chart(args_)!.markdown()
}

View File

@@ -77,7 +77,6 @@ module livekit
// token.grants.video = grant
// }
// // Method to generate a JWT token
// pub fn (token AccessToken) to_jwt() !string {
// // Create JWT payload
@@ -150,4 +149,4 @@ module livekit
// // Parse and return the claims as ClaimGrants
// return json.decode(ClaimGrants, payload_json)
// }
// }

View File

@@ -1,4 +1,4 @@
module zdb
module zerodb_client
import freeflowuniverse.herolib.core.redisclient
import freeflowuniverse.herolib.ui.console
@@ -14,11 +14,12 @@ pub mut:
// /tmp/redis-default.sock
pub fn get(addr string, auth string, namespace string) !ZDB {
console.print_header(' ZDB get: addr:${addr} namespace:${namespace}')
mut redis := redisclient.get(addr)!
mut redis := redisclient.new(addr)!
mut zdb := ZDB{
redis: redis
}
println('Here..')
if auth != '' {
zdb.redis.send_expect_ok(['AUTH', auth])!
}

View File

@@ -2,6 +2,7 @@ module generic
import freeflowuniverse.herolib.ui.console
import freeflowuniverse.herolib.core.pathlib
import freeflowuniverse.herolib.osal
fn generate_exec(path string, reset bool) ! {
mut args := args_get(path)!
@@ -43,12 +44,15 @@ fn generate_exec(path string, reset bool) ! {
if args.reset {
path_templ_dir.delete()!
}
if args.templates {
if !path_templ_dir.exists() {
mut templ_6 := $tmpl('templates/atemplate.yaml')
pathlib.template_write(templ_6, '${args.path}/templates/atemplate.yaml', true)!
}
}
console.print_debug('formating dir ${args.path}')
osal.execute_silent('v fmt -w ${args.path}')!
}
fn platform_check(args GeneratorArgs) ! {

View File

@@ -47,7 +47,7 @@ fn args_get(path string) !GeneratorArgs {
classname: p.get('classname')!
title: p.get_default('title', '')!
default: p.get_default_true('default')
supported_platforms: p.get_list('supported_platforms')!
supported_platforms: p.get_list_default('supported_platforms', [])!
singleton: p.get_default_false('singleton')
templates: p.get_default_false('templates')
reset: p.get_default_false('reset')

View File

@@ -1,15 +1,18 @@
module ${args.name}
@if args.hasconfig
import freeflowuniverse.herolib.core.base
@end
import freeflowuniverse.herolib.core.playbook
import freeflowuniverse.herolib.ui.console
import freeflowuniverse.herolib.data.paramsparser
@if args.cat == .installer
import freeflowuniverse.herolib.sysadmin.startupmanager
import freeflowuniverse.herolib.osal.zinit
@if args.startupmanager
import time
@end
@end
__global (
${args.name}_global map[string]&${args.classname}

View File

@@ -29,6 +29,15 @@ pub fn cmd_docusaurus(mut cmdroot Command) {
description: 'Url where docusaurus source is.'
})
cmd_run.add_flag(Flag{
flag: .string
required: false
name: 'path'
abbrev: 'p'
// default: ''
description: 'Path where docusaurus source is.'
})
cmd_run.add_flag(Flag{
flag: .string
required: false
@@ -36,7 +45,7 @@ pub fn cmd_docusaurus(mut cmdroot Command) {
abbrev: 'dk'
// default: ''
description: 'Path of SSH Key used to deploy.'
})
})
cmd_run.add_flag(Flag{
flag: .string
@@ -46,7 +55,6 @@ pub fn cmd_docusaurus(mut cmdroot Command) {
description: 'Path where to publish.'
})
cmd_run.add_flag(Flag{
flag: .bool
required: false
@@ -78,20 +86,25 @@ pub fn cmd_docusaurus(mut cmdroot Command) {
description: 'Run your dev environment on local browser.'
})
cmd_run.add_flag(Flag{
flag: .bool
required: false
name: 'new'
abbrev: 'n'
description: 'create a new docusaurus site.'
})
cmdroot.add_command(cmd_run)
}
fn cmd_docusaurus_execute(cmd Command) ! {
mut update := cmd.flags.get_bool('update') or { false }
mut init := cmd.flags.get_bool('new') or { false }
mut url := cmd.flags.get_string('url') or { '' }
mut publish_path := cmd.flags.get_string('publish') or { '' }
mut deploykey := cmd.flags.get_string('deploykey') or { '' }
// mut path := cmd.flags.get_string('path') or { '' }
// if path == '' {
// path = os.getwd()
// }
// path = path.replace('~', os.home_dir())
mut path := cmd.flags.get_string('path') or { '' }
mut buildpublish := cmd.flags.get_bool('buildpublish') or { false }
mut builddevpublish := cmd.flags.get_bool('builddevpublish') or { false }
@@ -101,43 +114,30 @@ fn cmd_docusaurus_execute(cmd Command) ! {
// eprintln("specify build, builddev or dev")
// exit(1)
// }
mut docs := docusaurus.new(update: update)!
if publish_path.len>0 {
_ := docs.build(
url: url
update: update
publish_path: publish_path
deploykey:deploykey
)!
mut docs := docusaurus.new(update: update)!
mut site := docs.get(
url: url
path: path
update: update
publish_path: publish_path
deploykey: deploykey
init: init
)!
if publish_path.len > 0 {
site.build()!
}
if buildpublish {
// Create a new docusaurus site
_ := docs.build_publish(
url: url
update: update
deploykey:deploykey
)!
site.build_publish()!
}
if builddevpublish {
// Create a new docusaurus site
_ := docs.build_dev_publish(
url: url
update: update
deploykey:deploykey
)!
site.build_dev_publish()!
}
if dev {
// Create a new docusaurus site
_ := docs.dev(
url: url
update: update
deploykey:deploykey
)!
site.dev()!
}
}

Some files were not shown because too many files have changed in this diff Show More