Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 13 additions & 6 deletions alfred/ci.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@


@alfred.command("ci", help="continuous integration pipeline")
@alfred.option('--front', '-f', help="run for frontend only", is_flag=True, default=False)
@alfred.option('--docs', '-d', help="run for docs only", is_flag=True, default=False)
@alfred.option('--back', '-b', help="run for backend only", is_flag=True, default=False)
@alfred.option('--e2e', '-e', help="run for end-to-end only", default=None)
@alfred.option("--front", "-f", help="run for frontend only", is_flag=True, default=False)
@alfred.option("--docs", "-d", help="run for docs only", is_flag=True, default=False)
@alfred.option("--back", "-b", help="run for backend only", is_flag=True, default=False)
@alfred.option("--e2e", "-e", help="run for end-to-end only", default=None)
def ci(front, back, e2e, docs):
no_flags = (not front and not back and not e2e and not docs)
no_flags = not front and not back and not e2e and not docs

if front or no_flags:
alfred.invoke_command("npm.lint")
Expand All @@ -27,21 +27,28 @@ def ci(front, back, e2e, docs):
if e2e:
alfred.invoke_command("npm.e2e", browser=e2e)


@alfred.command("ci.mypy", help="typing checking with mypy on ./src/writer")
def ci_mypy():
alfred.run("mypy ./src/writer --exclude app_templates/*")


@alfred.command("ci.ruff", help="linting with ruff")
@alfred.option('--fix', '-f', help="fix linting errors", is_flag=True, default=False)
@alfred.option("--fix", "-f", help="fix linting errors", is_flag=True, default=False)
def ci_ruff(fix):
if fix:
alfred.run("ruff check --fix")
else:
alfred.run("ruff check")


@alfred.command("ci.pytest", help="run pytest on ./tests")
def ci_test():
os.chdir("tests")
alfred.run("pytest")


@alfred.command("ci.pytest.blocks", help="run pytest on ./tests")
def ci_test_blocks():
os.chdir("tests")
alfred.run("pytest backend/blocks")
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"

[tool.poetry]
name = "writer"
version = "0.8.3rc7"
version = "0.8.3rc8"
description = "An open-source, Python framework for building feature-rich apps that are fully integrated with the Writer platform."
authors = ["Writer, Inc."]
readme = "README.md"
Expand Down
9 changes: 9 additions & 0 deletions src/ui/public/components/workflows_code.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion src/ui/src/builder/sidebar/BuilderSidebarToolkit.vue
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ function getRelevantToolsInCategory(categoryId: string) {
if (def.category != categoryId) return false;
if (!def.toolkit && activeToolkit.value !== "core") return false;
if (def.toolkit && def.toolkit !== activeToolkit.value) return false;
if (def.deprecated) return false;
return true;
});
const enriched = typeList.map((type) => {
Expand All @@ -130,7 +131,7 @@ function handleDragEnd(ev: DragEvent) {
function getToolIcons(tool: ReturnType<typeof getRelevantToolsInCategory>[0]) {
return [
`/components/${tool.type}.svg`,
`/components/category_${tool.category}.svg`,
`/components/${activeToolkit.value == "workflows" ? "workflows_" : ""}category_${tool.category}.svg`,
].map((p) => convertAbsolutePathtoFullURL(p));
}

Expand Down
2 changes: 1 addition & 1 deletion src/ui/src/components/workflows/WorkflowsWorkflow.vue
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ const temporaryNodeCoordinates = shallowRef<
Record<Component["id"], { x: number; y: number }>
>({});

const AUTOARRANGE_ROW_GAP_PX = 48;
const AUTOARRANGE_ROW_GAP_PX = 64;
const AUTOARRANGE_COLUMN_GAP_PX = 128;

const nodes = computed(() =>
Expand Down
26 changes: 25 additions & 1 deletion src/ui/src/components/workflows/abstract/WorkflowsNode.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
:class="{
'WorkflowsNode--trigger': isTrigger,
'WorkflowsNode--intelligent': isIntelligent,
'WorkflowsNode--deprecated': isDeprecated,
'WorkflowsNode--running': completionStyle == 'running',
'WorkflowsNode--success': completionStyle == 'success',
'WorkflowsNode--error': completionStyle == 'error',
Expand All @@ -24,6 +25,9 @@
class="nodeNamer"
:block-name="def.name"
></WorkflowsNodeNamer>
<div v-if="isDeprecated" class="deprecationNotice">
Deprecated
</div>
</div>
<div
v-for="(outs, fieldKey) in dynamicOuts"
Expand Down Expand Up @@ -120,6 +124,10 @@ const isIntelligent = computed(() => {
return def?.value?.category == "Writer";
});

const isDeprecated = computed(() => {
return def?.value?.deprecated;
});

const completionStyle = computed(() => {
if (latestKnownOutcome.value == null) return null;
if (latestKnownOutcome.value == "in_progress") return "running";
Expand Down Expand Up @@ -245,6 +253,10 @@ watch(isEngaged, () => {
animation: shadowPulse 1s infinite alternate ease-in-out;
}

.WorkflowsNode--deprecated {
filter: grayscale(1);
}

@keyframes shadowPulse {
0% {
box-shadow: 0px 2px 24px -16px #6985ff;
Expand Down Expand Up @@ -326,11 +338,12 @@ watch(isEngaged, () => {
}

.title {
display: flex;
display: grid;
gap: 10px;
padding: 12px;
border-radius: 12px 12px 0 0;
align-items: center;
grid-template-columns: 24px 1fr;
}

.WorkflowsNode--intelligent .title {
Expand All @@ -342,6 +355,17 @@ watch(isEngaged, () => {
height: 24px;
}

.title .deprecationNotice {
font-size: 12px;
text-transform: uppercase;
font-size: 12px;
font-weight: 500;
line-height: 12px; /* 100% */
letter-spacing: 1.3px;
text-transform: uppercase;
color: var(--builderSecondaryTextColor);
}

.WorkflowsNode--trigger .title img {
border-radius: 50%;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ function handleAliasEditorMousemove(ev: MouseEvent) {
<style scoped>
.WorkflowsNodeNamer {
width: 100%;
overflow: hidden;
}

.blockName {
Expand Down
3 changes: 0 additions & 3 deletions src/ui/src/core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,6 @@ export function generateCore() {
*/
async function init() {
await initSession();
addMailSubscription("pageChange", (pageKey: string) => {
setActivePageFromKey(pageKey);
});
sendKeepAliveMessage();
if (mode.value != "edit") return;
}
Expand Down
23 changes: 21 additions & 2 deletions src/ui/src/renderer/ComponentRenderer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,15 @@
</template>

<script setup lang="ts">
import { inject, ref, computed, watch, onBeforeMount, onMounted } from "vue";
import {
inject,
ref,
computed,
watch,
onBeforeMount,
onMounted,
nextTick,
} from "vue";
import { Component } from "@/writerTypes";
import ComponentProxy from "./ComponentProxy.vue";
import RendererNotifications from "./RendererNotifications.vue";
Expand All @@ -39,11 +47,19 @@ const wf = inject(injectionKeys.core);
const wfbm = inject(injectionKeys.builderManager);
const templateEvaluator = useEvaluator(wf);
const importedModulesSpecifiers: Record<string, string> = {};
const lastActivePageId = ref({});

const activeRootId = computed<Component["id"]>(
() => wfbm?.activeRootId.value ?? "root",
);

watch(activeRootId, (newMode, previousMode) => {
lastActivePageId.value[previousMode] = wf.activePageId;
const lastPageId = lastActivePageId.value?.[newMode];
if (!lastPageId) return;
wf.setActivePageId(lastPageId);
});

const coreRootFields = templateEvaluator.getEvaluatedFields([
{ componentId: "root", instanceNumber: 0 },
]);
Expand Down Expand Up @@ -157,8 +173,11 @@ function addMailSubscriptions() {
el.rel = "noopener noreferrer";
el.click();
});
wf.addMailSubscription("pageChange", (pageKey: string) => {
wf.addMailSubscription("pageChange", async (pageKey: string) => {
wfbm.setMode("ui");
await nextTick();
changePageInHash(pageKey);
wf.setActivePageFromKey(pageKey);
});
wf.addMailSubscription(
"routeVarsChange",
Expand Down
3 changes: 2 additions & 1 deletion src/ui/src/writerTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,11 @@ export type WriterComponentDefinition = {
description: string; // Short description
docs?: string; // Collapsible mini-docs
toolkit?: "core" | "workflows";
deprecated?: boolean;
category?: string; // Category (Layout, Content, etc)
allowedChildrenTypes?: (string | "*" | "inherit")[]; // Which component types are allowed inside (if any)
allowedParentTypes?: string[]; // Which component types can contain this type of component
slot?: string; // In which slot component should render whgen "*" is used it will render in all slots
slot?: string; // In which slot component should render when "*" is used it will render in all slots
fields?: Record<
string, // Id for the field
WriterComponentDefinitionField
Expand Down
2 changes: 2 additions & 0 deletions src/writer/blocks/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from writer.blocks.addtostatelist import AddToStateList
from writer.blocks.calleventhandler import CallEventHandler
from writer.blocks.changepage import ChangePage
from writer.blocks.code import CodeBlock
from writer.blocks.foreach import ForEach
from writer.blocks.httprequest import HTTPRequest
Expand Down Expand Up @@ -35,3 +36,4 @@
WriterAddToKG.register("workflows_writeraddtokg")
UIEventTrigger.register("workflows_uieventtrigger")
CodeBlock.register("workflows_code")
ChangePage.register("workflows_changepage")
69 changes: 36 additions & 33 deletions src/writer/blocks/calleventhandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,44 +7,47 @@


class CallEventHandler(WorkflowBlock):

@classmethod
def register(cls, type: str):
super(CallEventHandler, cls).register(type)
register_abstract_template(type, AbstractTemplate(
baseType="workflows_node",
writer={
"name": "Call event handler",
"description": "Executes an event handler.",
"category": "Logic",
"fields": {
"name": {
"name": "Name",
"type": "Handler",
"desc": "The name of the event handling function."
},
"additionalArgs": {
"name": "Additional arguments",
"init": '{ "my_arg": 2 }',
"type": "Object",
"control": "Textarea",
"default": "{}"
},
},
"outs": {
"success": {
"name": "Success",
"description": "The event handler execution was successful.",
"style": "success",
register_abstract_template(
type,
AbstractTemplate(
baseType="workflows_node",
writer={
"name": "Call event handler",
"description": "Executes an event handler.",
"category": "Logic",
"deprecated": True,
"fields": {
"name": {
"name": "Name",
"type": "Handler",
"desc": "The name of the event handling function.",
},
"additionalArgs": {
"name": "Additional arguments",
"init": '{ "my_arg": 2 }',
"type": "Object",
"control": "Textarea",
"default": "{}",
},
},
"error": {
"name": "Error",
"description": "The event handler execution wasn't successful.",
"style": "error",
"outs": {
"success": {
"name": "Success",
"description": "The event handler execution was successful.",
"style": "success",
},
"error": {
"name": "Error",
"description": "The event handler execution wasn't successful.",
"style": "error",
},
},
},
}
))
),
)

def run(self):
try:
Expand All @@ -59,7 +62,7 @@ def run(self):
"state": self.runner.session.session_state,
"context": self.execution_environment,
"session": writer.core._event_handler_session_info(),
"ui": writer.core._event_handler_ui_manager()
"ui": writer.core._event_handler_ui_manager(),
} | additional_args

handler_args = inspect.getfullargspec(callable_handler).args
Expand Down
48 changes: 48 additions & 0 deletions src/writer/blocks/changepage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
from writer.abstract import register_abstract_template
from writer.blocks.base_block import WorkflowBlock
from writer.ss_types import AbstractTemplate


class ChangePage(WorkflowBlock):
@classmethod
def register(cls, type: str):
super(ChangePage, cls).register(type)
register_abstract_template(
type,
AbstractTemplate(
baseType="workflows_node",
writer={
"name": "Change page",
"description": "Changes the active page.",
"category": "Other",
"fields": {
"pageKey": {
"name": "Page key",
"type": "Text",
"desc": "The identifying key of the target page.",
},
},
"outs": {
"success": {
"name": "Success",
"description": "The page change was successful.",
"style": "success",
},
"error": {
"name": "Error",
"description": "The event handler execution wasn't successful.",
"style": "error",
},
},
},
),
)

def run(self):
try:
page_key = self._get_field("pageKey", required=True)
self.runner.session.session_state.set_page(page_key)
self.outcome = "success"
except BaseException as e:
self.outcome = "error"
raise e
Loading