update
parent
4d84e5c5c9
commit
038d89ced1
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,53 @@
|
|||
"""auto
|
||||
|
||||
Revision ID: 2515ed7e2966
|
||||
Revises: 72853b8d2126
|
||||
Create Date: 2026-08-07 14:49:26.409410+00:00
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
import sqlmodel # SQLModel renders AutoString() into migrations but adds no import
|
||||
|
||||
|
||||
revision: str = '2515ed7e2966'
|
||||
down_revision: Union[str, None] = '72853b8d2126'
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
# Deliberately NOT schema-qualified: Inbox_Messages.application_status carries
|
||||
# type.schema = None, so the ORM emits the type name unqualified and resolves it
|
||||
# through search_path. Creating it as app.<name> would not match.
|
||||
application_status = sa.Enum(
|
||||
'PROCESS', 'PENDING', 'APPROVED', 'REJECTED', 'ONHOLD', 'CLOSED',
|
||||
name='candidate_application_status',
|
||||
)
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
# op.add_column does NOT emit CREATE TYPE, so the ALTER below would fail with
|
||||
# `type "candidate_application_status" does not exist`.
|
||||
application_status.create(op.get_bind(), checkfirst=True)
|
||||
# server_default is required, not cosmetic: the column is NOT NULL and every
|
||||
# existing row would be null without it, which Postgres rejects outright.
|
||||
op.add_column(
|
||||
'inbox_messages',
|
||||
sa.Column(
|
||||
'application_status',
|
||||
application_status,
|
||||
nullable=False,
|
||||
server_default='CLOSED',
|
||||
),
|
||||
schema='app',
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_column('inbox_messages', 'application_status', schema='app')
|
||||
# drop_column leaves the TYPE behind; without this, re-running upgrade fails
|
||||
# with `type "candidate_application_status" already exists`.
|
||||
application_status.drop(op.get_bind(), checkfirst=True)
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
"""auto
|
||||
|
||||
Revision ID: 8c67df87f19c
|
||||
Revises: 2515ed7e2966
|
||||
Create Date: 2026-08-07 14:55:42.858317+00:00
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
import sqlmodel # SQLModel renders AutoString() into migrations but adds no import
|
||||
from sqlalchemy.dialects import postgresql
|
||||
|
||||
revision: str = '8c67df87f19c'
|
||||
down_revision: Union[str, None] = '2515ed7e2966'
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.alter_column('inbox_messages', 'application_status',
|
||||
existing_type=postgresql.ENUM('PROCESS', 'PENDING', 'APPROVED', 'REJECTED', 'ONHOLD', 'CLOSED', name='candidate_application_status'),
|
||||
server_default=None,
|
||||
existing_nullable=False,
|
||||
schema='app')
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.alter_column('inbox_messages', 'application_status',
|
||||
existing_type=postgresql.ENUM('PROCESS', 'PENDING', 'APPROVED', 'REJECTED', 'ONHOLD', 'CLOSED', name='candidate_application_status'),
|
||||
server_default=sa.text("'CLOSED'::candidate_application_status"),
|
||||
existing_nullable=False,
|
||||
schema='app')
|
||||
# ### end Alembic commands ###
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
"""add experience to inbox_messages
|
||||
|
||||
Revision ID: fcd3f4d69b60
|
||||
Revises: 8c67df87f19c
|
||||
Create Date: 2026-08-10 09:56:55.290497+00:00
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
import sqlmodel # SQLModel renders AutoString() into migrations but adds no import
|
||||
|
||||
|
||||
revision: str = 'fcd3f4d69b60'
|
||||
down_revision: Union[str, None] = '8c67df87f19c'
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.add_column('inbox_messages', sa.Column('experience', sqlmodel.sql.sqltypes.AutoString(), nullable=True), schema='app')
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_column('inbox_messages', 'experience', schema='app')
|
||||
# ### end Alembic commands ###
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
"""auto
|
||||
|
||||
Revision ID: ed78f1706042
|
||||
Revises: fcd3f4d69b60
|
||||
Create Date: 2026-08-11 10:07:53.324376+00:00
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
import sqlmodel # SQLModel renders AutoString() into migrations but adds no import
|
||||
|
||||
|
||||
revision: str = 'ed78f1706042'
|
||||
down_revision: Union[str, None] = 'fcd3f4d69b60'
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.add_column('inbox_messages', sa.Column('candidate_phone_number', sqlmodel.sql.sqltypes.AutoString(), nullable=True), schema='app')
|
||||
op.add_column('inbox_messages', sa.Column('current_employment', sqlmodel.sql.sqltypes.AutoString(), nullable=True), schema='app')
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_column('inbox_messages', 'current_employment', schema='app')
|
||||
op.drop_column('inbox_messages', 'candidate_phone_number', schema='app')
|
||||
# ### end Alembic commands ###
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
"""auto
|
||||
|
||||
Revision ID: d0b62342a32f
|
||||
Revises: ed78f1706042
|
||||
Create Date: 2026-08-11 11:49:25.965217+00:00
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
import sqlmodel # SQLModel renders AutoString() into migrations but adds no import
|
||||
|
||||
|
||||
revision: str = 'd0b62342a32f'
|
||||
down_revision: Union[str, None] = 'ed78f1706042'
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('notes',
|
||||
sa.Column('id', sa.Uuid(), nullable=False),
|
||||
sa.Column('note', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
|
||||
sa.Column('created_at', sa.DateTime(), nullable=False),
|
||||
sa.Column('updated_at', sa.DateTime(), nullable=False),
|
||||
sa.Column('user_id', sa.Uuid(), nullable=True),
|
||||
sa.Column('created_by', sa.Uuid(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['created_by'], ['app.users.id'], name=op.f('fk_notes_created_by_users')),
|
||||
sa.ForeignKeyConstraint(['user_id'], ['app.users.id'], name=op.f('fk_notes_user_id_users')),
|
||||
sa.PrimaryKeyConstraint('id', name=op.f('pk_notes')),
|
||||
schema='app'
|
||||
)
|
||||
op.create_table('activity',
|
||||
sa.Column('id', sa.Uuid(), nullable=False),
|
||||
sa.Column('activity_type', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
|
||||
sa.Column('activity_date', sa.DateTime(), nullable=False),
|
||||
sa.Column('activity_time', sa.DateTime(), nullable=False),
|
||||
sa.Column('activity_status', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
|
||||
sa.Column('description', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
|
||||
sa.Column('inbox_id', sa.Integer(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['inbox_id'], ['app.inbox.id'], name=op.f('fk_activity_inbox_id_inbox')),
|
||||
sa.PrimaryKeyConstraint('id', name=op.f('pk_activity')),
|
||||
schema='app'
|
||||
)
|
||||
op.create_table('feedback',
|
||||
sa.Column('id', sa.Uuid(), nullable=False),
|
||||
sa.Column('review', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
|
||||
sa.Column('financial_status', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
|
||||
sa.Column('score', sa.Float(), nullable=False),
|
||||
sa.Column('note', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(), nullable=False),
|
||||
sa.Column('updated_at', sa.DateTime(), nullable=False),
|
||||
sa.Column('reviewed_by', sa.Uuid(), nullable=True),
|
||||
sa.Column('inbox_id', sa.Integer(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['inbox_id'], ['app.inbox.id'], name=op.f('fk_feedback_inbox_id_inbox')),
|
||||
sa.ForeignKeyConstraint(['reviewed_by'], ['app.users.id'], name=op.f('fk_feedback_reviewed_by_users')),
|
||||
sa.PrimaryKeyConstraint('id', name=op.f('pk_feedback')),
|
||||
schema='app'
|
||||
)
|
||||
op.create_table('interviews',
|
||||
sa.Column('id', sa.Uuid(), nullable=False),
|
||||
sa.Column('interview_date', sa.DateTime(), nullable=False),
|
||||
sa.Column('interview_time', sa.DateTime(), nullable=False),
|
||||
sa.Column('interview_type', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
|
||||
sa.Column('interview_status', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
|
||||
sa.Column('inbox_id', sa.Integer(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['inbox_id'], ['app.inbox.id'], name=op.f('fk_interviews_inbox_id_inbox')),
|
||||
sa.PrimaryKeyConstraint('id', name=op.f('pk_interviews')),
|
||||
schema='app'
|
||||
)
|
||||
op.add_column('inbox', sa.Column('favorite', sa.Boolean(), nullable=True), schema='app')
|
||||
op.add_column('inbox', sa.Column('rating', sa.Float(), nullable=True), schema='app')
|
||||
op.add_column('inbox_messages', sa.Column('candidate_education', sqlmodel.sql.sqltypes.AutoString(), nullable=True), schema='app')
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_column('inbox_messages', 'candidate_education', schema='app')
|
||||
op.drop_column('inbox', 'rating', schema='app')
|
||||
op.drop_column('inbox', 'favorite', schema='app')
|
||||
op.drop_table('interviews', schema='app')
|
||||
op.drop_table('feedback', schema='app')
|
||||
op.drop_table('activity', schema='app')
|
||||
op.drop_table('notes', schema='app')
|
||||
# ### end Alembic commands ###
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
"""auto
|
||||
|
||||
Revision ID: 681a78158447
|
||||
Revises: d0b62342a32f
|
||||
Create Date: 2026-08-11 13:11:58.032282+00:00
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
import sqlmodel # SQLModel renders AutoString() into migrations but adds no import
|
||||
from sqlalchemy.dialects import postgresql
|
||||
|
||||
revision: str = '681a78158447'
|
||||
down_revision: Union[str, None] = 'd0b62342a32f'
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.alter_column('activity', 'activity_date',
|
||||
existing_type=postgresql.TIMESTAMP(),
|
||||
type_=sa.DateTime(timezone=True),
|
||||
existing_nullable=False,
|
||||
schema='app')
|
||||
op.alter_column('activity', 'activity_time',
|
||||
existing_type=postgresql.TIMESTAMP(),
|
||||
type_=sa.DateTime(timezone=True),
|
||||
existing_nullable=False,
|
||||
schema='app')
|
||||
op.alter_column('feedback', 'created_at',
|
||||
existing_type=postgresql.TIMESTAMP(),
|
||||
type_=sa.DateTime(timezone=True),
|
||||
existing_nullable=False,
|
||||
schema='app')
|
||||
op.alter_column('feedback', 'updated_at',
|
||||
existing_type=postgresql.TIMESTAMP(),
|
||||
type_=sa.DateTime(timezone=True),
|
||||
existing_nullable=False,
|
||||
schema='app')
|
||||
op.alter_column('interviews', 'interview_date',
|
||||
existing_type=postgresql.TIMESTAMP(),
|
||||
type_=sa.DateTime(timezone=True),
|
||||
existing_nullable=False,
|
||||
schema='app')
|
||||
op.alter_column('interviews', 'interview_time',
|
||||
existing_type=postgresql.TIMESTAMP(),
|
||||
type_=sa.DateTime(timezone=True),
|
||||
existing_nullable=False,
|
||||
schema='app')
|
||||
op.alter_column('notes', 'created_at',
|
||||
existing_type=postgresql.TIMESTAMP(),
|
||||
type_=sa.DateTime(timezone=True),
|
||||
existing_nullable=False,
|
||||
schema='app')
|
||||
op.alter_column('notes', 'updated_at',
|
||||
existing_type=postgresql.TIMESTAMP(),
|
||||
type_=sa.DateTime(timezone=True),
|
||||
existing_nullable=False,
|
||||
schema='app')
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.alter_column('notes', 'updated_at',
|
||||
existing_type=sa.DateTime(timezone=True),
|
||||
type_=postgresql.TIMESTAMP(),
|
||||
existing_nullable=False,
|
||||
schema='app')
|
||||
op.alter_column('notes', 'created_at',
|
||||
existing_type=sa.DateTime(timezone=True),
|
||||
type_=postgresql.TIMESTAMP(),
|
||||
existing_nullable=False,
|
||||
schema='app')
|
||||
op.alter_column('interviews', 'interview_time',
|
||||
existing_type=sa.DateTime(timezone=True),
|
||||
type_=postgresql.TIMESTAMP(),
|
||||
existing_nullable=False,
|
||||
schema='app')
|
||||
op.alter_column('interviews', 'interview_date',
|
||||
existing_type=sa.DateTime(timezone=True),
|
||||
type_=postgresql.TIMESTAMP(),
|
||||
existing_nullable=False,
|
||||
schema='app')
|
||||
op.alter_column('feedback', 'updated_at',
|
||||
existing_type=sa.DateTime(timezone=True),
|
||||
type_=postgresql.TIMESTAMP(),
|
||||
existing_nullable=False,
|
||||
schema='app')
|
||||
op.alter_column('feedback', 'created_at',
|
||||
existing_type=sa.DateTime(timezone=True),
|
||||
type_=postgresql.TIMESTAMP(),
|
||||
existing_nullable=False,
|
||||
schema='app')
|
||||
op.alter_column('activity', 'activity_time',
|
||||
existing_type=sa.DateTime(timezone=True),
|
||||
type_=postgresql.TIMESTAMP(),
|
||||
existing_nullable=False,
|
||||
schema='app')
|
||||
op.alter_column('activity', 'activity_date',
|
||||
existing_type=sa.DateTime(timezone=True),
|
||||
type_=postgresql.TIMESTAMP(),
|
||||
existing_nullable=False,
|
||||
schema='app')
|
||||
# ### end Alembic commands ###
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
"""auto
|
||||
|
||||
Revision ID: 67c4c7974afa
|
||||
Revises: 681a78158447
|
||||
Create Date: 2026-08-11 13:52:11.674108+00:00
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
import sqlmodel # SQLModel renders AutoString() into migrations but adds no import
|
||||
|
||||
|
||||
revision: str = '67c4c7974afa'
|
||||
down_revision: Union[str, None] = '681a78158447'
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.add_column('inbox_messages', sa.Column('assigned_job_post_id', sa.Uuid(), nullable=True), schema='app')
|
||||
op.create_index(op.f('ix_inbox_messages_assigned_job_post_id'), 'inbox_messages', ['assigned_job_post_id'], unique=False, schema='app')
|
||||
op.create_foreign_key(op.f('fk_inbox_messages_assigned_job_post_id_job_posts'), 'inbox_messages', 'job_posts', ['assigned_job_post_id'], ['id'], source_schema='app', referent_schema='app')
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_constraint(op.f('fk_inbox_messages_assigned_job_post_id_job_posts'), 'inbox_messages', schema='app', type_='foreignkey')
|
||||
op.drop_index(op.f('ix_inbox_messages_assigned_job_post_id'), table_name='inbox_messages', schema='app')
|
||||
op.drop_column('inbox_messages', 'assigned_job_post_id', schema='app')
|
||||
# ### end Alembic commands ###
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
"""auto
|
||||
|
||||
Revision ID: 4b34909ae551
|
||||
Revises: 67c4c7974afa
|
||||
Create Date: 2026-08-12 07:46:38.028948+00:00
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
import sqlmodel # SQLModel renders AutoString() into migrations but adds no import
|
||||
|
||||
|
||||
revision: str = '4b34909ae551'
|
||||
down_revision: Union[str, None] = '67c4c7974afa'
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('manual_upload_candidate',
|
||||
sa.Column('id', sa.Uuid(), nullable=False),
|
||||
sa.Column('candidate_email', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
|
||||
sa.Column('candidate_name', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
|
||||
sa.Column('candidate_phone', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
|
||||
sa.Column('job_post_id', sa.Uuid(), nullable=True),
|
||||
sa.Column('full_text', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
|
||||
sa.Column('current_company', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
|
||||
sa.Column('user_id', sa.Uuid(), nullable=True),
|
||||
sa.Column('platform', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
|
||||
sa.Column('created_by', sa.Uuid(), nullable=True),
|
||||
sa.Column('experience', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
|
||||
sa.Column('status', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
|
||||
sa.Column('created_at', sa.DateTime(timezone=True), nullable=False),
|
||||
sa.Column('updated_at', sa.DateTime(timezone=True), nullable=False),
|
||||
sa.ForeignKeyConstraint(['created_by'], ['app.users.id'], name=op.f('fk_manual_upload_candidate_created_by_users')),
|
||||
sa.ForeignKeyConstraint(['job_post_id'], ['app.job_posts.id'], name=op.f('fk_manual_upload_candidate_job_post_id_job_posts')),
|
||||
sa.ForeignKeyConstraint(['user_id'], ['app.users.id'], name=op.f('fk_manual_upload_candidate_user_id_users')),
|
||||
sa.PrimaryKeyConstraint('id', name=op.f('pk_manual_upload_candidate')),
|
||||
schema='app'
|
||||
)
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_table('manual_upload_candidate', schema='app')
|
||||
# ### end Alembic commands ###
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
"""auto
|
||||
|
||||
Revision ID: 1a7c0e30aaab
|
||||
Revises: 4b34909ae551
|
||||
Create Date: 2026-08-12 08:17:21.212665+00:00
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
import sqlmodel # SQLModel renders AutoString() into migrations but adds no import
|
||||
|
||||
|
||||
revision: str = '1a7c0e30aaab'
|
||||
down_revision: Union[str, None] = '4b34909ae551'
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.add_column('manual_upload_candidate', sa.Column('referral_by', sqlmodel.sql.sqltypes.AutoString(), server_default='', nullable=False), schema='app')
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_column('manual_upload_candidate', 'referral_by', schema='app')
|
||||
# ### end Alembic commands ###
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
"""auto
|
||||
|
||||
Revision ID: 6ec5e105dce3
|
||||
Revises: 1a7c0e30aaab
|
||||
Create Date: 2026-08-12 08:45:01.957310+00:00
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
import sqlmodel # SQLModel renders AutoString() into migrations but adds no import
|
||||
|
||||
|
||||
revision: str = '6ec5e105dce3'
|
||||
down_revision: Union[str, None] = '1a7c0e30aaab'
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.add_column('manual_upload_candidate', sa.Column('file_name', sqlmodel.sql.sqltypes.AutoString(), server_default='', nullable=False), schema='app')
|
||||
op.add_column('manual_upload_candidate', sa.Column('file_path', sqlmodel.sql.sqltypes.AutoString(), server_default='', nullable=False), schema='app')
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_column('manual_upload_candidate', 'file_path', schema='app')
|
||||
op.drop_column('manual_upload_candidate', 'file_name', schema='app')
|
||||
# ### end Alembic commands ###
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
"""Taskiq CV-upload broker — isolated Redis stream so manual uploads
|
||||
never sit behind the bulk /email/fetch backlog.
|
||||
|
||||
Worker: taskiq worker taskiq_management.cv_broker_setup:cv_broker inbox.cv_tasks
|
||||
Scheduler: taskiq scheduler taskiq_management.cv_broker_setup:cv_scheduler inbox.cv_tasks
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
|
||||
from dotenv import load_dotenv
|
||||
from taskiq import TaskiqScheduler
|
||||
from taskiq.middlewares import SmartRetryMiddleware
|
||||
from taskiq.schedule_sources import LabelScheduleSource
|
||||
from taskiq_redis import (
|
||||
ListRedisScheduleSource,
|
||||
RedisAsyncResultBackend,
|
||||
RedisStreamBroker,
|
||||
)
|
||||
|
||||
from taskiq_management.broker_setup import MAX_RETRIES,RETRY_DELAY
|
||||
from taskiq_management.middleware import DeadLetterMiddleware
|
||||
|
||||
load_dotenv()
|
||||
|
||||
REDIS_URL=os.getenv("REDIS_URL","redis://localhost:6379/0")
|
||||
CV_QUEUE_NAME=os.getenv("TASKIQ_CV_QUEUE_NAME","cv_upload")
|
||||
|
||||
result_backend=RedisAsyncResultBackend(redis_url=REDIS_URL)
|
||||
cv_schedule_source=ListRedisScheduleSource(url=REDIS_URL,prefix="taskiq:schedule:cv")
|
||||
|
||||
cv_broker=(
|
||||
RedisStreamBroker(
|
||||
url=REDIS_URL,
|
||||
queue_name=CV_QUEUE_NAME,
|
||||
consumer_group_name=os.getenv("TASKIQ_CONSUMER_GROUP","taskiq"),
|
||||
idle_timeout=int(os.getenv("TASKIQ_IDLE_TIMEOUT_MS","600000")),
|
||||
)
|
||||
.with_result_backend(result_backend)
|
||||
.with_middlewares(
|
||||
DeadLetterMiddleware(redis_url=REDIS_URL),
|
||||
SmartRetryMiddleware(
|
||||
default_retry_count=MAX_RETRIES,
|
||||
default_retry_label=True,
|
||||
default_delay=RETRY_DELAY,
|
||||
use_jitter=True,
|
||||
use_delay_exponent=True,
|
||||
max_delay_exponent=float(os.getenv("TASKIQ_MAX_DELAY","120")),
|
||||
schedule_source=cv_schedule_source,
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
cv_scheduler=TaskiqScheduler(
|
||||
broker=cv_broker,
|
||||
sources=[cv_schedule_source,LabelScheduleSource(cv_broker)],
|
||||
)
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"hash": "4acff9bb",
|
||||
"configHash": "53a8a5ec",
|
||||
"lockfileHash": "fac4afd8",
|
||||
"browserHash": "5b5a9255",
|
||||
"optimized": {},
|
||||
"chunks": {}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"type": "module"
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
import{r as n,j as s,I as c,a9 as i}from"./index-BTPmxtwM.js";function d(){const[e,a]=n.useState(0);return s.jsxs("div",{className:"page",children:[s.jsxs("div",{className:"page-head",children:[s.jsxs("div",{children:[s.jsx("h1",{className:"page-title",children:"AI Assistant"}),s.jsx("p",{className:"page-sub",children:"Your recruiting copilot — powered by AI (interface preview)"})]}),s.jsxs("div",{className:"page-head-actions",children:[s.jsxs("span",{className:"integration-status pending",children:[s.jsx("span",{className:"pulse"}),"Model endpoint · Not connected"]}),s.jsxs("button",{className:"btn btn-secondary",onClick:()=>a(t=>t+1),children:[s.jsx(c,{name:"plus"})," New Chat"]})]})]}),s.jsx("div",{className:"card",children:s.jsx("div",{className:"card-body",children:s.jsx(i,{resetKey:e})})})]})}export{d as default};
|
||||
//# sourceMappingURL=AiAssistant-B1ZQ2wQY.js.map
|
||||
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"AiAssistant-B1ZQ2wQY.js","sources":["../../src/screens/AiAssistant.jsx"],"sourcesContent":["import { useState } from 'react'\r\nimport Chat from '../app/ai/Chat'\r\nimport { Icon } from '../ui/primitives'\r\n\r\nexport default function AiAssistant() {\r\n // Bumping the key resets the transcript — the old AI.newChat().\r\n const [resetKey, setResetKey] = useState(0)\r\n\r\n return (\r\n <div className=\"page\">\r\n <div className=\"page-head\">\r\n <div>\r\n <h1 className=\"page-title\">AI Assistant</h1>\r\n <p className=\"page-sub\">Your recruiting copilot — powered by AI (interface preview)</p>\r\n </div>\r\n <div className=\"page-head-actions\">\r\n <span className=\"integration-status pending\">\r\n <span className=\"pulse\" />Model endpoint · Not connected\r\n </span>\r\n <button className=\"btn btn-secondary\" onClick={() => setResetKey((k) => k + 1)}>\r\n <Icon name=\"plus\" /> New Chat\r\n </button>\r\n </div>\r\n </div>\r\n <div className=\"card\">\r\n <div className=\"card-body\">\r\n <Chat resetKey={resetKey} />\r\n </div>\r\n </div>\r\n </div>\r\n )\r\n}\r\n"],"names":["AiAssistant","resetKey","setResetKey","useState","jsxs","jsx","k","Icon","Chat"],"mappings":"8DAIA,SAAwBA,GAAc,CAEpC,KAAM,CAACC,EAAUC,CAAW,EAAIC,EAAAA,SAAS,CAAC,EAE1C,OACEC,EAAAA,KAAC,MAAA,CAAI,UAAU,OACb,SAAA,CAAAA,EAAAA,KAAC,MAAA,CAAI,UAAU,YACb,SAAA,CAAAA,OAAC,MAAA,CACC,SAAA,CAAAC,EAAAA,IAAC,KAAA,CAAG,UAAU,aAAa,SAAA,eAAY,EACvCA,EAAAA,IAAC,IAAA,CAAE,UAAU,WAAW,SAAA,6DAAA,CAA2D,CAAA,EACrF,EACAD,EAAAA,KAAC,MAAA,CAAI,UAAU,oBACb,SAAA,CAAAA,EAAAA,KAAC,OAAA,CAAK,UAAU,6BACd,SAAA,CAAAC,EAAAA,IAAC,OAAA,CAAK,UAAU,OAAA,CAAQ,EAAE,gCAAA,EAC5B,EACAD,EAAAA,KAAC,SAAA,CAAO,UAAU,oBAAoB,QAAS,IAAMF,EAAaI,GAAMA,EAAI,CAAC,EAC3E,SAAA,CAAAD,EAAAA,IAACE,EAAA,CAAK,KAAK,MAAA,CAAO,EAAE,WAAA,CAAA,CACtB,CAAA,CAAA,CACF,CAAA,EACF,EACAF,EAAAA,IAAC,MAAA,CAAI,UAAU,OACb,SAAAA,EAAAA,IAAC,MAAA,CAAI,UAAU,YACb,SAAAA,MAACG,EAAA,CAAK,SAAAP,CAAA,CAAoB,CAAA,CAC5B,CAAA,CACF,CAAA,EACF,CAEJ"}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
import{d,r as c,af as n,j as e,I as t,B as o}from"./index-BTPmxtwM.js";import{M as m}from"./Modal-B8aWFZt2.js";function p(){const{toast:l}=d(),[a,i]=c.useState(null),r=n.filter(s=>s.status==="Beta").length;return e.jsxs("div",{className:"page",children:[e.jsxs("div",{className:"page-head",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"page-title",children:"AI Studio"}),e.jsx("p",{className:"page-sub",children:"Next-generation AI modules — designed and API-ready for backend integration"})]}),e.jsx("div",{className:"page-head-actions",children:e.jsxs("span",{className:"integration-status pending",children:[e.jsx("span",{className:"pulse"}),r," in Beta"]})})]}),e.jsx("div",{className:"card brand-hero mb-18",children:e.jsxs("div",{className:"card-body",style:{display:"flex",alignItems:"center",gap:20,flexWrap:"wrap"},children:[e.jsx("div",{className:"ai-logo",style:{margin:0,width:56,height:56},children:e.jsx(t,{name:"sparkles"})}),e.jsxs("div",{style:{flex:1,minWidth:220},children:[e.jsx("h2",{style:{fontSize:19,marginBottom:4},children:"Everything is API-ready"}),e.jsx("p",{style:{opacity:.88},children:"Each module below ships with a complete, production-grade interface. Connect your model endpoint to activate them — no UI work required."})]}),e.jsxs("button",{className:"btn btn-on-brand",onClick:()=>l("Integration guide opened","info"),children:[e.jsx(t,{name:"external"})," Integration Guide"]})]})}),e.jsx("div",{className:"grid g-3",children:n.map(s=>e.jsx("div",{className:"card",style:{cursor:"pointer"},onClick:()=>i(s),children:e.jsxs("div",{className:"card-body",children:[e.jsxs("div",{className:"flex items-center",style:{justifyContent:"space-between",marginBottom:12},children:[e.jsx("span",{className:`kpi-icn ${s.cls}`,style:{width:46,height:46,borderRadius:13},children:e.jsx(t,{name:s.icon})}),e.jsx(o,{className:s.status==="Beta"?"b-indigo":"b-gray",children:s.status})]}),e.jsx("div",{className:"lr-title",style:{fontSize:15},children:s.name}),e.jsx("div",{className:"lr-sub",style:{marginTop:5,lineHeight:1.5},children:s.desc}),e.jsxs("div",{style:{marginTop:14,color:"var(--primary)",fontWeight:600,fontSize:13},children:[s.status==="Beta"?"Try it":"Join waitlist"," ",e.jsx(t,{name:"arrow-right"})]})]})},s.name))}),a&&e.jsxs(m,{title:a.name,subtitle:`${a.status} · AI Module`,size:"modal-lg",onClose:()=>i(null),footer:e.jsx("button",{className:"btn btn-secondary",onClick:()=>i(null),children:"Close"}),children:[e.jsxs("div",{className:"flex items-center gap-16",style:{marginBottom:18},children:[e.jsx("span",{className:`kpi-icn ${a.cls}`,style:{width:56,height:56,borderRadius:16},children:e.jsx(t,{name:a.icon})}),e.jsxs("div",{children:[e.jsx("div",{className:"fw-600",style:{fontSize:16},children:a.name}),e.jsx("div",{className:"text-muted",children:a.desc})]})]}),e.jsx("div",{className:"card",style:{boxShadow:"none",background:"var(--bg-sunken)"},children:e.jsxs("div",{className:"card-body",children:[e.jsx("div",{className:"form-section-title",style:{marginTop:0},children:"API Contract (preview)"}),e.jsx("pre",{className:"resume-thumb",style:{maxHeight:"none"},children:`POST /api/ai/${a.name.toLowerCase().replace(/ /g,"-")}
|
||||
{
|
||||
"context": { "jobId": "JOB-1001", "candidateIds": [...] },
|
||||
"options": { "model": "claude-opus", "stream": true }
|
||||
}
|
||||
|
||||
→ 200 OK
|
||||
{
|
||||
"result": { ... },
|
||||
"usage": { "tokens": 1240 }
|
||||
}`})]})}),e.jsxs("p",{className:"text-muted text-sm",style:{marginTop:14},children:[e.jsx(t,{name:"lock"})," This feature’s UI is complete. Backend wiring is the only remaining step."]})]})]})}export{p as default};
|
||||
//# sourceMappingURL=AiStudio-CIA10Amn.js.map
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,2 @@
|
|||
import{u as b,a as v,s as S,r as y,T as m,j as e,I as x,A as w}from"./index-BTPmxtwM.js";const D={"Phone Screen":"b-blue",Technical:"b-indigo","System Design":"b-purple","Onsite Loop":"b-teal","Hiring Manager":"b-amber","Culture Fit":"b-green","Final Round":"b-red"},f=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"];function C(l,i){const r=new Date(l,i,1).getDay(),c=new Date(l,i+1,0).getDate(),u=new Date(l,i,0).getDate(),s=[];for(let t=r-1;t>=0;t--)s.push({day:u-t,other:!0});for(let t=1;t<=c;t++)s.push({day:t,other:!1,date:new Date(l,i,t)});for(;s.length%7!==0||s.length<42;)s.push({day:s.length-c-r+1,other:!0});return s.slice(0,42)}function I(){const l=b(),{data:i=[]}=v(S("interviews")),[{year:r,month:c},u]=y.useState({year:m.getFullYear(),month:m.getMonth()}),s=y.useMemo(()=>C(r,c),[r,c]),t=new Date(r,c).toLocaleDateString("en-US",{month:"long",year:"numeric"}),g=m.toDateString(),j=i.filter(a=>a.when.toDateString()===g),p=a=>u(({year:d,month:o})=>{const h=o+a;return h<0?{year:d-1,month:11}:h>11?{year:d+1,month:0}:{year:d,month:h}}),N=a=>l("/candidates",{state:{openCandidate:a}});return e.jsxs("div",{className:"page",children:[e.jsxs("div",{className:"page-head",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"page-title",children:"Calendar"}),e.jsx("p",{className:"page-sub",children:"Interview schedule at a glance"})]}),e.jsxs("div",{className:"page-head-actions",children:[e.jsxs("div",{className:"flex items-center gap-8",children:[e.jsx("button",{className:"btn btn-icon btn-secondary",onClick:()=>p(-1),"aria-label":"Previous month",children:e.jsx(x,{name:"chevron-left"})}),e.jsx("span",{className:"fw-600",style:{minWidth:140,textAlign:"center"},children:t}),e.jsx("button",{className:"btn btn-icon btn-secondary",onClick:()=>p(1),"aria-label":"Next month",children:e.jsx(x,{name:"chevron-right"})})]}),e.jsxs("button",{className:"btn btn-primary",onClick:()=>l("/interviews",{state:{openSchedule:!0}}),children:[e.jsx(x,{name:"plus"})," Schedule"]})]})]}),e.jsxs("div",{className:"grid g-2-1",children:[e.jsx("div",{className:"card",children:e.jsx("div",{className:"card-body",children:e.jsxs("div",{className:"cal-grid",children:[f.map(a=>e.jsx("div",{className:"cal-dow",children:a},a)),s.map((a,d)=>{const o=!a.other&&a.date?i.filter(n=>n.when.toDateString()===a.date.toDateString()):[],h=!a.other&&a.date&&a.date.toDateString()===g;return e.jsxs("div",{className:`cal-cell ${a.other?"other":""} ${h?"today":""}`,children:[e.jsx("div",{className:"cal-date",children:a.day}),o.slice(0,3).map(n=>e.jsxs("div",{className:`cal-event ${D[n.type]||"b-blue"}`,title:`${n.candidate} · ${n.type}`,onClick:()=>N(n.candidateId),children:[n.when.toLocaleTimeString("en-US",{hour:"numeric"})," ",n.candidate.split(" ")[0]]},n.id)),o.length>3&&e.jsxs("div",{className:"cal-event b-gray",children:["+",o.length-3," more"]})]},d)})]})})}),e.jsxs("div",{className:"card",style:{alignSelf:"start"},children:[e.jsx("div",{className:"card-head",children:e.jsxs("div",{children:[e.jsx("h3",{children:"Today"}),e.jsx("span",{className:"ch-sub",children:m.toLocaleDateString("en-US",{month:"long",day:"numeric",year:"numeric"})})]})}),e.jsx("div",{className:"card-body",children:e.jsx("div",{className:"list-tight",children:j.length===0?e.jsx("p",{className:"text-muted",children:"No interviews today"}):j.map(a=>e.jsxs("div",{className:"list-row",style:{cursor:"pointer"},onClick:()=>N(a.candidateId),children:[e.jsx(w,{name:a.candidate,initials:a.candInitials,color:a.color}),e.jsxs("div",{className:"lr-main",children:[e.jsx("div",{className:"lr-title",children:a.candidate}),e.jsx("div",{className:"lr-sub",children:a.type})]}),e.jsx("div",{className:"lr-right",children:e.jsx("div",{className:"fw-600 text-sm",children:a.when.toLocaleTimeString("en-US",{hour:"numeric",minute:"2-digit"})})})]},a.id))})})]})]})]})}export{I as default};
|
||||
//# sourceMappingURL=Calendar-C28nSZlh.js.map
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,2 @@
|
|||
import{j as e,E as k,r as f,I as p}from"./index-BTPmxtwM.js";function N({columns:l,rows:i,pageSize:r=10}){const[t,o]=f.useState({key:null,dir:1}),[s,d]=f.useState(1);f.useEffect(()=>d(1),[i]);const a=f.useMemo(()=>{if(!t.key)return i;const n=l.find(c=>c.key===t.key);return[...i].sort((c,m)=>{let u=n!=null&&n.sortValue?n.sortValue(c):c[t.key],j=n!=null&&n.sortValue?n.sortValue(m):m[t.key];return typeof u=="string"&&(u=u.toLowerCase(),j=(j||"").toLowerCase()),u<j?-1*t.dir:u>j?1*t.dir:0})},[i,l,t]),h=a.length,g=Math.max(1,Math.ceil(h/r)),b=Math.min(s,g),x=(b-1)*r;function y(n){o(c=>c.key===n?{key:n,dir:c.dir*-1}:{key:n,dir:1})}return{pageRows:a.slice(x,x+r),sort:t,toggleSort:y,page:b,pages:g,setPage:d,from:h?x+1:0,to:Math.min(x+r,h),total:h,pageButtons:v(b,g)}}function v(l,i){const r=[];for(let t=1;t<=i;t++)t===1||t===i||Math.abs(t-l)<=1?r.push(t):r[r.length-1]!=="…"&&r.push("…");return r}function C({from:l,to:i,total:r,page:t,pages:o,setPage:s,pageButtons:d}){return e.jsxs("div",{className:"pagination",children:[e.jsxs("span",{className:"page-info",children:["Showing ",e.jsxs("b",{children:[l,"–",i]})," of ",e.jsx("b",{children:r})]}),e.jsxs("div",{className:"page-controls",children:[e.jsx("button",{className:"page-btn",disabled:t===1,onClick:()=>s(t-1),"aria-label":"Previous page",children:e.jsx(p,{name:"chevron-left"})}),d.map((a,h)=>a==="…"?e.jsx("span",{className:"page-btn",style:{cursor:"default"},children:"…"},`gap-${h}`):e.jsx("button",{className:`page-btn ${a===t?"active":""}`,onClick:()=>s(a),"aria-current":a===t?"page":void 0,children:a},a)),e.jsx("button",{className:"page-btn",disabled:t===o,onClick:()=>s(t+1),"aria-label":"Next page",children:e.jsx(p,{name:"chevron-right"})})]})]})}function S({columns:l,rows:i,pageSize:r=10,empty:t}){const o=N({columns:l,rows:i,pageSize:r});return e.jsxs("div",{className:"dt",children:[e.jsx("div",{className:"table-wrap",children:e.jsxs("table",{className:"data",children:[e.jsx("thead",{children:e.jsx("tr",{children:l.map(s=>{const d=o.sort.key===s.key,a=[s.sortable?"sortable":"",d?o.sort.dir===1?"sorted-asc":"sorted-desc":""].filter(Boolean).join(" ");return e.jsxs("th",{className:a,style:{textAlign:s.align||"left"},onClick:s.sortable?()=>o.toggleSort(s.key):void 0,children:[s.label,s.sortable&&e.jsx("span",{className:"sort-ind",children:d?o.sort.dir===1?"▲":"▼":"⇅"})]},s.key)})})}),e.jsx("tbody",{children:o.pageRows.length===0?e.jsx("tr",{children:e.jsx("td",{colSpan:l.length,children:e.jsx(k,{children:t})})}):o.pageRows.map((s,d)=>e.jsx("tr",{children:l.map(a=>e.jsx("td",{style:{textAlign:a.align||"left"},children:a.render?a.render(s):s[a.key]??""},a.key))},s.id??d))})]})}),e.jsx(C,{...o})]})}export{S as D,C as P,N as u};
|
||||
//# sourceMappingURL=DataTable-D5imKbZq.js.map
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,2 @@
|
|||
import{d as c,r as d,j as e,I as i}from"./index-BTPmxtwM.js";const l=[{q:"How do I create a new job requisition?",a:'Navigate to Jobs and click "Create Job". Fill in the required fields marked with an asterisk and click Save. The job will immediately appear in your listings.'},{q:"How does the AI candidate score work?",a:"The AI score (0–100) evaluates how well a candidate matches the job requirements based on skills, experience, and education. Higher scores indicate stronger matches."},{q:"Can I move candidates between pipeline stages?",a:"Yes. Open the Pipeline view and simply drag any candidate card between stage columns. The candidate’s status updates automatically."},{q:"How do I schedule an interview?",a:'Go to Interviews or Calendar and click "Schedule Interview". Select the candidate, round, date, time, and interviewers.'},{q:"How do I export reports?",a:'On the Reports page, use the "Export Report" button for a full PDF, or the CSV buttons on individual tables.'}],o=[{icn:"file",t:"Documentation",d:"Complete product guides",cls:"i-indigo"},{icn:"video",t:"Video Tutorials",d:"Watch step-by-step walkthroughs",cls:"i-red"},{icn:"message",t:"Live Chat",d:"Chat with our support team",cls:"i-green"},{icn:"users",t:"Community",d:"Connect with other recruiters",cls:"i-purple"}];function p(){const{toast:n}=c(),[t,r]=d.useState(null);return e.jsxs("div",{className:"page",children:[e.jsx("div",{className:"page-head",children:e.jsxs("div",{children:[e.jsx("h1",{className:"page-title",children:"Help Center"}),e.jsx("p",{className:"page-sub",children:"Find answers and get support"})]})}),e.jsx("div",{className:"card brand-hero mb-18",children:e.jsxs("div",{className:"card-body",style:{padding:32,textAlign:"center"},children:[e.jsx("h2",{style:{fontSize:22,marginBottom:8},children:"How can we help you?"}),e.jsx("p",{style:{opacity:.85,marginBottom:18},children:"Search our knowledge base or browse the topics below"}),e.jsxs("div",{className:"topbar-search",style:{maxWidth:480,margin:"0 auto"},children:[e.jsx(i,{name:"search"}),e.jsx("input",{placeholder:"Search help articles…"})]})]})}),e.jsx("div",{className:"grid g-kpi mb-18",children:o.map(s=>e.jsx("div",{className:"card",style:{cursor:"pointer"},onClick:()=>n(`Opening ${s.t}`,"info"),children:e.jsxs("div",{className:"card-body",style:{textAlign:"center"},children:[e.jsx("span",{className:`kpi-icn ${s.cls}`,style:{margin:"0 auto 12px",width:48,height:48,borderRadius:14},children:e.jsx(i,{name:s.icn})}),e.jsx("div",{className:"fw-600",children:s.t}),e.jsx("div",{className:"lr-sub",style:{marginTop:4},children:s.d})]})},s.t))}),e.jsxs("div",{className:"card",children:[e.jsx("div",{className:"card-head",children:e.jsx("div",{children:e.jsx("h3",{children:"Frequently Asked Questions"})})}),e.jsx("div",{className:"card-body",children:l.map((s,a)=>e.jsxs("div",{className:"setting-row",style:{cursor:"pointer",flexDirection:"column",alignItems:"stretch"},onClick:()=>r(t===a?null:a),children:[e.jsxs("div",{className:"flex items-center",style:{justifyContent:"space-between"},children:[e.jsx("h4",{children:s.q}),e.jsx("span",{style:{color:"var(--text-3)",transition:".2s",transform:t===a?"rotate(90deg)":"rotate(0deg)"},children:e.jsx(i,{name:"chevron-right"})})]}),t===a&&e.jsx("p",{style:{marginTop:10},children:s.a})]},s.q))})]})]})}export{p as default};
|
||||
//# sourceMappingURL=Help-CrblBaFq.js.map
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,2 @@
|
|||
import{r as l,av as N,j as t,I as g}from"./index-BTPmxtwM.js";let c=0;function w(){c+=1,document.body.style.overflow="hidden"}function R(){c=Math.max(0,c-1),c===0&&(document.body.style.overflow="")}const j='a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])';function L({open:d=!0,title:i,subtitle:u,size:p,footer:f,onClose:s,children:E}){const m=l.useRef(null),x=l.useRef(null),n=l.useCallback(()=>s==null?void 0:s(),[s]);return l.useEffect(()=>{var a,b;if(!d)return;x.current=document.activeElement,w();const r=m.current;(b=(a=(r==null?void 0:r.querySelector(j))??r)==null?void 0:a.focus)==null||b.call(a);const v=e=>{if(e.key==="Escape"){e.stopPropagation(),n();return}if(e.key!=="Tab"||!r)return;const o=Array.from(r.querySelectorAll(j)).filter(k=>k.offsetParent!==null);if(!o.length)return;const h=o[0],y=o[o.length-1];e.shiftKey&&document.activeElement===h?(e.preventDefault(),y.focus()):!e.shiftKey&&document.activeElement===y&&(e.preventDefault(),h.focus())};return document.addEventListener("keydown",v,!0),()=>{var e,o;document.removeEventListener("keydown",v,!0),R(),(o=(e=x.current)==null?void 0:e.focus)==null||o.call(e)}},[d,n]),d?N.createPortal(t.jsxs("div",{className:"modal-root open",children:[t.jsx("div",{className:"modal-backdrop",onClick:n}),t.jsxs("div",{className:`modal ${p||""}`,role:"dialog","aria-modal":"true","aria-label":typeof i=="string"?i:void 0,tabIndex:-1,ref:m,children:[t.jsxs("div",{className:"modal-head",children:[t.jsxs("div",{children:[t.jsx("h2",{children:i}),u&&t.jsx("p",{children:u})]}),t.jsx("button",{className:"modal-close",onClick:n,"aria-label":"Close",children:t.jsx(g,{name:"x"})})]}),t.jsx("div",{className:"modal-body",children:E}),f&&t.jsx("div",{className:"modal-foot",children:f})]})]}),document.body):null}export{L as M};
|
||||
//# sourceMappingURL=Modal-B8aWFZt2.js.map
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,2 @@
|
|||
import{d as m,a as x,s as h,g as j,j as s,I as i}from"./index-BTPmxtwM.js";function u(){const{toast:t}=m(),{data:o=[]}=x(h("notifications")),n=j("notifications"),l=a=>n(e=>e.map((c,r)=>r===a?{...c,unread:!1}:c)),d=()=>{n(a=>a.map(e=>({...e,unread:!1}))),t("All notifications marked as read","success")};return s.jsxs("div",{className:"page",children:[s.jsxs("div",{className:"page-head",children:[s.jsxs("div",{children:[s.jsx("h1",{className:"page-title",children:"Notifications"}),s.jsx("p",{className:"page-sub",children:"Stay on top of hiring activity"})]}),s.jsxs("div",{className:"page-head-actions",children:[s.jsxs("button",{className:"btn btn-secondary",onClick:d,children:[s.jsx(i,{name:"check"})," Mark all read"]}),s.jsx("button",{className:"btn btn-ghost",onClick:()=>t("Notification settings","info"),children:s.jsx(i,{name:"more"})})]})]}),s.jsx("div",{className:"card",children:s.jsx("div",{className:"list-tight",style:{padding:0},children:o.map((a,e)=>s.jsxs("div",{className:`notif-row${a.unread?" unread":""}`,onClick:()=>l(e),children:[s.jsx("span",{className:`notif-icn ${a.color}`,children:s.jsx(i,{name:a.icon})}),s.jsxs("div",{className:"notif-body",children:[s.jsx("div",{className:"notif-title",children:a.title}),s.jsx("div",{className:"notif-text",children:a.text}),s.jsx("div",{className:"notif-time",children:a.time})]}),a.unread&&s.jsx("span",{className:"dot dot-blue",style:{position:"static",border:"none",alignSelf:"center"}})]},a.id??`${a.title}-${e}`))})})]})}export{u as default};
|
||||
//# sourceMappingURL=Notifications-C-babC9D.js.map
|
||||
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"Notifications-C-babC9D.js","sources":["../../src/screens/Notifications.jsx"],"sourcesContent":["import { useQuery } from '@tanstack/react-query'\r\nimport { Icon } from '../ui/primitives'\r\nimport { useToast } from '../ui/Toast'\r\nimport { seedQuery, useSeedMutation } from '../data/seedQueries'\r\n\r\nexport default function Notifications() {\r\n const { toast } = useToast()\r\n const { data: notifications = [] } = useQuery(seedQuery('notifications'))\r\n const update = useSeedMutation('notifications')\r\n\r\n // Marking one read used to be `this.classList.remove('unread')` — a DOM edit\r\n // the badge count never saw. Writing to the cache keeps the sidebar in sync.\r\n const markOne = (i) => update((ns) => ns.map((n, j) => (j === i ? { ...n, unread: false } : n)))\r\n const markAll = () => {\r\n update((ns) => ns.map((n) => ({ ...n, unread: false })))\r\n toast('All notifications marked as read', 'success')\r\n }\r\n\r\n return (\r\n <div className=\"page\">\r\n <div className=\"page-head\">\r\n <div>\r\n <h1 className=\"page-title\">Notifications</h1>\r\n <p className=\"page-sub\">Stay on top of hiring activity</p>\r\n </div>\r\n <div className=\"page-head-actions\">\r\n <button className=\"btn btn-secondary\" onClick={markAll}><Icon name=\"check\" /> Mark all read</button>\r\n <button className=\"btn btn-ghost\" onClick={() => toast('Notification settings', 'info')}>\r\n <Icon name=\"more\" />\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <div className=\"card\">\r\n <div className=\"list-tight\" style={{ padding: 0 }}>\r\n {notifications.map((n, i) => (\r\n <div\r\n key={n.id ?? `${n.title}-${i}`}\r\n className={`notif-row${n.unread ? ' unread' : ''}`}\r\n onClick={() => markOne(i)}\r\n >\r\n <span className={`notif-icn ${n.color}`}><Icon name={n.icon} /></span>\r\n <div className=\"notif-body\">\r\n <div className=\"notif-title\">{n.title}</div>\r\n <div className=\"notif-text\">{n.text}</div>\r\n <div className=\"notif-time\">{n.time}</div>\r\n </div>\r\n {n.unread && (\r\n <span className=\"dot dot-blue\" style={{ position: 'static', border: 'none', alignSelf: 'center' }} />\r\n )}\r\n </div>\r\n ))}\r\n </div>\r\n </div>\r\n </div>\r\n )\r\n}\r\n"],"names":["Notifications","toast","useToast","notifications","useQuery","seedQuery","update","useSeedMutation","markOne","i","ns","n","j","markAll","jsxs","jsx","Icon"],"mappings":"2EAKA,SAAwBA,GAAgB,CACtC,KAAM,CAAE,MAAAC,CAAA,EAAUC,EAAA,EACZ,CAAE,KAAMC,EAAgB,CAAA,GAAOC,EAASC,EAAU,eAAe,CAAC,EAClEC,EAASC,EAAgB,eAAe,EAIxCC,EAAWC,GAAMH,EAAQI,GAAOA,EAAG,IAAI,CAACC,EAAGC,IAAOA,IAAMH,EAAI,CAAE,GAAGE,EAAG,OAAQ,EAAA,EAAUA,CAAE,CAAC,EACzFE,EAAU,IAAM,CACpBP,EAAQI,GAAOA,EAAG,IAAKC,IAAO,CAAE,GAAGA,EAAG,OAAQ,EAAA,EAAQ,CAAC,EACvDV,EAAM,mCAAoC,SAAS,CACrD,EAEA,OACEa,EAAAA,KAAC,MAAA,CAAI,UAAU,OACb,SAAA,CAAAA,EAAAA,KAAC,MAAA,CAAI,UAAU,YACb,SAAA,CAAAA,OAAC,MAAA,CACC,SAAA,CAAAC,EAAAA,IAAC,KAAA,CAAG,UAAU,aAAa,SAAA,gBAAa,EACxCA,EAAAA,IAAC,IAAA,CAAE,UAAU,WAAW,SAAA,gCAAA,CAA8B,CAAA,EACxD,EACAD,EAAAA,KAAC,MAAA,CAAI,UAAU,oBACb,SAAA,CAAAA,EAAAA,KAAC,SAAA,CAAO,UAAU,oBAAoB,QAASD,EAAS,SAAA,CAAAE,EAAAA,IAACC,EAAA,CAAK,KAAK,OAAA,CAAQ,EAAE,gBAAA,EAAc,EAC3FD,EAAAA,IAAC,SAAA,CAAO,UAAU,gBAAgB,QAAS,IAAMd,EAAM,wBAAyB,MAAM,EACpF,SAAAc,MAACC,EAAA,CAAK,KAAK,OAAO,CAAA,CACpB,CAAA,CAAA,CACF,CAAA,EACF,QAEC,MAAA,CAAI,UAAU,OACb,SAAAD,EAAAA,IAAC,OAAI,UAAU,aAAa,MAAO,CAAE,QAAS,CAAA,EAC3C,WAAc,IAAI,CAACJ,EAAGF,IACrBK,EAAAA,KAAC,MAAA,CAEC,UAAW,YAAYH,EAAE,OAAS,UAAY,EAAE,GAChD,QAAS,IAAMH,EAAQC,CAAC,EAExB,SAAA,CAAAM,EAAAA,IAAC,OAAA,CAAK,UAAW,aAAaJ,EAAE,KAAK,GAAI,SAAAI,EAAAA,IAACC,EAAA,CAAK,KAAML,EAAE,IAAA,CAAM,EAAE,EAC/DG,EAAAA,KAAC,MAAA,CAAI,UAAU,aACb,SAAA,CAAAC,EAAAA,IAAC,MAAA,CAAI,UAAU,cAAe,SAAAJ,EAAE,MAAM,EACtCI,EAAAA,IAAC,MAAA,CAAI,UAAU,aAAc,WAAE,KAAK,EACpCA,EAAAA,IAAC,MAAA,CAAI,UAAU,aAAc,WAAE,IAAA,CAAK,CAAA,EACtC,EACCJ,EAAE,QACDI,EAAAA,IAAC,OAAA,CAAK,UAAU,eAAe,MAAO,CAAE,SAAU,SAAU,OAAQ,OAAQ,UAAW,SAAS,CAAG,CAAA,CAAA,EAXhGJ,EAAE,IAAM,GAAGA,EAAE,KAAK,IAAIF,CAAC,EAAA,CAc/B,EACH,CAAA,CACF,CAAA,EACF,CAEJ"}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,2 @@
|
|||
import{d as A,u as D,a as p,s as v,g as C,r,j as e,I,A as y,S as T}from"./index-BTPmxtwM.js";const j=[{name:"Applied",color:"var(--stage-1)"},{name:"Screening",color:"var(--stage-2)"},{name:"Assessment",color:"var(--stage-3)"},{name:"Interview",color:"var(--stage-4)"},{name:"Offer",color:"var(--stage-5)"},{name:"Hired",color:"var(--stage-6)"},{name:"Rejected",color:"var(--stage-7)"}];function O(){const{toast:h}=A(),u=D(),{data:l=[]}=p(v("candidates")),{data:x=[]}=p(v("jobs")),N=C("candidates"),[d,f]=r.useState(""),[c,o]=r.useState(null),[b,i]=r.useState(null),g=r.useMemo(()=>d?l.filter(a=>a.jobId===d):l,[l,d]),k=r.useMemo(()=>{const a=Object.fromEntries(j.map(n=>[n.name,[]]));for(const n of g)a[n.stage]&&a[n.stage].push(n);return a},[g]);function S(a){i(null);const n=c;if(o(null),!n)return;const s=l.find(t=>t.id===n);!s||s.stage===a||(N(t=>t.map(m=>m.id===n?{...m,stage:a,status:a}:m)),h(`${s.name} moved to ${a}`,"success"))}return e.jsxs("div",{className:"page",children:[e.jsxs("div",{className:"page-head",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"page-title",children:"Pipeline"}),e.jsx("p",{className:"page-sub",children:"Drag candidates between stages to update their status"})]}),e.jsxs("div",{className:"page-head-actions",children:[e.jsxs("select",{className:"select",value:d,onChange:a=>f(a.target.value),children:[e.jsx("option",{value:"",children:"All Jobs"}),x.filter(a=>a.status==="Open").map(a=>e.jsx("option",{value:a.id,children:a.title},a.id))]}),e.jsxs("button",{className:"btn btn-primary",onClick:()=>u("/candidates",{state:{openAdd:!0}}),children:[e.jsx(I,{name:"plus"})," Add Candidate"]})]})]}),e.jsx("div",{className:"kanban",children:j.map(a=>{const n=k[a.name]??[];return e.jsxs("div",{className:"kanban-col",children:[e.jsxs("div",{className:"kanban-col-head",children:[e.jsx("span",{className:"k-dot",style:{background:a.color}}),e.jsx("h4",{children:a.name}),e.jsx("span",{className:"k-count",children:n.length})]}),e.jsx("div",{className:`kanban-cards${b===a.name?" drag-over":""}`,onDragOver:s=>{s.preventDefault(),i(a.name)},onDragLeave:()=>i(s=>s===a.name?null:s),onDrop:s=>{s.preventDefault(),S(a.name)},children:n.map(s=>e.jsxs("div",{className:`k-card${c===s.id?" dragging":""}`,draggable:!0,onDragStart:t=>{o(s.id),t.dataTransfer.effectAllowed="move",t.dataTransfer.setData("text/plain",s.id)},onDragEnd:()=>{o(null),i(null)},onClick:()=>{c||u("/candidates",{state:{openCandidate:s.id}})},children:[e.jsxs("div",{className:"k-card-top",children:[e.jsx(y,{name:s.name,initials:s.initials,color:s.color}),e.jsxs("div",{children:[e.jsx("div",{className:"kc-name",children:s.name}),e.jsx("div",{className:"kc-role",children:s.currentTitle})]})]}),e.jsx("div",{className:"kc-role",children:s.jobTitle}),e.jsx("div",{className:"k-tags",children:s.skills.slice(0,3).map(t=>e.jsx("span",{className:"tag",children:t},t))}),e.jsxs("div",{className:"k-card-meta",children:[e.jsx("span",{className:"cell-sub",children:s.currentCompany}),e.jsx(T,{score:s.aiScore})]})]},s.id))})]},a.name)})})]})}export{j as KANBAN_STAGES,O as default};
|
||||
//# sourceMappingURL=Pipeline-Bhzm15UM.js.map
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,2 @@
|
|||
import{r as u,j as e}from"./index-BTPmxtwM.js";function d({tabs:n,value:c,onChange:o,className:r="tabs"}){const l=u.useId();return e.jsx("div",{className:r,role:"tablist",children:n.map(s=>{const a=s.key??s,i=s.label??s,t=a===c;return e.jsxs("button",{id:`${l}-${a}`,role:"tab","aria-selected":t,className:`tab${t?" active":""}`,onClick:()=>o(a),children:[i,s.count!=null&&e.jsx("span",{className:"tab-count",children:s.count})]},a)})})}export{d as T};
|
||||
//# sourceMappingURL=Tabs-DVZeUemd.js.map
|
||||
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"Tabs-DVZeUemd.js","sources":["../../src/ui/Tabs.jsx"],"sourcesContent":["/* ============================================================\r\n Tabs.jsx — new primitive.\r\n\r\n js/ui.js had no tab component, so settings (10 tabs), candidates (8), inbox\r\n (7) and rbac each hand-rolled one by pre-rendering every pane and toggling\r\n `.active`. One component replaces four ad-hoc implementations, and only the\r\n active pane is mounted — which also means a chart in a hidden pane no longer\r\n draws into a zero-width canvas.\r\n ============================================================ */\r\n\r\nimport { useId, useState } from 'react'\r\n\r\nexport function Tabs({ tabs, value, onChange, className = 'tabs' }) {\r\n const id = useId()\r\n return (\r\n <div className={className} role=\"tablist\">\r\n {tabs.map((t) => {\r\n const key = t.key ?? t\r\n const label = t.label ?? t\r\n const active = key === value\r\n return (\r\n <button\r\n key={key}\r\n id={`${id}-${key}`}\r\n role=\"tab\"\r\n aria-selected={active}\r\n className={`tab${active ? ' active' : ''}`}\r\n onClick={() => onChange(key)}\r\n >\r\n {label}\r\n {t.count != null && <span className=\"tab-count\">{t.count}</span>}\r\n </button>\r\n )\r\n })}\r\n </div>\r\n )\r\n}\r\n\r\n/** Uncontrolled convenience wrapper: <TabPanel tabs={[{key,label,render}]} /> */\r\nexport default function TabPanel({ tabs, initial, className }) {\r\n const [value, setValue] = useState(initial ?? tabs[0]?.key)\r\n const active = tabs.find((t) => t.key === value) ?? tabs[0]\r\n return (\r\n <>\r\n <Tabs tabs={tabs} value={value} onChange={setValue} className={className} />\r\n <div role=\"tabpanel\">{active?.render?.()}</div>\r\n </>\r\n )\r\n}\r\n"],"names":["Tabs","tabs","value","onChange","className","id","useId","jsx","t","key","label","active","jsxs"],"mappings":"+CAYO,SAASA,EAAK,CAAE,KAAAC,EAAM,MAAAC,EAAO,SAAAC,EAAU,UAAAC,EAAY,QAAU,CAClE,MAAMC,EAAKC,EAAAA,MAAA,EACX,OACEC,MAAC,OAAI,UAAAH,EAAsB,KAAK,UAC7B,SAAAH,EAAK,IAAKO,GAAM,CACf,MAAMC,EAAMD,EAAE,KAAOA,EACfE,EAAQF,EAAE,OAASA,EACnBG,EAASF,IAAQP,EACvB,OACEU,EAAAA,KAAC,SAAA,CAEC,GAAI,GAAGP,CAAE,IAAII,CAAG,GAChB,KAAK,MACL,gBAAeE,EACf,UAAW,MAAMA,EAAS,UAAY,EAAE,GACxC,QAAS,IAAMR,EAASM,CAAG,EAE1B,SAAA,CAAAC,EACAF,EAAE,OAAS,MAAQD,EAAAA,IAAC,QAAK,UAAU,YAAa,WAAE,KAAA,CAAM,CAAA,CAAA,EARpDE,CAAA,CAWX,CAAC,CAAA,CACH,CAEJ"}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
import{d as P,a as S,s as F,g as R,r as u,j as e,I as v,Q as O,E as f,h as _,A as k,S as D,B as I,y as M,z as q,q as B}from"./index-BTPmxtwM.js";import{t as L,A as $,C as H,l as Q}from"./Candidates-DDm6mZmg.js";import"./useMutation-CMO99S-s.js";import"./Modal-B8aWFZt2.js";import"./DataTable-D5imKbZq.js";import"./Tabs-DVZeUemd.js";import"./jobPosts-CNShlpwX.js";const T=100,y=["Applied","Screening","Assessment","Interview","Offer","Hired"],w={PENDING:"Applied",CLOSED:"Applied",PROCESS:"Screening",ONHOLD:"Screening",APPROVED:"Hired",REJECTED:"Rejected"};function G(t){const a=parseInt(t,10);return Number.isFinite(a)?a:null}function z(t,a){const r=t.name||a.name,i=(t.job_posts||[]).map(h=>h.title).find(Boolean),o=w[t.application_status]||a.stage,d=G(t.experience);return{...a,userId:t.user_id,name:r,initials:q(r),color:M(r),email:t.email||a.email,experience:d??a.experience,stage:o,status:o,currentTitle:i||a.currentTitle,jobTitle:i||a.jobTitle}}function J(t,a){if(!a.length)return[];const r=new Map;for(const i of t){const o=i.user_id??`inbox-${i.inbox_id}`;r.has(o)||r.set(o,i)}return[...r.values()].map((i,o)=>z(i,a[o%a.length]))}function ee(){const{toast:t}=P(),{data:a=[]}=S(F("candidates")),r=R("candidates"),[i,o]=u.useState(""),[d,h]=u.useState(""),[N,c]=u.useState(null),[b,x]=u.useState(null),p=S({queryKey:B.candidates.list({limit:T}),queryFn:()=>Q({limit:T})}),g=u.useMemo(()=>J(L(p.data),a),[p.data,a]),C=u.useMemo(()=>g.filter(s=>!(d&&s.department!==d||i&&!(s.name+s.currentCompany+s.skills.join(" ")).toLowerCase().includes(i.toLowerCase()))),[g,i,d]);function A(s){r(n=>n.map(l=>l.id===s.id?{...l,favorite:!l.favorite}:l)),c(n=>n&&n.id===s.id?{...n,favorite:!n.favorite}:n),t(s.favorite?"Removed from favorites":`${s.name} added to favorites`,"success")}function E(s){const n=y.indexOf(s.stage);if(n===-1||n>=y.length-1){t(`${s.name} cannot be advanced further`,"warning");return}const l=y[n+1];r(m=>m.map(j=>j.id===s.id?{...j,stage:l,status:l}:j)),c(m=>m&&m.id===s.id?{...m,stage:l,status:l}:m),t(`${s.name} moved to ${l}`,"success")}return e.jsxs("div",{className:"page",children:[e.jsxs("div",{className:"page-head",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"page-title",children:"Talent Pool"}),e.jsxs("p",{className:"page-sub",children:[g.length," silver-medalists & passive candidates to re-engage"]})]}),e.jsx("div",{className:"page-head-actions",children:e.jsxs("button",{className:"btn btn-primary",onClick:()=>t("Talent campaign created","success"),children:[e.jsx(v,{name:"send"})," Start Campaign"]})})]}),e.jsx("div",{className:"card mb-18",children:e.jsx("div",{className:"card-body",style:{padding:16},children:e.jsxs("div",{className:"toolbar",style:{marginBottom:0},children:[e.jsxs("div",{className:"toolbar-search",children:[e.jsx(v,{name:"search"}),e.jsx("input",{value:i,onChange:s=>o(s.target.value),placeholder:"Search by name, skill, company…"})]}),e.jsxs("select",{className:"select",value:d,onChange:s=>h(s.target.value),children:[e.jsx("option",{value:"",children:"All Departments"}),O.map(s=>e.jsx("option",{children:s},s))]})]})})}),e.jsx("div",{className:"grid g-3",children:C.length===0?e.jsx("div",{style:{gridColumn:"1/-1"},children:p.isError?e.jsx(f,{title:"Could not load talent pool",children:_(p.error,"Please try again.")}):p.isPending?e.jsx(f,{title:"Loading talent pool…",children:"Fetching candidates."}):e.jsx(f,{title:"No talent found",children:"Try a different search or department."})}):C.map(s=>e.jsx("div",{className:"card",style:{cursor:"pointer"},onClick:()=>c(s),children:e.jsxs("div",{className:"card-body",children:[e.jsxs("div",{className:"flex items-center gap-12",style:{marginBottom:12},children:[e.jsx(k,{name:s.name,initials:s.initials,color:s.color,className:"avatar-lg"}),e.jsxs("div",{style:{flex:1,minWidth:0},children:[e.jsx("div",{className:"lr-title",children:s.name}),e.jsx("div",{className:"lr-sub",children:s.currentTitle})]}),e.jsx(D,{score:s.aiScore})]}),e.jsx("div",{className:"k-tags",style:{marginBottom:12},children:s.skills.slice(0,4).map(n=>e.jsx("span",{className:"tag",children:n},n))}),e.jsx("div",{className:"divider",style:{margin:"12px 0"}}),e.jsxs("div",{className:"flex items-center",style:{justifyContent:"space-between"},children:[e.jsxs("span",{className:"cell-sub",children:[e.jsx(v,{name:"briefcase"})," ",s.experience," yrs"]}),e.jsx("span",{className:"cell-sub",children:s.currentCompany}),e.jsx(I,{className:"b-gray",children:s.source})]})]})},s.id))}),b&&e.jsx($,{candidate:b,onClose:()=>x(null),onProfile:s=>{x(null),c(s)}}),N&&e.jsx(H,{candidate:N,onClose:()=>c(null),onAdvance:E,onToggleFav:A,onAtsMatch:s=>{c(null),x(s)}})]})}export{ee as default};
|
||||
//# sourceMappingURL=TalentPool-CbXp920L.js.map
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,2 @@
|
|||
import{a1 as i}from"./index-BTPmxtwM.js";function f({search:a,top:e,skip:t,ids:r,activeOnly:o=!0}={}){const n=Array.isArray(r)?r.filter(Boolean).join(","):r;return i("/job/fetch",{params:{search:a,top:e,skip:t,ids:n||void 0,active_only:o}})}export{f as l};
|
||||
//# sourceMappingURL=jobPosts-CNShlpwX.js.map
|
||||
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"jobPosts-CNShlpwX.js","sources":["../../src/api/jobPosts.js"],"sourcesContent":["import { request } from '../lib/apiClient'\r\n\r\n/**\r\n * Active job posts — Job Matching hydrates suggestions and the manual picker.\r\n *\r\n * Permissioned with job_board.view (not jobs.*). `ids` is a comma-joined list\r\n * so one round trip can resolve a whole suggestion rail.\r\n */\r\nexport function list({ search, top, skip, ids, activeOnly = true } = {}) {\r\n const idParam = Array.isArray(ids) ? ids.filter(Boolean).join(',') : ids\r\n return request('/job/fetch', {\r\n params: {\r\n search,\r\n top,\r\n skip,\r\n ids: idParam || undefined,\r\n active_only: activeOnly,\r\n },\r\n })\r\n}\r\n"],"names":["list","search","top","skip","ids","activeOnly","idParam","request"],"mappings":"yCAQO,SAASA,EAAK,CAAE,OAAAC,EAAQ,IAAAC,EAAK,KAAAC,EAAM,IAAAC,EAAK,WAAAC,EAAa,EAAI,EAAK,GAAI,CACvE,MAAMC,EAAU,MAAM,QAAQF,CAAG,EAAIA,EAAI,OAAO,OAAO,EAAE,KAAK,GAAG,EAAIA,EACrE,OAAOG,EAAQ,aAAc,CAC3B,OAAQ,CACN,OAAAN,EACA,IAAAC,EACA,KAAAC,EACA,IAAKG,GAAW,OAChB,YAAaD,CACnB,CACA,CAAG,CACH"}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
import{a1 as e}from"./index-BTPmxtwM.js";function o(){return e("/roles/fetch")}function s(r){return e("/roles/create",{method:"POST",body:r})}export{s as c,o as l};
|
||||
//# sourceMappingURL=roles-DSy_gQji.js.map
|
||||
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"roles-DSy_gQji.js","sources":["../../src/api/roles.js"],"sourcesContent":["import { request } from '../lib/apiClient'\r\n\r\n/** Roles with their expanded `bundles` and resolved `effective_permissions`. */\r\nexport function listRoles() {\r\n return request('/roles/fetch')\r\n}\r\nexport function createRole(body) {\r\n return request('/roles/create', { method: 'POST', body })\r\n}\r\nexport function updateRole(recordId, body) {\r\n return request('/roles/update', { method: 'PUT', params: { record_id: recordId }, body })\r\n}\r\nexport function deleteRole(recordId) {\r\n return request('/roles/delete', { method: 'DELETE', params: { record_id: recordId } })\r\n}\r\n\r\n/** Permission bundles (41 seeded), each resolving to a set of tag names. */\r\nexport function listPermissions() {\r\n return request('/permissions/fetch')\r\n}\r\nexport function createPermission(body) {\r\n return request('/permissions/create', { method: 'POST', body })\r\n}\r\nexport function updatePermission(recordId, body) {\r\n return request('/permissions/update', { method: 'PUT', params: { record_id: recordId }, body })\r\n}\r\n\r\n/** The 104-tag catalog: 13 modules x 8 actions. */\r\nexport function listPermissionTags() {\r\n return request('/permission-tags/fetch')\r\n}\r\n"],"names":["listRoles","request","createRole","body"],"mappings":"yCAGO,SAASA,GAAY,CAC1B,OAAOC,EAAQ,cAAc,CAC/B,CACO,SAASC,EAAWC,EAAM,CAC/B,OAAOF,EAAQ,gBAAiB,CAAE,OAAQ,OAAQ,KAAAE,CAAI,CAAE,CAC1D"}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
var R=i=>{throw TypeError(i)};var E=(i,t,s)=>t.has(i)||R("Cannot "+s);var e=(i,t,s)=>(E(i,t,"read from private field"),s?s.call(i):t.get(i)),b=(i,t,s)=>t.has(i)?R("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(i):t.set(i,s),p=(i,t,s,r)=>(E(i,t,"write to private field"),r?r.call(i,s):t.set(i,s),s),y=(i,t,s)=>(E(i,t,"access private method"),s);import{ao as q,ap as U,aq as j,ar as k,as as P,e as L,r as v,at as A,au as D}from"./index-BTPmxtwM.js";var a,c,o,h,n,C,S,w,I=(w=class extends q{constructor(t,s){super();b(this,n);b(this,a);b(this,c);b(this,o);b(this,h);p(this,a,t),this.setOptions(s),this.bindMethods(),y(this,n,C).call(this)}bindMethods(){this.mutate=this.mutate.bind(this),this.reset=this.reset.bind(this)}setOptions(t){var r;const s=this.options;this.options=e(this,a).defaultMutationOptions(t),U(this.options,s)||e(this,a).getMutationCache().notify({type:"observerOptionsUpdated",mutation:e(this,o),observer:this}),s!=null&&s.mutationKey&&this.options.mutationKey&&j(s.mutationKey)!==j(this.options.mutationKey)?this.reset():((r=e(this,o))==null?void 0:r.state.status)==="pending"&&e(this,o).setOptions(this.options)}onUnsubscribe(){var t;this.hasListeners()||(t=e(this,o))==null||t.removeObserver(this)}onMutationUpdate(t){y(this,n,C).call(this),y(this,n,S).call(this,t)}getCurrentResult(){return e(this,c)}reset(){var t;(t=e(this,o))==null||t.removeObserver(this),p(this,o,void 0),y(this,n,C).call(this),y(this,n,S).call(this)}mutate(t,s){var r;return p(this,h,s),(r=e(this,o))==null||r.removeObserver(this),p(this,o,e(this,a).getMutationCache().build(e(this,a),this.options)),e(this,o).addObserver(this),e(this,o).execute(t)}},a=new WeakMap,c=new WeakMap,o=new WeakMap,h=new WeakMap,n=new WeakSet,C=function(){var s;const t=((s=e(this,o))==null?void 0:s.state)??k();p(this,c,{...t,isPending:t.status==="pending",isSuccess:t.status==="success",isError:t.status==="error",isIdle:t.status==="idle",mutate:this.mutate,reset:this.reset})},S=function(t){P.batch(()=>{var s,r,u,f,d,O,x,K;if(e(this,h)&&this.hasListeners()){const m=e(this,c).variables,M=e(this,c).context,g={client:e(this,a),meta:this.options.meta,mutationKey:this.options.mutationKey};if((t==null?void 0:t.type)==="success"){try{(r=(s=e(this,h)).onSuccess)==null||r.call(s,t.data,m,M,g)}catch(l){Promise.reject(l)}try{(f=(u=e(this,h)).onSettled)==null||f.call(u,t.data,null,m,M,g)}catch(l){Promise.reject(l)}}else if((t==null?void 0:t.type)==="error"){try{(O=(d=e(this,h)).onError)==null||O.call(d,t.error,m,M,g)}catch(l){Promise.reject(l)}try{(K=(x=e(this,h)).onSettled)==null||K.call(x,void 0,t.error,m,M,g)}catch(l){Promise.reject(l)}}}this.listeners.forEach(m=>{m(e(this,c))})})},w);function z(i,t){const s=L(),[r]=v.useState(()=>new I(s,i));v.useEffect(()=>{r.setOptions(i)},[r,i]);const u=v.useSyncExternalStore(v.useCallback(d=>r.subscribe(P.batchCalls(d)),[r]),()=>r.getCurrentResult(),()=>r.getCurrentResult()),f=v.useCallback((d,O)=>{r.mutate(d,O).catch(A)},[r]);if(u.error&&D(r.options.throwOnError,[u.error]))throw u.error;return{...u,mutate:f,mutateAsync:u.mutate}}export{z as u};
|
||||
//# sourceMappingURL=useMutation-CMO99S-s.js.map
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,32 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="light">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<!-- viewport-fit=cover lets the layout reach under the iOS notch/home bar;
|
||||
the safe-area insets in styles.css keep content clear of them.
|
||||
No maximum-scale/user-scalable — pinch-zoom must stay available. -->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||
<meta name="color-scheme" content="light dark" />
|
||||
<meta name="mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
||||
<meta name="format-detection" content="telephone=no" />
|
||||
<!-- Per-route titles are set at runtime by useRouteMeta. -->
|
||||
<title>TalentFlow · Applicant Tracking System</title>
|
||||
<meta name="theme-color" content="#004d43" media="(prefers-color-scheme: light)" />
|
||||
<meta name="theme-color" content="#0e1d1f" media="(prefers-color-scheme: dark)" />
|
||||
|
||||
<!-- Utopia brand type: Belleza (main headings) + Inter as the metric-
|
||||
compatible stand-in for Neue Montreal, which is a licensed face.
|
||||
If Neue Montreal is installed locally it wins via the CSS stack. -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Belleza&family=Inter:wght@400;500;600;700;800&display=swap" />
|
||||
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><rect width='100' height='100' rx='22' fill='%23004d43'/><g transform='translate(14 32) scale(0.72)'><path d='M100 3.65C97.86 20.99 91.89 43.03 79.48 55.33 76 58.77 71.84 61.46 66.96 62.14 50.4 64.46 41.84 47.5 29.07 42.7 21.85 39.98 14.5 42.02 9.66 47.95 6.54 51.78 4.49 56.35 2.97 61.13 2.41 61.64 0.97 61.66 0 61.31L0 0.13C1.05 0 2.27 0.02 3.09 0.28 14.9 15.86 26.77 30.82 40.15 45.28L60.79 24.7C67.38 18.22 74.41 12.74 82.59 8.51 88.11 5.83 93.64 3.93 100 3.65Z' fill='%23ceff71'/></g></svg>" />
|
||||
<script type="module" crossorigin src="/assets/index-BTPmxtwM.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-CSn67wit.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
</html>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue