Skip to content

Commit

Permalink
Merge branch 'feature/community-addons' of https://github.com/elliotB…
Browse files Browse the repository at this point in the history
  • Loading branch information
elliotBraem committed Oct 25, 2023
2 parents 5be82c5 + 775e953 commit 2769df3
Show file tree
Hide file tree
Showing 12 changed files with 919 additions and 31 deletions.
124 changes: 124 additions & 0 deletions playwright-tests/tests/addons.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
const { test, expect } = require("@playwright/test");

test.describe("Wallet is connected", () => {
test.use({
storageState: "playwright-tests/storage-states/wallet-connected.json",
});

test.describe("AddonsConfigurator", () => {
const baseUrl =
"/devgovgigs.near/widget/app?page=community.configuration&handle=devhub-test";
// const dropdownSelector =
// 'input[data-component="near/widget/DIG.InputSelect"]';
// const addButtonSelector = "button.btn-success:has(i.bi.bi-plus)";
// const toggleButtonSelector = 'button[role="switch"]';
// const moveUpButtonSelector = "button.btn-secondary:has(i.bi.bi-arrow-up)";
// const removeButtonSelector =
// "button.btn-outline-danger:has(i.bi.bi-trash-fill)";

test("Addons configuration section comes up on load", async ({ page }) => {
await page.goto(baseUrl);

const addonsConfiguratorSelector = 'span:has-text("Addons")';

await page.waitForSelector(addonsConfiguratorSelector, {
state: "visible",
});
});
});
});

// NOTE:
// The below tests need some more work.
// We are using the DIG component, which is essentially a Radix Select field.
// Radix select renders as an input and requires to be focused, then value inputted, before the option can be selected.
// I was having trouble making this work.

// test('Can add an addon to the list', async ({ page }) => {
// await page.goto(baseUrl);

// await page.click(dropdownSelector);
// await page.fill(dropdownSelector, 'Wiki');
// await page.click(`li:has-text('Wiki')`);

// await page.waitForSelector(addButtonSelector, {
// state: "visible",
// });

// await page.click(addButtonSelector);

// const addedAddon = await page.$('input[type="text"].form-control[disabled][value="Wiki"]'); // You will need to fill this in
// expect(addedAddon).toBeTruthy();
// });

// test('Can reorder addons in the list', async ({ page }) => {
// await page.goto(baseUrl);

// await page.click(dropdownSelector);
// await page.inputValue(dropdownSelector, 'Wiki');
// await page.click(`li:has-text('Wiki')`);

// await page.waitForSelector(addButtonSelector, {
// state: "visible",
// });

// await page.click(addButtonSelector);

// await page.inputValue(dropdownSelector, 'telegram');
// await page.click(addButtonSelector);

// await page.waitForSelector(moveUpButtonSelector, {
// state: "visible",
// });

// await page.click(moveUpButtonSelector);

// const firstAddon = await page.$('input[type="text"].form-control[disabled][value="Telegram"]');
// const secondAddon = await page.$('input[type="text"].form-control[disabled][value="Wiki"]');
// expect(firstAddon).toBeTruthy();
// expect(secondAddon).toBeTruthy();
// });

// test('Can remove an addon from the list', async ({ page }) => {
// await page.goto(baseUrl);

// await page.inputValue(dropdownSelector, 'Wiki');

// await page.waitForSelector(addButtonSelector, {
// state: "visible",
// });

// await page.click(addButtonSelector);

// await page.waitForSelector(removeButtonSelector, {
// state: "visible",
// });

// await page.click(removeButtonSelector);

// const removedAddon = await page.$('input[type="text"].form-control[disabled][value="Wiki"]'); // You will need to fill this in
// expect(removedAddon).toBeNull();
// });

// test('Can toggle to disable an addon', async ({ page }) => {
// await page.goto(baseUrl);

// await page.inputValue(dropdownSelector, 'Wiki');
// await page.waitForSelector(addButtonSelector, {
// state: "visible",
// });

// await page.click(addButtonSelector);

// await page.waitForSelector(toggleButtonSelector, {
// state: "visible",
// });

// await page.click(toggleButtonSelector);

// const toggleState = await page.getAttribute(toggleButtonSelector, 'aria-checked');
// expect(toggleState).toBe('false');
// });
// });

// });
48 changes: 24 additions & 24 deletions src/core/adapter/devhub-contract.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -113,30 +113,30 @@ function getAvailableAddons() {
configurator_widget:
"${REPL_DEVHUB}/widget/devhub.entity.addon.telegram.Configurator",
},
{
id: "github",
title: "Github",
description: "Connect your github",
view_widget: "${REPL_DEVHUB}/widget/devhub.entity.addon.github.Viewer",
configurator_widget:
"${REPL_DEVHUB}/widget/devhub.entity.addon.github.Configurator",
},
{
id: "kanban",
title: "Kanban",
description: "Connect your github kanban board",
view_widget: "${REPL_DEVHUB}/widget/devhub.entity.addon.kanban.Viewer",
configurator_widget:
"${REPL_DEVHUB}/widget/devhub.entity.addon.kanban.Configurator",
},
{
id: "blog",
title: "Blog",
description: "Create a blog for your community",
view_widget: "${REPL_DEVHUB}/widget/devhub.entity.addon.blog.Viewer",
configurator_widget:
"${REPL_DEVHUB}/widget/devhub.entity.addon.blog.Configurator",
},
// {
// id: "github",
// title: "Github",
// description: "Connect your github",
// view_widget: "${REPL_DEVHUB}/widget/devhub.entity.addon.github.Viewer",
// configurator_widget:
// "${REPL_DEVHUB}/widget/devhub.entity.addon.github.Configurator",
// },
// {
// id: "kanban",
// title: "Kanban",
// description: "Connect your github kanban board",
// view_widget: "${REPL_DEVHUB}/widget/devhub.entity.addon.kanban.Viewer",
// configurator_widget:
// "${REPL_DEVHUB}/widget/devhub.entity.addon.kanban.Configurator",
// },
// {
// id: "blog",
// title: "Blog",
// description: "Create a blog for your community",
// view_widget: "${REPL_DEVHUB}/widget/devhub.entity.addon.blog.Viewer",
// configurator_widget:
// "${REPL_DEVHUB}/widget/devhub.entity.addon.blog.Configurator",
// },
];
// return Near.view("${REPL_DEVHUB_CONTRACT}", "get_available_addons") ?? null;
}
Expand Down
1 change: 0 additions & 1 deletion src/devhub/components/templates/AppLayout.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,6 @@ const AppHeader = ({ page }) => {
};

function AppLayout({ page, children }) {
console.log("page", page);
return (
<Container>
<AppHeader page={page} />
Expand Down
117 changes: 117 additions & 0 deletions src/devhub/entity/addon/telegram/Configurator.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
const { Tile } =
VM.require("${REPL_DEVHUB}/widget/devhub.components.molecule.Tile") ||
(() => <></>);

const { data, onSubmit } = props;

const Container = styled.div`
display: flex;
flex-direction: column;
width: 100%;
`;

const Item = styled.div`
padding: 10px;
margin: 5px;
display: flex;
align-items: center;
flex-direction: row;
gap: 10px;
`;

const EditableField = styled.input`
flex: 1;
`;
const initialData = data.handles;
const [handles, setHandles] = useState(initialData || []);
const [newItem, setNewItem] = useState("");

const handleAddItem = () => {
if (newItem) {
setHandles([...handles, newItem]);
setNewItem("");
}
};

const handleDeleteItem = (index) => {
const updatedData = [...handles];
updatedData.splice(index, 1);
setHandles(updatedData);
};

const handleSubmit = () => {
onSubmit({ handles: handles.map((handle) => handle.trim()) });
};

return (
<Tile className="p-3">
<Container>
{handles.map((item, index) => (
<Item key={index}>
<div className="flex-grow-1">
<Widget
// TODO: LEGACY.
src="${REPL_DEVHUB}/widget/gigs-board.components.molecule.text-input"
props={{
className: "flex-grow-1",
value: item,
placeholder: "Telegram Handle",
inputProps: {
prefix: "https://t.me/",
disabled: true,
},
}}
/>
</div>
<button
className="btn btn-outline-danger"
onClick={() => handleDeleteItem(index)}
>
<i className="bi bi-trash-fill" />
</button>
</Item>
))}
<Item>
<div className="flex-grow-1">
<Widget
// TODO: LEGACY.
src="${REPL_DEVHUB}/widget/gigs-board.components.molecule.text-input"
props={{
className: "flex-grow-1",
onChange: (e) => setNewItem(e.target.value),
value: newItem,
placeholder: "Telegram Handle",
inputProps: {
prefix: "https://t.me/",
},
}}
/>
</div>
<button
className="btn btn-success"
onClick={handleAddItem}
disabled={newItem === ""}
>
<i className="bi bi-plus" />
</button>
</Item>
<div
className={"d-flex align-items-center justify-content-end gap-3 mt-4"}
>
<Widget
src={"${REPL_DEVHUB}/widget/devhub.components.molecule.Button"}
props={{
classNames: { root: "btn-success" },
disabled: initialData === handles,
icon: {
type: "bootstrap_icon",
variant: "bi-check-circle-fill",
},
label: "Submit",
onClick: handleSubmit,
}}
/>
</div>
</Container>
</Tile>
);
51 changes: 51 additions & 0 deletions src/devhub/entity/addon/telegram/Viewer.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
const { handles } = props;

const CenteredMessage = styled.div`
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 100%;
height: ${(p) => p.height ?? "100%"};
`;

if (!handles || handles.length === 0) {
return (
<CenteredMessage height={"384px"}>
<h2>No Telegram Configured</h2>
</CenteredMessage>
);
} else {
return (
<div>
{(handles || []).map((tg) => (
<>
<iframe
iframeResizer
src={
"https://j96g3uepe0.execute-api.us-east-1.amazonaws.com/groups-ui/" +
tg
}
frameborder="0"
// width and minWidth required by iframeResizer
style={{
width: "1px",
minWidth: "100%",
marginTop: "20px",
}}
></iframe>

<a href={"https://t.me/" + tg} target="_blank">
<Widget
src={"${REPL_DEVHUB}/widget/devhub.components.molecule.Button"}
props={{
classNames: { root: "btn-primary" },
label: "View More",
}}
/>
</a>
</>
))}
</div>
);
}
Loading

0 comments on commit 2769df3

Please sign in to comment.