Working on CLI templates
This commit is contained in:
parent
6b34c2d29b
commit
1a9c9e6b8a
17 changed files with 106 additions and 5184 deletions
8
cmd/common.go
Normal file
8
cmd/common.go
Normal file
|
@ -0,0 +1,8 @@
|
|||
package cmd
|
||||
|
||||
var logo = ` ____ _
|
||||
| _ \ _ __ ___ | |__ ___
|
||||
| |_) | '__/ _ \| '_ \ / _ \
|
||||
| __/| | | (_) | |_) | (_) |
|
||||
|_| |_| \___/|_.__/ \___/
|
||||
`
|
|
@ -1,40 +0,0 @@
|
|||
/*
|
||||
Copyright © 2024 NAME HERE <EMAIL ADDRESS>
|
||||
*/
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// createCmd represents the create command
|
||||
var createCmd = &cobra.Command{
|
||||
Use: "create",
|
||||
Short: "A brief description of your command",
|
||||
Long: `A longer description that spans multiple lines and likely contains examples
|
||||
and usage of using your command. For example:
|
||||
|
||||
Cobra is a CLI library for Go that empowers applications.
|
||||
This application is a tool to generate the needed files
|
||||
to quickly create a Cobra application.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
fmt.Println("create called")
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(createCmd)
|
||||
|
||||
// Here you will define your flags and configuration settings.
|
||||
|
||||
// Cobra supports Persistent Flags which will work for this command
|
||||
// and all subcommands, e.g.:
|
||||
|
||||
createCmd.PersistentFlags().StringP("input", "i", "", "Specify an input file")
|
||||
|
||||
// Cobra supports local flags which will only run when this command
|
||||
// is called directly, e.g.:
|
||||
// createCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
|
||||
}
|
|
@ -5,59 +5,110 @@ package cmd
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"git.andreafazzi.eu/andrea/probo/cmd/filter"
|
||||
"git.andreafazzi.eu/andrea/probo/cmd/util"
|
||||
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/charmbracelet/glamour"
|
||||
"github.com/charmbracelet/huh"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"github.com/muesli/termenv"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// filterCmd represents the filter command
|
||||
var filterCmd = &cobra.Command{
|
||||
Use: "filter",
|
||||
Short: "Create a new filter",
|
||||
Long: "Create a new filter for selecting quizzes and participants",
|
||||
Run: createFilter,
|
||||
}
|
||||
var longDescription string = `
|
||||
# Filters
|
||||
|
||||
**Filters can made selection over stores.**
|
||||
|
||||
Filters allow you to narrow down selections across various stores. By
|
||||
using filters, you can select participants, quizzes, and
|
||||
responses. The command triggers a Text User Interface (TUI) that runs
|
||||
a jq filter, displaying the outcome in real-time. After you're content
|
||||
with the filtered JSON, pressing ⏎ will present the result on
|
||||
stdout, enabling you to further process it by piping it forward.
|
||||
|
||||
## Examples
|
||||
|
||||
Filter over participants store.
|
||||
|
||||
**probo filter participants**
|
||||
|
||||
Filter over quizzes store using the jq filter in tags.jq file
|
||||
|
||||
**probo filter quizzes -i data/filters/tags.jq**
|
||||
|
||||
Filter over participants and pipe the result on the next filter. The result is then stored in a JSON file.
|
||||
|
||||
**probo filter participants | probo filter quizzes > data/json/selection.json**
|
||||
`
|
||||
|
||||
func init() {
|
||||
createCmd.AddCommand(filterCmd)
|
||||
|
||||
filterCmd.Flags().StringP("type", "t", "participants", "Select the type of filter (participants or quizzes)")
|
||||
desc, err := glamour.Render(fmt.Sprintf("```\n%s```\n%s", logo, longDescription), "dark")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
func createFilter(cmd *cobra.Command, args []string) {
|
||||
f := util.LogToFile()
|
||||
if f != nil {
|
||||
defer f.Close()
|
||||
filterCmd := &cobra.Command{
|
||||
Use: "filter {participants,quizzes,responses}",
|
||||
Short: "Filter the given store",
|
||||
Long: desc,
|
||||
Run: runFilter,
|
||||
}
|
||||
|
||||
rootCmd.AddCommand(filterCmd)
|
||||
filterCmd.PersistentFlags().StringP("input", "i", "", "Specify an input file")
|
||||
}
|
||||
|
||||
func runFilter(cmd *cobra.Command, args []string) {
|
||||
var storeType string
|
||||
|
||||
path, err := cmd.Flags().GetString("input")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
filterType, err := cmd.Flags().GetString("type")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
if len(args) < 1 {
|
||||
f := util.LogToFile()
|
||||
if f != nil {
|
||||
defer f.Close()
|
||||
}
|
||||
|
||||
lipgloss.SetColorProfile(termenv.TrueColor)
|
||||
|
||||
form := huh.NewForm(huh.NewGroup(
|
||||
huh.NewSelect[string]().
|
||||
Title("Choose the store you want to filter").
|
||||
Options(
|
||||
huh.NewOption("Participants", "participants"),
|
||||
huh.NewOption("Quizzes", "quizzes"),
|
||||
huh.NewOption("Responses", "responses"),
|
||||
).Value(&storeType),
|
||||
))
|
||||
|
||||
err = form.Run()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
} else {
|
||||
storeType = args[0]
|
||||
}
|
||||
|
||||
model, err := tea.NewProgram(
|
||||
filter.New(path, filterType, util.ReadStdin()),
|
||||
filter.New(path, storeType, util.ReadStdin()),
|
||||
tea.WithOutput(os.Stderr),
|
||||
).Run()
|
||||
if err != nil {
|
||||
fmt.Println("Error running program:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
result := model.(*filter.FilterModel)
|
||||
|
||||
if result.Result != "" {
|
||||
fmt.Fprintf(os.Stdout, result.Result)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -176,23 +176,6 @@ func (m *FilterModel) marshalJSON() {
|
|||
return
|
||||
}
|
||||
if m.InputJson != "" {
|
||||
// result := make([]interface{}, 2)
|
||||
// err := json.Unmarshal([]byte(m.InputJson), &result[0])
|
||||
// if err != nil {
|
||||
// panic(err)
|
||||
// }
|
||||
|
||||
// filtered := fmt.Sprintf("{\"%s\": %s}", m.filterType, m.FilteredJson)
|
||||
// err = json.Unmarshal([]byte(filtered), &result[1])
|
||||
// if err != nil {
|
||||
// panic(err)
|
||||
// }
|
||||
|
||||
// resultJson, err := json.Marshal(result)
|
||||
// if err != nil {
|
||||
// panic(err)
|
||||
// }
|
||||
// m.Result = string(resultJson)
|
||||
m.Result = fmt.Sprintf("{%s, \"%s\": %s}", strings.Trim(m.InputJson, "{}"), m.filterType, m.FilteredJson)
|
||||
} else {
|
||||
var result interface{}
|
||||
|
@ -307,28 +290,39 @@ func (m *FilterModel) loadStore() tea.Cmd {
|
|||
return func() tea.Msg {
|
||||
var jsonStore []byte
|
||||
|
||||
if m.filterType == "participants" {
|
||||
switch m.filterType {
|
||||
case "participants":
|
||||
pStore, err := file.NewDefaultParticipantFileStore()
|
||||
if err != nil {
|
||||
return errorMsg{err}
|
||||
panic(err)
|
||||
}
|
||||
|
||||
jsonStore, err = pStore.Storer.Json()
|
||||
if err != nil {
|
||||
return errorMsg{err}
|
||||
panic(err)
|
||||
}
|
||||
} else if m.filterType == "quizzes" {
|
||||
case "quizzes":
|
||||
qStore, err := file.NewDefaultQuizFileStore()
|
||||
if err != nil {
|
||||
return errorMsg{err}
|
||||
panic(err)
|
||||
}
|
||||
|
||||
jsonStore, err = qStore.Storer.Json()
|
||||
if err != nil {
|
||||
return errorMsg{err}
|
||||
panic(err)
|
||||
}
|
||||
|
||||
} else {
|
||||
case "responses":
|
||||
qStore, err := file.NewDefaultResponseFileStore()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
jsonStore, err = qStore.Storer.Json()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
default:
|
||||
panic("Unknown filter type!")
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,8 @@ var (
|
|||
ErrorState: []string{"ERROR 📖", "%v", "STORE 🟢"},
|
||||
}
|
||||
filterTypeFormats = map[string]string{
|
||||
"participants": "👫👫 Participants filter 👫👫",
|
||||
"quizzes": "❓❓ Quizzes filter ❓❓",
|
||||
"participants": "👫 Participants filter 👫",
|
||||
"quizzes": "❓ Quizzes filter ❓",
|
||||
"responses": "📝 Responsesfilter 📝",
|
||||
}
|
||||
)
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
/*
|
||||
Copyright © 2024 NAME HERE <EMAIL ADDRESS>
|
||||
*/
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"git.andreafazzi.eu/andrea/probo/pkg/store/file"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// participantsCmd represents the participants command
|
||||
var participantsCmd = &cobra.Command{
|
||||
Use: "participants",
|
||||
Short: "A brief description of your command",
|
||||
Long: `A longer description that spans multiple lines and likely contains examples
|
||||
and usage of using your command. For example:
|
||||
|
||||
Cobra is a CLI library for Go that empowers applications.
|
||||
This application is a tool to generate the needed files
|
||||
to quickly create a Cobra application.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
importCSV(cmd, args)
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
importCmd.AddCommand(participantsCmd)
|
||||
|
||||
// Here you will define your flags and configuration settings.
|
||||
|
||||
// Cobra supports Persistent Flags which will work for this command
|
||||
// and all subcommands, e.g.:
|
||||
// participantsCmd.PersistentFlags().String("foo", "", "A help for foo")
|
||||
|
||||
// Cobra supports local flags which will only run when this command
|
||||
// is called directly, e.g.:
|
||||
// participantsCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
|
||||
}
|
||||
|
||||
func importCSV(cmd *cobra.Command, args []string) {
|
||||
pStore, err := file.NewDefaultParticipantFileStore()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
_, err = pStore.ImportCSV(args[0])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
3
cmd/templates/filter.tmpl
Normal file
3
cmd/templates/filter.tmpl
Normal file
|
@ -0,0 +1,3 @@
|
|||
{{define "description"}}
|
||||
{{.Description}}
|
||||
{{end}}
|
2
cmd/templates/layout.tmpl
Normal file
2
cmd/templates/layout.tmpl
Normal file
|
@ -0,0 +1,2 @@
|
|||
{{.Logo}}
|
||||
{{template "description" .}}
|
121
misc/logseq/.gitignore
vendored
121
misc/logseq/.gitignore
vendored
|
@ -1,121 +0,0 @@
|
|||
.DS_Store
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Snowpack dependency directory (https://snowpack.dev/)
|
||||
web_modules/
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Microbundle cache
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
.env.test
|
||||
.env.production
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
.parcel-cache
|
||||
|
||||
# Next.js build output
|
||||
.next
|
||||
out
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
.nuxt
|
||||
dist
|
||||
|
||||
# Gatsby files
|
||||
.cache/
|
||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
.tern-port
|
||||
|
||||
# Stores VSCode versions used for testing VSCode extensions
|
||||
.vscode-test
|
||||
|
||||
# yarn v2
|
||||
.yarn/cache
|
||||
.yarn/unplugged
|
||||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.*
|
||||
|
||||
*~
|
|
@ -1,21 +0,0 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2022 Andrea Fazzi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -1,21 +0,0 @@
|
|||
Copyright (c) 2022 Andrea Fazzi
|
||||
|
||||
MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -1,4 +0,0 @@
|
|||
# What's that?
|
||||
|
||||
A very basic boilerplate useful to start devoloping a
|
||||
[Logseq](https://logseq.com/) plugin.
|
|
@ -1,10 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-hierarchy" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="gray" fill="gray" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||
<circle cx="12" cy="5" r="2" />
|
||||
<circle cx="5" cy="19" r="2" />
|
||||
<circle cx="19" cy="19" r="2" />
|
||||
<path d="M6.5 17.5l5.5 -4.5l5.5 4.5" />
|
||||
<line x1="12" y1="7" x2="12" y2="13" />
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 471 B |
4707
misc/logseq/package-lock.json
generated
4707
misc/logseq/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -1,29 +0,0 @@
|
|||
{
|
||||
"logseq": {
|
||||
"id": "logseq-probo-plugin",
|
||||
"title": "logseq-probo-plugin",
|
||||
"icon": "./icon.svg"
|
||||
},
|
||||
"name": "logseq-probo-plugin",
|
||||
"version": "1.2.0",
|
||||
"description": "",
|
||||
"main": "dist/index.html",
|
||||
"targets": {
|
||||
"main": false
|
||||
},
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"build": "parcel build --no-source-maps src/index.html --public-url ./"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "Andrea Fazzi",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@logseq/libs": "^0.0.1-alpha.35",
|
||||
"js-base64": "^3.7.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"buffer": "^6.0.3",
|
||||
"parcel": "^2.2.0"
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script src="index.ts" type="module"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,121 +0,0 @@
|
|||
import "@logseq/libs";
|
||||
import { BlockEntity } from "@logseq/libs/dist/LSPlugin.user";
|
||||
|
||||
const endpoint = 'http://localhost:3000/quizzes';
|
||||
|
||||
const uniqueIdentifier = () =>
|
||||
Math.random()
|
||||
.toString(36)
|
||||
.replace(/[^a-z]+/g, "");
|
||||
|
||||
const sanitizeBlockContent = (text: string) => text.replace(/((?<=::).*|.*::)/g, "").replace(/{.*}/, "").trim()
|
||||
|
||||
async function fetchQuizzes() {
|
||||
const { status: status, content: quizzes } = await fetch(endpoint).then(res => res.json())
|
||||
const ret = quizzes || []
|
||||
|
||||
return ret.map((quiz, i) => {
|
||||
return `${i + 1}. ${quiz.Question.Text}`
|
||||
})
|
||||
}
|
||||
|
||||
const render = (id, slot, status: ("modified" | "saved" | "error")) => {
|
||||
logseq.provideUI({
|
||||
key: `${id}`,
|
||||
slot,
|
||||
reset: true,
|
||||
template: `
|
||||
${status === 'saved' ? '<button data-on-click="createOrUpdateQuiz" class="renderBtn">Save</button><span>saved</span>' : '<button data-on-click="createOrUpdateQuiz" class="renderBtn">Save</button>'}
|
||||
|
||||
`,
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
const main = () => {
|
||||
console.log("logseq-probo-plugin LOADED!");
|
||||
|
||||
logseq.Editor.registerSlashCommand("Get All Quizzes", async () => {
|
||||
const currBlock = await logseq.Editor.getCurrentBlock();
|
||||
|
||||
let blocks = await fetchQuizzes()
|
||||
|
||||
blocks = blocks.map((it: BlockEntity) => ({ content: it }))
|
||||
|
||||
await logseq.Editor.insertBatchBlock(currBlock.uuid, blocks, {
|
||||
sibling: false
|
||||
})
|
||||
});
|
||||
|
||||
logseq.Editor.registerSlashCommand("Create a new Probo quiz", async () => {
|
||||
await logseq.Editor.insertAtEditingCursor(
|
||||
`{{renderer :probo_${uniqueIdentifier()}}}`
|
||||
);
|
||||
|
||||
});
|
||||
|
||||
logseq.App.onMacroRendererSlotted(async ({ slot, payload }) => {
|
||||
const [type] = payload.arguments;
|
||||
|
||||
if (!type.startsWith(":probo")) return
|
||||
|
||||
const id = type.split("_")[1]?.trim();
|
||||
const proboId = `probo_${id}`;
|
||||
|
||||
let status: ("modified" | "saved" | "error")
|
||||
|
||||
logseq.provideModel({
|
||||
async createOrUpdateQuiz() {
|
||||
const parentBlock = await logseq.Editor.getBlock(payload.uuid, { includeChildren: true });
|
||||
const answers = parentBlock.children.map((answer: BlockEntity, i: number) => {
|
||||
return { text: answer.content, correct: (i == 0) ? true : false }
|
||||
})
|
||||
|
||||
const quiz = {
|
||||
question: { text: sanitizeBlockContent(parentBlock.content) },
|
||||
answers: answers
|
||||
}
|
||||
|
||||
if (parentBlock.properties.proboQuizUuid) {
|
||||
const res = await fetch(endpoint + `/update/${parentBlock.properties.proboQuizUuid}`, { method: 'PUT', body: JSON.stringify(quiz) })
|
||||
const data = await res.json();
|
||||
await logseq.Editor.upsertBlockProperty(parentBlock.uuid, `probo-quiz-uuid`, data.content.ID)
|
||||
render(proboId, slot, "saved")
|
||||
} else {
|
||||
const res = await fetch(endpoint + '/create', { method: 'POST', body: JSON.stringify(quiz) })
|
||||
const data = await res.json();
|
||||
await logseq.Editor.upsertBlockProperty(parentBlock.uuid, `probo-quiz-uuid`, data.content.ID)
|
||||
render(proboId, slot, "saved")
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
logseq.provideStyle(`
|
||||
.renderBtn {
|
||||
border: 1px solid white;
|
||||
border-radius: 8px;
|
||||
padding: 5px;
|
||||
margin-right: 5px;
|
||||
font-size: 80%;
|
||||
background-color: black;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.renderBtn:hover {
|
||||
background-color: white;
|
||||
color: black;
|
||||
}
|
||||
`);
|
||||
|
||||
logseq.provideUI({
|
||||
key: `${proboId}`,
|
||||
slot,
|
||||
reset: true,
|
||||
template: `<button data-on-click="createOrUpdateQuiz" class="renderBtn">Save</button>`,
|
||||
});
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
logseq.ready(main).catch(console.error);
|
Loading…
Reference in a new issue