Skip to content

Commit

Permalink
WIP: sheets
Browse files Browse the repository at this point in the history
  • Loading branch information
ananthakumaran committed Jan 7, 2024
1 parent 8236a09 commit 9299cc9
Show file tree
Hide file tree
Showing 32 changed files with 1,534 additions and 118 deletions.
4 changes: 4 additions & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,10 @@ func GetJournalPath() string {
return config.JournalPath
}

func GetSheetDir() string {
return filepath.Dir(GetJournalPath())
}

func GetDBPath() string {
if !filepath.IsAbs(config.DBPath) {
return filepath.Join(GetConfigDir(), config.DBPath)
Expand Down
39 changes: 39 additions & 0 deletions internal/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,45 @@ func Build(db *gorm.DB, enableCompression bool) *gin.Engine {
c.JSON(200, SaveFile(db, ledgerFile))
})

router.GET("/api/sheets/files", func(c *gin.Context) {
c.JSON(200, GetSheets(db))
})

router.POST("/api/sheets/file", func(c *gin.Context) {
var sheetFile SheetFile
if err := c.ShouldBindJSON(&sheetFile); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}

c.JSON(200, GetSheet(sheetFile))
})

router.POST("/api/sheets/file/delete_backups", func(c *gin.Context) {
var sheetFile SheetFile
if err := c.ShouldBindJSON(&sheetFile); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}

c.JSON(200, DeleteSheetBackups(sheetFile))
})

router.POST("/api/sheets/save", func(c *gin.Context) {
if config.GetConfig().Readonly {
c.JSON(200, gin.H{"saved": false, "message": "Readonly mode"})
return
}

var sheetFile SheetFile
if err := c.ShouldBindJSON(&sheetFile); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}

c.JSON(200, SaveSheetFile(db, sheetFile))
})

router.GET("/api/account/tf_idf", func(c *gin.Context) {
c.JSON(200, prediction.GetTfIdf(db))
})
Expand Down
148 changes: 148 additions & 0 deletions internal/server/sheet.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
package server

import (
"path/filepath"
"sort"
"time"

"os"

"github.com/ananthakumaran/paisa/internal/config"
"github.com/bmatcuk/doublestar/v4"
"github.com/gin-gonic/gin"
"github.com/samber/lo"
log "github.com/sirupsen/logrus"
"gorm.io/gorm"
)

const EXTENSION = ".paisa"

type SheetFile struct {
Name string `json:"name"`
Content string `json:"content"`
Versions []string `json:"versions"`
Operation string `json:"operation"`
}

func GetSheets(db *gorm.DB) gin.H {
dir := config.GetSheetDir()
paths, _ := doublestar.FilepathGlob(dir + "/**/*" + EXTENSION)

files := []*SheetFile{}
for _, path := range paths {
files = append(files, readSheetFileWithVersions(dir, path))
}

return gin.H{"files": files}
}

func GetSheet(file SheetFile) gin.H {
dir := config.GetSheetDir()
return gin.H{"file": readSheetFile(dir, filepath.Join(dir, file.Name))}
}

func DeleteSheetBackups(file SheetFile) gin.H {
dir := config.GetSheetDir()

if !config.GetConfig().Readonly {
versions, _ := filepath.Glob(filepath.Join(dir, file.Name+".backup.*"))
for _, version := range versions {
err := os.Remove(version)
if err != nil {
log.Fatal(err)
}
}
}

return gin.H{"file": readSheetFileWithVersions(dir, filepath.Join(dir, file.Name))}
}

func SaveSheetFile(db *gorm.DB, file SheetFile) gin.H {
dir := config.GetSheetDir()

filePath := filepath.Join(dir, file.Name)
backupPath := filepath.Join(dir, file.Name+".backup."+time.Now().Format("2006-01-02-15-04-05.000"))

err := os.MkdirAll(filepath.Dir(filePath), 0700)
if err != nil {
log.Warn(err)
return gin.H{"saved": false, "message": "Failed to create directory"}
}

fileStat, err := os.Stat(filePath)
if err != nil && file.Operation != "overwrite" && file.Operation != "create" {
log.Warn(err)
return gin.H{"saved": false, "message": "File does not exist"}
}

var perm os.FileMode = 0644
if err == nil {
if file.Operation == "create" {
return gin.H{"saved": false, "message": "File already exists"}
}

perm = fileStat.Mode().Perm()
existingContent, err := os.ReadFile(filePath)
if err != nil {
log.Warn(err)
return gin.H{"saved": false, "message": "Failed to read file"}
}

err = os.WriteFile(backupPath, existingContent, perm)
if err != nil {
log.Warn(err)
return gin.H{"saved": false, "message": "Failed to create backup"}
}
}

err = os.WriteFile(filePath, []byte(file.Content), perm)
if err != nil {
log.Warn(err)
return gin.H{"saved": false, "message": "Failed to write file"}
}

return gin.H{"saved": true, "file": readSheetFileWithVersions(dir, filePath)}
}

func readSheetFile(dir string, path string) *SheetFile {
content, err := os.ReadFile(path)
if err != nil {
log.Fatal(err)
}

name, err := filepath.Rel(dir, path)

return &SheetFile{
Name: name,
Content: string(content),
}
}

func readSheetFileWithVersions(dir string, path string) *SheetFile {
content, err := os.ReadFile(path)
if err != nil {
log.Fatal(err)
}

versions, _ := filepath.Glob(filepath.Join(filepath.Dir(path), filepath.Base(path)+".backup.*"))
versionPaths := lo.Map(versions, func(path string, _ int) string {
name, err := filepath.Rel(dir, path)
if err != nil {
log.Fatal(err)
}

return name
})
sort.Sort(sort.Reverse(sort.StringSlice(versionPaths)))

name, err := filepath.Rel(dir, path)
if err != nil {
log.Fatal(err)
}

return &SheetFile{
Name: name,
Content: string(content),
Versions: versionPaths,
}
}
14 changes: 14 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
"version": "0.0.1",
"private": true,
"scripts": {
"parser-build": "lezer-generator src/lib/search/parser/query.grammar -o src/lib/search/parser/parser",
"parser-build-debug": "lezer-generator src/lib/search/parser/query.grammar --names -o src/lib/search/parser/parser",
"parser-build": "lezer-generator src/lib/sheet/language.grammar -o src/lib/sheet/parser && lezer-generator src/lib/search/parser/query.grammar -o src/lib/search/parser/parser",
"parser-build-debug": "lezer-generator src/lib/sheet/language.grammar --names -o src/lib/sheet/parser && lezer-generator src/lib/search/parser/query.grammar --names -o src/lib/search/parser/parser",
"dev": "vite dev --host 0.0.0.0",
"build": "vite build",
"build:watch": "vite build --watch",
Expand All @@ -28,6 +28,7 @@
"@lezer/lr": "^1.3.10",
"@types/json-schema": "^7.0.12",
"arima": "^0.2.5",
"bignumber.js": "^9.1.2",
"bulma": "^0.9.4",
"bulma-switch": "^2.0.4",
"bulma-toast": "^2.4.2",
Expand Down
24 changes: 23 additions & 1 deletion src/app.scss
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,10 @@ svg text {
fill: $grey-lighter;
}

.has-background-grey-lightest {
background-color: $grey-lightest;
}

.svg-text-grey-light {
fill: $grey-light;
}
Expand Down Expand Up @@ -374,6 +378,16 @@ svg text {
box-shadow: $shadow;
}

.box.box-r-none {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}

.box.box-l-none {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}

.box {
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.1);
}
Expand Down Expand Up @@ -522,7 +536,7 @@ nav.level.grid-2 {
}

.cm-activeLineGutter {
background-color: $grey-light !important;
background-color: $grey-lightest !important;
color: $grey-dark;
font-weight: bold;
}
Expand Down Expand Up @@ -679,6 +693,14 @@ nav.level.grid-2 {
height: 200px;
}

.sheet-result {
background-color: $white-ter;
color: $grey;
}

.sheet-editor .cm-editor {
}

.search-query-editor {
border: 1px solid $grey-lighter;
border-radius: $radius;
Expand Down
3 changes: 2 additions & 1 deletion src/lib/components/FileModal.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
export let label = "Save As";
export let help = "Create or overwrite existing file";
export let placeholder = "expense.ledger";
export let open = false;
let destinationFile = "";
Expand All @@ -19,7 +20,7 @@
<div class="field" slot="body">
<label class="label" for="save-filename">File Name</label>
<div class="control" id="save-filename">
<input class="input" type="text" placeholder="expense.ledger" bind:value={destinationFile} />
<input class="input" type="text" {placeholder} bind:value={destinationFile} />
<p class="help">{help}</p>
</div>
</div>
Expand Down
1 change: 1 addition & 0 deletions src/lib/components/Navbar.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@
href: "/more",
children: [
{ label: "Configuration", href: "/config", tag: "alpha", help: "config" },
{ label: "Sheets", href: "/sheets" },
{ label: "Goals", href: "/goals", help: "goals" },
{ label: "Doctor", href: "/doctor" },
{ label: "Logs", href: "/logs" }
Expand Down
2 changes: 1 addition & 1 deletion src/lib/import.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { describe, expect, test } from "bun:test";

import { parse, render, asRows } from "./sheet";
import { parse, render, asRows } from "./spreadsheet";
import fs from "fs";
import helpers from "./template_helpers";
import _ from "lodash";
Expand Down
2 changes: 1 addition & 1 deletion src/lib/search/parser/highlight.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { styleTags, tags as t } from "@lezer/highlight";

export const jsonHighlighting = styleTags({
export const queryHighlighting = styleTags({
Quoted: t.string,
UnQuoted: t.string,
Number: t.number,
Expand Down
4 changes: 2 additions & 2 deletions src/lib/search/parser/parser.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions src/lib/search/parser/parser.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { describe, test } from "bun:test";
import { jsonLanguage } from "./query";
import { queryLanguage } from "./query";
import { fileTests } from "@lezer/generator/dist/test";

import * as fs from "fs";
Expand All @@ -13,6 +13,6 @@ for (const file of fs.readdirSync(caseDir)) {
const name = /^[^.]*/.exec(file)[0];
describe(name, () => {
for (const { name, run } of fileTests(fs.readFileSync(path.join(caseDir, file), "utf8"), file))
test(name, () => run(jsonLanguage.parser));
test(name, () => run(queryLanguage.parser));
});
}
2 changes: 1 addition & 1 deletion src/lib/search/parser/query.grammar
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,6 @@ DateValue { "[" dateChar+ "]" }

@skip { whitespace }

@external propSource jsonHighlighting from "./highlight"
@external propSource queryHighlighting from "./highlight"

@detectDelim
Loading

0 comments on commit 9299cc9

Please sign in to comment.