feat(group): Added group management functionality
- Added database interaction logic, supported inserting new group data, and integrated the Tauri SQL plugin for local data storage - Added a floating button on the nodes page to redirect to the addGroup page - Modified the app icon and title to improve the user experience - Adjusted the Tauri configuration file, optimized window settings, and app identifiers
This commit is contained in:
@@ -2,9 +2,9 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<link rel="icon" type="image/svg+xml" href="/src/assets/logo.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Tauri + Vue + Typescript App</title>
|
||||
<title>Spary🌊</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
11
package.json
11
package.json
@@ -12,13 +12,15 @@
|
||||
"dependencies": {
|
||||
"@fontsource/roboto": "5.2.7",
|
||||
"@mdi/font": "7.4.47",
|
||||
"@tauri-apps/api": "^2",
|
||||
"@tauri-apps/plugin-opener": "^2",
|
||||
"@tauri-apps/plugin-sql": "~2",
|
||||
"vue": "^3.5.21",
|
||||
"vue-router": "^4.5.1",
|
||||
"vuetify": "^3.10.1",
|
||||
"@tauri-apps/api": "^2",
|
||||
"@tauri-apps/plugin-opener": "^2"
|
||||
"vuetify": "^3.10.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tauri-apps/cli": "^2",
|
||||
"@tsconfig/node22": "^22.0.0",
|
||||
"@types/node": "^22.9.0",
|
||||
"@vitejs/plugin-vue": "^6.0.1",
|
||||
@@ -33,7 +35,6 @@
|
||||
"unplugin-vue-router": "^0.15.0",
|
||||
"vite": "^7.1.5",
|
||||
"vite-plugin-vuetify": "^2.1.2",
|
||||
"vue-tsc": "^3.0.7",
|
||||
"@tauri-apps/cli": "^2"
|
||||
"vue-tsc": "^3.0.7"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,4 @@ tauri = { version = "2", features = [] }
|
||||
tauri-plugin-opener = "2"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
sea-orm = { version = "2.0.0-rc", features = [ "sqlx-sqlite", "runtime-tokio-native-tls", "macros" ] }
|
||||
once_cell = "1.21.3"
|
||||
|
||||
tauri-plugin-sql = { version = "2", features = ["sqlite"] }
|
||||
|
||||
@@ -2,9 +2,13 @@
|
||||
"$schema": "../gen/schemas/desktop-schema.json",
|
||||
"identifier": "default",
|
||||
"description": "Capability for the main window",
|
||||
"windows": ["main"],
|
||||
"windows": [
|
||||
"main"
|
||||
],
|
||||
"permissions": [
|
||||
"core:default",
|
||||
"opener:default"
|
||||
"opener:default",
|
||||
"sql:default",
|
||||
"sql:allow-execute"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
|
||||
14
src-tauri/src/group.rs
Normal file
14
src-tauri/src/group.rs
Normal file
@@ -0,0 +1,14 @@
|
||||
#[tauri::command]
|
||||
pub fn add_group(
|
||||
group_name: String,
|
||||
group_subscribe_url: Option<String>,
|
||||
group_arguments: Option<String>,
|
||||
) {
|
||||
let message = match (&group_subscribe_url, &group_arguments) {
|
||||
(Some(url), Some(args)) => format!("add_group: {} {} {}", group_name, url, args),
|
||||
(Some(url), None) => format!("add_group: {} {}", group_name, url),
|
||||
(None, Some(args)) => format!("add_group: {} {}", group_name, args),
|
||||
(None, None) => format!("add_group: {}", group_name),
|
||||
};
|
||||
println!("{}", message);
|
||||
}
|
||||
@@ -1,13 +1,29 @@
|
||||
// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
|
||||
|
||||
use crate::group::add_group;
|
||||
use crate::spary::spary_switch;
|
||||
use tauri_plugin_sql::{Migration, MigrationKind};
|
||||
mod group;
|
||||
mod spary;
|
||||
|
||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||
pub fn run() {
|
||||
let migrations = vec![
|
||||
Migration {
|
||||
version: 1,
|
||||
description: "create_initial_tables",
|
||||
sql: "CREATE TABLE `group`(id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR(60) NOT NULL,url TEXT NULL, arguments JSON NOT NULL default '{}', created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP)",
|
||||
kind: MigrationKind::Up,
|
||||
}
|
||||
];
|
||||
tauri::Builder::default()
|
||||
.plugin(
|
||||
tauri_plugin_sql::Builder::default()
|
||||
.add_migrations("sqlite:spary.db", migrations)
|
||||
.build(),
|
||||
)
|
||||
.plugin(tauri_plugin_opener::init())
|
||||
.invoke_handler(tauri::generate_handler![spary_switch])
|
||||
.invoke_handler(tauri::generate_handler![spary_switch, add_group])
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
}
|
||||
|
||||
@@ -1,14 +1,7 @@
|
||||
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
|
||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||
|
||||
use once_cell::sync::OnceCell;
|
||||
use sea_orm::DatabaseConnection;
|
||||
|
||||
mod entity;
|
||||
|
||||
static DB: OnceCell<DatabaseConnection> = OnceCell::new();
|
||||
|
||||
|
||||
fn main() {
|
||||
spary_lib::run()
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
|
||||
#[tauri::command]
|
||||
pub fn spary_switch(status:bool) {
|
||||
pub fn spary_switch(status: bool) {
|
||||
println!("Spraying {status}");
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"$schema": "https://schema.tauri.app/config/2",
|
||||
"productName": "spary",
|
||||
"version": "0.1.0",
|
||||
"identifier": "com.tain.spary",
|
||||
"identifier": "one.tain.spary",
|
||||
"build": {
|
||||
"beforeDevCommand": "yarn dev",
|
||||
"devUrl": "http://localhost:1420",
|
||||
@@ -15,11 +15,6 @@
|
||||
"title": "spary",
|
||||
"width": 800,
|
||||
"height": 600
|
||||
},
|
||||
{
|
||||
"title": "addGroup",
|
||||
"width": 800,
|
||||
"height": 600
|
||||
}
|
||||
],
|
||||
"security": {
|
||||
|
||||
1
src/components.d.ts
vendored
1
src/components.d.ts
vendored
@@ -8,6 +8,7 @@ export {}
|
||||
/* prettier-ignore */
|
||||
declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
AddGroup: typeof import('./components/nodeEdit/addGroup.vue')['default']
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
RouterView: typeof import('vue-router')['RouterView']
|
||||
Spary: typeof import('./components/index/spary.vue')['default']
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<v-container class="fill-height d-flex align-center justify-center" max-width="900">
|
||||
<v-container class="fill-height d-flex align-center justify-center">
|
||||
<div>
|
||||
<v-switch
|
||||
:label="String(functionStatus)"
|
||||
|
||||
122
src/components/nodeEdit/addGroup.vue
Normal file
122
src/components/nodeEdit/addGroup.vue
Normal file
@@ -0,0 +1,122 @@
|
||||
<script setup lang="ts">
|
||||
import {ref, onMounted, computed} from 'vue'
|
||||
import {invoke} from '@tauri-apps/api/core'
|
||||
import Database from '@tauri-apps/plugin-sql'
|
||||
|
||||
const db = ref<any>(null)
|
||||
const db_ready = ref(false)
|
||||
|
||||
onMounted(async () => {
|
||||
db.value = await Database.load('sqlite:spary.db')
|
||||
db_ready.value = true
|
||||
})
|
||||
|
||||
const groupName = ref('')
|
||||
const groupNameRule = [
|
||||
(value: string): boolean | string => {
|
||||
if (value?.length >= 3 && value?.length <= 15) return true
|
||||
return 'Group name must be between 3 and 15 characters.'
|
||||
},
|
||||
]
|
||||
|
||||
const groupSubscribeUrl = ref<string | null>(null)
|
||||
const groupSubscribeUrlRule = [
|
||||
(value: string): boolean | string => {
|
||||
if (!value) {
|
||||
return true
|
||||
}
|
||||
try {
|
||||
new URL(value)
|
||||
return true
|
||||
} catch (e) {
|
||||
return 'URL is not valid.'
|
||||
}
|
||||
},
|
||||
]
|
||||
|
||||
const groupArguments = ref<string | null>(null)
|
||||
const isAdding = ref(false)
|
||||
|
||||
const isAddDisabled = computed(() => {
|
||||
return !groupName.value || groupName.value.length < 3 || groupName.value.length > 15 || isAdding.value || !db_ready.value
|
||||
})
|
||||
|
||||
async function addGroup() {
|
||||
if (!isAddDisabled.value) {
|
||||
add_group(groupName.value, groupSubscribeUrl.value, groupArguments.value)
|
||||
|
||||
const check_repeat_one = await db.value.select(
|
||||
"SELECT * FROM `group` WHERE name = ?",
|
||||
[groupName.value]
|
||||
)
|
||||
console.log(check_repeat_one)
|
||||
if (check_repeat_one.length > 0) {
|
||||
alert("Group already exists.")
|
||||
return
|
||||
}
|
||||
|
||||
let add_result
|
||||
const params = [groupName.value];
|
||||
let sqlStmt = "INSERT INTO `group` (name";
|
||||
|
||||
if (groupSubscribeUrl.value) {
|
||||
sqlStmt += ", url";
|
||||
params.push(groupSubscribeUrl.value);
|
||||
}
|
||||
|
||||
if (groupArguments.value) {
|
||||
sqlStmt += ", arguments";
|
||||
params.push(groupArguments.value);
|
||||
}
|
||||
|
||||
sqlStmt += ") VALUES (" + params.map(() => "?").join(", ") + ")";
|
||||
add_result = await db.value.execute(sqlStmt, params);
|
||||
|
||||
if (add_result.rowsAffected > 0) {
|
||||
alert("Group added.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function add_group(groupName: string, groupSubscribeUrl: string | null, groupArguments: string | null) {
|
||||
isAdding.value = true
|
||||
try {
|
||||
await invoke("add_group", {groupName, groupSubscribeUrl, groupArguments})
|
||||
} finally {
|
||||
isAdding.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-container>
|
||||
<v-sheet class="mx-auto" width="80vw">
|
||||
<v-form fast-fail @submit.prevent>
|
||||
<v-text-field
|
||||
v-model="groupName"
|
||||
:rules="groupNameRule"
|
||||
label="Group name"
|
||||
></v-text-field>
|
||||
|
||||
<v-text-field
|
||||
v-model="groupSubscribeUrl"
|
||||
:rules="groupSubscribeUrlRule"
|
||||
label="Subscribe URL"
|
||||
></v-text-field>
|
||||
<v-textarea
|
||||
v-model="groupArguments"
|
||||
label="Arguments"
|
||||
></v-textarea>
|
||||
<v-btn
|
||||
class="mt-2"
|
||||
type="submit"
|
||||
block
|
||||
:disabled="isAddDisabled"
|
||||
:loading="isAdding"
|
||||
@click="addGroup">
|
||||
Add
|
||||
</v-btn>
|
||||
</v-form>
|
||||
</v-sheet>
|
||||
</v-container>
|
||||
</template>
|
||||
7
src/pages/addGroup.vue
Normal file
7
src/pages/addGroup.vue
Normal file
@@ -0,0 +1,7 @@
|
||||
<template>
|
||||
<add-group/>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import AddGroup from '../components/nodeEdit/addGroup.vue'
|
||||
</script>
|
||||
@@ -1,11 +1,36 @@
|
||||
<script setup lang="ts">
|
||||
import {useRouter} from "vue-router";
|
||||
const router = useRouter()
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
<div class="fab-fixed">
|
||||
<v-speed-dial location="left top" transition="slide-y-transition">
|
||||
<template v-slot:activator="{ props: activatorProps }">
|
||||
<v-fab v-bind="activatorProps" size="large" icon="mdi-plus"></v-fab>
|
||||
</template>
|
||||
<v-btn key="1" prepend-icon="mdi-group"
|
||||
@click="router.push('/addGroup')">
|
||||
<template v-slot:prepend>
|
||||
<v-icon color="success"></v-icon>
|
||||
</template>
|
||||
add group
|
||||
</v-btn>
|
||||
<v-btn key="2" prepend-icon="mdi-airplane-marker">
|
||||
<template v-slot:prepend>
|
||||
<v-icon color="success"></v-icon>
|
||||
</template>
|
||||
add node
|
||||
</v-btn>
|
||||
</v-speed-dial>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.fab-fixed {
|
||||
position: fixed;
|
||||
bottom: 16px;
|
||||
right: 16px;
|
||||
}
|
||||
</style>
|
||||
5
src/typed-router.d.ts
vendored
5
src/typed-router.d.ts
vendored
@@ -19,6 +19,7 @@ declare module 'vue-router/auto-routes' {
|
||||
*/
|
||||
export interface RouteNamedMap {
|
||||
'/': RouteRecordInfo<'/', '/', Record<never, never>, Record<never, never>>,
|
||||
'/addGroup': RouteRecordInfo<'/addGroup', '/addGroup', Record<never, never>, Record<never, never>>,
|
||||
'/nodes': RouteRecordInfo<'/nodes', '/nodes', Record<never, never>, Record<never, never>>,
|
||||
'/settings': RouteRecordInfo<'/settings', '/settings', Record<never, never>, Record<never, never>>,
|
||||
}
|
||||
@@ -38,6 +39,10 @@ declare module 'vue-router/auto-routes' {
|
||||
routes: '/'
|
||||
views: never
|
||||
}
|
||||
'src/pages/addGroup.vue': {
|
||||
routes: '/addGroup'
|
||||
views: never
|
||||
}
|
||||
'src/pages/nodes.vue': {
|
||||
routes: '/nodes'
|
||||
views: never
|
||||
|
||||
@@ -585,7 +585,7 @@
|
||||
estraverse "^5.3.0"
|
||||
picomatch "^4.0.3"
|
||||
|
||||
"@tauri-apps/api@^2", "@tauri-apps/api@^2.8.0":
|
||||
"@tauri-apps/api@^2", "@tauri-apps/api@^2.6.0", "@tauri-apps/api@^2.8.0":
|
||||
version "2.8.0"
|
||||
resolved "https://registry.yarnpkg.com/@tauri-apps/api/-/api-2.8.0.tgz#0348a2b3ba5982ec67a7d569f329b4a55d7d5f1e"
|
||||
integrity sha512-ga7zdhbS2GXOMTIZRT0mYjKJtR9fivsXzsyq5U3vjDL0s6DTMwYRm0UHNjzTY5dh4+LSC68Sm/7WEiimbQNYlw==
|
||||
@@ -669,6 +669,13 @@
|
||||
dependencies:
|
||||
"@tauri-apps/api" "^2.8.0"
|
||||
|
||||
"@tauri-apps/plugin-sql@~2":
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@tauri-apps/plugin-sql/-/plugin-sql-2.3.0.tgz#36a5fca276877c051380df4a506622aaddedbcf9"
|
||||
integrity sha512-JYwIocfsLaDWa41LMiZWuzts7yCJR+EpZPRmgpO7Gd7XiAS9S67dKz306j/k/d9XntB0YopMRBol2OIWMschuA==
|
||||
dependencies:
|
||||
"@tauri-apps/api" "^2.6.0"
|
||||
|
||||
"@tsconfig/node22@^22.0.0":
|
||||
version "22.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@tsconfig/node22/-/node22-22.0.2.tgz#1e04e2c5cc946dac787d69bb502462a851ae51b6"
|
||||
|
||||
Reference in New Issue
Block a user