Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use genesis as backend service #22

Merged
merged 15 commits into from
Nov 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 6 additions & 7 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
# Google credentials
OAUTH_URI=
OAUTH_CLIENT_ID=
OAUTH_SCOPE=https://www.googleapis.com/auth/drive.appdata
# Backend host, usually /api if hosted locally and used via proxy
# See https://github.com/simonwep/genesis
OCULAR_GENESIS_HOST=/api

# Ackee tracker details
ACKEE_HOST=
ACKEE_DOMAIN_ID=
# Optional, pre-filled login credentials for local testing
OCULAR_TEST_USERNAME=
OCULAR_TEST_PASSWORD=
59 changes: 36 additions & 23 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@ name: CI

on: push

env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
OCULAR_GENESIS_HOST: /api

jobs:
build:
name: Build app
Expand All @@ -25,12 +30,6 @@ jobs:
run: pnpm run lint

- name: Build
env:
OAUTH_URI: ${{ secrets.OAUTH_URI }}
OAUTH_SCOPE: ${{ secrets.OAUTH_SCOPE }}
OAUTH_CLIENT_ID: ${{ secrets.OAUTH_CLIENT_ID }}
ACKEE_HOST: ${{ secrets.ACKEE_HOST }}
ACKEE_DOMAIN_ID: ${{ secrets.ACKEE_DOMAIN_ID }}
run: pnpm run build

- name: Upload artifact
Expand All @@ -40,26 +39,40 @@ jobs:
name: app
path: dist

deploy:
name: Deploy app to GitHub Pages
runs-on: ubuntu-latest
build_docker:
if: startsWith(github.event.ref, 'refs/tags/v')
name: Build and publish docker image
needs: build
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v3
- name: Download artifact
uses: actions/download-artifact@v3
- name: Checkout repository
uses: actions/checkout@v4

- name: Log in to the Container registry
uses: docker/login-action@v3
with:
name: app
path: dist
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Pre-Deploy
run: |
cp dist/index.html dist/404.html
touch dist/.nojekyll
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=semver,pattern=v{{version}}
type=semver,pattern=v{{major}}.{{minor}}

- name: Deploy
uses: JamesIves/github-pages-deploy-action@v4
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
branch: gh-pages
folder: dist
push: true
provenance: false
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
OCULAR_GENESIS_HOST=${{ env.OCULAR_GENESIS_HOST }}
6 changes: 3 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
### Commit guidelines
## Commit guidelines

This project *strictly* follows [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/).
Check out [their explanation](https://www.conventionalcommits.org/en/v1.0.0/#summary) of how to use it.
In this project we have the following scopes / types:

#### Scopes
### Scopes

* `core` - Core code, anything app / user-facing related.
* `setup` - Anything *only* relevant to the build-process / CI.

#### Types
### Types

* `feat` - A new feature.
* `refactor` - A refactoring.
Expand Down
8 changes: 2 additions & 6 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
FROM node:18-alpine AS build
FROM node:20-alpine AS build

ARG OAUTH_URI
ARG OAUTH_CLIENT_ID
ARG OAUTH_SCOPE
ARG ACKEE_HOST
ARG ACKEE_DOMAIN_ID
ARG OCULAR_GENESIS_HOST

ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
Expand Down
64 changes: 21 additions & 43 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,68 +18,46 @@

### Features

- 🥳 Simple login via google.
- 🌚 Dark and light theme.
- 💻 Installable (PWA).
- ⬆️ Import your data from Google sheet's annual planner.
- ️ Export your data as a single `.json`-file.
- 🕰 Track budgets across year.
- 🦾 Self-hosted.
- 🕶️ Dark and light theme.
- 💻 Installable as a PWA.
- 🔼 Import your data from Google sheet's annual planner.
- 🛠️ Export your data as a single `.json`-file.
- 🎇 Track budgets across multiple years.
- 🙈 Privacy mode for when you're in a public place.
- 🪩 Simple and straight-forward UI.
- ⚡️ Simple and straight-forward UI.

> Check out the [demo](https://ocular.reinisch.io#demo)!
> Looking for the legacy google-app based version? Check out the [legacy](https://github.com/simonwep/ocular/tree/legacy) branch.

### Summary

A small budgeting app as an alternative to Google sheet's annual budget planner.
The goal of the app is **not** to track individual expenses, work with multiple currencies at a time or anything related (if you're looking for something like this, check out [firefly-iii](https://www.firefly-iii.org/)).

This app comes without any backend and all your data is stored in your google-drive account as an app (no worry - you can always export your data in the app).
**This app does not have access to anything else except its own files**.
The (latest) version I use is automatically deployed to [ocular.reinisch.io](https://ocular.reinisch.io) - but feel free to [set it up yourself](#development)!

> **Attention:** It's currently **not** possibly to sync the app with your personal gmail account due to the google-cloud app not being verified yet.
> You can still use it and download / upload your data or [deploy it yourself](#development) (which is even cooler!).
This app comes with its own backend (by using [genesis](https://github.com/simonwep/genesis)), so the only thing you need to do is to host it somewhere.
Your data stays on your server and is not shared with anyone else.

### State of this project

I consider the current state of it as the MVP for personal use.
But I'm planning on adding more [features](https://github.com/Simonwep/ocular/issues) - I'm not planning of making it any more in-depth as it already is, planned features may only include adding a way to define goals or general improvements for mobile usage.
As I already said, if you're looking for an in-depth tool to manage your finances check out [firefly](https://www.firefly-iii.org/)!

### Contributing

If you want to work on this, make sure to out the [contributing guidelines](CONTRIBUTING.md) :)
Furthermore this project *does not* have releases.
Because of its simplicity the master branch is considered stable and any new feature will directly be merged into it.

#### Development

This app requires [NodeJS LTS](https://nodejs.org/en/) and uses [vite](https://vitejs.dev/) as builder.
You can build and preview the app using the following commands:
### Development

```sh
npm run build
npm run preview
```
This app uses [genesis](https://github.com/simonwep/genesis) as generic backend.
Go to the [genesis](https://github.com/simonwep/genesis) repository and follow the instructions to set it up first.

To work on it simply run `npm run dev`.
To run the frontend make sure you have the latest [node LTS](https://nodejs.org/en/) installed, as well as [pnpm](https://pnpm.io/).
You can then start the frontend by running `pnpm run dev` in the root directory.

#### Production
### Production

To run this app in production and to add cloud connectivity, you'll need a [Google Cloud App](https://console.cloud.google.com) with
the `drive.appdata` scope.
This app is deployed using [docker-compose](https://docs.docker.com/compose/).
See [ocular-docker](https://github.com/simonwep/ocular-docker) for deployment.

After you've set up your app fill copy the [.env.example](.env.example) to `.env` and fill in your credentials.


##### Using docker

This project can be build as a docker-image, that serves the app via nginx.
You can build and run it via:

```sh
docker build -t ocular . && docker run -p 8080:80 ocular
```
### Contributing

Ocular should then be available under [localhost:8080](http://localhost:8080)
If you want to work on this, make sure to out the [contributing guidelines](CONTRIBUTING.md) :)
Other than that, follow the steps under [development](#development) to get started.
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,11 @@
"lint:i18n:fix": "pnpm run lint:i18n --fix",
"lint": "pnpm run lint:i18n && pnpm run lint:src",
"lint:fix": "pnpm run lint:i18n:fix && pnpm run lint:src:fix",
"test:ci": "pnpm run build && pnpm run lint:fix",
"test:ci": "pnpm run lint:fix && pnpm run build",
"gen:icons": "node scripts/icons.js"
},
"dependencies": {
"@popperjs/core": "2.11.8",
"ackee-tracker": "5.1.0",
"echarts": "5.4.3",
"li18nt": "5.0.0",
"papaparse": "5.4.1",
Expand Down
32 changes: 5 additions & 27 deletions pnpm-lock.yaml

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

2 changes: 1 addition & 1 deletion src/app/App.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<div ref="root" :class="$style.app">
<LoadingScreen
:loading="storage.state.status === 'loading'"
:loading="storage.status.value === 'loading'"
:class="$style.root"
:import="() => import('./pages/Frame.vue')"
/>
Expand Down
1 change: 1 addition & 0 deletions src/app/components/base/alert/Alert.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type AlertType = 'error' | 'success' | 'warning';
48 changes: 48 additions & 0 deletions src/app/components/base/alert/Alert.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<template>
<p :class="[$style.alert, classes]">
<Icon :class="$style.icon" :icon="mapping[type][1]" />
<span>{{ text }}</span>
</p>
</template>

<script lang="ts" setup>
import { computed } from 'vue';
import { AlertType } from '@components/base/alert/Alert.types';
import { AppIcon } from '@components/base/icon/Icon.types';
import Icon from '@components/base/icon/Icon.vue';
import { Color, useThemeStyles } from '@composables';
import { ClassNames } from '@utils';

const props = defineProps<{
class?: ClassNames;
text: string;
type: AlertType;
}>();

const mapping: Record<AlertType, [Color, AppIcon]> = {
error: ['danger', 'error-warning-line'],
success: ['success', 'check'],
warning: ['warning', 'error-warning-line']
};

const classes = computed(() => props.class);
const theme = useThemeStyles(() => mapping[props.type][0]);
</script>

<style lang="scss" module>
.alert {
display: flex;
gap: 4px;
color: v-bind('theme.color.base');
border: 2px dashed v-bind('theme.color.base');
padding: 4px 6px;
font-weight: var(--font-weight-l);
font-size: var(--font-size-xs);
border-radius: var(--border-radius-m);

.icon {
width: 17px;
flex-shrink: 0;
}
}
</style>
Loading