Merge branch 'develop' of https://github.com/frappe/frappe into ft/add-apply-module-export-filter-on-export-customization
This commit is contained in:
commit
c56a725b53
366 changed files with 30392 additions and 10163 deletions
|
|
@ -96,6 +96,7 @@
|
|||
"hljs": true,
|
||||
"Awesomplete": true,
|
||||
"Sortable": true,
|
||||
"gemoji": true,
|
||||
"Showdown": true,
|
||||
"Taggle": true,
|
||||
"Gantt": true,
|
||||
|
|
|
|||
18
.github/actions/setup/action.yml
vendored
18
.github/actions/setup/action.yml
vendored
|
|
@ -100,10 +100,16 @@ runs:
|
|||
run: |
|
||||
# Install System Dependencies
|
||||
start_time=$(date +%s)
|
||||
curl -LsS https://r.mariadb.com/downloads/mariadb_repo_setup | sudo bash
|
||||
curl -LsS https://r.mariadb.com/downloads/mariadb_repo_setup | sudo bash -s -- --mariadb-server-version="mariadb-11.8.5"
|
||||
|
||||
sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
|
||||
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
|
||||
|
||||
sudo apt -qq update
|
||||
sudo apt -qq remove mysql-server mysql-client
|
||||
sudo apt -qq install libcups2-dev redis-server mariadb-client libmariadb-dev
|
||||
sudo apt -qq remove -y postgresql-client postgresql-client-16 postgresql-client-common
|
||||
sudo apt -qq install libcups2-dev redis-server mariadb-client libmariadb-dev postgresql-client-18 libpq-dev
|
||||
echo "/usr/lib/postgresql/18/bin" >> $GITHUB_PATH
|
||||
|
||||
wget -q -O /tmp/wkhtmltox.deb https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6.1-2/wkhtmltox_0.12.6.1-2.jammy_amd64.deb
|
||||
sudo apt install /tmp/wkhtmltox.deb
|
||||
|
|
@ -169,6 +175,14 @@ runs:
|
|||
mariadb --host 127.0.0.1 --port 3306 -u root -p${{ inputs.db-root-password }} -e "FLUSH PRIVILEGES";
|
||||
fi
|
||||
|
||||
if [ "$DB" == "postgres" ]; then
|
||||
export PGPASSWORD='travis'
|
||||
psql -h 127.0.0.1 -p 5432 -c "CREATE DATABASE test_frappe" -U postgres
|
||||
psql -h 127.0.0.1 -p 5432 -c "CREATE USER test_frappe WITH PASSWORD 'test_frappe'" -U postgres
|
||||
psql -h 127.0.0.1 -p 5432 -U postgres -c "GRANT ALL PRIVILEGES ON DATABASE test_frappe TO test_frappe;"
|
||||
unset PGPASSWORD
|
||||
fi
|
||||
|
||||
- shell: bash -e {0}
|
||||
run: |
|
||||
# Install App(s)
|
||||
|
|
|
|||
18
.github/helper/db/postgres.json
vendored
Normal file
18
.github/helper/db/postgres.json
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"db_host": "127.0.0.1",
|
||||
"db_port": 5432,
|
||||
"db_name": "test_frappe",
|
||||
"db_password": "test_frappe",
|
||||
"db_type": "postgres",
|
||||
"allow_tests": true,
|
||||
"auto_email_id": "test@example.com",
|
||||
"mail_server": "localhost",
|
||||
"mail_port": 2525,
|
||||
"mail_login": "test@example.com",
|
||||
"mail_password": "test",
|
||||
"admin_password": "admin",
|
||||
"root_login": "postgres",
|
||||
"root_password": "travis",
|
||||
"host_name": "http://test_site:8000",
|
||||
"server_script_enabled": true
|
||||
}
|
||||
19
.github/workflows/_base-server-tests.yml
vendored
19
.github/workflows/_base-server-tests.yml
vendored
|
|
@ -9,7 +9,7 @@ on:
|
|||
python-version:
|
||||
required: false
|
||||
type: string
|
||||
default: '3.13'
|
||||
default: '3.14'
|
||||
node-version:
|
||||
required: false
|
||||
type: number
|
||||
|
|
@ -22,6 +22,10 @@ on:
|
|||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
enable-postgres:
|
||||
required: false
|
||||
type: boolean
|
||||
default: true
|
||||
enable-coverage:
|
||||
required: false
|
||||
type: boolean
|
||||
|
|
@ -62,9 +66,20 @@ jobs:
|
|||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
db: ${{ fromJson(inputs.enable-sqlite && '["mariadb", "sqlite"]' || '["mariadb"]') }}
|
||||
db: ${{ fromJson(inputs.enable-sqlite && (inputs.enable-postgres && '["mariadb", "postgres", "sqlite"]' || '["mariadb", "sqlite"]') || (inputs.enable-postgres && '["mariadb", "postgres"]' || '["mariadb"]')) }}
|
||||
index: ${{ fromJson(needs.gen-idx-integration.outputs.indices) }}
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:18.0
|
||||
ports:
|
||||
- 5432:5432
|
||||
env:
|
||||
POSTGRES_PASSWORD: travis
|
||||
options: >-
|
||||
--health-cmd pg_isready
|
||||
--health-interval 10s
|
||||
--health-timeout 5s
|
||||
--health-retries 3
|
||||
mariadb:
|
||||
image: mariadb:11.8
|
||||
ports:
|
||||
|
|
|
|||
2
.github/workflows/_base-type-check.yml
vendored
2
.github/workflows/_base-type-check.yml
vendored
|
|
@ -5,7 +5,7 @@ on:
|
|||
python-version:
|
||||
required: false
|
||||
type: string
|
||||
default: '3.13.0'
|
||||
default: '3.14.0'
|
||||
|
||||
jobs:
|
||||
typecheck:
|
||||
|
|
|
|||
2
.github/workflows/_base-ui-tests.yml
vendored
2
.github/workflows/_base-ui-tests.yml
vendored
|
|
@ -9,7 +9,7 @@ on:
|
|||
python-version:
|
||||
required: false
|
||||
type: string
|
||||
default: '3.13'
|
||||
default: '3.14'
|
||||
node-version:
|
||||
required: false
|
||||
type: number
|
||||
|
|
|
|||
2
.github/workflows/generate-pot-file.yml
vendored
2
.github/workflows/generate-pot-file.yml
vendored
|
|
@ -25,7 +25,7 @@ jobs:
|
|||
- name: Setup Python
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: "3.13"
|
||||
python-version: "3.14"
|
||||
|
||||
- name: Run script to update POT file
|
||||
run: |
|
||||
|
|
|
|||
8
.github/workflows/linters.yml
vendored
8
.github/workflows/linters.yml
vendored
|
|
@ -41,7 +41,7 @@ jobs:
|
|||
- name: 'Setup Environment'
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.13'
|
||||
python-version: '3.14'
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
- name: Validate Docs
|
||||
|
|
@ -60,7 +60,7 @@ jobs:
|
|||
- uses: actions/checkout@v5
|
||||
- uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.13'
|
||||
python-version: '3.14'
|
||||
cache: pip
|
||||
|
||||
- name: Download Semgrep rules
|
||||
|
|
@ -78,7 +78,7 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.13'
|
||||
python-version: '3.14'
|
||||
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
|
|
@ -106,6 +106,6 @@ jobs:
|
|||
- uses: actions/checkout@v5
|
||||
- uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.13'
|
||||
python-version: '3.14'
|
||||
cache: pip
|
||||
- uses: pre-commit/action@v3.0.1
|
||||
|
|
|
|||
2
.github/workflows/on_release.yml
vendored
2
.github/workflows/on_release.yml
vendored
|
|
@ -26,7 +26,7 @@ jobs:
|
|||
|
||||
- uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.13'
|
||||
python-version: '3.14'
|
||||
- name: Set up bench and build assets
|
||||
run: |
|
||||
npm install -g yarn
|
||||
|
|
|
|||
2
.github/workflows/publish-assets-develop.yml
vendored
2
.github/workflows/publish-assets-develop.yml
vendored
|
|
@ -19,7 +19,7 @@ jobs:
|
|||
node-version: 22
|
||||
- uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.13'
|
||||
python-version: '3.14'
|
||||
- name: Set up bench and build assets
|
||||
run: |
|
||||
npm install -g yarn
|
||||
|
|
|
|||
2
.github/workflows/run-indinvidual-tests.yml
vendored
2
.github/workflows/run-indinvidual-tests.yml
vendored
|
|
@ -74,7 +74,7 @@ jobs:
|
|||
- name: Setup Python
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.13'
|
||||
python-version: '3.14'
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v6
|
||||
|
|
|
|||
1
.github/workflows/server-tests.yml
vendored
1
.github/workflows/server-tests.yml
vendored
|
|
@ -44,6 +44,7 @@ jobs:
|
|||
name: Tests
|
||||
uses: ./.github/workflows/_base-server-tests.yml
|
||||
with:
|
||||
enable-postgres: ${{ contains(github.event.pull_request.labels.*.name, 'postgres') }} # This enables PostgreSQL to run tests
|
||||
enable-sqlite: false # This will test against both MariaDB and SQLite if enabled
|
||||
parallel-runs: 2
|
||||
enable-coverage: ${{ github.event_name != 'pull_request' }}
|
||||
|
|
|
|||
|
|
@ -36,5 +36,9 @@ module.exports = defineConfig({
|
|||
testIsolation: false,
|
||||
baseUrl: "http://test_site_ui:8000",
|
||||
specPattern: ["./cypress/integration/*.js", "**/ui_test_*.js"],
|
||||
excludeSpecPattern: [
|
||||
"./cypress/integration/workspace.js",
|
||||
"./cypress/integration/workspace_blocks.js",
|
||||
],
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@ context("Awesome Bar", () => {
|
|||
before(() => {
|
||||
cy.visit("/login");
|
||||
cy.login();
|
||||
cy.visit("/app/todo"); // Make sure ToDo filters are cleared.
|
||||
cy.visit("/desk/todo"); // Make sure ToDo filters are cleared.
|
||||
cy.clear_filters();
|
||||
cy.visit("/app/web-page"); // Make sure Blog Post filters are cleared.
|
||||
cy.visit("/desk/web-page"); // Make sure Blog Post filters are cleared.
|
||||
cy.clear_filters();
|
||||
cy.visit("/app/build"); // Go to some other page.
|
||||
cy.visit("/desk/build"); // Go to some other page.
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
|
|
@ -18,7 +18,7 @@ context("Awesome Bar", () => {
|
|||
});
|
||||
|
||||
after(() => {
|
||||
cy.visit("/app/todo"); // Make sure we're not bleeding any filters to the next spec.
|
||||
cy.visit("/desk/todo"); // Make sure we're not bleeding any filters to the next spec.
|
||||
cy.clear_filters();
|
||||
});
|
||||
|
||||
|
|
@ -28,7 +28,7 @@ context("Awesome Bar", () => {
|
|||
cy.get(".awesomplete").findByRole("listbox").should("be.visible");
|
||||
cy.get("@awesome_bar").type("{enter}");
|
||||
cy.get(".title-text").should("contain", "To Do");
|
||||
cy.location("pathname").should("eq", "/app/todo");
|
||||
cy.location("pathname").should("eq", "/desk/todo");
|
||||
});
|
||||
|
||||
it("finds text in doctype list", () => {
|
||||
|
|
@ -40,7 +40,7 @@ context("Awesome Bar", () => {
|
|||
cy.get('[data-original-title="ID"]:visible > input').should("have.value", "%test%");
|
||||
|
||||
// filter preserved, now finds something else
|
||||
cy.visit("/app/todo");
|
||||
cy.visit("/desk/todo");
|
||||
cy.get(".title-text").should("contain", "To Do");
|
||||
cy.wait(200); // Wait a bit longer before checking the filter.
|
||||
cy.get('[data-original-title="ID"]:visible > input').as("filter");
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
context("Attach Control", () => {
|
||||
before(() => {
|
||||
cy.login();
|
||||
cy.visit("/app/doctype");
|
||||
cy.visit("/desk/doctype");
|
||||
return cy
|
||||
.window()
|
||||
.its("frappe")
|
||||
|
|
@ -166,7 +166,7 @@ context("Attach Control", () => {
|
|||
context("Attach Control with Failed Document Save", () => {
|
||||
before(() => {
|
||||
cy.login();
|
||||
cy.visit("/app/doctype");
|
||||
cy.visit("/desk/doctype");
|
||||
return cy
|
||||
.window()
|
||||
.its("frappe")
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
context("Control Autocomplete", () => {
|
||||
before(() => {
|
||||
cy.login();
|
||||
cy.visit("/app");
|
||||
cy.visit("/desk");
|
||||
cy.wait(4000);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
context("Control Barcode", () => {
|
||||
beforeEach(() => {
|
||||
cy.login();
|
||||
cy.visit("/app/website");
|
||||
cy.visit("/desk/website");
|
||||
});
|
||||
|
||||
function get_dialog_with_barcode() {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
context("Control Color", () => {
|
||||
before(() => {
|
||||
cy.login();
|
||||
cy.visit("/app/website");
|
||||
cy.visit("/desk/website");
|
||||
});
|
||||
|
||||
function get_dialog_with_color() {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ context("Control Currency", () => {
|
|||
|
||||
before(() => {
|
||||
cy.login();
|
||||
cy.visit("/app/website");
|
||||
cy.visit("/desk/website");
|
||||
});
|
||||
|
||||
function get_dialog_with_currency(df_options = {}) {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
context("Data Control", () => {
|
||||
before(() => {
|
||||
cy.login();
|
||||
cy.visit("/app/doctype");
|
||||
cy.visit("/desk/doctype");
|
||||
return cy
|
||||
.window()
|
||||
.its("frappe")
|
||||
|
|
@ -39,7 +39,7 @@ context("Data Control", () => {
|
|||
});
|
||||
|
||||
it("check custom formatters", () => {
|
||||
cy.visit(`/app/doctype/User`);
|
||||
cy.visit(`/desk/doctype/User`);
|
||||
cy.get(
|
||||
'[data-fieldname="fields"] .grid-row[data-idx="3"] [data-fieldname="fieldtype"] .static-area'
|
||||
).should("have.text", "Section Break");
|
||||
|
|
@ -49,7 +49,10 @@ context("Data Control", () => {
|
|||
cy.new_form("Test Data Control");
|
||||
|
||||
//Checking the URL for the new form of the doctype
|
||||
cy.location("pathname").should("contains", "/app/test-data-control/new-test-data-control");
|
||||
cy.location("pathname").should(
|
||||
"contains",
|
||||
"/desk/test-data-control/new-test-data-control"
|
||||
);
|
||||
cy.get(".title-text").should("have.text", "New Test Data Control");
|
||||
cy.get('.frappe-control[data-fieldname="name1"]')
|
||||
.find("label")
|
||||
|
|
@ -130,7 +133,7 @@ context("Data Control", () => {
|
|||
//Checking if the fields contains the data which has been filled in
|
||||
cy.location("pathname").should(
|
||||
"not.contains",
|
||||
"/app/test-data-control/new-test-data-control"
|
||||
"/desk/test-data-control/new-test-data-control"
|
||||
);
|
||||
cy.get_field("name1").should("have.value", "Komal");
|
||||
cy.get_field("email").should("have.value", "komal@test.com");
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
context("Date Control", () => {
|
||||
before(() => {
|
||||
cy.login();
|
||||
cy.visit("/app");
|
||||
cy.visit("/desk");
|
||||
});
|
||||
|
||||
function get_dialog(date_field_options) {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
context("Date Range Control", () => {
|
||||
before(() => {
|
||||
cy.login();
|
||||
cy.visit("/app");
|
||||
cy.visit("/desk");
|
||||
});
|
||||
|
||||
function get_dialog() {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
context("Control Duration", () => {
|
||||
before(() => {
|
||||
cy.login();
|
||||
cy.visit("/app/website");
|
||||
cy.visit("/desk/website");
|
||||
});
|
||||
|
||||
function get_dialog_with_duration(hide_days = 0, hide_seconds = 0) {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
context("Dynamic Link", () => {
|
||||
before(() => {
|
||||
cy.login();
|
||||
cy.visit("/app/doctype");
|
||||
cy.visit("/desk/doctype");
|
||||
return cy
|
||||
.window()
|
||||
.its("frappe")
|
||||
|
|
@ -107,7 +107,7 @@ context("Dynamic Link", () => {
|
|||
});
|
||||
|
||||
it("Creating a dynamic link and verifying it", () => {
|
||||
cy.visit("/app/test-dynamic-link");
|
||||
cy.visit("/desk/test-dynamic-link");
|
||||
|
||||
//Clicking on the Document ID field
|
||||
cy.get_field("doc_type").clear();
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
context("Control Float", () => {
|
||||
before(() => {
|
||||
cy.login();
|
||||
cy.visit("/app/website");
|
||||
cy.visit("/desk/website");
|
||||
});
|
||||
|
||||
function get_dialog_with_float() {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
context("Control Icon", () => {
|
||||
before(() => {
|
||||
cy.login();
|
||||
cy.visit("/app/website");
|
||||
cy.visit("/desk/website");
|
||||
});
|
||||
|
||||
function get_dialog_with_icon() {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
context("Control Link", () => {
|
||||
before(() => {
|
||||
cy.login();
|
||||
cy.visit("/app/website");
|
||||
cy.visit("/desk/website");
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
cy.visit("/app/website");
|
||||
cy.visit("/desk/website");
|
||||
cy.create_records({
|
||||
doctype: "ToDo",
|
||||
description: "this is a test todo for link",
|
||||
|
|
@ -120,7 +120,7 @@ context("Control Link", () => {
|
|||
cy.get("@input").trigger("mouseover");
|
||||
cy.get(".frappe-control[data-fieldname=link] .btn-open")
|
||||
.should("be.visible")
|
||||
.should("have.attr", "href", `/app/todo/${todos[0]}`);
|
||||
.should("have.attr", "href", `/desk/todo/${todos[0]}`);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -176,7 +176,7 @@ context("Control Link", () => {
|
|||
|
||||
it("should update dependant fields (via fetch_from)", () => {
|
||||
cy.get("@todos").then((todos) => {
|
||||
cy.visit(`/app/todo/${todos[0]}`);
|
||||
cy.visit(`/desk/todo/${todos[0]}`);
|
||||
cy.intercept("POST", "/api/method/frappe.desk.search.search_link").as("search_link");
|
||||
cy.intercept("/api/method/frappe.client.validate_link*").as("validate_link");
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
context("Control Markdown Editor", () => {
|
||||
before(() => {
|
||||
cy.login();
|
||||
cy.visit("/app");
|
||||
cy.visit("/desk");
|
||||
});
|
||||
|
||||
it("should allow inserting images by drag and drop", () => {
|
||||
cy.visit("/app/web-page/new");
|
||||
cy.visit("/desk/web-page/new");
|
||||
cy.fill_field("content_type", "Markdown", "Select");
|
||||
cy.get_field("main_section_md", "Markdown Editor").selectFile(
|
||||
"cypress/fixtures/sample_image.jpg",
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import doctype_with_phone from "../fixtures/doctype_with_phone";
|
|||
context("Control Phone", () => {
|
||||
before(() => {
|
||||
cy.login();
|
||||
cy.visit("/app/website");
|
||||
cy.visit("/desk/website");
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
|
@ -68,13 +68,13 @@ context("Control Phone", () => {
|
|||
});
|
||||
|
||||
it("existing document should render phone field with data", () => {
|
||||
cy.visit("/app/doctype");
|
||||
cy.visit("/desk/doctype");
|
||||
cy.insert_doc("DocType", doctype_with_phone, true);
|
||||
cy.clear_cache();
|
||||
|
||||
// Creating custom doctype
|
||||
cy.insert_doc("DocType", doctype_with_phone, true);
|
||||
cy.visit("/app/doctype-with-phone");
|
||||
cy.visit("/desk/doctype-with-phone");
|
||||
cy.click_listview_primary_button("Add Doctype With Phone");
|
||||
|
||||
// create a record
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
context("Control Rating", () => {
|
||||
before(() => {
|
||||
cy.login();
|
||||
cy.visit("/app/website");
|
||||
cy.visit("/desk/website");
|
||||
});
|
||||
|
||||
function get_dialog_with_rating() {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
context("Control Select", () => {
|
||||
before(() => {
|
||||
cy.login();
|
||||
cy.visit("/app/website");
|
||||
cy.visit("/desk/website");
|
||||
});
|
||||
|
||||
function get_dialog_with_select() {
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ describe(
|
|||
() => {
|
||||
before(() => {
|
||||
cy.login();
|
||||
cy.visit(`/app/note/new`);
|
||||
cy.visit(`/desk/note/new`);
|
||||
// close the sidebar cause default is expanded
|
||||
cy.get(".body-sidebar .collapse-sidebar-link").click();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
context("Customize Form", () => {
|
||||
before(() => {
|
||||
cy.login();
|
||||
cy.visit("/app/customize-form");
|
||||
cy.visit("/desk/customize-form");
|
||||
});
|
||||
it("Changing to naming rule should update autoname", () => {
|
||||
cy.fill_field("doc_type", "ToDo", "Link").blur();
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
describe("Dashboard view", { scrollBehavior: false }, () => {
|
||||
before(() => {
|
||||
cy.login();
|
||||
cy.visit("/app");
|
||||
cy.visit("/desk");
|
||||
});
|
||||
|
||||
it("should load", () => {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
context("Dashboard Chart", () => {
|
||||
before(() => {
|
||||
cy.login();
|
||||
cy.visit("/app/website");
|
||||
cy.visit("/desk/website");
|
||||
});
|
||||
|
||||
it("Check filter populate for child table doctype", () => {
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ context("Dashboard links", () => {
|
|||
});
|
||||
|
||||
it("Adding a new contact, checking for the counter on the dashboard and deleting the created contact", () => {
|
||||
cy.visit("/app/contact");
|
||||
cy.visit("/desk/contact");
|
||||
cy.clear_filters();
|
||||
|
||||
cy.visit(`/app/user/${cy.config("testUser")}`);
|
||||
|
|
@ -48,7 +48,7 @@ context("Dashboard links", () => {
|
|||
cy.get('[data-doctype="Contact"]').contains("Contact").click();
|
||||
|
||||
//Deleting the newly created contact
|
||||
cy.visit("/app/contact");
|
||||
cy.visit("/desk/contact");
|
||||
cy.get(".list-subject > .select-like > .list-row-checkbox").eq(0).click({ force: true });
|
||||
cy.findByRole("button", { name: "Actions" }).click();
|
||||
cy.get('.actions-btn-group [data-label="Delete"]').click();
|
||||
|
|
@ -56,7 +56,7 @@ context("Dashboard links", () => {
|
|||
|
||||
//To check if the counter from the "Contact" doc link is removed
|
||||
cy.wait(700);
|
||||
cy.visit("/app/user");
|
||||
cy.visit("/desk/user");
|
||||
cy.get(".list-row-col > .level-item > .ellipsis").eq(0).click({ force: true });
|
||||
cy.get('[data-doctype="Contact"]').should("contain", "Contact");
|
||||
});
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ const doctype_name = data_field_validation_doctype.name;
|
|||
context("Data Field Input Validation in New Form", () => {
|
||||
before(() => {
|
||||
cy.login();
|
||||
cy.visit("/app/website");
|
||||
cy.visit("/desk/website");
|
||||
return cy.insert_doc("DocType", data_field_validation_doctype, true);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ const doctype_name = datetime_doctype.name;
|
|||
context("Control Date, Time and DateTime", () => {
|
||||
before(() => {
|
||||
cy.login();
|
||||
cy.visit("/app/website");
|
||||
cy.visit("/desk/website");
|
||||
return cy.insert_doc("DocType", datetime_doctype, true);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
context("Depends On", () => {
|
||||
before(() => {
|
||||
cy.login();
|
||||
cy.visit("/app/website");
|
||||
cy.visit("/desk/website");
|
||||
return cy
|
||||
.window()
|
||||
.its("frappe")
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ context("FileUploader", () => {
|
|||
});
|
||||
|
||||
beforeEach(() => {
|
||||
cy.visit("/app");
|
||||
cy.visit("/desk");
|
||||
cy.wait(2000); // workspace can load async and clear active dialog
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ const type_value = (value) => {
|
|||
context("Form", () => {
|
||||
before(() => {
|
||||
cy.login();
|
||||
cy.visit("/app/website");
|
||||
cy.visit("/desk/website");
|
||||
return cy
|
||||
.window()
|
||||
.its("frappe")
|
||||
|
|
@ -28,11 +28,11 @@ context("Form", () => {
|
|||
|
||||
beforeEach(() => {
|
||||
cy.login();
|
||||
cy.visit("/app/website");
|
||||
cy.visit("/desk/website");
|
||||
});
|
||||
|
||||
it("create a new form", () => {
|
||||
cy.visit("/app/todo/new");
|
||||
cy.visit("/desk/todo/new");
|
||||
cy.get_field("description", "Text Editor")
|
||||
.type("this is a test todo", { force: true })
|
||||
.wait(1000);
|
||||
|
|
@ -51,7 +51,7 @@ context("Form", () => {
|
|||
});
|
||||
|
||||
it("navigates between documents with child table list filters applied", () => {
|
||||
cy.visit("/app/contact");
|
||||
cy.visit("/desk/contact");
|
||||
|
||||
cy.clear_filters();
|
||||
cy.get('.standard-filter-section [data-fieldname="name"] input')
|
||||
|
|
@ -60,7 +60,7 @@ context("Form", () => {
|
|||
cy.click_listview_row_item_with_text("Test Form Contact 3");
|
||||
|
||||
// clear filters
|
||||
cy.visit("/app/contact");
|
||||
cy.visit("/desk/contact");
|
||||
cy.clear_filters();
|
||||
});
|
||||
|
||||
|
|
@ -70,7 +70,7 @@ context("Form", () => {
|
|||
let valid_email = "user@email.com";
|
||||
let expectBackgroundColor = "rgb(255, 245, 245)";
|
||||
|
||||
cy.visit("/app/contact/new");
|
||||
cy.visit("/desk/contact/new");
|
||||
cy.fill_field("company_name", "Test Company");
|
||||
|
||||
cy.get('.frappe-control[data-fieldname="email_ids"]').as("table");
|
||||
|
|
@ -105,7 +105,7 @@ context("Form", () => {
|
|||
});
|
||||
|
||||
it("update docfield property using set_df_property in child table", () => {
|
||||
cy.visit("/app/contact/Test Form Contact 1");
|
||||
cy.visit("/desk/contact/Test Form Contact 1");
|
||||
cy.window()
|
||||
.its("cur_frm")
|
||||
.then((frm) => {
|
||||
|
|
|
|||
|
|
@ -3,18 +3,18 @@ const doctype_name = form_builder_doctype.name;
|
|||
context("Form Builder", () => {
|
||||
before(() => {
|
||||
cy.login();
|
||||
cy.visit("/app");
|
||||
cy.visit("/desk");
|
||||
return cy.insert_doc("DocType", form_builder_doctype, true);
|
||||
});
|
||||
|
||||
it("Open Form Builder for Web Form Doctype/Customize Form", () => {
|
||||
// doctype
|
||||
cy.visit("/app/doctype/Web Form");
|
||||
cy.visit("/desk/doctype/Web Form");
|
||||
cy.findByRole("tab", { name: "Form" }).click();
|
||||
cy.get(".form-builder-container").should("exist");
|
||||
|
||||
// customize form
|
||||
cy.visit("/app/customize-form?doc_type=Web%20Form");
|
||||
cy.visit("/desk/customize-form?doc_type=Web%20Form");
|
||||
cy.findByRole("tab", { name: "Form" }).click();
|
||||
cy.get(".form-builder-container").should("exist");
|
||||
});
|
||||
|
|
@ -264,7 +264,7 @@ context("Form Builder", () => {
|
|||
|
||||
cy.findByRole("button", { name: "Save" }).click({ force: true });
|
||||
|
||||
cy.visit("/app/form-builder-doctype/new");
|
||||
cy.visit("/desk/form-builder-doctype/new");
|
||||
cy.get("[data-fieldname='data3'] .clearfix label").should("have.text", "New Title");
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ const doctype_name = doctype_with_tab_break.name;
|
|||
context("Form Tab Break", () => {
|
||||
before(() => {
|
||||
cy.login();
|
||||
cy.visit("/app/website");
|
||||
cy.visit("/desk/website");
|
||||
return cy.insert_doc("DocType", doctype_with_tab_break, true);
|
||||
});
|
||||
it("Should switch tab and open correct tabs on validation error", () => {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
context.skip("Form Tour", () => {
|
||||
before(() => {
|
||||
cy.login();
|
||||
cy.visit("/app");
|
||||
cy.visit("/desk");
|
||||
return cy
|
||||
.window()
|
||||
.its("frappe")
|
||||
|
|
@ -11,11 +11,11 @@ context.skip("Form Tour", () => {
|
|||
});
|
||||
|
||||
const open_test_form_tour = () => {
|
||||
cy.visit("/app/form-tour/Test Form Tour");
|
||||
cy.visit("/desk/form-tour/Test Form Tour");
|
||||
cy.findByRole("button", { name: "Show Tour" }).should("be.visible").as("show_tour");
|
||||
cy.get("@show_tour").click();
|
||||
cy.wait(500);
|
||||
cy.url().should("include", "/app/contact");
|
||||
cy.url().should("include", "/desk/contact");
|
||||
};
|
||||
|
||||
it("jump to a form tour", open_test_form_tour);
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
context("Grid", () => {
|
||||
beforeEach(() => {
|
||||
cy.login();
|
||||
cy.visit("/app/website");
|
||||
cy.visit("/desk/website");
|
||||
});
|
||||
before(() => {
|
||||
cy.login();
|
||||
cy.visit("/app/website");
|
||||
cy.visit("/desk/website");
|
||||
return cy
|
||||
.window()
|
||||
.its("frappe")
|
||||
|
|
@ -16,7 +16,7 @@ context("Grid", () => {
|
|||
});
|
||||
});
|
||||
it("update docfield property using update_docfield_property", () => {
|
||||
cy.visit("/app/contact/Test Contact");
|
||||
cy.visit("/desk/contact/Test Contact");
|
||||
cy.window()
|
||||
.its("cur_frm")
|
||||
.then((frm) => {
|
||||
|
|
@ -40,7 +40,7 @@ context("Grid", () => {
|
|||
});
|
||||
});
|
||||
it("update docfield property using toggle_display", () => {
|
||||
cy.visit("/app/contact/Test Contact");
|
||||
cy.visit("/desk/contact/Test Contact");
|
||||
cy.window()
|
||||
.its("cur_frm")
|
||||
.then((frm) => {
|
||||
|
|
@ -64,7 +64,7 @@ context("Grid", () => {
|
|||
});
|
||||
});
|
||||
it("update docfield property using toggle_enable", () => {
|
||||
cy.visit("/app/contact/Test Contact");
|
||||
cy.visit("/desk/contact/Test Contact");
|
||||
cy.window()
|
||||
.its("cur_frm")
|
||||
.then((frm) => {
|
||||
|
|
@ -88,7 +88,7 @@ context("Grid", () => {
|
|||
});
|
||||
});
|
||||
it("update docfield property using toggle_reqd", () => {
|
||||
cy.visit("/app/contact/Test Contact");
|
||||
cy.visit("/desk/contact/Test Contact");
|
||||
cy.window()
|
||||
.its("cur_frm")
|
||||
.then((frm) => {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
context("Grid Configuration", () => {
|
||||
beforeEach(() => {
|
||||
cy.login();
|
||||
cy.visit("/app/website-settings");
|
||||
cy.visit("/desk/website-settings");
|
||||
});
|
||||
it("Set user wise grid settings", () => {
|
||||
cy.findByRole("tab", { name: "Navbar" }).click();
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
context("Grid Pagination", () => {
|
||||
beforeEach(() => {
|
||||
cy.login();
|
||||
cy.visit("/app/website");
|
||||
cy.visit("/desk/website");
|
||||
});
|
||||
before(() => {
|
||||
cy.login();
|
||||
cy.visit("/app/website");
|
||||
cy.visit("/desk/website");
|
||||
return cy
|
||||
.window()
|
||||
.its("frappe")
|
||||
|
|
@ -16,14 +16,14 @@ context("Grid Pagination", () => {
|
|||
});
|
||||
});
|
||||
it("creates pages for child table", () => {
|
||||
cy.visit("/app/contact/Test Contact");
|
||||
cy.visit("/desk/contact/Test Contact");
|
||||
cy.get('.frappe-control[data-fieldname="phone_nos"]').as("table");
|
||||
cy.get("@table").find(".current-page-number").should("have.value", "1");
|
||||
cy.get("@table").find(".total-page-number").should("contain", "20");
|
||||
cy.get("@table").find(".grid-body .grid-row").should("have.length", 50);
|
||||
});
|
||||
it("goes to the next and previous page", () => {
|
||||
cy.visit("/app/contact/Test Contact");
|
||||
cy.visit("/desk/contact/Test Contact");
|
||||
cy.get('.frappe-control[data-fieldname="phone_nos"]').as("table");
|
||||
cy.get("@table").find(".next-page").click();
|
||||
cy.get("@table").find(".current-page-number").should("have.value", "2");
|
||||
|
|
@ -36,7 +36,7 @@ context("Grid Pagination", () => {
|
|||
cy.get("@table").find(".grid-body .grid-row").first().should("have.attr", "data-idx", "1");
|
||||
});
|
||||
it("adds and deletes rows and changes page", () => {
|
||||
cy.visit("/app/contact/Test Contact");
|
||||
cy.visit("/desk/contact/Test Contact");
|
||||
cy.get('.frappe-control[data-fieldname="phone_nos"]').as("table");
|
||||
cy.get("@table").findByRole("button", { name: "Add Row" }).click();
|
||||
cy.get("@table").find(".grid-body .row-index").should("contain", 1001);
|
||||
|
|
@ -49,7 +49,7 @@ context("Grid Pagination", () => {
|
|||
cy.get("@table").find(".total-page-number").should("contain", "20");
|
||||
});
|
||||
it("go to specific page, use up and down arrow, type characters, 0 page and more than existing page", () => {
|
||||
cy.visit("/app/contact/Test Contact");
|
||||
cy.visit("/desk/contact/Test Contact");
|
||||
cy.get('.frappe-control[data-fieldname="phone_nos"]').as("table");
|
||||
cy.get("@table").find(".current-page-number").focus().clear().type("17").blur();
|
||||
cy.get("@table").find(".grid-body .row-index").should("contain", 801);
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ context("Grid Search", () => {
|
|||
before(() => {
|
||||
cy.visit("/login");
|
||||
cy.login();
|
||||
cy.visit("/app/website");
|
||||
cy.visit("/desk/website");
|
||||
cy.insert_doc("DocType", child_table_doctype, true);
|
||||
cy.insert_doc("DocType", child_table_doctype_1, true);
|
||||
cy.insert_doc("DocType", doctype_with_child_table, true);
|
||||
|
|
@ -40,7 +40,7 @@ context("Grid Search", () => {
|
|||
});
|
||||
});
|
||||
|
||||
cy.visit(`/app/doctype-with-child-table/Test Grid Search`);
|
||||
cy.visit(`/desk/doctype-with-child-table/Test Grid Search`);
|
||||
|
||||
cy.get('.frappe-control[data-fieldname="child_table_1"]').as("table");
|
||||
cy.get("@table").find(".grid-row-check:last").click();
|
||||
|
|
@ -49,7 +49,7 @@ context("Grid Search", () => {
|
|||
});
|
||||
|
||||
it("test search field for different fieldtypes", () => {
|
||||
cy.visit(`/app/doctype-with-child-table/Test Grid Search`);
|
||||
cy.visit(`/desk/doctype-with-child-table/Test Grid Search`);
|
||||
|
||||
cy.get('.frappe-control[data-fieldname="child_table_1"]').as("table");
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
context("Kanban Board", () => {
|
||||
before(() => {
|
||||
cy.login("frappe@example.com");
|
||||
cy.visit("/app");
|
||||
cy.visit("/desk");
|
||||
});
|
||||
|
||||
it("Create ToDo Kanban", () => {
|
||||
cy.visit("/app/todo");
|
||||
cy.visit("/desk/todo");
|
||||
|
||||
cy.get(".page-actions .custom-btn-group button").click();
|
||||
cy.get(".page-actions .custom-btn-group ul.dropdown-menu li").contains("Kanban").click();
|
||||
|
|
@ -33,7 +33,7 @@ context("Kanban Board", () => {
|
|||
});
|
||||
|
||||
it("Add and Remove fields", () => {
|
||||
cy.visit("/app/todo/view/kanban/ToDo Kanban");
|
||||
cy.visit("/desk/todo/view/kanban/ToDo Kanban");
|
||||
|
||||
cy.intercept(
|
||||
"POST",
|
||||
|
|
@ -110,7 +110,7 @@ context("Kanban Board", () => {
|
|||
|
||||
cy.switch_to_user(not_system_manager);
|
||||
|
||||
cy.visit("/app/todo/view/kanban/Admin Kanban");
|
||||
cy.visit("/desk/todo/view/kanban/Admin Kanban");
|
||||
|
||||
// Menu button should be hidden (dropdown for 'Save Filters' and 'Delete Kanban Board')
|
||||
cy.get(".no-list-sidebar .menu-btn-group .btn-default[data-original-title='Menu']").should(
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
context("List Paging", () => {
|
||||
before(() => {
|
||||
cy.login();
|
||||
cy.visit("/app/website");
|
||||
cy.visit("/desk/website");
|
||||
return cy
|
||||
.window()
|
||||
.its("frappe")
|
||||
|
|
@ -11,7 +11,7 @@ context("List Paging", () => {
|
|||
});
|
||||
|
||||
it("test load more with count selection buttons", () => {
|
||||
cy.visit("/app/todo/view/report");
|
||||
cy.visit("/desk/todo/view/report");
|
||||
cy.clear_filters();
|
||||
|
||||
cy.get(".list-paging-area .list-count").should("contain.text", "20 of");
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
context("List View", () => {
|
||||
before(() => {
|
||||
cy.login();
|
||||
cy.visit("/app/website");
|
||||
cy.visit("/desk/website");
|
||||
return cy
|
||||
.window()
|
||||
.its("frappe")
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
context("List View Settings", () => {
|
||||
beforeEach(() => {
|
||||
cy.login();
|
||||
cy.visit("/app/website");
|
||||
cy.visit("/desk/website");
|
||||
});
|
||||
it("Default settings", () => {
|
||||
cy.visit("/app/List/DocType/List");
|
||||
cy.visit("/desk/List/DocType/List");
|
||||
cy.clear_filters();
|
||||
cy.get(".list-count").should("contain", "20 of");
|
||||
cy.get(".list-stats").should("contain", "Tags");
|
||||
});
|
||||
it("disable count and sidebar stats then verify", () => {
|
||||
cy.wait(300);
|
||||
cy.visit("/app/List/DocType/List");
|
||||
cy.visit("/desk/List/DocType/List");
|
||||
cy.clear_filters();
|
||||
cy.wait(300);
|
||||
cy.get(".list-count").should("contain", "20 of");
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ context("Login", () => {
|
|||
cy.get("#login_password").type(Cypress.env("adminPassword"));
|
||||
|
||||
cy.findByRole("button", { name: "Login" }).click();
|
||||
cy.location("pathname").should("match", /^\/app/);
|
||||
cy.location("pathname").should("match", /^\/desk/);
|
||||
cy.window().its("frappe.session.user").should("eq", "Administrator");
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
context("MultiSelectDialog", () => {
|
||||
before(() => {
|
||||
cy.login();
|
||||
cy.visit("/app");
|
||||
cy.visit("/desk");
|
||||
const contact_template = {
|
||||
doctype: "Contact",
|
||||
first_name: "Test",
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ context("Navigation", () => {
|
|||
before(() => {
|
||||
cy.visit("/login");
|
||||
cy.login();
|
||||
cy.visit("/app/website");
|
||||
cy.visit("/desk/website");
|
||||
});
|
||||
it("Navigate to route with hash in document name", () => {
|
||||
cy.insert_doc(
|
||||
|
|
@ -15,14 +15,14 @@ context("Navigation", () => {
|
|||
},
|
||||
true
|
||||
);
|
||||
cy.visit(`/app/client-script/${encodeURIComponent("ABC#123")}`);
|
||||
cy.visit(`/desk/client-script/${encodeURIComponent("ABC#123")}`);
|
||||
cy.title().should("eq", "ABC#123");
|
||||
cy.go("back");
|
||||
cy.title().should("eq", "Website");
|
||||
});
|
||||
|
||||
it("Navigate to previous page after login", () => {
|
||||
cy.visit("/app/todo");
|
||||
cy.visit("/desk/todo");
|
||||
cy.get(".page-head").findByTitle("To Do").should("be.visible");
|
||||
cy.clear_filters();
|
||||
cy.call("logout");
|
||||
|
|
@ -31,6 +31,6 @@ context("Navigation", () => {
|
|||
cy.location("pathname").should("eq", "/login");
|
||||
cy.login();
|
||||
cy.reload().as("reload");
|
||||
cy.location("pathname").should("eq", "/app/todo");
|
||||
cy.location("pathname").should("eq", "/desk/todo");
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
context("Number Card", () => {
|
||||
before(() => {
|
||||
cy.login();
|
||||
cy.visit("/app/website");
|
||||
cy.visit("/desk/website");
|
||||
});
|
||||
|
||||
it("Check filter populate for child table doctype", () => {
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@ context.skip("Permissions API", () => {
|
|||
before(() => {
|
||||
cy.visit("/login");
|
||||
cy.remove_role("frappe@example.com", "System Manager");
|
||||
cy.visit("/app");
|
||||
cy.visit("/desk");
|
||||
});
|
||||
|
||||
it("Checks permissions via `has_perm` for Kanban Board DocType", () => {
|
||||
cy.visit("/app/kanban-board/view/list");
|
||||
cy.visit("/desk/kanban-board/view/list");
|
||||
cy.window()
|
||||
.its("frappe")
|
||||
.then((frappe) => {
|
||||
|
|
@ -20,7 +20,7 @@ context.skip("Permissions API", () => {
|
|||
});
|
||||
|
||||
it("Checks permissions via `get_perm` for Kanban Board DocType", () => {
|
||||
cy.visit("/app/kanban-board/view/list");
|
||||
cy.visit("/desk/kanban-board/view/list");
|
||||
cy.window()
|
||||
.its("frappe")
|
||||
.then((frappe) => {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
context("Query Report", () => {
|
||||
before(() => {
|
||||
cy.login();
|
||||
cy.visit("/app/website");
|
||||
cy.visit("/desk/website");
|
||||
cy.insert_doc(
|
||||
"Report",
|
||||
{
|
||||
|
|
@ -19,7 +19,7 @@ context("Query Report", () => {
|
|||
});
|
||||
|
||||
it("add custom column in report", () => {
|
||||
cy.visit("/app/query-report/Permitted Documents For User");
|
||||
cy.visit("/desk/query-report/Permitted Documents For User");
|
||||
|
||||
cy.get(".page-form.flex", { timeout: 60000 })
|
||||
.should("have.length", 1)
|
||||
|
|
@ -77,12 +77,12 @@ context("Query Report", () => {
|
|||
.findByRole("button", { name: "Submit" })
|
||||
.click({ timeout: 1000, force: true });
|
||||
|
||||
cy.visit("/app/query-report/" + report);
|
||||
cy.visit("/desk/query-report/" + report);
|
||||
cy.get(".datatable").should("exist");
|
||||
};
|
||||
|
||||
it("test multi level query report", () => {
|
||||
cy.visit("/app/query-report/Test ToDo Report");
|
||||
cy.visit("/desk/query-report/Test ToDo Report");
|
||||
cy.get(".datatable").should("exist");
|
||||
|
||||
save_report_and_open("Test ToDo Report 1", " 1");
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ const doctype_name = custom_submittable_doctype.name;
|
|||
context("Report View", () => {
|
||||
before(() => {
|
||||
cy.login();
|
||||
cy.visit("/app/website");
|
||||
cy.visit("/desk/website");
|
||||
cy.insert_doc("DocType", custom_submittable_doctype, true);
|
||||
cy.clear_cache();
|
||||
cy.insert_doc(
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
context("Rounding behaviour", () => {
|
||||
before(() => {
|
||||
cy.login();
|
||||
cy.visit("/app/");
|
||||
cy.visit("/desk/");
|
||||
});
|
||||
|
||||
it("Commercial Rounding", () => {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
const list_view = "/app/todo";
|
||||
const list_view = "/desk/todo";
|
||||
|
||||
// test round trip with filter types
|
||||
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ context("Sidebar", () => {
|
|||
before(() => {
|
||||
cy.visit("/");
|
||||
cy.login();
|
||||
cy.visit("/app");
|
||||
cy.visit("/desk");
|
||||
return cy
|
||||
.window()
|
||||
.its("frappe")
|
||||
|
|
@ -87,7 +87,7 @@ context("Sidebar", () => {
|
|||
description: "Sidebar Attachment ToDo",
|
||||
}).then((todo) => {
|
||||
let todo_name = todo.message.name;
|
||||
cy.visit("/app/todo");
|
||||
cy.visit("/desk/todo");
|
||||
cy.click_sidebar_button("Assigned To");
|
||||
|
||||
//To check if no filter is available in "Assigned To" dropdown
|
||||
|
|
@ -99,7 +99,7 @@ context("Sidebar", () => {
|
|||
cy.get_field("assign_to_me", "Check").click();
|
||||
cy.wait(1000);
|
||||
cy.get(".modal-footer > .standard-actions > .btn-primary").click();
|
||||
cy.visit("/app/todo");
|
||||
cy.visit("/desk/todo");
|
||||
cy.click_sidebar_button("Assigned To");
|
||||
|
||||
//To check if filter is added in "Assigned To" dropdown after assignment
|
||||
|
|
@ -136,7 +136,7 @@ context("Sidebar", () => {
|
|||
cy.get(".assignments > .avatar-group > .avatar > .avatar-frame").click();
|
||||
cy.get(".remove-btn").click({ force: true });
|
||||
cy.hide_dialog();
|
||||
cy.visit("/app/todo");
|
||||
cy.visit("/desk/todo");
|
||||
cy.click_sidebar_button("Assigned To");
|
||||
cy.get(".empty-state").should("contain", "No filters found");
|
||||
});
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ context("Realtime updates", () => {
|
|||
});
|
||||
|
||||
beforeEach(() => {
|
||||
cy.visit("/app/todo");
|
||||
cy.visit("/desk/todo");
|
||||
// required because immediately after load socket is still connecting.
|
||||
// Not a huge deal breaker in prod.
|
||||
cy.wait(500);
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ const doctype_name = data_field_validation_doctype.name;
|
|||
context("URL Data Field Input", () => {
|
||||
before(() => {
|
||||
cy.login();
|
||||
cy.visit("/app/website");
|
||||
cy.visit("/desk/website");
|
||||
return cy.insert_doc("DocType", data_field_validation_doctype, true);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
context("Utils", () => {
|
||||
before(() => {
|
||||
cy.login();
|
||||
cy.visit("/app");
|
||||
cy.visit("/desk");
|
||||
});
|
||||
|
||||
function run_util(name, ...args) {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
context("View", () => {
|
||||
before(() => {
|
||||
cy.login();
|
||||
cy.visit("/app/website");
|
||||
cy.visit("/desk/website");
|
||||
});
|
||||
|
||||
it("Route to ToDo List View", () => {
|
||||
cy.visit("/app/todo/view/list");
|
||||
cy.visit("/desk/todo/view/list");
|
||||
cy.wait(500);
|
||||
cy.window()
|
||||
.its("cur_list")
|
||||
|
|
@ -15,7 +15,7 @@ context("View", () => {
|
|||
});
|
||||
|
||||
it("Route to ToDo Report View", () => {
|
||||
cy.visit("/app/todo/view/report");
|
||||
cy.visit("/desk/todo/view/report");
|
||||
cy.wait(500);
|
||||
cy.window()
|
||||
.its("cur_list")
|
||||
|
|
@ -25,7 +25,7 @@ context("View", () => {
|
|||
});
|
||||
|
||||
it("Route to ToDo Dashboard View", () => {
|
||||
cy.visit("/app/todo/view/dashboard");
|
||||
cy.visit("/desk/todo/view/dashboard");
|
||||
cy.wait(500);
|
||||
cy.window()
|
||||
.its("cur_list")
|
||||
|
|
@ -35,7 +35,7 @@ context("View", () => {
|
|||
});
|
||||
|
||||
it("Route to ToDo Gantt View", () => {
|
||||
cy.visit("/app/todo/view/gantt");
|
||||
cy.visit("/desk/todo/view/gantt");
|
||||
cy.wait(500);
|
||||
cy.window()
|
||||
.its("cur_list")
|
||||
|
|
@ -46,7 +46,7 @@ context("View", () => {
|
|||
|
||||
it("Route to ToDo Kanban View", () => {
|
||||
cy.call("frappe.tests.ui_test_helpers.create_kanban").then(() => {
|
||||
cy.visit("/app/note/view/kanban/_Note _Kanban");
|
||||
cy.visit("/desk/note/view/kanban/_Note _Kanban");
|
||||
cy.wait(500);
|
||||
cy.window()
|
||||
.its("cur_list")
|
||||
|
|
@ -57,7 +57,7 @@ context("View", () => {
|
|||
});
|
||||
|
||||
it("Route to ToDo Calendar View", () => {
|
||||
cy.visit("/app/todo/view/calendar");
|
||||
cy.visit("/desk/todo/view/calendar");
|
||||
cy.wait(500);
|
||||
cy.window()
|
||||
.its("cur_list")
|
||||
|
|
@ -68,7 +68,7 @@ context("View", () => {
|
|||
|
||||
it("Route to Custom Tree View", () => {
|
||||
cy.call("frappe.tests.ui_test_helpers.setup_tree_doctype").then(() => {
|
||||
cy.visit("/app/custom-tree/view/tree");
|
||||
cy.visit("/desk/custom-tree/view/tree");
|
||||
cy.wait(500);
|
||||
cy.window()
|
||||
.its("cur_tree")
|
||||
|
|
@ -137,7 +137,7 @@ context("View", () => {
|
|||
|
||||
it("Route to default view from app/{doctype}", () => {
|
||||
cy.call("frappe.tests.ui_test_helpers.setup_default_view", { view: "Report" }).then(() => {
|
||||
cy.visit("/app/event");
|
||||
cy.visit("/desk/event");
|
||||
cy.wait(500);
|
||||
cy.window()
|
||||
.its("cur_list")
|
||||
|
|
@ -149,7 +149,7 @@ context("View", () => {
|
|||
|
||||
it("Route to default view from app/{doctype}/view", () => {
|
||||
cy.call("frappe.tests.ui_test_helpers.setup_default_view", { view: "Report" }).then(() => {
|
||||
cy.visit("/app/event/view");
|
||||
cy.visit("/desk/event/view");
|
||||
cy.wait(500);
|
||||
cy.window()
|
||||
.its("cur_list")
|
||||
|
|
@ -164,7 +164,7 @@ context("View", () => {
|
|||
view: "Report",
|
||||
force_reroute: true,
|
||||
}).then(() => {
|
||||
cy.visit("/app/event");
|
||||
cy.visit("/desk/event");
|
||||
cy.wait(500);
|
||||
cy.window()
|
||||
.its("cur_list")
|
||||
|
|
@ -179,7 +179,7 @@ context("View", () => {
|
|||
view: "Report",
|
||||
force_reroute: true,
|
||||
}).then(() => {
|
||||
cy.visit("/app/event/view");
|
||||
cy.visit("/desk/event/view");
|
||||
cy.wait(500);
|
||||
cy.window()
|
||||
.its("cur_list")
|
||||
|
|
@ -194,7 +194,7 @@ context("View", () => {
|
|||
view: "Report",
|
||||
force_reroute: true,
|
||||
}).then(() => {
|
||||
cy.visit("/app/event/view/list");
|
||||
cy.visit("/desk/event/view/list");
|
||||
cy.wait(500);
|
||||
cy.window()
|
||||
.its("cur_list")
|
||||
|
|
@ -206,17 +206,17 @@ context("View", () => {
|
|||
|
||||
it("Validate Route History for Default View", () => {
|
||||
cy.call("frappe.tests.ui_test_helpers.setup_default_view", { view: "Report" }).then(() => {
|
||||
cy.visit("/app/event");
|
||||
cy.visit("/app/event/view/list");
|
||||
cy.location("pathname").should("eq", "/app/event/view/list");
|
||||
cy.visit("/desk/event");
|
||||
cy.visit("/desk/event/view/list");
|
||||
cy.location("pathname").should("eq", "/desk/event/view/list");
|
||||
cy.go("back");
|
||||
cy.location("pathname").should("eq", "/app/event");
|
||||
cy.location("pathname").should("eq", "/desk/event");
|
||||
});
|
||||
});
|
||||
|
||||
it("Route to Form", () => {
|
||||
const test_user = cy.config("testUser");
|
||||
cy.visit(`/app/user/${test_user}`);
|
||||
cy.visit(`/desk/user/${test_user}`);
|
||||
cy.window()
|
||||
.its("cur_frm")
|
||||
.then((frm) => {
|
||||
|
|
@ -225,7 +225,7 @@ context("View", () => {
|
|||
});
|
||||
|
||||
it("Route to Website Workspace", () => {
|
||||
cy.visit("/app/website");
|
||||
cy.visit("/desk/website");
|
||||
cy.get(".title-text").should("contain", "Website");
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
context("Web Form", () => {
|
||||
before(() => {
|
||||
cy.login("Administrator");
|
||||
cy.visit("/app/");
|
||||
cy.visit("/desk/");
|
||||
return cy
|
||||
.window()
|
||||
.its("frappe")
|
||||
|
|
@ -11,7 +11,7 @@ context("Web Form", () => {
|
|||
});
|
||||
|
||||
it("Create Web Form", () => {
|
||||
cy.visit("/app/web-form/new");
|
||||
cy.visit("/desk/web-form/new");
|
||||
|
||||
cy.intercept("POST", "/api/method/frappe.desk.form.save.savedocs").as("save_form");
|
||||
|
||||
|
|
@ -40,7 +40,11 @@ context("Web Form", () => {
|
|||
cy.url().should("include", "/note/new");
|
||||
|
||||
cy.fill_field("title", "Guest Note 1");
|
||||
cy.get(".web-form-actions button").contains("Save").click();
|
||||
cy.window()
|
||||
.its("__")
|
||||
.then((__) => {
|
||||
cy.get(".web-form-actions button").contains(__("Save")).click();
|
||||
});
|
||||
|
||||
cy.url().should("include", "/note/new");
|
||||
|
||||
|
|
@ -51,7 +55,7 @@ context("Web Form", () => {
|
|||
it("Login Required", () => {
|
||||
cy.call("logout");
|
||||
cy.login("Administrator");
|
||||
cy.visit("/app/web-form/note");
|
||||
cy.visit("/desk/web-form/note");
|
||||
|
||||
cy.findByRole("tab", { name: "Settings" }).click();
|
||||
cy.get('input[data-fieldname="login_required"]').check({ force: true });
|
||||
|
|
@ -70,7 +74,7 @@ context("Web Form", () => {
|
|||
|
||||
it("Show List", () => {
|
||||
cy.login("Administrator");
|
||||
cy.visit("/app/web-form/note");
|
||||
cy.visit("/desk/web-form/note");
|
||||
|
||||
cy.findByRole("tab", { name: "Settings" }).click();
|
||||
cy.get(".section-head").contains("List Settings").click();
|
||||
|
|
@ -84,7 +88,7 @@ context("Web Form", () => {
|
|||
});
|
||||
|
||||
it("Show Custom List Title", () => {
|
||||
cy.visit("/app/web-form/note");
|
||||
cy.visit("/desk/web-form/note");
|
||||
|
||||
cy.findByRole("tab", { name: "Settings" }).click();
|
||||
|
||||
|
|
@ -107,7 +111,7 @@ context("Web Form", () => {
|
|||
cy.get(".web-list-table thead th").contains("Sr.");
|
||||
cy.get(".web-list-table thead th").contains("Title");
|
||||
|
||||
cy.visit("/app/web-form/note");
|
||||
cy.visit("/desk/web-form/note");
|
||||
|
||||
cy.findByRole("tab", { name: "Settings" }).click();
|
||||
|
||||
|
|
@ -156,7 +160,7 @@ context("Web Form", () => {
|
|||
});
|
||||
|
||||
it("Custom Breadcrumbs", () => {
|
||||
cy.visit("/app/web-form/note");
|
||||
cy.visit("/desk/web-form/note");
|
||||
|
||||
cy.findByRole("tab", { name: "Customization" }).click();
|
||||
cy.fill_field("breadcrumbs", '[{"label": _("Notes"), "route":"note"}]', "Code");
|
||||
|
|
@ -188,7 +192,7 @@ context("Web Form", () => {
|
|||
});
|
||||
|
||||
it("Edit Mode", () => {
|
||||
cy.visit("/app/web-form/note");
|
||||
cy.visit("/desk/web-form/note");
|
||||
|
||||
cy.findByRole("tab", { name: "Settings" }).click();
|
||||
cy.get('input[data-fieldname="allow_edit"]').check();
|
||||
|
|
@ -212,7 +216,7 @@ context("Web Form", () => {
|
|||
});
|
||||
|
||||
it("Allow Multiple Response", () => {
|
||||
cy.visit("/app/web-form/note");
|
||||
cy.visit("/desk/web-form/note");
|
||||
|
||||
cy.findByRole("tab", { name: "Settings" }).click();
|
||||
cy.get('input[data-fieldname="allow_multiple"]').check();
|
||||
|
|
@ -230,7 +234,7 @@ context("Web Form", () => {
|
|||
});
|
||||
|
||||
it("Allow Delete", () => {
|
||||
cy.visit("/app/web-form/note");
|
||||
cy.visit("/desk/web-form/note");
|
||||
|
||||
cy.findByRole("tab", { name: "Settings" }).click();
|
||||
cy.get('input[data-fieldname="allow_delete"]').check();
|
||||
|
|
|
|||
|
|
@ -2,16 +2,23 @@ context("Workspace 2.0", () => {
|
|||
before(() => {
|
||||
cy.visit("/login");
|
||||
cy.login();
|
||||
return cy
|
||||
.window()
|
||||
.its("frappe")
|
||||
.then((frappe) => {
|
||||
return frappe.xcall("frappe.tests.ui_test_helpers.empty_my_workspaces");
|
||||
});
|
||||
});
|
||||
|
||||
it("Navigate to page from sidebar", () => {
|
||||
cy.visit("/app/build");
|
||||
cy.visit("/desk/build");
|
||||
cy.get(".codex-editor__redactor .ce-block");
|
||||
cy.get('.sidebar-item-container[item-title="Website"]').first().click();
|
||||
cy.location("pathname").should("eq", "/app/website");
|
||||
cy.get('.sidebar-item-container[item-name="Page"]').first().click();
|
||||
cy.location("pathname").should("eq", "/desk/page");
|
||||
});
|
||||
|
||||
it("Create Private Page", () => {
|
||||
cy.visit("/desk/website");
|
||||
cy.intercept({
|
||||
method: "POST",
|
||||
url: "api/method/frappe.desk.doctype.workspace.workspace.new_page",
|
||||
|
|
@ -27,61 +34,16 @@ context("Workspace 2.0", () => {
|
|||
cy.get_open_dialog().find(".btn-primary").click();
|
||||
|
||||
// check if sidebar item is added in pubic section
|
||||
cy.get('.sidebar-item-container[item-title="Test Private Page"]').should(
|
||||
"have.attr",
|
||||
"item-public",
|
||||
"0"
|
||||
);
|
||||
cy.get('.sidebar-item-container[item-name="Test Private Page"]');
|
||||
cy.wait(300);
|
||||
cy.get('.standard-actions .btn-primary[data-label="Save"]').click();
|
||||
cy.wait(300);
|
||||
cy.get('.sidebar-item-container[item-title="Test Private Page"]').should(
|
||||
"have.attr",
|
||||
"item-public",
|
||||
"0"
|
||||
);
|
||||
|
||||
cy.wait("@new_page");
|
||||
});
|
||||
|
||||
it("Create Child Page", () => {
|
||||
cy.intercept({
|
||||
method: "POST",
|
||||
url: "api/method/frappe.desk.doctype.workspace.workspace.new_page",
|
||||
}).as("new_page");
|
||||
|
||||
cy.get(".codex-editor__redactor .ce-block");
|
||||
cy.get(".btn-new-workspace").click();
|
||||
cy.fill_field("title", "Test Child Page", "Data");
|
||||
cy.fill_field("parent", "Test Private Page", "Select");
|
||||
cy.fill_field("type", "Workspace", "Select");
|
||||
cy.get_open_dialog().find(".modal-header").click();
|
||||
cy.wait(300);
|
||||
cy.get_open_dialog().find(".btn-primary").click();
|
||||
|
||||
// check if sidebar item is added in pubic section
|
||||
cy.get('.sidebar-item-container[item-title="Test Child Page"]').should(
|
||||
"have.attr",
|
||||
"item-public",
|
||||
"0"
|
||||
);
|
||||
cy.wait(300);
|
||||
cy.get('.standard-actions .btn-primary[data-label="Save"]').click();
|
||||
cy.wait(300);
|
||||
cy.get('.sidebar-item-container[item-title="Test Child Page"]').should(
|
||||
"have.attr",
|
||||
"item-public",
|
||||
"0"
|
||||
);
|
||||
cy.get('.sidebar-item-container[item-name="Test Private Page"]');
|
||||
|
||||
cy.wait("@new_page");
|
||||
});
|
||||
|
||||
it("Add New Block", () => {
|
||||
cy.get('.sidebar-item-container[item-title="Test Private Page"]').as("sidebar-item");
|
||||
|
||||
cy.get("@sidebar-item").find(".standard-sidebar-item").first().click({ force: true });
|
||||
|
||||
cy.get(".btn-edit-workspace").click({ force: true });
|
||||
|
||||
cy.get(".ce-block").click().type("{enter}");
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
context("Workspace Blocks", () => {
|
||||
before(() => {
|
||||
cy.login();
|
||||
cy.visit("/app");
|
||||
cy.visit("/desk");
|
||||
return cy
|
||||
.window()
|
||||
.its("frappe")
|
||||
|
|
@ -11,12 +11,13 @@ context("Workspace Blocks", () => {
|
|||
});
|
||||
|
||||
it("Create Test Page", () => {
|
||||
cy.remove_doc("Workspace", `Test Block Page-${Cypress.config("testUser")}`, true);
|
||||
cy.intercept({
|
||||
method: "POST",
|
||||
url: "api/method/frappe.desk.doctype.workspace.workspace.new_page",
|
||||
}).as("new_page");
|
||||
|
||||
cy.visit("/app/website");
|
||||
cy.visit("/desk/website");
|
||||
cy.get(".codex-editor__redactor .ce-block");
|
||||
cy.get(".btn-new-workspace").click();
|
||||
cy.fill_field("title", "Test Block Page", "Data");
|
||||
|
|
@ -25,19 +26,11 @@ context("Workspace Blocks", () => {
|
|||
cy.get_open_dialog().find(".btn-primary").click();
|
||||
|
||||
// check if sidebar item is added in private section
|
||||
cy.get('.sidebar-item-container[item-title="Test Block Page"]').should(
|
||||
"have.attr",
|
||||
"item-public",
|
||||
"0"
|
||||
);
|
||||
cy.get('.sidebar-item-container[item-name="Test Block Page"]');
|
||||
cy.wait(300);
|
||||
cy.get('.standard-actions .btn-primary[data-label="Save"]').click();
|
||||
cy.wait(300);
|
||||
cy.get('.sidebar-item-container[item-title="Test Block Page"]').should(
|
||||
"have.attr",
|
||||
"item-public",
|
||||
"0"
|
||||
);
|
||||
cy.get('.sidebar-item-container[item-name="Test Block Page"]');
|
||||
|
||||
cy.wait("@new_page");
|
||||
});
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ Cypress.Commands.add("get_doc", (doctype, name) => {
|
|||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add("remove_doc", (doctype, name) => {
|
||||
Cypress.Commands.add("remove_doc", (doctype, name, ignore_missing) => {
|
||||
return cy
|
||||
.window()
|
||||
.its("frappe.csrf_token")
|
||||
|
|
@ -138,9 +138,9 @@ Cypress.Commands.add("remove_doc", (doctype, name) => {
|
|||
Accept: "application/json",
|
||||
"X-Frappe-CSRF-Token": csrf_token,
|
||||
},
|
||||
failOnStatusCode: !ignore_missing,
|
||||
})
|
||||
.then((res) => {
|
||||
expect(res.status).eq(202);
|
||||
return res.body;
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1355,9 +1355,9 @@ def get_list(doctype, *args, **kwargs):
|
|||
# filter as a list of lists
|
||||
frappe.get_list("ToDo", fields="*", filters = [["modified", ">", "2014-01-01"]])
|
||||
"""
|
||||
import frappe.model.db_query
|
||||
import frappe.model.qb_query
|
||||
|
||||
return frappe.model.db_query.DatabaseQuery(doctype).execute(*args, **kwargs)
|
||||
return frappe.model.qb_query.DatabaseQuery(doctype).execute(*args, **kwargs)
|
||||
|
||||
|
||||
def get_all(doctype, *args, **kwargs):
|
||||
|
|
|
|||
|
|
@ -78,12 +78,13 @@ def read_doc(doctype: str, name: str):
|
|||
doc = frappe.get_doc(doctype, name)
|
||||
doc.check_permission("read")
|
||||
doc.apply_fieldlevel_read_permissions()
|
||||
doc_dict = doc.as_dict()
|
||||
if sbool(frappe.form_dict.get("expand_links")):
|
||||
doc_dict = doc.as_dict()
|
||||
get_values_for_link_and_dynamic_link_fields(doc_dict)
|
||||
get_values_for_table_and_multiselect_fields(doc_dict)
|
||||
return doc_dict
|
||||
|
||||
return doc_dict
|
||||
return doc
|
||||
|
||||
|
||||
def get_values_for_link_and_dynamic_link_fields(doc_dict):
|
||||
|
|
|
|||
|
|
@ -79,9 +79,9 @@ def get_default_path():
|
|||
return get_route(user_default_app)
|
||||
|
||||
if len(_apps) == 1:
|
||||
return _apps[0].get("route") or "/apps"
|
||||
return _apps[0].get("route") or "/desk"
|
||||
elif is_desk_apps(_apps):
|
||||
return "/app"
|
||||
return "/desk"
|
||||
return "/apps"
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -201,7 +201,7 @@ class LoginManager:
|
|||
frappe.local.cookie_manager.set_cookie("system_user", "yes", deduplicate=True)
|
||||
if not resume:
|
||||
frappe.local.response["message"] = "Logged In"
|
||||
frappe.local.response["home_page"] = get_default_path() or "/app"
|
||||
frappe.local.response["home_page"] = get_default_path() or "/desk"
|
||||
|
||||
if not resume:
|
||||
frappe.response["full_name"] = self.full_name
|
||||
|
|
|
|||
|
|
@ -85,14 +85,17 @@ frappe.ui.form.on("Auto Repeat", {
|
|||
},
|
||||
|
||||
preview_message: function (frm) {
|
||||
if (frm.is_dirty()) {
|
||||
frappe.msgprint(__("Please save the form before previewing the message"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (frm.doc.message) {
|
||||
frappe.call({
|
||||
method: "frappe.automation.doctype.auto_repeat.auto_repeat.generate_message_preview",
|
||||
type: "POST",
|
||||
args: {
|
||||
reference_dt: frm.doc.reference_doctype,
|
||||
reference_doc: frm.doc.reference_document,
|
||||
subject: frm.doc.subject,
|
||||
message: frm.doc.message,
|
||||
name: frm.doc.name,
|
||||
},
|
||||
callback: function (r) {
|
||||
if (r.message) {
|
||||
|
|
|
|||
|
|
@ -605,14 +605,15 @@ def update_reference(docname: str, reference: str):
|
|||
return "success" # backward compatbility
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def generate_message_preview(reference_dt, reference_doc, message=None, subject=None):
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def generate_message_preview(name: str):
|
||||
frappe.has_permission("Auto Repeat", "write", throw=True)
|
||||
doc = frappe.get_doc(reference_dt, reference_doc)
|
||||
auto_repeat = frappe.get_doc("Auto Repeat", str(name))
|
||||
doc = frappe.get_doc(auto_repeat.reference_doctype, auto_repeat.reference_document)
|
||||
doc.check_permission()
|
||||
subject_preview = _("Please add a subject to your email")
|
||||
msg_preview = frappe.render_template(message, {"doc": doc})
|
||||
if subject:
|
||||
subject_preview = frappe.render_template(subject, {"doc": doc})
|
||||
msg_preview = frappe.render_template(auto_repeat.message, {"doc": doc})
|
||||
if auto_repeat.subject:
|
||||
subject_preview = frappe.render_template(auto_repeat.subject, {"doc": doc})
|
||||
|
||||
return {"message": msg_preview, "subject": subject_preview}
|
||||
|
|
|
|||
|
|
@ -1,345 +0,0 @@
|
|||
{
|
||||
"charts": [],
|
||||
"content": "[{\"id\":\"sR-UFcO7II\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Import Data\",\"col\":3}},{\"id\":\"IkcVmgWb3z\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"ToDo\",\"col\":3}},{\"id\":\"6wir-jZFRE\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"File\",\"col\":3}},{\"id\":\"45a1jzQkTm\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Assignment Rule\",\"col\":3}},{\"id\":\"EgtURZsoiF\",\"type\":\"spacer\",\"data\":{\"col\":12}},{\"id\":\"0yceBIfhHM\",\"type\":\"card\",\"data\":{\"card_name\":\"Data\",\"col\":4}},{\"id\":\"42WbBA9rpj\",\"type\":\"card\",\"data\":{\"card_name\":\"Tools\",\"col\":4}},{\"id\":\"wE9n7TIrAc\",\"type\":\"card\",\"data\":{\"card_name\":\"Alerts and Notifications\",\"col\":4}},{\"id\":\"7_U7_xCOos\",\"type\":\"card\",\"data\":{\"card_name\":\"Email\",\"col\":4}},{\"id\":\"3imoh2oqsJ\",\"type\":\"card\",\"data\":{\"card_name\":\"Printing\",\"col\":4}},{\"id\":\"SlYKJZj5r3\",\"type\":\"card\",\"data\":{\"card_name\":\"Automation\",\"col\":4}}]",
|
||||
"creation": "2020-03-02 14:53:24.980279",
|
||||
"custom_blocks": [],
|
||||
"docstatus": 0,
|
||||
"doctype": "Workspace",
|
||||
"for_user": "",
|
||||
"hide_custom": 0,
|
||||
"icon": "tool",
|
||||
"idx": 0,
|
||||
"is_hidden": 0,
|
||||
"label": "Tools",
|
||||
"links": [
|
||||
{
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Automation",
|
||||
"link_count": 3,
|
||||
"onboard": 0,
|
||||
"type": "Card Break"
|
||||
},
|
||||
{
|
||||
"dependencies": "",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Assignment Rule",
|
||||
"link_count": 0,
|
||||
"link_to": "Assignment Rule",
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Milestone",
|
||||
"link_count": 0,
|
||||
"link_to": "Milestone",
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Auto Repeat",
|
||||
"link_count": 0,
|
||||
"link_to": "Auto Repeat",
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Tools",
|
||||
"link_count": 4,
|
||||
"onboard": 0,
|
||||
"type": "Card Break"
|
||||
},
|
||||
{
|
||||
"dependencies": "",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "To Do",
|
||||
"link_count": 0,
|
||||
"link_to": "ToDo",
|
||||
"link_type": "DocType",
|
||||
"onboard": 1,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Calendar",
|
||||
"link_count": 0,
|
||||
"link_to": "Event",
|
||||
"link_type": "DocType",
|
||||
"onboard": 1,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Note",
|
||||
"link_count": 0,
|
||||
"link_to": "Note",
|
||||
"link_type": "DocType",
|
||||
"onboard": 1,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Files",
|
||||
"link_count": 0,
|
||||
"link_to": "File",
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Printing",
|
||||
"link_count": 4,
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Card Break"
|
||||
},
|
||||
{
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Print Format Builder",
|
||||
"link_count": 0,
|
||||
"link_to": "print-format-builder",
|
||||
"link_type": "Page",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Print Format Builder (New)",
|
||||
"link_count": 0,
|
||||
"link_to": "print-format-builder-beta",
|
||||
"link_type": "Page",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Print Settings",
|
||||
"link_count": 0,
|
||||
"link_to": "Print Settings",
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Print Heading",
|
||||
"link_count": 0,
|
||||
"link_to": "Print Heading",
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Alerts and Notifications",
|
||||
"link_count": 3,
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Card Break"
|
||||
},
|
||||
{
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Notification",
|
||||
"link_count": 0,
|
||||
"link_to": "Notification",
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Auto Email Report",
|
||||
"link_count": 0,
|
||||
"link_to": "Auto Email Report",
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Notification Settings",
|
||||
"link_count": 0,
|
||||
"link_to": "Notification Settings",
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"description": "Manage your data",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Data",
|
||||
"link_count": 5,
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Card Break"
|
||||
},
|
||||
{
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Import Data",
|
||||
"link_count": 0,
|
||||
"link_to": "Data Import",
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Export Data",
|
||||
"link_count": 0,
|
||||
"link_to": "Data Export",
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Bulk Update",
|
||||
"link_count": 0,
|
||||
"link_to": "Bulk Update",
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Download Backups",
|
||||
"link_count": 0,
|
||||
"link_to": "backups",
|
||||
"link_type": "Page",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Deleted Documents",
|
||||
"link_count": 0,
|
||||
"link_to": "Deleted Document",
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Email",
|
||||
"link_count": 4,
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Card Break"
|
||||
},
|
||||
{
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Email Account",
|
||||
"link_count": 0,
|
||||
"link_to": "Email Account",
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Email Domain",
|
||||
"link_count": 0,
|
||||
"link_to": "Email Domain",
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Email Template",
|
||||
"link_count": 0,
|
||||
"link_to": "Email Template",
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Email Group",
|
||||
"link_count": 0,
|
||||
"link_to": "Email Group",
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
}
|
||||
],
|
||||
"modified": "2025-06-27 11:39:44.392114",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Automation",
|
||||
"name": "Tools",
|
||||
"number_cards": [],
|
||||
"owner": "Administrator",
|
||||
"parent_page": "",
|
||||
"public": 1,
|
||||
"quick_lists": [],
|
||||
"restrict_to_domain": "",
|
||||
"roles": [],
|
||||
"sequence_id": 1.0,
|
||||
"shortcuts": [
|
||||
{
|
||||
"color": "Grey",
|
||||
"doc_view": "List",
|
||||
"label": "Import Data",
|
||||
"link_to": "Data Import",
|
||||
"type": "DocType"
|
||||
},
|
||||
{
|
||||
"doc_view": "",
|
||||
"label": "ToDo",
|
||||
"link_to": "ToDo",
|
||||
"stats_filter": "[[\"ToDo\",\"status\",\"=\",\"Open\",false]]",
|
||||
"type": "DocType"
|
||||
},
|
||||
{
|
||||
"label": "File",
|
||||
"link_to": "File",
|
||||
"type": "DocType"
|
||||
},
|
||||
{
|
||||
"label": "Assignment Rule",
|
||||
"link_to": "Assignment Rule",
|
||||
"type": "DocType"
|
||||
}
|
||||
],
|
||||
"title": "Tools"
|
||||
}
|
||||
|
|
@ -14,6 +14,7 @@ from frappe.core.doctype.installed_applications.installed_applications import (
|
|||
)
|
||||
from frappe.core.doctype.navbar_settings.navbar_settings import get_app_logo, get_navbar_settings
|
||||
from frappe.desk.doctype.changelog_feed.changelog_feed import get_changelog_feed_items
|
||||
from frappe.desk.doctype.desktop_icon.desktop_icon import get_desktop_icons
|
||||
from frappe.desk.doctype.form_tour.form_tour import get_onboarding_ui_tours
|
||||
from frappe.desk.doctype.route_history.route_history import frequently_visited_links
|
||||
from frappe.desk.form.load import get_meta_bundle
|
||||
|
|
@ -41,6 +42,7 @@ def get_bootinfo():
|
|||
|
||||
# user
|
||||
get_user(bootinfo)
|
||||
# desktop icon info
|
||||
|
||||
# system info
|
||||
bootinfo.sitename = frappe.local.site
|
||||
|
|
@ -55,6 +57,7 @@ def get_bootinfo():
|
|||
bootinfo.modules = {}
|
||||
bootinfo.module_list = []
|
||||
load_desktop_data(bootinfo)
|
||||
bootinfo.desktop_icons = get_desktop_icons(bootinfo=bootinfo)
|
||||
bootinfo.letter_heads = get_letter_heads()
|
||||
bootinfo.active_domains = frappe.get_active_domains()
|
||||
bootinfo.all_domains = [d.get("name") for d in frappe.get_all("Domain")]
|
||||
|
|
@ -148,8 +151,12 @@ def load_conf_settings(bootinfo):
|
|||
def load_desktop_data(bootinfo):
|
||||
from frappe.desk.desktop import get_workspace_sidebar_items
|
||||
|
||||
bootinfo.sidebar_pages = get_workspace_sidebar_items()
|
||||
allowed_pages = [d.name for d in bootinfo.sidebar_pages.get("pages")]
|
||||
bootinfo.workspaces = get_workspace_sidebar_items()
|
||||
bootinfo.show_app_icons_as_folder = frappe.db.get_single_value(
|
||||
"Desktop Settings", "show_app_icons_as_folder"
|
||||
)
|
||||
bootinfo.workspace_sidebar_item = get_sidebar_items()
|
||||
allowed_pages = [d.name for d in bootinfo.workspaces.get("pages")]
|
||||
bootinfo.module_wise_workspaces = get_controller("Workspace").get_module_wise_workspaces()
|
||||
bootinfo.dashboards = frappe.get_all("Dashboard")
|
||||
bootinfo.app_data = []
|
||||
|
|
@ -196,7 +203,7 @@ def load_desktop_data(bootinfo):
|
|||
frappe.get_hooks("app_home", app_name=app_name)
|
||||
and frappe.get_hooks("app_home", app_name=app_name)[0]
|
||||
)
|
||||
or (workspaces and "/app/" + frappe.utils.slug(workspaces[0]))
|
||||
or (workspaces and "/desk/" + frappe.utils.slug(workspaces[0]))
|
||||
or "",
|
||||
app_logo_url=app_info.get("logo")
|
||||
or frappe.get_hooks("app_logo_url", app_name=app_name)
|
||||
|
|
@ -360,7 +367,7 @@ def add_home_page(bootinfo, docs):
|
|||
bootinfo["home_page"] = page.name
|
||||
except (frappe.DoesNotExistError, frappe.PermissionError):
|
||||
frappe.clear_last_message()
|
||||
bootinfo["home_page"] = "Workspaces"
|
||||
bootinfo["home_page"] = "desktop"
|
||||
|
||||
|
||||
def add_timezone_info(bootinfo):
|
||||
|
|
@ -518,3 +525,68 @@ def get_sentry_dsn():
|
|||
return
|
||||
|
||||
return os.getenv("FRAPPE_SENTRY_DSN")
|
||||
|
||||
|
||||
def get_sidebar_items():
|
||||
sidebars = frappe.get_all(
|
||||
"Workspace Sidebar", fields=["name", "header_icon"], filters={"name": ["not like", "%My Workspaces%"]}
|
||||
)
|
||||
add_user_specific_sidebar(sidebars)
|
||||
sidebar_items = {}
|
||||
|
||||
for s in sidebars:
|
||||
w = frappe.get_doc("Workspace Sidebar", s["name"])
|
||||
sidebar_items[s["name"].lower()] = {
|
||||
"label": s["name"],
|
||||
"items": [],
|
||||
"header_icon": s["header_icon"],
|
||||
"module": w.module,
|
||||
}
|
||||
for si in w.items:
|
||||
workspace_sidebar = {
|
||||
"label": si.label,
|
||||
"link_to": si.link_to,
|
||||
"link_type": si.link_type,
|
||||
"type": si.type,
|
||||
"icon": si.icon,
|
||||
"child": si.child,
|
||||
"collapsible": si.collapsible,
|
||||
"indent": si.indent,
|
||||
"keep_closed": si.keep_closed,
|
||||
"display_depends_on": si.display_depends_on,
|
||||
"url": si.url,
|
||||
"show_arrow": si.show_arrow,
|
||||
"filters": si.filters,
|
||||
"route_options": si.route_options,
|
||||
}
|
||||
if si.link_type == "Report" and si.link_to:
|
||||
report_type, ref_doctype = frappe.db.get_value(
|
||||
"Report", si.link_to, ["report_type", "ref_doctype"]
|
||||
)
|
||||
workspace_sidebar["report"] = {
|
||||
"report_type": report_type,
|
||||
"ref_doctype": ref_doctype,
|
||||
}
|
||||
|
||||
if (
|
||||
"My Workspaces" in s["name"]
|
||||
or si.type == "Section Break"
|
||||
or w.is_item_allowed(si.link_to, si.link_type)
|
||||
):
|
||||
sidebar_items[s["name"].lower()]["items"].append(workspace_sidebar)
|
||||
|
||||
old_name = f"my workspaces-{frappe.session.user}"
|
||||
if old_name in sidebar_items:
|
||||
sidebar_items["my workspaces"] = sidebar_items.pop(old_name)
|
||||
return sidebar_items
|
||||
|
||||
|
||||
def add_user_specific_sidebar(sidebars):
|
||||
try:
|
||||
my_workspace_for_user = frappe.get_doc("Workspace Sidebar", f"My Workspaces-{frappe.session.user}")
|
||||
sidebars.append(
|
||||
{"name": my_workspace_for_user.name, "header_icon": my_workspace_for_user.header_icon}
|
||||
)
|
||||
except frappe.DoesNotExistError:
|
||||
my_workspace = frappe.get_doc("Workspace Sidebar", "My Workspaces")
|
||||
sidebars.append({"name": my_workspace.name, "header_icon": my_workspace.header_icon})
|
||||
|
|
|
|||
|
|
@ -1584,6 +1584,33 @@ def bypass_patch(context: CliCtxObj, patch_name: str, yes: bool):
|
|||
frappe.destroy()
|
||||
|
||||
|
||||
@click.command("create-desktop-icons-and-sidebar")
|
||||
@pass_context
|
||||
def create_icons_and_sidebar(context: CliCtxObj):
|
||||
"""Create desktop icons and workspace sidebars."""
|
||||
from frappe.desk.doctype.desktop_icon.desktop_icon import create_desktop_icons
|
||||
from frappe.desk.doctype.workspace_sidebar.workspace_sidebar import (
|
||||
create_workspace_sidebar_for_workspaces,
|
||||
)
|
||||
|
||||
if not context.sites:
|
||||
raise SiteNotSpecifiedError
|
||||
for site in context.sites:
|
||||
frappe.init(site)
|
||||
frappe.connect()
|
||||
try:
|
||||
print("Creating Desktop Icons")
|
||||
create_desktop_icons()
|
||||
print("Creating Workspace Sidebars")
|
||||
create_workspace_sidebar_for_workspaces()
|
||||
# Saving it in a command need it
|
||||
frappe.db.commit() # nosemgrep
|
||||
except Exception as e:
|
||||
print(f"Error creating icons {site}: {e}")
|
||||
finally:
|
||||
frappe.destroy()
|
||||
|
||||
|
||||
commands = [
|
||||
add_system_manager,
|
||||
add_user_for_sites,
|
||||
|
|
@ -1620,4 +1647,5 @@ commands = [
|
|||
trim_database,
|
||||
clear_log_table,
|
||||
bypass_patch,
|
||||
create_icons_and_sidebar,
|
||||
]
|
||||
|
|
|
|||
|
|
@ -469,11 +469,10 @@ class TestCommands(BaseTestCommands):
|
|||
self.assertEqual(check_password("Administrator", original_password), "Administrator")
|
||||
|
||||
@skipIf(
|
||||
not (frappe.conf.root_password and frappe.conf.admin_password and frappe.conf.db_type == "mariadb"),
|
||||
not (frappe.conf.root_password and frappe.conf.admin_password and frappe.conf.db_type != "sqlite"),
|
||||
"DB Root password and Admin password not set in config",
|
||||
)
|
||||
def test_bench_drop_site_should_archive_site(self):
|
||||
# TODO: Make this test postgres compatible
|
||||
site = TEST_SITE
|
||||
|
||||
self.execute(
|
||||
|
|
@ -499,7 +498,7 @@ class TestCommands(BaseTestCommands):
|
|||
self.assertTrue(os.path.exists(archive_directory))
|
||||
|
||||
@skipIf(
|
||||
not (frappe.conf.root_password and frappe.conf.admin_password and frappe.conf.db_type == "mariadb"),
|
||||
not (frappe.conf.root_password and frappe.conf.admin_password and frappe.conf.db_type != "sqlite"),
|
||||
"DB Root password and Admin password not set in config",
|
||||
)
|
||||
def test_force_install_app(self):
|
||||
|
|
@ -656,10 +655,10 @@ class TestBackups(BaseTestCommands):
|
|||
except OSError:
|
||||
pass
|
||||
|
||||
@run_only_if(db_type_is.MARIADB)
|
||||
def test_backup_no_options(self):
|
||||
"""Take a backup without any options"""
|
||||
before_backup = fetch_latest_backups(partial=True)
|
||||
time.sleep(1)
|
||||
self.execute("bench --site {site} backup")
|
||||
after_backup = fetch_latest_backups(partial=True)
|
||||
|
||||
|
|
@ -1003,9 +1002,11 @@ class TestDBCli(BaseTestCommands):
|
|||
self.execute("bench --site {site} db-console", kwargs={"cmd_input": cmd_input})
|
||||
self.assertEqual(self.returncode, 0)
|
||||
|
||||
@run_only_if(db_type_is.MARIADB)
|
||||
def test_db_cli_with_sql(self):
|
||||
self.execute("bench --site {site} db-console -e 'select 1'")
|
||||
if frappe.db.db_type == "postgres":
|
||||
self.execute("bench --site {site} db-console -c 'select 1'")
|
||||
elif frappe.db.db_type == "mariadb":
|
||||
self.execute("bench --site {site} db-console -e 'select 1'")
|
||||
self.assertEqual(self.returncode, 0)
|
||||
self.assertIn("1", self.stdout)
|
||||
|
||||
|
|
|
|||
|
|
@ -437,6 +437,7 @@ def run_parallel_tests(
|
|||
@click.option("--parallel", is_flag=True, help="Run UI Test in parallel mode")
|
||||
@click.option("--with-coverage", is_flag=True, help="Generate coverage report")
|
||||
@click.option("--browser", default="chrome", help="Browser to run tests in")
|
||||
@click.option("--spec", help="Spec file to run")
|
||||
@click.option("--ci-build-id")
|
||||
@pass_context
|
||||
def run_ui_tests(
|
||||
|
|
@ -448,6 +449,7 @@ def run_ui_tests(
|
|||
browser="chrome",
|
||||
ci_build_id=None,
|
||||
cypressargs=None,
|
||||
spec=None,
|
||||
):
|
||||
"Run UI tests"
|
||||
site = get_site(context)
|
||||
|
|
@ -494,6 +496,8 @@ def run_ui_tests(
|
|||
|
||||
# run for headless mode
|
||||
run_or_open = f"run --browser {browser}" if headless else "open"
|
||||
if headless and spec:
|
||||
run_or_open += f" --spec {spec}"
|
||||
formatted_command = f"{site_env} {password_env} {coverage_env} {cypress_path} {run_or_open}"
|
||||
|
||||
if os.environ.get("CYPRESS_RECORD_KEY"):
|
||||
|
|
|
|||
|
|
@ -310,7 +310,7 @@ def get_address_display_list(doctype: str, name: str) -> list[dict]:
|
|||
["Dynamic Link", "parenttype", "=", "Address"],
|
||||
],
|
||||
fields=["*"],
|
||||
order_by="is_primary_address DESC, `tabAddress`.creation ASC",
|
||||
order_by="is_primary_address DESC, creation ASC",
|
||||
)
|
||||
for a in address_list:
|
||||
a["display"] = get_address_display(a)
|
||||
|
|
|
|||
|
|
@ -486,7 +486,7 @@ def get_contact_display_list(doctype: str, name: str) -> list[dict]:
|
|||
["Dynamic Link", "parenttype", "=", "Contact"],
|
||||
],
|
||||
fields=["*"],
|
||||
order_by="is_primary_contact DESC, `tabContact`.creation ASC",
|
||||
order_by="is_primary_contact DESC, creation ASC",
|
||||
)
|
||||
|
||||
for contact in contact_list:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
{
|
||||
"based_on": "creation",
|
||||
"chart_name": "Background Job Activity",
|
||||
"chart_type": "Count",
|
||||
"creation": "2025-09-08 11:56:13.469137",
|
||||
"currency": "",
|
||||
"docstatus": 0,
|
||||
"doctype": "Dashboard Chart",
|
||||
"document_type": "Scheduled Job Type",
|
||||
"dynamic_filters_json": "[]",
|
||||
"filters_json": "[]",
|
||||
"group_by_type": "Count",
|
||||
"idx": 0,
|
||||
"is_public": 0,
|
||||
"is_standard": 1,
|
||||
"last_synced_on": "2025-10-30 21:36:33.646973",
|
||||
"modified": "2025-10-30 21:37:11.340673",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Core",
|
||||
"name": "Background Job Activity",
|
||||
"number_of_groups": 0,
|
||||
"owner": "Administrator",
|
||||
"parent_document_type": "",
|
||||
"roles": [],
|
||||
"show_values_over_chart": 0,
|
||||
"source": "",
|
||||
"time_interval": "Daily",
|
||||
"timeseries": 1,
|
||||
"timespan": "Last Year",
|
||||
"type": "Line",
|
||||
"use_report_chart": 0,
|
||||
"value_based_on": "",
|
||||
"y_axis": []
|
||||
}
|
||||
|
|
@ -50,7 +50,7 @@ class TestActivityLog(IntegrationTestCase):
|
|||
"user": "Administrator",
|
||||
"operation": operation,
|
||||
},
|
||||
order_by="`creation` DESC",
|
||||
order_by="creation DESC",
|
||||
)
|
||||
|
||||
name = names[0]
|
||||
|
|
|
|||
|
|
@ -34,9 +34,10 @@
|
|||
}
|
||||
],
|
||||
"grid_page_length": 50,
|
||||
"in_create": 1,
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2025-05-21 17:09:55.054044",
|
||||
"modified": "2025-10-29 11:26:28.177653",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Core",
|
||||
"name": "API Request Log",
|
||||
|
|
|
|||
|
|
@ -236,7 +236,7 @@ def get_import_status(data_import_name: str):
|
|||
import_status = {"status": data_import.status}
|
||||
logs = frappe.get_all(
|
||||
"Data Import Log",
|
||||
fields=["count(*) as count", "success"],
|
||||
fields=[{"COUNT": "*", "as": "count"}, "success"],
|
||||
filters={"data_import": data_import_name},
|
||||
group_by="success",
|
||||
)
|
||||
|
|
|
|||
|
|
@ -165,9 +165,9 @@ class Exporter:
|
|||
filters = self.export_filters
|
||||
|
||||
if self.meta.is_nested_set():
|
||||
order_by = f"`tab{self.doctype}`.`lft` ASC"
|
||||
order_by = "lft ASC"
|
||||
else:
|
||||
order_by = f"`tab{self.doctype}`.`creation` DESC"
|
||||
order_by = "creation DESC"
|
||||
|
||||
parent_fields = [format_column_name(df) for df in self.fields if df.parent == self.doctype]
|
||||
parent_data = frappe.db.get_list(
|
||||
|
|
|
|||
|
|
@ -153,24 +153,25 @@ class TestDocType(IntegrationTestCase):
|
|||
def test_all_depends_on_fields_conditions(self):
|
||||
import re
|
||||
|
||||
docfields = frappe.get_all(
|
||||
"DocField",
|
||||
or_filters={
|
||||
"ifnull(depends_on, '')": ("!=", ""),
|
||||
"ifnull(collapsible_depends_on, '')": ("!=", ""),
|
||||
"ifnull(mandatory_depends_on, '')": ("!=", ""),
|
||||
"ifnull(read_only_depends_on, '')": ("!=", ""),
|
||||
},
|
||||
fields=[
|
||||
"parent",
|
||||
"depends_on",
|
||||
"collapsible_depends_on",
|
||||
"mandatory_depends_on",
|
||||
"read_only_depends_on",
|
||||
"fieldname",
|
||||
"fieldtype",
|
||||
],
|
||||
DocField = frappe.qb.DocType("DocField")
|
||||
docfields_query = (
|
||||
frappe.qb.from_(DocField)
|
||||
.select(
|
||||
DocField.parent,
|
||||
DocField.depends_on,
|
||||
DocField.collapsible_depends_on,
|
||||
DocField.mandatory_depends_on,
|
||||
DocField.read_only_depends_on,
|
||||
DocField.fieldname,
|
||||
)
|
||||
.where(
|
||||
(DocField.depends_on != "")
|
||||
| (DocField.collapsible_depends_on != "")
|
||||
| (DocField.mandatory_depends_on != "")
|
||||
| (DocField.read_only_depends_on != "")
|
||||
)
|
||||
)
|
||||
docfields = docfields_query.run(as_dict=True)
|
||||
|
||||
pattern = r'[\w\.:_]+\s*={1}\s*[\w\.@\'"]+'
|
||||
for field in docfields:
|
||||
|
|
@ -840,7 +841,20 @@ class TestDocType(IntegrationTestCase):
|
|||
],
|
||||
).insert(ignore_if_duplicate=True)
|
||||
decimal_field_type = frappe.db.get_column_type(doctype.name, "decimal_field")
|
||||
self.assertIn("(30,3)", decimal_field_type.lower())
|
||||
if frappe.db.db_type == "postgres":
|
||||
result = frappe.db.sql(
|
||||
"""
|
||||
SELECT numeric_precision, numeric_scale
|
||||
FROM information_schema.columns
|
||||
WHERE lower(table_name) = lower(%s)
|
||||
AND column_name = %s
|
||||
""",
|
||||
(f"tab{doctype.name}", "decimal_field"),
|
||||
)
|
||||
length, precision = result[0]
|
||||
self.assertEqual((length, precision), (30, 3))
|
||||
elif frappe.db.db_type == "mariadb":
|
||||
self.assertIn("(30,3)", decimal_field_type.lower())
|
||||
|
||||
def test_decimal_field_precision_exceeds_length(self):
|
||||
doctype = new_doctype(
|
||||
|
|
|
|||
|
|
@ -56,7 +56,15 @@ class InstalledApplications(Document):
|
|||
},
|
||||
)
|
||||
|
||||
self.save()
|
||||
try:
|
||||
savepoint = "update_installed_apps"
|
||||
frappe.db.savepoint(savepoint)
|
||||
self.save()
|
||||
except frappe.db.DataError:
|
||||
frappe.db.rollback(save_point=savepoint)
|
||||
# Tolerate primary key change on versions during migrate
|
||||
self.save(ignore_version=True)
|
||||
|
||||
frappe.clear_cache(doctype="System Settings")
|
||||
frappe.db.set_single_value("System Settings", "setup_complete", frappe.is_setup_complete())
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ frappe.ui.form.on("Permission Inspector", {
|
|||
ref_doctype(frm) {
|
||||
frm.doc.docname = ""; // Usually doctype change invalidates docname
|
||||
call_debug(frm);
|
||||
frm.trigger("add_custom_perm_types");
|
||||
},
|
||||
user: call_debug,
|
||||
permission_type: call_debug,
|
||||
|
|
@ -21,4 +22,21 @@ frappe.ui.form.on("Permission Inspector", {
|
|||
frm.call("debug");
|
||||
}
|
||||
},
|
||||
add_custom_perm_types(frm) {
|
||||
if (!frm.doc.ref_doctype) return;
|
||||
|
||||
const doctype_ptype_map = frm.doc.__onload.doctype_ptype_map;
|
||||
if (!Object.keys(doctype_ptype_map).length) return;
|
||||
|
||||
const standard_options = frm.meta.fields.find(
|
||||
(f) => f.fieldname === "permission_type"
|
||||
).options;
|
||||
const custom_options = doctype_ptype_map[frm.doc.ref_doctype]?.join("\n");
|
||||
|
||||
frm.set_df_property(
|
||||
"permission_type",
|
||||
"options",
|
||||
`${standard_options}\n${custom_options}`
|
||||
);
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -37,6 +37,11 @@ class PermissionInspector(Document):
|
|||
user: DF.Link
|
||||
# end: auto-generated types
|
||||
|
||||
def onload(self):
|
||||
from frappe.core.doctype.permission_type.permission_type import get_doctype_ptype_map
|
||||
|
||||
self.set_onload("doctype_ptype_map", get_doctype_ptype_map())
|
||||
|
||||
@frappe.whitelist()
|
||||
def debug(self):
|
||||
if not (self.ref_doctype and self.user):
|
||||
|
|
|
|||
0
frappe/core/doctype/permission_type/__init__.py
Normal file
0
frappe/core/doctype/permission_type/__init__.py
Normal file
8
frappe/core/doctype/permission_type/permission_type.js
Normal file
8
frappe/core/doctype/permission_type/permission_type.js
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
// Copyright (c) 2025, Frappe Technologies and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
// frappe.ui.form.on("Permission Type", {
|
||||
// refresh(frm) {
|
||||
|
||||
// },
|
||||
// });
|
||||
55
frappe/core/doctype/permission_type/permission_type.json
Normal file
55
frappe/core/doctype/permission_type/permission_type.json
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"actions": [],
|
||||
"creation": "2025-07-28 13:12:03.573433",
|
||||
"doctype": "DocType",
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"perm_type",
|
||||
"doc_type"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "perm_type",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Permission Type",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "doc_type",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Applies To (DocType)",
|
||||
"options": "DocType",
|
||||
"reqd": 1
|
||||
}
|
||||
],
|
||||
"grid_page_length": 50,
|
||||
"in_create": 1,
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2025-11-13 16:17:58.536849",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Core",
|
||||
"name": "Permission Type",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Administrator",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"read_only": 1,
|
||||
"row_format": "Dynamic",
|
||||
"sort_field": "creation",
|
||||
"sort_order": "DESC",
|
||||
"states": []
|
||||
}
|
||||
135
frappe/core/doctype/permission_type/permission_type.py
Normal file
135
frappe/core/doctype/permission_type/permission_type.py
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
# Copyright (c) 2025, Frappe Technologies and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from collections import defaultdict
|
||||
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.model.document import Document
|
||||
from frappe.modules.export_file import delete_folder
|
||||
from frappe.utils.caching import site_cache
|
||||
|
||||
# doctypes where custom fields for permission types will be created
|
||||
CUSTOM_FIELD_TARGET = ["Custom DocPerm", "DocPerm", "DocShare"]
|
||||
|
||||
|
||||
class PermissionType(Document):
|
||||
# begin: auto-generated types
|
||||
# This code is auto-generated. Do not modify anything in this block.
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from frappe.types import DF
|
||||
|
||||
doc_type: DF.Link
|
||||
perm_type: DF.Data
|
||||
# end: auto-generated types
|
||||
|
||||
def autoname(self):
|
||||
self.name = f"{frappe.scrub(self.doc_type)}_{frappe.scrub(self.perm_type)}"
|
||||
|
||||
def before_insert(self):
|
||||
self.perm_type = frappe.scrub(self.perm_type)
|
||||
|
||||
def validate(self):
|
||||
from frappe.permissions import std_rights
|
||||
|
||||
if self.perm_type in std_rights:
|
||||
frappe.throw(
|
||||
_("Permission Type '{0}' is reserved. Please choose another name.").format(self.perm_type)
|
||||
)
|
||||
|
||||
def can_write(self):
|
||||
return (
|
||||
frappe.conf.developer_mode
|
||||
or frappe.flags.in_migrate
|
||||
or frappe.flags.in_install
|
||||
or frappe.flags.in_test
|
||||
)
|
||||
|
||||
def should_export(self):
|
||||
return (
|
||||
frappe.conf.developer_mode
|
||||
and not frappe.flags.in_migrate
|
||||
and not frappe.flags.in_install
|
||||
and not frappe.flags.in_test
|
||||
)
|
||||
|
||||
def get_folder_path(self):
|
||||
app = frappe.get_doctype_app(self.doc_type)
|
||||
folder = frappe.get_app_source_path(app, app, "permission_types")
|
||||
return folder
|
||||
|
||||
def on_update(self):
|
||||
if not self.can_write():
|
||||
frappe.throw(_("Creation of this document is only permitted in developer mode."))
|
||||
|
||||
for target in CUSTOM_FIELD_TARGET:
|
||||
self.create_custom_field(target)
|
||||
|
||||
if self.should_export():
|
||||
from frappe.modules.export_file import export_to_files
|
||||
|
||||
module = frappe.db.get_value("DocType", self.doc_type, "module")
|
||||
export_to_files(record_list=[["Permission Type", self.name]], record_module=module)
|
||||
|
||||
def before_export(self, export_doc):
|
||||
del export_doc["idx"]
|
||||
del export_doc["docstatus"]
|
||||
for key in list(export_doc.keys()):
|
||||
if key.startswith("_"):
|
||||
del export_doc[key]
|
||||
|
||||
def create_custom_field(self, target):
|
||||
from frappe.custom.doctype.custom_field.custom_field import create_custom_field
|
||||
|
||||
if not self.custom_field_exists(target):
|
||||
field = "share_doctype" if target == "DocShare" else "parent"
|
||||
depends_on = f"eval:doc.{field} == '{self.doc_type}'"
|
||||
|
||||
create_custom_field(
|
||||
target,
|
||||
{
|
||||
"fieldname": self.perm_type,
|
||||
"label": frappe.unscrub(self.perm_type),
|
||||
"fieldtype": "Check",
|
||||
"insert_after": "append",
|
||||
"depends_on": depends_on,
|
||||
},
|
||||
)
|
||||
|
||||
def on_trash(self):
|
||||
if not self.can_write():
|
||||
frappe.throw(_("Deletion of this document is only permitted in developer mode."))
|
||||
|
||||
for target in CUSTOM_FIELD_TARGET:
|
||||
self.delete_custom_field(target)
|
||||
|
||||
if self.should_export():
|
||||
module = frappe.db.get_value("DocType", self.doc_type, "module")
|
||||
delete_folder(module, "Permission Type", self.name)
|
||||
|
||||
def delete_custom_field(self, target):
|
||||
if name := self.custom_field_exists(target):
|
||||
frappe.delete_doc("Custom Field", name)
|
||||
|
||||
def custom_field_exists(self, target):
|
||||
return frappe.db.exists(
|
||||
"Custom Field",
|
||||
{
|
||||
"fieldname": self.perm_type,
|
||||
"dt": target,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@site_cache
|
||||
def get_doctype_ptype_map():
|
||||
ptypes = frappe.get_all("Permission Type", fields=["perm_type", "doc_type"], order_by="perm_type")
|
||||
|
||||
doctype_ptype_map = defaultdict(list)
|
||||
for pt in ptypes:
|
||||
if pt.perm_type not in doctype_ptype_map[pt.doc_type]:
|
||||
doctype_ptype_map[pt.doc_type].append(pt.perm_type)
|
||||
return dict(doctype_ptype_map)
|
||||
103
frappe/core/doctype/permission_type/test_permission_type.py
Normal file
103
frappe/core/doctype/permission_type/test_permission_type.py
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
# Copyright (c) 2025, Frappe Technologies and Contributors
|
||||
# See license.txt
|
||||
|
||||
import frappe
|
||||
from frappe.permissions import update_permission_property
|
||||
from frappe.tests import IntegrationTestCase
|
||||
|
||||
# On IntegrationTestCase, the doctype test records and all
|
||||
# link-field test record dependencies are recursively loaded
|
||||
# Use these module variables to add/remove to/from that list
|
||||
EXTRA_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"]
|
||||
IGNORE_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"]
|
||||
|
||||
|
||||
class IntegrationTestPermissionType(IntegrationTestCase):
|
||||
"""
|
||||
Integration tests for PermissionType.
|
||||
Use this class for testing interactions between multiple components.
|
||||
"""
|
||||
|
||||
def test_approve_ptype_on_blog_post(self):
|
||||
"""Test that custom permission types are applied correctly."""
|
||||
user_role = "Website Manager"
|
||||
doc_type = "Web Page"
|
||||
ptype_name = "approve"
|
||||
|
||||
user = self._create_test_user("test_approve_permission@example.com", user_role)
|
||||
|
||||
ptype_doc = self._create_permission_type(ptype_name, doc_type)
|
||||
|
||||
try:
|
||||
self._verify_custom_fields_created(ptype_doc, doc_type)
|
||||
|
||||
self._verify_user_lacks_permission(doc_type, ptype_name, user.name)
|
||||
|
||||
update_permission_property(
|
||||
doctype=doc_type, role=user_role, permlevel=0, ptype=ptype_name, value=1
|
||||
)
|
||||
|
||||
self._verify_user_has_permission(doc_type, ptype_name, user.name)
|
||||
|
||||
update_permission_property(
|
||||
doctype=doc_type, role=user_role, permlevel=0, ptype=ptype_name, value=0
|
||||
)
|
||||
|
||||
finally:
|
||||
frappe.delete_doc("User", user.name, force=True)
|
||||
frappe.delete_doc("Permission Type", ptype_doc.name, force=True)
|
||||
|
||||
def test_permission_type_creation_reserved_name(self):
|
||||
"""Test that permission types with reserved names are rejected."""
|
||||
doc = frappe.get_doc(
|
||||
{
|
||||
"doctype": "Permission Type",
|
||||
"perm_type": "read",
|
||||
"doc_type": "ToDo",
|
||||
"module": "Core",
|
||||
}
|
||||
)
|
||||
|
||||
with self.assertRaises(frappe.exceptions.ValidationError):
|
||||
doc.insert()
|
||||
|
||||
def _create_test_user(self, email, role):
|
||||
"""Create a test user with the specified role."""
|
||||
user = frappe.new_doc("User")
|
||||
user.email = email
|
||||
user.first_name = email.split("@", 1)[0]
|
||||
user.insert(ignore_if_duplicate=True)
|
||||
user.reload()
|
||||
user.add_roles(role)
|
||||
return user
|
||||
|
||||
def _create_permission_type(self, name, doc_type):
|
||||
"""Create a permission type for the specified doctype."""
|
||||
ptype_doc = frappe.get_doc(
|
||||
{
|
||||
"doctype": "Permission Type",
|
||||
"perm_type": name,
|
||||
"doc_type": doc_type,
|
||||
"module": "Core",
|
||||
}
|
||||
)
|
||||
ptype_doc.insert(ignore_if_duplicate=True)
|
||||
ptype_doc.reload()
|
||||
return ptype_doc
|
||||
|
||||
def _verify_custom_fields_created(self, ptype_doc, doc_type):
|
||||
"""Verify that custom fields are created for the permission type."""
|
||||
for target in ["Custom DocPerm", "DocPerm", "DocShare"]:
|
||||
custom_field = frappe.get_doc("Custom Field", {"dt": target, "fieldname": ptype_doc.perm_type})
|
||||
self.assertEqual(custom_field.dt, target)
|
||||
self.assertEqual(custom_field.fieldname, ptype_doc.perm_type)
|
||||
self.assertEqual(custom_field.fieldtype, "Check")
|
||||
self.assertIn(doc_type, custom_field.depends_on)
|
||||
|
||||
def _verify_user_lacks_permission(self, doc_type, ptype_name, user_name):
|
||||
"""Verify that user does not have the specified permission type."""
|
||||
self.assertFalse(frappe.has_permission(doc_type, ptype=ptype_name, user=user_name))
|
||||
|
||||
def _verify_user_has_permission(self, doc_type, ptype_name, user_name):
|
||||
"""Verify that user has the specified permission type."""
|
||||
self.assertTrue(frappe.has_permission(doc_type, ptype=ptype_name, user=user_name))
|
||||
|
|
@ -63,9 +63,12 @@ class TestPreparedReport(IntegrationTestCase):
|
|||
self.assertEqual(len(prepared_data["result"]), len(generated_data["result"]))
|
||||
self.assertEqual(len(prepared_data), len(generated_data))
|
||||
|
||||
@run_only_if(db_type_is.MARIADB)
|
||||
def test_start_status_and_kill_jobs(self):
|
||||
with test_report(report_type="Query Report", query="select sleep(10)") as report:
|
||||
if frappe.db.db_type == "postgres":
|
||||
query = "select pg_sleep(5)"
|
||||
elif frappe.db.db_type == "mariadb":
|
||||
query = "select sleep(5)"
|
||||
with test_report(report_type="Query Report", query=query) as report:
|
||||
doc = self.create_prepared_report(report.name)
|
||||
self.wait_for_status(doc, "Started")
|
||||
job_id = doc.job_id
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"grid_page_length": 50,
|
||||
"links": [
|
||||
{
|
||||
"link_doctype": "User",
|
||||
|
|
@ -43,7 +44,7 @@
|
|||
"table_fieldname": "role_profiles"
|
||||
}
|
||||
],
|
||||
"modified": "2024-03-23 16:03:37.104710",
|
||||
"modified": "2025-11-15 20:00:18.844434",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Core",
|
||||
"name": "Role Profile",
|
||||
|
|
@ -74,9 +75,11 @@
|
|||
"write": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
"sort_field": "creation",
|
||||
"sort_order": "DESC",
|
||||
"states": [],
|
||||
"title_field": "role_profile",
|
||||
"track_changes": 1
|
||||
}
|
||||
"track_changes": 1,
|
||||
"translated_doctype": 1
|
||||
}
|
||||
|
|
|
|||
|
|
@ -176,6 +176,13 @@ class TestRQJob(IntegrationTestCase):
|
|||
if frappe.conf.use_mysqlclient:
|
||||
# TEMP: Add extra allowance for running two connectors, this should be rolled back before v16
|
||||
LAST_MEASURED_USAGE += 2
|
||||
|
||||
# Observed higher usage on 3.14. Temporarily raising the limit
|
||||
from sys import version_info
|
||||
|
||||
if version_info >= (3, 14):
|
||||
LAST_MEASURED_USAGE += 5
|
||||
|
||||
self.assertLessEqual(rss, LAST_MEASURED_USAGE * 1.05, msg)
|
||||
|
||||
def test_clear_failed_jobs(self):
|
||||
|
|
@ -184,7 +191,7 @@ class TestRQJob(IntegrationTestCase):
|
|||
|
||||
jobs = [frappe.enqueue(method=self.BG_JOB, queue="short", fail=True) for _ in range(limit * 2)]
|
||||
self.check_status(jobs[-1], "failed")
|
||||
self.assertLessEqual(RQJob.get_count(filters=[["RQ Job", "status", "=", "failed"]]), limit * 1.1)
|
||||
self.assertLessEqual(RQJob.get_count(filters=[["RQ Job", "status", "=", "failed"]]), limit * 1.2)
|
||||
|
||||
|
||||
def test_func(fail=False, sleep=0):
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue