Merge pull request #125 from getmaxun/develop
chore: release public v0.0.1
This commit is contained in:
16
README.md
16
README.md
@@ -1,7 +1,7 @@
|
|||||||
<h1 align="center">
|
<h1 align="center">
|
||||||
<div>
|
<div>
|
||||||
<a href="https://maxun-website.vercel.app/">
|
<a href="https://maxun-website.vercel.app/">
|
||||||
<img src="/public/img/maxunlogo.png" width="50" />
|
<img src="/src/assets/maxunlogo.png" width="50" />
|
||||||
<br>
|
<br>
|
||||||
Maxun
|
Maxun
|
||||||
</a>
|
</a>
|
||||||
@@ -18,7 +18,8 @@ Maxun lets you train a robot in 2 minutes and scrape the web on auto-pilot. Web
|
|||||||
<a href="https://maxun-website.vercel.app/"><b>Website</b></a> |
|
<a href="https://maxun-website.vercel.app/"><b>Website</b></a> |
|
||||||
<a href="https://discord.com/invite/NFhWDCdb"><b>Discord</b></a> |
|
<a href="https://discord.com/invite/NFhWDCdb"><b>Discord</b></a> |
|
||||||
<a href="https://x.com/maxun_io"><b>Twitter</b></a> |
|
<a href="https://x.com/maxun_io"><b>Twitter</b></a> |
|
||||||
<a href="https://docs.google.com/forms/d/e/1FAIpQLSdbD2uhqC4sbg4eLZ9qrFbyrfkXZ2XsI6dQ0USRCQNZNn5pzg/viewform"><b>Join Maxun Cloud</b></a>
|
<a href="https://docs.google.com/forms/d/e/1FAIpQLSdbD2uhqC4sbg4eLZ9qrFbyrfkXZ2XsI6dQ0USRCQNZNn5pzg/viewform"><b>Join Maxun Cloud</b></a> |
|
||||||
|
<a href="https://www.youtube.com/@MaxunOSS"><b>Watch Tutorials</b></a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||

|

|
||||||
@@ -109,6 +110,17 @@ BYOP (Bring Your Own Proxy) lets you connect external proxies to bypass anti-bot
|
|||||||
# Cloud
|
# Cloud
|
||||||
We offer a managed cloud version to run Maxun without having to manage the infrastructure and extract data at scale. Maxun cloud also deals with anti-bot detection, huge proxy network with automatic proxy rotation, and CAPTCHA solving. If this interests you, [join the cloud waitlist](https://docs.google.com/forms/d/e/1FAIpQLSdbD2uhqC4sbg4eLZ9qrFbyrfkXZ2XsI6dQ0USRCQNZNn5pzg/viewform) as we launch soon.
|
We offer a managed cloud version to run Maxun without having to manage the infrastructure and extract data at scale. Maxun cloud also deals with anti-bot detection, huge proxy network with automatic proxy rotation, and CAPTCHA solving. If this interests you, [join the cloud waitlist](https://docs.google.com/forms/d/e/1FAIpQLSdbD2uhqC4sbg4eLZ9qrFbyrfkXZ2XsI6dQ0USRCQNZNn5pzg/viewform) as we launch soon.
|
||||||
|
|
||||||
|
# Screenshots
|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
# Note
|
# Note
|
||||||
This project is in early stages of development. Your feedback is very important for us - we're actively working to improve the product. <a href="https://forms.gle/E8vRMVB7bUbsSktPA">Drop anonymous feedback here.</a>
|
This project is in early stages of development. Your feedback is very important for us - we're actively working to improve the product. <a href="https://forms.gle/E8vRMVB7bUbsSktPA">Drop anonymous feedback here.</a>
|
||||||
|
|
||||||
|
|||||||
@@ -52,9 +52,6 @@ services:
|
|||||||
# DEBUG: pw:api
|
# DEBUG: pw:api
|
||||||
# PWDEBUG: 1 # Enables debugging
|
# PWDEBUG: 1 # Enables debugging
|
||||||
CHROMIUM_FLAGS: '--disable-gpu --no-sandbox --headless=new'
|
CHROMIUM_FLAGS: '--disable-gpu --no-sandbox --headless=new'
|
||||||
volumes:
|
|
||||||
# - /tmp/.X11-unix:/tmp/.X11-unix
|
|
||||||
- /var/run/dbus:/var/run/dbus # Add this for D-Bus support
|
|
||||||
security_opt:
|
security_opt:
|
||||||
- seccomp=unconfined # This might help with browser sandbox issues
|
- seccomp=unconfined # This might help with browser sandbox issues
|
||||||
# Increase shared memory size for Chromium
|
# Increase shared memory size for Chromium
|
||||||
@@ -63,6 +60,10 @@ services:
|
|||||||
- postgres
|
- postgres
|
||||||
- redis
|
- redis
|
||||||
- minio
|
- minio
|
||||||
|
volumes:
|
||||||
|
- ./server:/app/server # Mount server source code for hot reloading
|
||||||
|
- ./maxun-core:/app/maxun-core # Mount maxun-core for any shared code updates
|
||||||
|
- /var/run/dbus:/var/run/dbus
|
||||||
|
|
||||||
frontend:
|
frontend:
|
||||||
build:
|
build:
|
||||||
@@ -71,6 +72,9 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "5173:5173"
|
- "5173:5173"
|
||||||
env_file: .env
|
env_file: .env
|
||||||
|
volumes:
|
||||||
|
- ./:/app # Mount entire frontend app directory for hot reloading
|
||||||
|
- /app/node_modules # Anonymous volume to prevent overwriting node_modules
|
||||||
depends_on:
|
depends_on:
|
||||||
- backend
|
- backend
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
name="description"
|
name="description"
|
||||||
content="Web site created using Vite"
|
content="Web site created using Vite"
|
||||||
/>
|
/>
|
||||||
<link rel="icon" type="image/png" href="img/maxunlogo.png">
|
<link rel="icon" type="image/png" href="src/assets/maxunlogo.png">
|
||||||
<title>Maxun | Open Source No Code Web Data Extraction Platform</title>
|
<title>Maxun | Open Source No Code Web Data Extraction Platform</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@@ -650,7 +650,7 @@ export async function handleRunRecording(id: string, userId: string) {
|
|||||||
throw new Error('browserId or runId or userId is undefined');
|
throw new Error('browserId or runId or userId is undefined');
|
||||||
}
|
}
|
||||||
|
|
||||||
const socket = io(`${process.env.BACKEND_URL}/${browserId}`, {
|
const socket = io(`${process.env.BACKEND_URL ? process.env.BACKEND_URL : 'http://localhost:8080'}/${browserId}`, {
|
||||||
transports: ['websocket'],
|
transports: ['websocket'],
|
||||||
rejectUnauthorized: false
|
rejectUnauthorized: false
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Client } from 'minio';
|
|||||||
import Run from '../models/Run';
|
import Run from '../models/Run';
|
||||||
|
|
||||||
const minioClient = new Client({
|
const minioClient = new Client({
|
||||||
endPoint: process.env.MINIO_ENDPOINT || 'localhost',
|
endPoint: process.env.MINIO_ENDPOINT ? process.env.MINIO_ENDPOINT : 'localhost',
|
||||||
port: parseInt(process.env.MINIO_PORT || '9000'),
|
port: parseInt(process.env.MINIO_PORT || '9000'),
|
||||||
useSSL: false,
|
useSSL: false,
|
||||||
accessKey: process.env.MINIO_ACCESS_KEY || 'minio-access-key',
|
accessKey: process.env.MINIO_ACCESS_KEY || 'minio-access-key',
|
||||||
@@ -108,7 +108,8 @@ class BinaryOutputService {
|
|||||||
await this.uploadBinaryOutputToMinioBucket(run, minioKey, binaryData);
|
await this.uploadBinaryOutputToMinioBucket(run, minioKey, binaryData);
|
||||||
|
|
||||||
// Construct the public URL for the uploaded object
|
// Construct the public URL for the uploaded object
|
||||||
const publicUrl = `http://${process.env.MINIO_ENDPOINT}:${process.env.MINIO_PORT}/${this.bucketName}/${minioKey}`;
|
// todo: use minio endpoint
|
||||||
|
const publicUrl = `http://localhost:${process.env.MINIO_PORT}/${this.bucketName}/${minioKey}`;
|
||||||
|
|
||||||
// Save the public URL in the result object
|
// Save the public URL in the result object
|
||||||
uploadedBinaryOutput[key] = publicUrl;
|
uploadedBinaryOutput[key] = publicUrl;
|
||||||
|
|||||||
@@ -223,7 +223,7 @@ export async function handleRunRecording(id: string, userId: string) {
|
|||||||
throw new Error('browserId or runId or userId is undefined');
|
throw new Error('browserId or runId or userId is undefined');
|
||||||
}
|
}
|
||||||
|
|
||||||
const socket = io(`${process.env.BACKEND_URL}/${browserId}`, {
|
const socket = io(`${process.env.BACKEND_URL ? process.env.BACKEND_URL : 'http://localhost:8080'}/${browserId}`, {
|
||||||
transports: ['websocket'],
|
transports: ['websocket'],
|
||||||
rejectUnauthorized: false
|
rejectUnauthorized: false
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
export const apiUrl = import.meta.env.VITE_BACKEND_URL;
|
export const apiUrl = import.meta.env.VITE_BACKEND_URL ? import.meta.env.VITE_BACKEND_URL : 'http://localhost:8080'
|
||||||
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
@@ -2,6 +2,7 @@ import React from 'react';
|
|||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import { Typography, FormControlLabel, Checkbox, Box } from '@mui/material';
|
import { Typography, FormControlLabel, Checkbox, Box } from '@mui/material';
|
||||||
import { useActionContext } from '../../context/browserActions';
|
import { useActionContext } from '../../context/browserActions';
|
||||||
|
import MaxunLogo from "../../assets/maxunlogo.png";
|
||||||
|
|
||||||
const CustomBoxContainer = styled.div`
|
const CustomBoxContainer = styled.div`
|
||||||
position: relative;
|
position: relative;
|
||||||
@@ -110,7 +111,7 @@ const ActionDescriptionBox = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<CustomBoxContainer>
|
<CustomBoxContainer>
|
||||||
<Logo src="/img/maxunlogo.png" alt="Maxun Logo" />
|
<Logo src={MaxunLogo} alt="Maxun Logo" />
|
||||||
<Triangle />
|
<Triangle />
|
||||||
<Content>
|
<Content>
|
||||||
{renderActionDescription()}
|
{renderActionDescription()}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { AuthContext } from '../../context/auth';
|
|||||||
import { SaveRecording } from '../molecules/SaveRecording';
|
import { SaveRecording } from '../molecules/SaveRecording';
|
||||||
import DiscordIcon from '../atoms/DiscordIcon';
|
import DiscordIcon from '../atoms/DiscordIcon';
|
||||||
import { apiUrl } from '../../apiConfig';
|
import { apiUrl } from '../../apiConfig';
|
||||||
|
import MaxunLogo from "../../assets/maxunlogo.png";
|
||||||
|
|
||||||
interface NavBarProps {
|
interface NavBarProps {
|
||||||
recordingName: string;
|
recordingName: string;
|
||||||
@@ -55,7 +56,7 @@ export const NavBar: React.FC<NavBarProps> = ({ recordingName, isRecording }) =>
|
|||||||
display: 'flex',
|
display: 'flex',
|
||||||
justifyContent: 'flex-start',
|
justifyContent: 'flex-start',
|
||||||
}}>
|
}}>
|
||||||
<img src="img/maxunlogo.png" width={45} height={40} style={{ borderRadius: '5px', margin: '5px 0px 5px 15px' }} />
|
<img src={MaxunLogo} width={45} height={40} style={{ borderRadius: '5px', margin: '5px 0px 5px 15px' }} />
|
||||||
<div style={{ padding: '11px' }}><ProjectName>Maxun</ProjectName></div>
|
<div style={{ padding: '11px' }}><ProjectName>Maxun</ProjectName></div>
|
||||||
</div>
|
</div>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useCallback, useEffect } from 'react';
|
import React, { useState, useCallback, useEffect, useMemo } from 'react';
|
||||||
import { Button, Paper, Box, TextField, IconButton } from "@mui/material";
|
import { Button, Paper, Box, TextField, IconButton } from "@mui/material";
|
||||||
import EditIcon from '@mui/icons-material/Edit';
|
import EditIcon from '@mui/icons-material/Edit';
|
||||||
import TextFieldsIcon from '@mui/icons-material/TextFields';
|
import TextFieldsIcon from '@mui/icons-material/TextFields';
|
||||||
@@ -373,6 +373,20 @@ export const RightSidePanel: React.FC<RightSidePanelProps> = ({ onFinishCapture
|
|||||||
stopGetScreenshot();
|
stopGetScreenshot();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const isConfirmCaptureDisabled = useMemo(() => {
|
||||||
|
// Check if we are in the initial stage and if there are no browser steps or no valid list selectors with fields
|
||||||
|
if (captureStage !== 'initial') return false;
|
||||||
|
|
||||||
|
const hasValidListSelector = browserSteps.some(step =>
|
||||||
|
step.type === 'list' &&
|
||||||
|
step.listSelector &&
|
||||||
|
Object.keys(step.fields).length > 0
|
||||||
|
);
|
||||||
|
|
||||||
|
// Disable the button if there are no valid list selectors or if there are unconfirmed list text fields
|
||||||
|
return !hasValidListSelector || hasUnconfirmedListTextFields;
|
||||||
|
}, [captureStage, browserSteps, hasUnconfirmedListTextFields]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Paper sx={{ height: '520px', width: 'auto', alignItems: "center", background: 'inherit' }} id="browser-actions" elevation={0}>
|
<Paper sx={{ height: '520px', width: 'auto', alignItems: "center", background: 'inherit' }} id="browser-actions" elevation={0}>
|
||||||
{/* <SimpleBox height={60} width='100%' background='lightGray' radius='0%'>
|
{/* <SimpleBox height={60} width='100%' background='lightGray' radius='0%'>
|
||||||
@@ -387,7 +401,7 @@ export const RightSidePanel: React.FC<RightSidePanelProps> = ({ onFinishCapture
|
|||||||
<Button
|
<Button
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
onClick={handleConfirmListCapture}
|
onClick={handleConfirmListCapture}
|
||||||
disabled={hasUnconfirmedListTextFields}
|
disabled={captureStage === 'initial' ? isConfirmCaptureDisabled : hasUnconfirmedListTextFields}
|
||||||
>
|
>
|
||||||
{captureStage === 'initial' ? 'Confirm Capture' :
|
{captureStage === 'initial' ? 'Confirm Capture' :
|
||||||
captureStage === 'pagination' ? 'Confirm Pagination' :
|
captureStage === 'pagination' ? 'Confirm Pagination' :
|
||||||
|
|||||||
Reference in New Issue
Block a user