FIX: users :)

This commit is contained in:
Nicolás Hatcher
2025-06-02 18:32:43 +02:00
parent 7635cbe1d1
commit abaeb3284a
13 changed files with 122 additions and 16 deletions

2
Cargo.lock generated
View File

@@ -1069,7 +1069,7 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasm"
version = "0.5.0"
version = "0.5.3"
dependencies = [
"ironcalc_base",
"serde",

View File

@@ -405,6 +405,7 @@ impl Model {
},
tables: HashMap::new(),
views,
users: Vec::new(),
};
let parsed_formulas = Vec::new();
let worksheets = &workbook.worksheets;

View File

@@ -39,6 +39,14 @@ pub struct WorkbookView {
pub window_height: i64,
}
#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
pub struct WebUser {
pub id: String,
pub sheet: u32,
pub row: i32,
pub column: i32,
}
/// An internal representation of an IronCalc Workbook
#[derive(Encode, Decode, Debug, PartialEq, Clone)]
pub struct Workbook {
@@ -51,6 +59,7 @@ pub struct Workbook {
pub metadata: Metadata,
pub tables: HashMap<String, Table>,
pub views: HashMap<u32, WorkbookView>,
pub users: Vec<WebUser>
}
/// A defined name. The `sheet_id` is the sheet index in case the name is local

View File

@@ -14,7 +14,7 @@ use crate::{
model::Model,
types::{
Alignment, BorderItem, CellType, Col, HorizontalAlignment, SheetProperties, SheetState,
Style, VerticalAlignment,
Style, VerticalAlignment, WebUser,
},
utils::is_valid_hex_color,
};
@@ -293,6 +293,11 @@ impl UserModel {
self.model.workbook.name = name.to_string();
}
/// Set users
pub fn set_users(&mut self, users: &[WebUser]) {
self.model.workbook.users = users.to_vec();
}
/// Undoes last change if any, places the change in the redo list and evaluates the model if needed
///
/// See also:

View File

@@ -1,6 +1,6 @@
[package]
name = "wasm"
version = "0.5.0"
version = "0.5.3"
authors = ["Nicolas Hatcher <nicolas@theuniverse.today>"]
description = "IronCalc Web bindings"
license = "MIT/Apache-2.0"

View File

@@ -201,6 +201,36 @@ defined_name_list_types = r"""
getDefinedNameList(): DefinedName[];
"""
set_users = r"""
/**
* @param {any} users
*/
setUsers(users: any): void;
"""
set_users_types = r"""
/**
* @param {WebUser[]} users
*/
setUsers(users: WebUser[]): void;
"""
get_users = r"""
/**
* @returns {any}
*/
getUsers(): any;
}
"""
get_users_types = r"""
/**
* @returns {WebUser[]}
*/
getUsers(): WebUser[];
}
"""
def fix_types(text):
text = text.replace(get_tokens_str, get_tokens_str_types)
text = text.replace(update_style_str, update_style_str_types)
@@ -215,6 +245,8 @@ def fix_types(text):
text = text.replace(clipboard, clipboard_types)
text = text.replace(paste_from_clipboard, paste_from_clipboard_types)
text = text.replace(defined_name_list, defined_name_list_types)
text = text.replace(set_users, set_users_types)
text = text.replace(get_users, get_users_types)
with open("types.ts") as f:
types_str = f.read()
header_types = "{}\n\n{}".format(header, types_str)

View File

@@ -6,7 +6,7 @@ use wasm_bindgen::{
use ironcalc_base::{
expressions::{lexer::util::get_tokens as tokenizer, types::Area, utils::number_to_column},
types::{CellType, Style},
types::{CellType, Style, WebUser},
BorderArea, ClipboardData, UserModel as BaseModel,
};
@@ -672,4 +672,18 @@ impl Model {
.delete_defined_name(name, scope)
.map_err(|e| to_js_error(e.to_string()))
}
#[wasm_bindgen(js_name = "setUsers")]
pub fn set_users(&mut self, users: JsValue) -> Result<(), JsError> {
let users: Vec<WebUser> =
serde_wasm_bindgen::from_value(users).map_err(|e| to_js_error(e.to_string()))?;
self.model.set_users(&users);
Ok(())
}
#[wasm_bindgen(js_name = "getUsers")]
pub fn get_users(&self) -> Result<JsValue, JsError> {
let users = self.model.get_model().workbook.users.clone();
serde_wasm_bindgen::to_value(&users).map_err(|e| to_js_error(e.to_string()))
}
}

View File

@@ -234,3 +234,10 @@ export interface DefinedName {
scope?: number;
formula: string;
}
export interface WebUser {
id: string;
sheet: number;
row: number;
column: number;
}

View File

@@ -1,16 +1,16 @@
{
"name": "@ironcalc/workbook",
"version": "0.5.1",
"version": "0.5.4",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@ironcalc/workbook",
"version": "0.5.1",
"version": "0.5.4",
"dependencies": {
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.0",
"@ironcalc/wasm": "0.5.0",
"@ironcalc/wasm": "0.5.3",
"@mui/material": "^6.4",
"@mui/system": "^6.4",
"i18next": "^23.11.1",
@@ -43,11 +43,6 @@
"react-dom": "^18.0.0 || ^19.0.0"
}
},
"../../bindings/wasm/pkg": {
"name": "@ironcalc/wasm",
"version": "0.5.0",
"license": "MIT/Apache-2.0"
},
"node_modules/@adobe/css-tools": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.2.tgz",
@@ -1060,8 +1055,10 @@
}
},
"node_modules/@ironcalc/wasm": {
"resolved": "../../bindings/wasm/pkg",
"link": true
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/@ironcalc/wasm/-/wasm-0.5.3.tgz",
"integrity": "sha512-ryQKR5ISkSQnnsxBYDnrAUN+GDiAQUx0MzkVpJr7VQXiymOSMZbHfpv5geum1eSJV4gw1ft69syuNolIhVZ4Hg==",
"license": "MIT/Apache-2.0"
},
"node_modules/@isaacs/cliui": {
"version": "8.0.2",

View File

@@ -1,6 +1,6 @@
{
"name": "@ironcalc/workbook",
"version": "0.5.1",
"version": "0.5.4",
"type": "module",
"main": "./dist/ironcalc.js",
"module": "./dist/ironcalc.js",
@@ -17,7 +17,7 @@
"dependencies": {
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.0",
"@ironcalc/wasm": "0.5.0",
"@ironcalc/wasm": "0.5.3",
"@mui/material": "^6.4",
"@mui/system": "^6.4",
"i18next": "^23.11.1",

View File

@@ -11,6 +11,10 @@ interface IronCalcProperties {
}
function IronCalc(properties: IronCalcProperties) {
properties.model.setUsers([
{ id: "john@doe.com", sheet: 0, row: 5, column: 6 },
{ id: "micheal@doe.com", sheet: 0, row: 1, column: 6 },
]);
return (
<ThemeProvider theme={theme}>
<Workbook model={properties.model} workbookState={new WorkbookState()} />

View File

@@ -19,6 +19,13 @@ import {
outlineColor,
} from "./constants";
export interface UserSelection {
userId: string;
color: string;
selection: [number, number, number, number, number]; // [sheet, rowStart, columnStart, rowEnd, columnEnd]
div: HTMLDivElement;
}
export interface CanvasSettings {
model: Model;
width: number;
@@ -1244,6 +1251,34 @@ export default class WorksheetCanvas {
editor.style.height = `${height - 1}px`;
}
private drawUsersSelection(): void {
const users = this.model.getUsers();
for (const handle of document.querySelectorAll(
".user-selection-ironcalc",
))
handle.remove();
const colors = [];
users.forEach((user, index) => {
const { sheet, row, column } = user;
if (sheet !== this.model.getSelectedSheet()) {
return;
}
const [x, y] = this.getCoordinatesByCell(row, column);
const width = this.getColumnWidth(sheet, column);
const height = this.getRowHeight(sheet, row);
const div = document.createElement("div");
const color = getColor(index + 1);
div.className = "user-selection-ironcalc";
div.style.left = `${x}px`;
div.style.top = `${y}px`;
div.style.width = `${width}px`;
div.style.height = `${height}px`;
div.style.border = `1px solid ${color}`;
div.style.position = "absolute";
this.canvas.parentElement?.appendChild(div);
});
}
private drawCellOutline(): void {
const { cellOutline, areaOutline, cellOutlineHandle } = this;
if (this.workbookState.getEditingCell()) {
@@ -1595,6 +1630,7 @@ export default class WorksheetCanvas {
context.stroke();
this.drawCellOutline();
this.drawUsersSelection();
this.drawCellEditor();
this.drawExtendToArea();
this.drawActiveRanges(topLeftCell, bottomRightCell);

View File

@@ -110,6 +110,7 @@ fn load_xlsx_from_reader<R: Read + std::io::Seek>(
metadata,
tables,
views,
users: Vec::new(),
})
}