Skip to content

Commit

Permalink
Merge branch 'develop' into feature/#1207-broadcast-callback
Browse files Browse the repository at this point in the history
  • Loading branch information
FredLL-Avaiga authored Jul 1, 2024
2 parents 2555dd8 + c5618f1 commit 9af19ae
Show file tree
Hide file tree
Showing 29 changed files with 256 additions and 106 deletions.
12 changes: 7 additions & 5 deletions .github/workflows/frontend.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,15 @@ jobs:
- if: steps.cache-gui-fe-build.outputs.cache-hit != 'true'
run: npm run build --if-present

- run: npm test
- if: steps.cache-gui-fe-build.outputs.cache-hit != 'true'
run: npm test

- name: Code coverage
if: matrix.os == 'ubuntu-latest' && github.event_name == 'pull_request'
uses: artiomtr/jest-coverage-report-action@v2.2.6
if: matrix.os == 'ubuntu-latest' && github.event_name == 'pull_request' && steps.cache-gui-fe-build.outputs.cache-hit != 'true'
uses: artiomtr/jest-coverage-report-action@v2.3.0
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
threshold: "80"
working-directory: "frontend/taipy-gui"
skip-step: "install"
working-directory: "./frontend/taipy-gui"
skip-step: install
annotations: failed-tests
1 change: 1 addition & 0 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ numpy = "<2.0.0"
freezegun = "*"
ipython = "*"
ipykernel = "*"
markdownify = "*"
mkdocs = "*"
mkdocs-autorefs = "*"
mkdocs-include-markdown-plugin = "*"
Expand Down
6 changes: 4 additions & 2 deletions frontend/taipy-gui/base/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export class TaipyApp {
appId: string;
clientId: string;
context: string;
metadata: Record<string, unknown>;
path: string | undefined;
routes: Route[] | undefined;
wsAdapters: WsAdapter[];
Expand All @@ -41,6 +42,7 @@ export class TaipyApp {
this.functionData = undefined;
this.clientId = "";
this.context = "";
this.metadata = {};
this.appId = "";
this.routes = undefined;
this.path = path;
Expand Down Expand Up @@ -162,7 +164,7 @@ export class TaipyApp {
if (!path || path === "") {
path = window.location.pathname.slice(1);
}
sendWsMessage(this.socket, "GMC", "get_module_context", { path: path }, this.clientId);
sendWsMessage(this.socket, "GMC", "get_module_context", { path: path || "/" }, this.clientId);
}

trigger(actionName: string, triggerId: string, payload: Record<string, unknown> = {}) {
Expand All @@ -175,7 +177,7 @@ export class TaipyApp {
}

getPageMetadata() {
return JSON.parse(localStorage.getItem("tp_cp_meta") || "{}");
return this.metadata;
}
}

Expand Down
1 change: 0 additions & 1 deletion frontend/taipy-gui/base/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,4 @@ export type { OnChangeHandler, OnInitHandler, ModuleData };

window.addEventListener("beforeunload", () => {
document.cookie = "tprh=;path=/;Max-Age=-99999999;";
localStorage.removeItem("tp_cp_meta");
});
12 changes: 9 additions & 3 deletions frontend/taipy-gui/base/src/wsAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,15 @@ export class TaipyWsAdapter extends WsAdapter {
taipyApp.clientId = id;
taipyApp.updateContext(taipyApp.path);
} else if (message.type === "GMC") {
const mc = (message.payload as Record<string, unknown>).data as string;
window.localStorage.setItem("ModuleContext", mc);
taipyApp.context = mc;
const payload = message.payload as Record<string, unknown>;
taipyApp.context = payload.context as string;
if (payload?.metadata) {
try {
taipyApp.metadata = JSON.parse((payload.metadata as string) || "{}");
} catch (e) {
console.error("Error parsing metadata from Taipy Designer", e);
}
}
} else if (message.type === "GDT") {
const payload = message.payload as Record<string, ModuleData>;
const variableData = payload.variable;
Expand Down
Binary file modified frontend/taipy-gui/public/favicon.ico
Binary file not shown.
Binary file modified frontend/taipy-gui/public/favicon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion frontend/taipy-gui/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="manifest" href="manifest.json" />
<link rel="icon" type="image/png" href="{{favicon}}" />
<link rel="icon" type="image/png" href="favicon.png" class="taipy-favicon" data-url="{{favicon}}" />
<link rel="apple-touch-icon" href="favicon.png" />
<title>{{title}}</title>
<script>{%- if config -%}
Expand Down
6 changes: 1 addition & 5 deletions frontend/taipy-gui/src/components/Taipy/Navigate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const Navigate = ({ to, params, tab, force }: NavigateProps) => {
const { dispatch, state } = useContext(TaipyContext);
const navigate = useNavigate();
const location = useLocation();
const SPECIAL_PARAMS = ["tp_reload_all", "tp_reload_same_route_only", "tprh", "tp_cp_meta"];
const SPECIAL_PARAMS = ["tp_reload_all", "tp_reload_same_route_only", "tprh"];

useEffect(() => {
if (to) {
Expand Down Expand Up @@ -65,10 +65,6 @@ const Navigate = ({ to, params, tab, force }: NavigateProps) => {
if (tprh !== undefined) {
// Add a session cookie for the resource handler id
document.cookie = `tprh=${tprh};path=/;`;
const meta = params?.tp_cp_meta;
if (meta !== undefined) {
localStorage.setItem("tp_cp_meta", meta);
}
navigate(0);
}
}
Expand Down
5 changes: 4 additions & 1 deletion frontend/taipy-gui/src/context/taipyReducers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { stylekitModeThemes, stylekitTheme } from "../themes/stylekit";
import { getBaseURL, TIMEZONE_CLIENT } from "../utils";
import { parseData } from "../utils/dataFormat";
import { MenuProps } from "../utils/lov";
import { getLocalStorageValue, IdMessage, storeClientId } from "./utils";
import { changeFavicon, getLocalStorageValue, IdMessage, storeClientId } from "./utils";
import { ligthenPayload, sendWsMessage, TAIPY_CLIENT_ID, WsMessage } from "./wsUtils";

enum Types {
Expand Down Expand Up @@ -228,6 +228,8 @@ const messageToAction = (message: WsMessage) => {
return createPartialAction((message as unknown as Record<string, string>).name, true);
} else if (message.type === "ACK") {
return createAckAction((message as unknown as IdMessage).id);
} else if (message.type === "FV") {
changeFavicon((message.payload as Record<string, string>)?.value);
}
}
return {} as TaipyBaseAction;
Expand Down Expand Up @@ -278,6 +280,7 @@ export const initializeWebSocket = (socket: Socket | undefined, dispatch: Dispat
socket.on("message", getWsMessageListener(dispatch));
// only now does the socket tries to open/connect
socket.connect();
changeFavicon();
}
};

Expand Down
20 changes: 20 additions & 0 deletions frontend/taipy-gui/src/context/utils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import axios from "axios";
import { TAIPY_CLIENT_ID } from "./wsUtils";

export const getLocalStorageValue = <T = string>(key: string, defaultValue: T, values?: T[]) => {
Expand All @@ -10,3 +11,22 @@ export const storeClientId = (id: string) => localStorage && localStorage.setIte
export interface IdMessage {
id: string;
}

export const changeFavicon = (url?: string) => {
const link: HTMLLinkElement | null = document.querySelector("link.taipy-favicon");
if (link) {
const { url: taipyUrl } = link.dataset;
const fetchUrl = url || (taipyUrl as string);
axios
.get(fetchUrl)
.then(() => {
link.href = fetchUrl;
})
.catch((error) => {
if (fetchUrl !== taipyUrl) {
link.href = taipyUrl as string;
}
console.log(error);
});
}
};
3 changes: 2 additions & 1 deletion frontend/taipy-gui/src/context/wsUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ export type WsMessageType =
| "GMC"
| "GDT"
| "AID"
| "GR";
| "GR"
| "FV";

export interface WsMessage {
type: WsMessageType;
Expand Down
85 changes: 44 additions & 41 deletions taipy/core/_entity/_migrate/_migrate_sql.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import os
import shutil
import sqlite3
from contextlib import closing
from typing import Dict, Tuple

from taipy.logger._taipy_logger import _TaipyLogger
Expand All @@ -24,32 +25,34 @@

def _load_all_entities_from_sql(db_file: str) -> Tuple[Dict, Dict]:
conn = sqlite3.connect(db_file)
query = "SELECT model_id, document FROM taipy_model"
query_version = "SELECT * FROM taipy_version"
cursor = conn.execute(query)
entities = {}
versions = {}

for row in cursor:
_id = row[0]
document = row[1]
entities[_id] = {"data": json.loads(document)}

cursor = conn.execute(query_version)
for row in cursor:
id = row[0]
config_id = row[1]
creation_date = row[2]
is_production = row[3]
is_development = row[4]
is_latest = row[5]
versions[id] = {
"config_id": config_id,
"creation_date": creation_date,
"is_production": is_production,
"is_development": is_development,
"is_latest": is_latest,
}
with closing(conn):
query = "SELECT model_id, document FROM taipy_model"
query_version = "SELECT * FROM taipy_version"
cursor = conn.execute(query)
entities = {}
versions = {}

for row in cursor:
_id = row[0]
document = row[1]
entities[_id] = {"data": json.loads(document)}

cursor = conn.execute(query_version)
for row in cursor:
id = row[0]
config_id = row[1]
creation_date = row[2]
is_production = row[3]
is_development = row[4]
is_latest = row[5]
versions[id] = {
"config_id": config_id,
"creation_date": creation_date,
"is_production": is_production,
"is_development": is_development,
"is_latest": is_latest,
}

return entities, versions


Expand Down Expand Up @@ -123,21 +126,21 @@ def __insert_version(version: dict, conn):

def __write_entities_to_sql(_entities: Dict, _versions: Dict, db_file: str):
conn = sqlite3.connect(db_file)

for k, entity in _entities.items():
if "SCENARIO" in k:
__insert_scenario(entity["data"], conn)
elif "TASK" in k:
__insert_task(entity["data"], conn)
elif "DATANODE" in k:
__insert_datanode(entity["data"], conn)
elif "JOB" in k:
__insert_job(entity["data"], conn)
elif "CYCLE" in k:
__insert_cycle(entity["data"], conn)

for _, version in _versions.items():
__insert_version(version, conn)
with closing(conn):
for k, entity in _entities.items():
if "SCENARIO" in k:
__insert_scenario(entity["data"], conn)
elif "TASK" in k:
__insert_task(entity["data"], conn)
elif "DATANODE" in k:
__insert_datanode(entity["data"], conn)
elif "JOB" in k:
__insert_job(entity["data"], conn)
elif "CYCLE" in k:
__insert_cycle(entity["data"], conn)

for _, version in _versions.items():
__insert_version(version, conn)


def _restore_migrate_sql_entities(path: str) -> bool:
Expand Down
4 changes: 2 additions & 2 deletions taipy/core/data/csv.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ def _write(self, data: Any):
)
else:
self._convert_data_to_dataframe(exposed_type, data).to_csv(
self._path, index=False, encoding=self.properties[self.__ENCODING_KEY], header=None
self._path, index=False, encoding=self.properties[self.__ENCODING_KEY], header=False
)

def write_with_column_names(self, data: Any, columns: Optional[List[str]] = None, job_id: Optional[JobId] = None):
Expand All @@ -201,6 +201,6 @@ def write_with_column_names(self, data: Any, columns: Optional[List[str]] = None
"""
df = self._convert_data_to_dataframe(self.properties[self._EXPOSED_TYPE_PROPERTY], data)
if columns and isinstance(df, pd.DataFrame):
df.columns = columns
df.columns = pd.Index(columns, dtype="object")
df.to_csv(self._path, index=False, encoding=self.properties[self.__ENCODING_KEY])
self.track_edit(timestamp=datetime.now(), job_id=job_id)
2 changes: 1 addition & 1 deletion taipy/core/data/excel.py
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ def __write_excel_with_multiple_sheets(self, data: Any, columns: List[str] = Non
if columns:
data[key].columns = columns

df.to_excel(writer, key, index=False, header=self.properties[self._HAS_HEADER_PROPERTY] or None)
df.to_excel(writer, key, index=False, header=self.properties[self._HAS_HEADER_PROPERTY] or False)

def _write(self, data: Any):
if isinstance(data, Dict):
Expand Down
8 changes: 4 additions & 4 deletions taipy/core/data/parquet.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,10 +214,10 @@ def write_with_kwargs(self, data: Any, job_id: Optional[JobId] = None, **write_k
}
kwargs.update(self.properties[self.__WRITE_KWARGS_PROPERTY])
kwargs.update(write_kwargs)
if isinstance(data, pd.Series):
df = pd.DataFrame(data)
else:
df = self._convert_data_to_dataframe(self.properties[self._EXPOSED_TYPE_PROPERTY], data)

df = self._convert_data_to_dataframe(self.properties[self._EXPOSED_TYPE_PROPERTY], data)
if isinstance(df, pd.Series):
df = pd.DataFrame(df)

# Ensure that the columns are strings, otherwise writing will fail with pandas 1.3.5
df.columns = df.columns.astype(str)
Expand Down
12 changes: 9 additions & 3 deletions taipy/core/data/sql_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
# specific language governing permissions and limitations under the License.

from datetime import datetime, timedelta
from typing import Any, Dict, List, Optional, Set
from typing import Any, Dict, List, Optional, Set, Union

import pandas as pd
from sqlalchemy import MetaData, Table
Expand Down Expand Up @@ -146,8 +146,14 @@ def __insert_dicts(cls, data: List[Dict], table: Any, connection: Any, delete_ta
connection.execute(table.insert(), data)

@classmethod
def __insert_dataframe(cls, df: pd.DataFrame, table: Any, connection: Any, delete_table: bool) -> None:
cls.__insert_dicts(df.to_dict(orient="records"), table, connection, delete_table)
def __insert_dataframe(
cls, df: Union[pd.DataFrame, pd.Series], table: Any, connection: Any, delete_table: bool
) -> None:
if isinstance(df, pd.Series):
data = [df.to_dict()]
elif isinstance(df, pd.DataFrame):
data = df.to_dict(orient="records")
cls.__insert_dicts(data, table, connection, delete_table)

@classmethod
def __delete_all_rows(cls, table: Any, connection: Any, delete_table: bool) -> None:
Expand Down
4 changes: 2 additions & 2 deletions taipy/gui/custom/_page.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,13 @@ class ResourceHandler(ABC):
User can implement this class to provide custom resources for the custom pages
"""

id: str = ""
rh_id: str = ""

def __init__(self) -> None:
_ExternalResourceHandlerManager().register(self)

def get_id(self) -> str:
return self.id if id != "" else str(id(self))
return self.rh_id if self.rh_id != "" else str(id(self))

@abstractmethod
def get_resources(self, path: str, taipy_resource_path: str) -> t.Any:
Expand Down
4 changes: 2 additions & 2 deletions taipy/gui/data/array_dict_data_accessor.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ def _get_dataframe(self, value: t.Any) -> t.Union[t.List[pd.DataFrame], pd.DataF
)
elif type_elt is dict:
return [pd.DataFrame(v) for v in value]
elif type_elt == _MapDict:
elif type_elt is _MapDict:
return [pd.DataFrame(v._dict) for v in value]
elif type_elt == pd.DataFrame:
elif type_elt is pd.DataFrame:
return value

elif len(types) == 2 and list in types and pd.DataFrame in types:
Expand Down
Loading

0 comments on commit 9af19ae

Please sign in to comment.